diff --git a/.github/actions/docker-build-push/action.yml b/.github/actions/docker-build-push/action.yml index f4e806e0f1..0fe559bf26 100644 --- a/.github/actions/docker-build-push/action.yml +++ b/.github/actions/docker-build-push/action.yml @@ -14,6 +14,10 @@ inputs: description: True if the image should be published required: true default: "false" + load: + description: True to load the built image into the local Docker daemon (for post-build verification steps); ignored when push is true + required: false + default: "false" gcrJsonKey: description: JSON key for Google Container Registry service account (required if push is true) required: false @@ -69,6 +73,7 @@ runs: labels: | revision=${{ github.sha }} push: ${{ inputs.push == 'true' }} + load: ${{ inputs.push != 'true' && inputs.load == 'true' }} cache-from: type=local,src=/tmp/.buildx-cache cache-to: type=local,dest=/tmp/.buildx-cache-new diff --git a/.github/actions/install-yarn-deps/action.yml b/.github/actions/install-yarn-deps/action.yml index 3a3725fb04..dba3951a4d 100644 --- a/.github/actions/install-yarn-deps/action.yml +++ b/.github/actions/install-yarn-deps/action.yml @@ -41,6 +41,10 @@ runs: # Note: lockfile checksums remain enforced (YARN_CHECKSUM_BEHAVIOR # is left at its default), so per-package integrity is still checked. export YARN_ENABLE_HARDENED_MODE=0 + # Git dependencies may run Corepack outside this workspace's pinned + # packageManager context. Use its known default there instead of + # querying yarn/latest, which can be rate-limited by the npm registry. + export COREPACK_DEFAULT_TO_LATEST=0 corepack enable yarn --version unset_args=() diff --git a/.github/workflows/client.yml b/.github/workflows/client.yml index 1de973a959..fdbc0dabbc 100644 --- a/.github/workflows/client.yml +++ b/.github/workflows/client.yml @@ -6,6 +6,7 @@ on: push: branches: - main + - dev paths-ignore: - "docs/**" - "infrastructure/**" @@ -28,6 +29,15 @@ on: # Automatic releases are now handled by the dedicated release.yml workflow +# One concurrency group per PR: re-pushing a PR cancels the superseded +# run (only the newest commit's run gates the PR). push / schedule / +# workflow_dispatch runs get their own group per run id with cancellation +# disabled, so main/dev pushes and the nightly schedule are never +# cancelled by a concurrent run. +concurrency: + group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.run_id }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: client-detect-changes: runs-on: ubuntu-latest @@ -60,7 +70,15 @@ jobs: filters: | path-filter: - './config/_electrum_urls/**' - - './pkg/bitcoin/electrum/**' + - './config/electrum*.go' + - './pkg/bitcoin/**' + - './internal/testdata/bitcoin/**' + - './go.mod' + - './go.sum' + - './third_party/**' + - './.github/workflows/client.yml' +# btcec-vendor-byte-identity runs on every event, every branch - gating by path was +# producing broken `if:` combinations with no upside. btcec-vendor-byte-identity: # Enforces the VENDOR.md byte-identity recipe and runs the # vendored upstream test suite. The root module's `go test ./...` @@ -74,9 +92,9 @@ jobs: - uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: - go-version: '1.24.1' + go-version-file: "go.mod" - name: Verify vendored btcec byte identity vs upstream v0.22.3 run: | @@ -112,7 +130,103 @@ jobs: run: | cd third_party/btcsuite/btcec && go test ./... - client-build-test-publish: + electrum-vendor-byte-identity: + # Enforces the VENDOR.md byte-identity recipe for go-electrum and + # runs the vendored upstream test suite. Mirrors the btcec-vendor-byte-identity + # job pattern: runs on every event, every branch without path gating. + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.24.1' + + - name: Verify vendored go-electrum byte identity vs upstream v0.0.0-20240206170935-6038cb594daa + run: | + set -e + go mod download github.com/keep-network/go-electrum@v0.0.0-20240206170935-6038cb594daa + upstream="$(go env GOMODCACHE)/github.com/keep-network/go-electrum@v0.0.0-20240206170935-6038cb594daa/electrum" + rm -rf /tmp/electrum-upstream + cp -R "$upstream" /tmp/electrum-upstream + chmod -R u+w /tmp/electrum-upstream + gofmt -w /tmp/electrum-upstream + + # Hash manifest comparison: every file in the upstream tree + # (minus vendoring-only files and locally patched files) must match + # the vendored copy byte-for-byte, and the file set must match exactly. + manifest() { + ( cd "$1" && find . -type f \ + ! -name go.mod ! -name go.sum ! -name LICENSE ! -name VENDOR.md \ + ! -name network.go ! -name transport.go ! -name transport_ws.go \ + ! -name scripthash.go \ + ! -name cancellation_test.go ! -name network_test.go \ + -print0 | sort -z | xargs -0 sha256sum ) + } + manifest /tmp/electrum-upstream | sort > /tmp/up.txt + manifest third_party/go-electrum/electrum | sort > /tmp/vend.txt + if ! diff -q /tmp/up.txt /tmp/vend.txt > /dev/null; then + echo '::error::Vendored go-electrum differs from upstream v0.0.0-20240206170935-6038cb594daa beyond the allowed local patches:' + diff /tmp/up.txt /tmp/vend.txt | head -40 + exit 1 + fi + + # Verify file sets match (no extra or missing files outside exclusions) + filelist() { + ( cd "$1" && find . -type f \ + ! -name go.mod ! -name go.sum ! -name LICENSE ! -name VENDOR.md \ + ! -name network.go ! -name transport.go ! -name transport_ws.go \ + ! -name scripthash.go \ + ! -name cancellation_test.go ! -name network_test.go \ + -printf '%P\n' | sort ) + } + filelist /tmp/electrum-upstream > /tmp/up_files.txt + filelist third_party/go-electrum/electrum | sort > /tmp/vend_files.txt + if ! diff -q /tmp/up_files.txt /tmp/vend_files.txt > /dev/null; then + echo '::error::File set mismatch between upstream and vendored go-electrum (outside allowed patches):' + diff /tmp/up_files.txt /tmp/vend_files.txt + exit 1 + fi + echo 'byte-identity OK' + + - name: Verify local patches differ from upstream + run: | + set -e + go mod download github.com/keep-network/go-electrum@v0.0.0-20240206170935-6038cb594daa + upstream="$(go env GOMODCACHE)/github.com/keep-network/go-electrum@v0.0.0-20240206170935-6038cb594daa/electrum" + # The four patched files MUST differ from upstream. + for f in network.go transport.go transport_ws.go scripthash.go; do + if diff -q "$upstream/$f" "third_party/go-electrum/electrum/$f" > /dev/null; then + echo "::error::Patched file $f is byte-identical to upstream - local patch appears missing" + exit 1 + fi + done + echo 'local patches verified (non-empty diffs)' + + - name: Run vendored go-electrum test suite + run: | + cd third_party/go-electrum && go test -race ./... + + electrum-lifecycle: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: "go.mod" + # Root ./... does not include tests inside the vendored Go module. + - name: Test Electrum lifecycle and native transports with the race detector + run: >- + go test -race -timeout 3m -count=1 + ./pkg/bitcoin/electrum ./config + github.com/checksum0/go-electrum/electrum + + # R2: the `go-build-env` Docker image is built once, up front, so the + # two test shards below can run against it in parallel and + # `client-build-test-publish` / `client-build-artifacts` consume it as + # an artifact without rebuilding. Same path-filter gating as before. + client-build-image: needs: client-detect-changes if: | github.event_name != 'pull_request' @@ -138,14 +252,48 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Cache Docker layers - uses: actions/cache@v4 + # R3 - per-branch Docker layer cache, one stable entry per push: + # save key = -buildx--- (immutable, + # no restore-keys on save - each sha is a fresh entry) + # deps hash = first 16 hex chars of sha256(Dockerfile, go.mod, go.sum, + # third_party/*/go.mod, third_party/*/go.sum) + # + # Restore (actions/cache/restore, `if: always()`) runs on every event. + # Save (actions/cache/save) runs only after a successful `Move cache`, + # gated to push / workflow_dispatch, so ephemeral PR refs and the + # nightly run never write to the branch pool, and a build or move + # failure can never publish a stale/incomplete cache under the + # immutable sha key - the save step simply does not run. + - name: Compute buildx deps hash + id: deps-hash + run: | + set -eu + # Recurse into third_party (btcsuite/btcec is nested two + # levels deep, go-electrum only one - `find` catches both). + files="Dockerfile go.mod go.sum" + if [ -d third_party ]; then + files="$files $(find third_party \( -name go.mod -o -name go.sum \) | LC_ALL=C sort)" + fi + # shellcheck disable=SC2086 # intentional word splitting + deps="$(sha256sum $files | sha256sum | awk '{print $1}' | cut -c1-16)" + echo "hash=${deps}" >> "$GITHUB_OUTPUT" + + - name: Restore Docker layer cache + if: always() + uses: actions/cache/restore@v4 with: path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ github.sha }} + key: ${{ runner.os }}-buildx-${{ github.ref_name }}-${{ steps.deps-hash.outputs.hash }}-${{ github.sha }} restore-keys: | + ${{ runner.os }}-buildx-${{ github.event.pull_request.base.ref && github.event.pull_request.base.ref || github.ref_name }}-${{ steps.deps-hash.outputs.hash }}- + ${{ runner.os }}-buildx-${{ github.event.pull_request.base.ref && github.event.pull_request.base.ref || github.ref_name }}- + ${{ runner.os }}-buildx-${{ github.sha }} ${{ runner.os }}-buildx- + - name: Ensure cache directory exists + if: always() + run: mkdir -p /tmp/.buildx-cache + - name: Build Docker Build Image uses: docker/build-push-action@v5 with: @@ -176,22 +324,252 @@ jobs: name: go-build-env-image path: /tmp/go-build-env-image.tar - - name: Run Go tests + - # Temp fix - move cache instead of copying (added below step and + # modified value of `cache-to`). + # https://github.com/docker/build-push-action/issues/252 + # https://github.com/moby/buildkit/issues/1896 + # Without the change some jobs were failing with `no space left on device`. + # On pull_request / schedule the cache step is restore-only, so the + # move is a no-op. On push / workflow_dispatch the move stages the + # freshly-built layers at /tmp/.buildx-cache for the `Save Docker + # layer cache` step below. + name: Move cache + if: success() + run: | + rm -rf /tmp/.buildx-cache + if [ -d /tmp/.buildx-cache-new ]; then + mv /tmp/.buildx-cache-new /tmp/.buildx-cache + fi + + # Explicit save, placed after a successful `Move cache` rather than + # relying on the combined actions/cache@v4's implicit end-of-job + # save: with the combined action the save fires from a post-job + # hook regardless of whether the build or move failed, which could + # publish the pre-build (stale/incomplete) restored layers under + # this run's immutable sha key - a dead entry that can never be + # corrected once written. actions/cache/save has no restore-keys + # (it is write-only) and only runs here, in-line, after Move cache + # has already succeeded. + - name: Save Docker layer cache + if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' + uses: actions/cache/save@v4 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.ref_name }}-${{ steps.deps-hash.outputs.hash }}-${{ github.sha }} + + # R2: 2-way sharded `go test ./...`. Both shards run in parallel on + # the `go-build-env` image; each executes a deterministic half of the + # sorted package list and uploads its own coverage profile. The + # merged 14% coverage gate runs in `client-build-test-publish` + # (the required-check context), which aggregates both shards. + client-go-tests: + needs: [client-detect-changes, client-build-image] + if: | + github.event_name != 'pull_request' + || needs.client-detect-changes.outputs.path-filter == 'true' + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + shard: [1, 2] + steps: + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Download Docker Build Image + uses: actions/download-artifact@v4 + with: + name: go-build-env-image + path: /tmp + + - name: Load Docker Build Image + run: | + docker load --input /tmp/go-build-env-image.tar + + # Deterministic 2-way split: `go list ./...` output is sorted + # (LC_ALL=C) and halved by index - shard 1 takes the first half, + # shard 2 the second - so the two shards together cover exactly + # the package set of the previous unsharded `./...` run. Both + # shards compute the split independently from the same image and + # checkout, so the split is stable across the two runs. + - name: Run Go tests (shard ${{ matrix.shard }}/2) run: | - mkdir -p ${{ github.workspace }}/coverage + set -euo pipefail + packages="$(docker run \ + --workdir /go/src/github.com/keep-network/keep-core \ + go-build-env \ + sh -c 'go list ./... | LC_ALL=C sort')" + total="$(printf '%s\n' "$packages" | grep -c . || true)" + if [ "$total" -lt 2 ]; then + echo "::error::Package list too short to shard (${total:-0} packages); refusing to run an incomplete test suite" + exit 1 + fi + half=$(( (total + 1) / 2 )) + if [ "${{ matrix.shard }}" = "1" ]; then + start=1 + end=$half + else + start=$(( half + 1 )) + end=$total + fi + shard_packages="$(printf '%s\n' "$packages" | sed -n "${start},${end}p")" + echo "::notice::Shard ${{ matrix.shard }}/2: packages ${start}-${end} of ${total}" docker run \ --workdir /go/src/github.com/keep-network/keep-core \ - -v ${{ github.workspace }}/coverage:/coverage \ + -e SHARD_PACKAGES="$(echo "$shard_packages" | tr '\n' ' ')" \ + -v "${{ github.workspace }}/coverage:/coverage" \ go-build-env \ - gotestsum -- -timeout 15m -coverprofile=/coverage/coverage.out ./... + sh -c 'gotestsum -- -timeout 15m -coverprofile=/coverage/coverage.out $SHARD_PACKAGES' - name: Upload coverage report uses: actions/upload-artifact@v4 with: - name: go-coverage + name: go-coverage-shard-${{ matrix.shard }} path: coverage/coverage.out + if-no-files-found: error + + # R2: aggregator behind the required `client-build-test-publish` + # check context. Fails whenever either test shard fails (via + # `needs`), or when the merged coverage gate below fails - the 14% + # total-coverage threshold is unchanged and is applied to the merged + # profile of both shards, exactly as before. + client-build-test-publish: + needs: [client-detect-changes, client-go-tests] + if: | + github.event_name != 'pull_request' + || needs.client-detect-changes.outputs.path-filter == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version-file: "go.mod" + + - name: Download coverage report (shard 1) + uses: actions/download-artifact@v4 + with: + name: go-coverage-shard-1 + path: coverage/shard-1 + + - name: Download coverage report (shard 2) + uses: actions/download-artifact@v4 + with: + name: go-coverage-shard-2 + path: coverage/shard-2 + + # Coverage gate: 14% minimum total. Baseline measured at PR #4256 + # (2026-08-19); no automated baseline-update mechanism exists. + # Merges the two shard profiles into one (the shards' per-package + # blocks do not overlap, so a set-union over the block records is + # equivalent to the single unsharded profile) and applies the + # original 14% gate to the merged total. + - name: Check coverage gate + run: | + set -eu + for f in coverage/shard-1/coverage.out coverage/shard-2/coverage.out; do + if [ ! -s "$f" ]; then + echo "::error::Missing or empty shard coverage profile $f; the coverage gate cannot run" + exit 1 + fi + done + { echo 'mode: set' + grep -hv '^mode:' coverage/shard-1/coverage.out coverage/shard-2/coverage.out \ + | LC_ALL=C sort -u + } > coverage/coverage.merged.out + go tool cover -func coverage/coverage.merged.out > /tmp/cover-func.txt + TOTAL=$(grep '^total:' /tmp/cover-func.txt | awk '{print $3}' | tr -d '%') + echo "Total coverage: ${TOTAL}%" + PASS=$(awk -v t="$TOTAL" 'BEGIN { print (t+0 >= 14) ? "yes" : "no" }') + if [ "$PASS" != "yes" ]; then + echo "::error::Coverage ${TOTAL}% is below the 14% minimum threshold" + exit 1 + fi + + - name: Upload merged coverage report + if: success() + uses: actions/upload-artifact@v4 + with: + name: go-coverage + path: coverage/coverage.merged.out if-no-files-found: warn + # R1: runtime image, client binaries and their archive moved off the + # PR critical path. This job runs in parallel with + # `client-integration-test` / `client-bench` and consumes the + # `go-build-env-image` artifact; the GCR publish and CI-notify steps + # keep their original `workflow_dispatch`-only gating. A failure here + # still red-lights the run. + client-build-artifacts: + needs: [client-detect-changes, client-build-image] + if: | + github.event_name != 'pull_request' + || needs.client-detect-changes.outputs.path-filter == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + # Fetch the whole history for the `git describe` command to work. + fetch-depth: 0 + + - name: Resolve versions + run: | + echo "version=$(git describe --tags --match "v[0-9]*" HEAD)" >> $GITHUB_ENV + echo "revision=$(git rev-parse --short HEAD)" >> $GITHUB_ENV + + - name: Load environment variables + uses: keep-network/ci/actions/load-env-variables@v2 + if: github.event_name == 'workflow_dispatch' + with: + environment: ${{ github.event.inputs.environment }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + # R3 consumer of the per-branch Docker layer cache written by + # `client-build-image`. This job is the second buildx user in a + # run and is restore-only - it never writes the branch's primary + # cache entry. The same deps-hash step is duplicated here + # because the two jobs run on separate runners. + - name: Compute buildx deps hash + id: deps-hash + run: | + set -eu + # Recurse into third_party (btcsuite/btcec is nested two + # levels deep, go-electrum only one - `find` catches both). + files="Dockerfile go.mod go.sum" + if [ -d third_party ]; then + files="$files $(find third_party \( -name go.mod -o -name go.sum \) | LC_ALL=C sort)" + fi + # shellcheck disable=SC2086 # intentional word splitting + deps="$(sha256sum $files | sha256sum | awk '{print $1}' | cut -c1-16)" + echo "hash=${deps}" >> "$GITHUB_OUTPUT" + + - name: Restore Docker layer cache + if: always() + uses: actions/cache/restore@v4 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.ref_name }}-${{ steps.deps-hash.outputs.hash }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx-${{ github.event.pull_request.base.ref && github.event.pull_request.base.ref || github.ref_name }}-${{ steps.deps-hash.outputs.hash }}- + ${{ runner.os }}-buildx-${{ github.event.pull_request.base.ref && github.event.pull_request.base.ref || github.ref_name }}- + ${{ runner.os }}-buildx-${{ github.sha }} + ${{ runner.os }}-buildx- + + - name: Ensure cache directory exists + if: always() + run: mkdir -p /tmp/.buildx-cache + + - name: Download Docker Build Image + uses: actions/download-artifact@v4 + with: + name: go-build-env-image + path: /tmp + + - name: Load Docker Build Image + run: | + docker load --input /tmp/go-build-env-image.tar - name: Build Docker Runtime Image if: github.event_name != 'workflow_dispatch' @@ -202,6 +580,7 @@ jobs: version=${{ env.version }} revision=${{ env.revision }} push: false + cache-from: type=local,src=/tmp/.buildx-cache context: . - name: Login to Google Container Registry @@ -232,6 +611,7 @@ jobs: VERSION=${{ env.version }} REVISION=${{ env.revision }} push: true + cache-from: type=local,src=/tmp/.buildx-cache context: . - name: Build Client Binaries @@ -244,8 +624,20 @@ jobs: VERSION=${{ env.version }} REVISION=${{ env.revision }} push: false + cache-from: type=local,src=/tmp/.buildx-cache context: . + - name: Verify Linux release compatibility + run: | + release_dir=$(mktemp -d) + trap 'rm -rf "$release_dir"' EXIT + tar -xzf out/bin/*-linux-amd64.tar.gz -C "$release_dir" + for image in debian:bullseye-slim ubuntu:20.04; do + docker run --rm --platform linux/amd64 \ + --mount "type=bind,src=$release_dir,dst=/release,readonly" \ + "$image" sh -ec 'getconf GNU_LIBC_VERSION; /release/keep-client --version' + done + - name: Archive Client Binaries uses: actions/upload-artifact@v4 with: @@ -279,16 +671,6 @@ jobs: upstream_ref: ${{ github.event.inputs.upstream_ref }} version: ${{ env.version }} - - # Temp fix - move cache instead of copying (added below step and - # modified value of `cache-to`). - # https://github.com/docker/build-push-action/issues/252 - # https://github.com/moby/buildkit/issues/1896 - # Without the change some jobs were failing with `no space left on device` - name: Move cache - run: | - rm -rf /tmp/.buildx-cache - mv /tmp/.buildx-cache-new /tmp/.buildx-cache - client-scan: needs: client-detect-changes if: | @@ -302,7 +684,7 @@ jobs: - uses: securego/gosec@master with: args: | - -exclude=G115,G118 + -exclude=G118 -exclude-dir=pkg/chain/ethereum/beacon/gen -exclude-dir=pkg/chain/ethereum/ecdsa/gen -exclude-dir=pkg/chain/ethereum/threshold/gen @@ -317,7 +699,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 + - uses: actions/setup-go@v6 with: go-version-file: "go.mod" - name: gofmt @@ -335,7 +717,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 + - uses: actions/setup-go@v6 with: go-version-file: "go.mod" - run: go vet @@ -348,16 +730,267 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 + - uses: actions/setup-go@v6 with: go-version-file: "go.mod" - name: Staticcheck uses: dominikh/staticcheck-action@v1.4.0 with: - version: "2025.1.1" + version: "2026.1" install-go: false checks: "-SA1019" + client-bench: + needs: [client-build-test-publish] + if: | + github.event_name == 'workflow_dispatch' + || github.event_name == 'schedule' + || github.event_name == 'pull_request' + || github.event_name == 'push' + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + pull-requests: write + env: + # PRs and the nightly schedule compare against the target/current + # branch's own history; workflow_dispatch runs compare against prior + # workflow_dispatch runs on the selected ref. + BENCHMARK_BASELINE_BRANCH: ${{ github.event_name == 'pull_request' && github.base_ref || github.ref_name }} + BENCHMARK_BASELINE_EVENT: ${{ github.event_name == 'workflow_dispatch' && 'workflow_dispatch' || 'push' }} + steps: + - uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Set up Go + uses: actions/setup-go@v6 + with: + go-version-file: "go.mod" + cache: false + + - name: Download Docker Build Image + uses: actions/download-artifact@v4 + with: + name: go-build-env-image + path: /tmp + + - name: Load Docker Build Image + run: | + docker load --input /tmp/go-build-env-image.tar + + # Baseline lookup: the most recent successful `go-bench` artifact from a + # `BENCHMARK_BASELINE_EVENT` run of client.yml. Branch refs use + # `BENCHMARK_BASELINE_BRANCH`; manually selected tags use their commit. + # `search_artifacts: true` is required because the newest matching run is + # not guaranteed to be the newest run overall, and it may not carry a + # `go-bench` artifact at all. A genuine absence of any matching artifact + # is reported (`if_no_artifact_found: warn`) rather than failing the job; + # any other download/API error surfaces as a normal step failure. + - name: Download previous benchmark results + id: download-prev + uses: dawidd6/action-download-artifact@bf251b5aa9c2f7eeb574a96ee720e24f801b7c11 # v6 + with: + name: go-bench + path: bench-prev + workflow: client.yml + branch: ${{ github.ref_type != 'tag' && env.BENCHMARK_BASELINE_BRANCH || '' }} + commit: ${{ github.ref_type == 'tag' && github.sha || '' }} + event: ${{ env.BENCHMARK_BASELINE_EVENT }} + search_artifacts: true + if_no_artifact_found: warn + + - name: Report missing benchmark baseline + if: steps.download-prev.outputs.found_artifact != 'true' + run: | + echo "::notice::No go-bench artifact found for a successful ${{ env.BENCHMARK_BASELINE_EVENT }} run of client.yml on ${{ env.BENCHMARK_BASELINE_BRANCH }}; comparison skipped. Pull requests require a successful push run on the target branch; other events require a successful matching ref/event run." + + - name: Run benchmarks + run: | + docker run \ + --workdir /go/src/github.com/keep-network/keep-core \ + go-build-env \ + go test -bench=. -benchmem -count=10 -run='^$' ./pkg/... \ + > bench.txt + cat bench.txt + + - name: Install benchstat + run: go install golang.org/x/perf/cmd/benchstat@v0.0.0-20260813145340-fd4a688df892 + + # Benchmark regression check: >12% slower than the baseline + # established by the most recent successful push run on the + # target/current branch (main/dev pushes seed their own branch's + # baseline as they land), or, for workflow_dispatch runs, the + # most recent successful workflow_dispatch run on the selected + # ref. A pull request's own `go-bench` artifact is never used as + # a baseline and never seeds its base branch. + # + # R5/D4: the comparison is always computed and posted; only the + # gate is event-dependent (below). + - name: Compare benchmarks + id: compare + if: steps.download-prev.outputs.found_artifact == 'true' && hashFiles('bench-prev/**') != '' + run: | + python3 - <<'EOF' + import glob, re + + def parse(path): + keys = set() + pkg = None + with open(path) as f: + for line in f: + line = line.rstrip("\n") + if line.startswith("pkg: "): + pkg = line[len("pkg: "):].strip() + continue + if not line.startswith("Benchmark"): + continue + tokens = line.split() + if len(tokens) < 4: + continue + name = re.sub(r'-\d+$', '', tokens[0]) # strip Go's trailing GOMAXPROCS suffix + values = tokens[2:] + for i in range(0, len(values) - 1, 2): + keys.add((pkg, name, values[i + 1])) + return keys + + prev_keys = set() + for path in glob.glob('bench-prev/*.txt'): + prev_keys |= parse(path) + curr_keys = parse('bench.txt') + + new_keys = sorted(curr_keys - prev_keys, key=lambda k: (k[0] or '', k[1], k[2])) + if new_keys: + print(f"::notice::{len(new_keys)} benchmark metric(s) have no baseline yet and are excluded from the regression check:") + for pkg, name, unit in new_keys: + print(f"::notice:: {pkg or 'unknown package'}: {name} ({unit})") + EOF + + benchstat bench-prev/*.txt bench.txt | tee benchstat-results.txt + + # D4: hard regression gate, enforced on pushes to the + # development trunk (`dev`) and on the nightly schedule (which + # runs the full suite on `main`), plus manual dispatch runs. + # A regression can only reach `main` after passing the `dev` + # gate, so pushes to `main` are not re-gated. + - name: Fail on benchmark regression + if: | + !cancelled() + && steps.compare.outcome == 'success' + && (github.event_name == 'schedule' + || github.event_name == 'workflow_dispatch' + || (github.event_name == 'push' && github.ref_name == 'dev')) + run: | + python3 - <<'EOF' + import sys, re + content = open('benchstat-results.txt').read() + regressions = [] + for line in content.splitlines(): + if '~' in line or not line.strip(): + continue + m = re.search(r'\+(\d+\.\d+)%', line) + if m and float(m.group(1)) > 12: + regressions.append(line) + if regressions: + print('Performance regressions >12% detected:') + for r in regressions: + print(' ', r) + sys.exit(1) + print('No benchmark regressions >12% against baseline.') + EOF + + # D4: on pull requests the same regression is advisory - reported + # in the job log, the job summary, and the PR comment, but the + # check reports success so a PR is never blocked by it. + - name: Report benchmark regression (advisory on pull_request) + if: | + !cancelled() + && github.event_name == 'pull_request' + && steps.compare.outcome == 'success' + run: | + python3 - <<'EOF' + import os + import re + content = open('benchstat-results.txt').read() + regressions = [] + for line in content.splitlines(): + if '~' in line or not line.strip(): + continue + m = re.search(r'\+(\d+\.\d+)%', line) + if m and float(m.group(1)) > 12: + regressions.append(line) + if regressions: + print('::warning::Performance regressions >12% detected (advisory on pull requests):') + for r in regressions: + print(f'::warning:: {r}') + with open(os.environ['GITHUB_STEP_SUMMARY'], 'a') as f: + f.write('## Benchmark regression (advisory)\n\n') + f.write('The following benchmarks regressed >12% against the baseline. ' + 'On pull requests this is advisory; the regression is a hard ' + 'failure on the push to dev that lands it and on the nightly ' + 'schedule run.\n\n') + for r in regressions: + f.write(f'- `{r}`\n') + else: + print('No benchmark regressions >12% against baseline.') + with open(os.environ['GITHUB_STEP_SUMMARY'], 'a') as f: + f.write('## Benchmark check\n\nNo regressions >12% against the baseline.\n') + EOF + + # Publish the same comparison that already gates the job into the PR + # conversation so reviewers see it without leaving the PR. The body is + # identified by an HTML marker; re-runs update the same comment instead + # of stacking one per push. `continue-on-error` defends against an org + # policy that strips comment-write permissions from GITHUB_TOKEN — the + # diff in the job log and the go-bench artifact remain authoritative. + - name: Post benchmark results to PR + if: ${{ always() && github.event_name == 'pull_request' }} + continue-on-error: true + env: + HAS_BASELINE: ${{ steps.download-prev.outputs.found_artifact == 'true' }} + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const marker = ''; + const header = '### `client-bench` results'; + const baselineNote = process.env.HAS_BASELINE === 'true' + ? 'Baseline: latest successful push on the target branch. Regressions >12% are advisory on pull requests (hard-fail on push to dev and on the nightly schedule).' + : 'No baseline yet — the next push on the target branch will seed it.'; + let benchSection; + try { + const benchstat = fs.readFileSync('benchstat-results.txt', 'utf-8').trim(); + benchSection = `\n\n
benchstat vs baseline\n\n\`\`\`\n${benchstat}\n\`\`\`\n
\n`; + } catch (err) { + benchSection = ''; + } + const body = `${marker}\n${header}\n\n${baselineNote}${benchSection}`; + const { owner, repo } = context.repo; + const issue_number = context.payload.pull_request.number; + const { data: comments } = await github.rest.issues.listComments({ + owner, repo, issue_number, + }); + const existing = comments.find(c => c.body && c.body.includes(marker)); + if (existing) { + await github.rest.issues.updateComment({ + owner, repo, comment_id: existing.id, body, + }); + } else { + await github.rest.issues.createComment({ + owner, repo, issue_number, body, + }); + } + + - name: Upload benchmark results + if: always() + uses: actions/upload-artifact@v4 + with: + name: go-bench + path: bench.txt + overwrite: true + if-no-files-found: warn + client-integration-test: needs: [client-detect-changes, electrum-integration-detect-changes, client-build-test-publish] if: | @@ -375,12 +1008,126 @@ jobs: path: /tmp - name: Load Docker Build Image + id: load-image run: | docker load --input /tmp/go-build-env-image.tar - name: Run Go Integration Tests + env: + ETHEREUM_MAINNET_RPC_URL: ${{ secrets.ETHEREUM_MAINNET_RPC_URL }} run: | docker run \ + -e ETHEREUM_MAINNET_RPC_URL \ --workdir /go/src/github.com/keep-network/keep-core \ go-build-env \ - gotestsum -- -timeout 20m -tags=integration ./... + sh -ec 'packages=$(go list ./...); + packages=$(printf "%s\n" "$packages" | grep -v "/pkg/bitcoin/electrum$"); + gotestsum -- -timeout 20m -tags=integration $packages' + + # Public Electrum servers can time out independently of this PR. Run + # their tests separately so they cannot mask other integration failures. + # They remain required for Bitcoin client/config/dependency changes and + # for every push, scheduled run, and manual run. + - name: Run public Electrum integration tests + if: ${{ !cancelled() && steps.load-image.outcome == 'success' }} + continue-on-error: ${{ github.event_name == 'pull_request' && needs.electrum-integration-detect-changes.outputs.path-filter == 'false' }} + run: | + docker run \ + --workdir /go/src/github.com/keep-network/keep-core \ + go-build-env \ + gotestsum -- -timeout 20m -tags=integration ./pkg/bitcoin/electrum + + # R8 aggregator gate: closes the fail-open edge of the dorny/paths-filter + # stub pattern - a `dorny/paths-filter` crash in `client-detect-changes` + # would otherwise propagate as a Success on every downstream required + # context (skipped jobs report Success), letting a PR reach main with the + # client checks never run. This job runs on every outcome and FAILS + # unless `client-detect-changes` succeeded AND each gated job + # succeeded, or was skipped only because the path filter was 'false' on + # a pull request; on non-PR events every gated job must have succeeded. + # The required-check context swap (client-build-test-publish -> + # client-gate) is time-gated by decision D2 and lands in a follow-up on + # protected main; the original required contexts stay in place. + client-gate: + if: always() + needs: + - client-detect-changes + - client-build-test-publish + - client-scan + - client-format + runs-on: ubuntu-latest + steps: + - name: Evaluate client gate + env: + EVENT: ${{ github.event_name }} + PATH_FILTER: ${{ needs.client-detect-changes.outputs.path-filter }} + DETECT: ${{ needs.client-detect-changes.result }} + BTP: ${{ needs.client-build-test-publish.result }} + SCAN: ${{ needs.client-scan.result }} + FORMAT: ${{ needs.client-format.result }} + run: | + # Skipped jobs report Success for required-check purposes, so + # this aggregator is the only place where a skip can be told + # apart from a genuine success. + normalize() { + case "$1" in + success) echo success ;; + skipped) echo skipped ;; + *) echo failed ;; + esac + } + detect="$(normalize "$DETECT")" + btp="$(normalize "$BTP")" + scan="$(normalize "$SCAN")" + format="$(normalize "$FORMAT")" + + # A `client-detect-changes` crash (dorny/paths-filter error) + # propagates as skipped success on every downstream required + # context; that is the fail-open edge this gate closes. + # detect-changes must succeed on every event. + if [ "$detect" != success ]; then + echo "::error::client-gate: client-detect-changes did not succeed ($DETECT); required client checks cannot be trusted" + exit 1 + fi + + # Was this gated job expected to run on this event? Derived + # directly from each job`s own `if:` condition: + # client-build-test-publish: event != pull_request || filter == true + # client-scan, client-format: event == push || filter == true + # A job that was expected to run must be `success`. A job that + # was not expected to run is fine as `skipped` (its own `if:` + # was false) or `success` (it ran anyway - never an error). + expected_run() { + case "$1" in + client-build-test-publish) + # event != pull_request || filter == true + [ "$EVENT" != "pull_request" ] || [ "$PATH_FILTER" = "true" ] + ;; + client-scan|client-format) + # event == push || filter == true + [ "$EVENT" = "push" ] || [ "$PATH_FILTER" = "true" ] + ;; + *) + return 1 + ;; + esac + } + + for pair in "client-build-test-publish:$BTP" \ + "client-scan:$SCAN" \ + "client-format:$FORMAT"; do + name="${pair%%:*}" + state="$(normalize "${pair#*:}")" + if [ "$state" = failed ]; then + echo "::error::client-gate: $name did not succeed (${pair#*:})" + exit 1 + fi + if expected_run "$name"; then + if [ "$state" != success ]; then + echo "::error::client-gate: $name was expected to run on event=$EVENT but was $state (path-filter=$PATH_FILTER)" + exit 1 + fi + fi + # Not expected to run and state is `skipped` or `success`: fine. + done + echo "client-gate: all required client checks succeeded (build-test-publish=${btp}, scan=${scan}, format=${format})" diff --git a/.github/workflows/contracts-ecdsa.yml b/.github/workflows/contracts-ecdsa.yml index 3ee91bba50..dfd25470c5 100644 --- a/.github/workflows/contracts-ecdsa.yml +++ b/.github/workflows/contracts-ecdsa.yml @@ -4,6 +4,7 @@ on: pull_request: branches: - main + - dev # We intend to use `workflow dispatch` in two different situations/paths # 1. If a workflow will be manually dispatched from branch named # `dapp-development`, workflow will deploy the contracts on the selected @@ -31,18 +32,45 @@ on: required: false default: "main" +permissions: + contents: read + +# One concurrency group per PR: re-pushing a PR cancels the superseded +# run (only the newest commit's run gates the PR). workflow_dispatch runs +# get their own group per run id with cancellation disabled, so manual +# runs are never cancelled by a concurrent run. +concurrency: + group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.run_id }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: contracts-detect-changes: runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: read outputs: - path-filter: ${{ steps.set-output.outputs.path-filter }} + path-filter: ${{ steps.filter.outputs.path-filter }} steps: - - name: Set path-filter output - id: set-output - run: echo "path-filter=true" >> $GITHUB_OUTPUT + - uses: actions/checkout@v3 + if: github.event_name == 'pull_request' + + - uses: dorny/paths-filter@v2 + if: github.event_name == 'pull_request' + id: filter + with: + filters: | + path-filter: + - './solidity/ecdsa/**' + - './.github/workflows/contracts-ecdsa.yml' + - './.github/actions/install-yarn-deps/**' + - './.github/actions/docker-build-push/**' contracts-lint: needs: contracts-detect-changes + if: | + needs.contracts-detect-changes.outputs.path-filter == 'true' + || github.event_name != 'pull_request' runs-on: ubuntu-latest defaults: run: @@ -52,10 +80,10 @@ jobs: - uses: actions/setup-node@v3 with: - # Using fixed version, because 18.16 was sometimes causing issues with - # artifacts generation during `hardhat compile` - see - # https://github.com/NomicFoundation/hardhat/issues/3877 - node-version: "22.23.1" + # Pinned to match the Dockerfiles exactly so CI and the image cannot + # drift apart. Node 24 requires hardhat >= 2.26 - below it, the solc + # download fails with HH502 (see PR description for details). + node-version: "24.11.1" - uses: ./.github/actions/install-yarn-deps with: @@ -67,8 +95,14 @@ jobs: - name: Lint run: yarn lint + - name: Typecheck + run: yarn typecheck + contracts-slither: needs: contracts-detect-changes + if: | + needs.contracts-detect-changes.outputs.path-filter == 'true' + || github.event_name != 'pull_request' runs-on: ubuntu-latest defaults: run: @@ -78,10 +112,10 @@ jobs: - uses: actions/setup-node@v3 with: - # Using fixed version, because 18.16 was sometimes causing issues with - # artifacts generation during `hardhat compile` - see - # https://github.com/NomicFoundation/hardhat/issues/3877 - node-version: "22.23.1" + # Pinned to match the Dockerfiles exactly so CI and the image cannot + # drift apart. Node 24 requires hardhat >= 2.26 - below it, the solc + # download fails with HH502 (see PR description for details). + node-version: "24.11.1" - uses: actions/setup-python@v4 with: @@ -111,6 +145,9 @@ jobs: contracts-build-and-test: needs: contracts-detect-changes + if: | + needs.contracts-detect-changes.outputs.path-filter == 'true' + || github.event_name != 'pull_request' runs-on: ubuntu-latest defaults: run: @@ -120,10 +157,10 @@ jobs: - uses: actions/setup-node@v3 with: - # Using fixed version, because 18.16 was sometimes causing issues with - # artifacts generation during `hardhat compile` - see - # https://github.com/NomicFoundation/hardhat/issues/3877 - node-version: "22.23.1" + # Pinned to match the Dockerfiles exactly so CI and the image cannot + # drift apart. Node 24 requires hardhat >= 2.26 - below it, the solc + # download fails with HH502 (see PR description for details). + node-version: "24.11.1" - uses: ./.github/actions/install-yarn-deps with: @@ -138,6 +175,9 @@ jobs: contracts-deployment-dry-run: needs: contracts-detect-changes + if: | + needs.contracts-detect-changes.outputs.path-filter == 'true' + || github.event_name != 'pull_request' runs-on: ubuntu-latest defaults: run: @@ -147,10 +187,10 @@ jobs: - uses: actions/setup-node@v3 with: - # Using fixed version, because 18.16 was sometimes causing issues with - # artifacts generation during `hardhat compile` - see - # https://github.com/NomicFoundation/hardhat/issues/3877 - node-version: "22.23.1" + # Pinned to match the Dockerfiles exactly so CI and the image cannot + # drift apart. Node 24 requires hardhat >= 2.26 - below it, the solc + # download fails with HH502 (see PR description for details). + node-version: "24.11.1" - uses: ./.github/actions/install-yarn-deps with: @@ -164,13 +204,105 @@ jobs: with: imageName: keep-ecdsa-hardhat push: false + load: true context: ./solidity/ecdsa + - name: Verify non-root runtime user + run: | + docker run --rm --entrypoint sh "$IMAGE_NAME" -c 'test "$(id -u)" = 1000 && test "$(id -g)" = 1000' + docker run --rm --entrypoint sh "$IMAGE_NAME" -c 'test -w "$WORK_DIR"' + docker run --rm "$IMAGE_NAME" --help >/dev/null + + # Verifies that hardhat-deploy's `export`/`export.json` output - the + # artifact shape consumed downstream by @keep-network/tbtc-v2 - stays + # byte-identical to the committed baseline. This is the automated gate + # for the core safety constraint of issue #4216 (the hardhat-deploy v1 + # upgrade): without it, drift in the deploy/export artifact shape would + # only ever be caught by a one-off manual comparison, not by CI. A + # mismatch means the deploy/export artifact shape changed; if that is + # intentional, regenerate the baseline locally and commit + # solidity/ecdsa/export-baseline.sha256 alongside the change. + # + # The manifest includes the frozen legacy contracts and remaining external + # artifacts. Vendored sources/artifacts are committed; yarn.lock pins the + # installed dependencies. Regenerate this baseline when either changes. + contracts-export-byte-identity: + needs: contracts-detect-changes + if: github.event_name != 'pull_request' || needs.contracts-detect-changes.outputs.path-filter == 'true' + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./solidity/ecdsa + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-node@v3 + with: + # Pinned to match the Dockerfiles exactly so CI and the image cannot + # drift apart. Node 24 requires hardhat >= 2.26 - below it, the solc + # download fails with HH502 (see PR description for details). + node-version: "24.11.1" + + - uses: ./.github/actions/install-yarn-deps + with: + working-directory: ./solidity/ecdsa + + - name: Deploy contracts and generate export artifacts + run: | + yarn deploy:test --network hardhat --export export.json + yarn prepack + + - name: Verify export byte-identity against baseline + run: | + set -e + sha256sum export.json > /tmp/manifest.txt + # Sort paths consistently across developer machines and CI locales. + find export -type f | LC_ALL=C sort | xargs sha256sum >> /tmp/manifest.txt + if ! diff -q export-baseline.sha256 /tmp/manifest.txt > /dev/null; then + echo "::error::export.json / export/ artifacts differ from the committed baseline (solidity/ecdsa/export-baseline.sha256)." + echo "::error::If this change is intentional, regenerate the baseline locally (yarn deploy:test --network hardhat --export export.json && yarn prepack, then sha256sum export.json > export-baseline.sha256 && find export -type f | LC_ALL=C sort | xargs sha256sum >> export-baseline.sha256) and commit solidity/ecdsa/export-baseline.sha256 alongside it." + diff export-baseline.sha256 /tmp/manifest.txt || true + exit 1 + fi + echo "export byte-identity OK" + + # Verifies that the committed artifact JSONs in solidity/ecdsa/external/random-beacon-export/artifacts/ + # match the recorded SHA256 hashes in VENDOR.json. This closes the gap left by artifactSha256 which + # records the pristine pre-stripping upstream hash (by design) and cannot verify the committed files. + contracts-random-beacon-export-artifacts-byte-identity: + needs: contracts-detect-changes + if: github.event_name != 'pull_request' || needs.contracts-detect-changes.outputs.path-filter == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Verify random beacon export artifact byte-identity + run: | + set -e + MISMATCH=0 + while IFS= read -r line; do + KEY=$(echo "$line" | cut -d':' -f1) + EXPECTED=$(echo "$line" | cut -d':' -f2) + ACTUAL=$(sha256sum "solidity/ecdsa/external/random-beacon-export/artifacts/$KEY" 2>/dev/null | cut -d' ' -f1) + if [ "$ACTUAL" != "$EXPECTED" ]; then + echo "::error::Artifact $KEY mismatch: expected $EXPECTED, got $ACTUAL" + MISMATCH=1 + fi + done < <(jq -r '.committedSha256 | to_entries | .[] | "\(.key):\(.value)"' solidity/ecdsa/external/random-beacon-export/VENDOR.json) + if [ $MISMATCH -ne 0 ]; then + exit 1 + fi + echo 'committed artifact byte-identity OK' contracts-deployment-testnet: needs: [contracts-build-and-test] - if: | - github.event_name == 'workflow_dispatch' - && github.ref != 'refs/heads/dapp-development' + # The ethers v6 deployment exports break existing ethers v5 consumers. + # Block workflow_dispatch publication to the `` tag; this + # gate replaces the original dispatch condition, kept here so it can be + # restored: + # github.event_name == 'workflow_dispatch' + # && github.ref != 'refs/heads/dapp-development' + # Re-enable only after the consumer migration and release pins are ready; + # see solidity/docs/ethers-v6-compatibility.md#limits-and-release-gates. + if: ${{ false }} runs-on: ubuntu-latest defaults: run: @@ -180,10 +312,10 @@ jobs: - uses: actions/setup-node@v3 with: - # Using fixed version, because 18.16 was sometimes causing issues with - # artifacts generation during `hardhat compile` - see - # https://github.com/NomicFoundation/hardhat/issues/3877 - node-version: "22.23.1" + # Pinned to match the Dockerfiles exactly so CI and the image cannot + # drift apart. Node 24 requires hardhat >= 2.26 - below it, the solc + # download fails with HH502 (see PR description for details). + node-version: "24.11.1" registry-url: "https://registry.npmjs.org" - uses: ./.github/actions/install-yarn-deps @@ -197,22 +329,11 @@ jobs: upstream-builds: ${{ github.event.inputs.upstream_builds }} query: | threshold-contracts-version = github.com/threshold-network/solidity-contracts#version - random-beacon-version = github.com/keep-network/keep-core/random-beacon#version - name: Resolve latest contracts run: | yarn up \ - @threshold-network/solidity-contracts@${{ steps.upstream-builds-query.outputs.threshold-contracts-version }} \ - @keep-network/random-beacon@${{ steps.upstream-builds-query.outputs.random-beacon-version }} \ - @keep-network/sortition-pools - - # TODO: Remove this step. We replace sortition pools for deployment on testnet - # with forked contracts that were tweaked to make operators joining the pool - # easier. This should never be used outside of the test environment. On - # test environment it should be used temporarily only. - - name: Use Sortition Pool forked contracts - run: | - yarn up @keep-network/sortition-pools@github:keep-network/sortition-pools#test-fork + @threshold-network/solidity-contracts@${{ steps.upstream-builds-query.outputs.threshold-contracts-version }} - name: Configure tenderly env: @@ -268,9 +389,15 @@ jobs: # `dapp-development`. contracts-dapp-development-deployment-testnet: needs: [contracts-build-and-test] - if: | - github.event_name == 'workflow_dispatch' - && github.ref == 'refs/heads/dapp-development' + # The ethers v6 deployment exports break existing ethers v5 consumers. + # Block workflow_dispatch publication to the + # `dapp-development-` tag; this gate replaces the original + # dispatch condition, kept here so it can be restored: + # github.event_name == 'workflow_dispatch' + # && github.ref == 'refs/heads/dapp-development' + # Re-enable only after the consumer migration and release pins are ready; + # see solidity/docs/ethers-v6-compatibility.md#limits-and-release-gates. + if: ${{ false }} runs-on: ubuntu-latest defaults: run: @@ -280,10 +407,10 @@ jobs: - uses: actions/setup-node@v3 with: - # Using fixed version, because 18.16 was sometimes causing issues with - # artifacts generation during `hardhat compile` - see - # https://github.com/NomicFoundation/hardhat/issues/3877 - node-version: "22.23.1" + # Pinned to match the Dockerfiles exactly so CI and the image cannot + # drift apart. Node 24 requires hardhat >= 2.26 - below it, the solc + # download fails with HH502 (see PR description for details). + node-version: "24.11.1" registry-url: "https://registry.npmjs.org" - uses: ./.github/actions/install-yarn-deps @@ -297,15 +424,12 @@ jobs: upstream-builds: ${{ github.event.inputs.upstream_builds }} query: | threshold-contracts-version = github.com/threshold-network/solidity-contracts#version - random-beacon-version = github.com/keep-network/keep-core/random-beacon#version - name: Resolve latest contracts run: | yarn up \ - @threshold-network/solidity-contracts@${{ steps.upstream-builds-query.outputs.threshold-contracts-version }} \ - @keep-network/random-beacon@${{ steps.upstream-builds-query.outputs.random-beacon-version }} \ - @keep-network/sortition-pools - + @threshold-network/solidity-contracts@${{ steps.upstream-builds-query.outputs.threshold-contracts-version }} + - name: Deploy contracts env: CHAIN_API_URL: ${{ secrets.SEPOLIA_ETH_HOSTNAME_HTTP }} @@ -347,3 +471,81 @@ jobs: upstream_builds: ${{ github.event.inputs.upstream_builds }} upstream_ref: dapp-development version: ${{ steps.npm-version-bump.outputs.version }} + + + # R8 aggregator gate for the Solidity ECDSA workflow: closes the + # fail-open edge of the dorny/paths-filter stub pattern - a + # `dorny/paths-filter` crash in `contracts-detect-changes` would + # otherwise propagate as a Success on every downstream required + # context (skipped jobs report Success), letting a PR reach main with + # the contract checks never run. This job runs on every outcome and + # FAILS unless `contracts-detect-changes` succeeded AND each gated + # job succeeded, or was skipped only because the path filter was + # 'false' on a pull request; on non-PR events every gated job must + # have succeeded. The required-check context swap is time-gated by + # decision D2 and lands in a follow-up on protected main; the original + # required contexts stay in place. + contracts-gate-ecdsa: + if: always() + needs: + - contracts-detect-changes + - contracts-build-and-test + - contracts-lint + - contracts-deployment-dry-run + - contracts-slither + runs-on: ubuntu-latest + steps: + - name: Evaluate contracts gate + env: + EVENT: ${{ github.event_name }} + PATH_FILTER: ${{ needs.contracts-detect-changes.outputs.path-filter }} + DETECT: ${{ needs.contracts-detect-changes.result }} + BUILD_TEST: ${{ needs.contracts-build-and-test.result }} + LINT: ${{ needs.contracts-lint.result }} + DRY_RUN: ${{ needs.contracts-deployment-dry-run.result }} + SLITHER: ${{ needs.contracts-slither.result }} + run: | + # Skipped jobs report Success for required-check purposes, so + # this aggregator is the only place where a skip can be told + # apart from a genuine success. + normalize() { + case "$1" in + success) echo success ;; + skipped) echo skipped ;; + *) echo failed ;; + esac + } + echo "gate: detect=$DETECT build-test=$BUILD_TEST lint=$LINT dry-run=$DRY_RUN slither=$SLITHER" + if [ "$(normalize "$DETECT")" != "success" ]; then + echo "::error::contracts-gate: contracts-detect-changes did not succeed ($DETECT); required contract checks cannot be trusted" + exit 1 + fi + skip_allowed="false" + if [ "$EVENT" = "pull_request" ] && [ "$PATH_FILTER" = "false" ]; then + skip_allowed="true" + fi + for pair in "contracts-build-and-test:$BUILD_TEST" \ + "contracts-lint:$LINT" \ + "contracts-deployment-dry-run:$DRY_RUN" \ + "contracts-slither:$SLITHER"; do + name="${pair%%:*}" + state="$(normalize "${pair#*:}")" + case "$state" in + success) + echo "contracts-gate: $name succeeded" + ;; + skipped) + if [ "$skip_allowed" = "true" ]; then + echo "contracts-gate: $name skipped by path-filter (allowed on pull_request)" + else + echo "::error::contracts-gate: $name was skipped but no path-filter skip is allowed (event=$EVENT, path-filter=$PATH_FILTER)" + exit 1 + fi + ;; + *) + echo "::error::contracts-gate: $name did not succeed (${pair#*:})" + exit 1 + ;; + esac + done + echo "contracts-gate: all required contract checks succeeded" diff --git a/.github/workflows/contracts-random-beacon.yml b/.github/workflows/contracts-random-beacon.yml index 060cd09ad3..3a34463bba 100644 --- a/.github/workflows/contracts-random-beacon.yml +++ b/.github/workflows/contracts-random-beacon.yml @@ -4,6 +4,7 @@ on: pull_request: branches: - main + - dev # We intend to use `workflow dispatch` in two different situations/paths: # 1. If a workflow will be manually dispatched from branch named # `dapp-development`, workflow will deploy the contracts on the selected @@ -31,62 +32,85 @@ on: required: false default: "main" +permissions: + contents: read + +# One concurrency group per PR: re-pushing a PR cancels the superseded +# run (only the newest commit's run gates the PR). workflow_dispatch runs +# get their own group per run id with cancellation disabled, so manual +# runs are never cancelled by a concurrent run. +concurrency: + group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.run_id }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: contracts-detect-changes: runs-on: ubuntu-latest outputs: - path-filter: ${{ steps.set-output.outputs.path-filter }} + path-filter: ${{ steps.filter.outputs.path-filter }} steps: - - name: Set path-filter output - id: set-output - run: echo "path-filter=true" >> $GITHUB_OUTPUT + - uses: actions/checkout@v3 + if: github.event_name == 'pull_request' + - uses: dorny/paths-filter@v2 + if: github.event_name == 'pull_request' + id: filter + with: + filters: | + path-filter: + - './solidity/random-beacon/**' + - './solidity/ecdsa/external/random-beacon-export/**' + - './.github/workflows/contracts-random-beacon.yml' + - './.github/actions/install-yarn-deps/**' + - './.github/actions/docker-build-push/**' contracts-lint: needs: contracts-detect-changes + if: | + needs.contracts-detect-changes.outputs.path-filter == 'true' + || github.event_name != 'pull_request' runs-on: ubuntu-latest defaults: run: working-directory: ./solidity/random-beacon steps: - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 with: - # Using fixed version, because 18.16 was sometimes causing issues with - # artifacts generation during `hardhat compile` - see - # https://github.com/NomicFoundation/hardhat/issues/3877 - node-version: "22.23.1" - + # Pinned to match the Dockerfiles exactly so CI and the image cannot + # drift apart. Node 24 requires hardhat >= 2.26 - below it, the solc + # download fails with HH502 (see PR description for details). + node-version: "24.11.1" - uses: ./.github/actions/install-yarn-deps with: working-directory: ./solidity/random-beacon - - name: Build run: yarn build - - name: Lint run: yarn lint + - name: Typecheck + run: yarn typecheck + contracts-slither: needs: contracts-detect-changes + if: | + needs.contracts-detect-changes.outputs.path-filter == 'true' + || github.event_name != 'pull_request' runs-on: ubuntu-latest defaults: run: working-directory: ./solidity/random-beacon steps: - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 with: - # Using fixed version, because 18.16 was sometimes causing issues with - # artifacts generation during `hardhat compile` - see - # https://github.com/NomicFoundation/hardhat/issues/3877 - node-version: "22.23.1" - + # Pinned to match the Dockerfiles exactly so CI and the image cannot + # drift apart. Node 24 requires hardhat >= 2.26 - below it, the solc + # download fails with HH502 (see PR description for details). + node-version: "24.11.1" - uses: actions/setup-python@v4 with: python-version: 3.10.8 - - name: Install Solidity env: SOLC_VERSION: 0.8.9 # according to solidity.version in hardhat.config.js @@ -94,21 +118,21 @@ jobs: pip3 install solc-select solc-select install $SOLC_VERSION solc-select use $SOLC_VERSION - - name: Install Slither env: SLITHER_VERSION: 0.8.3 run: pip3 install slither-analyzer==$SLITHER_VERSION - - uses: ./.github/actions/install-yarn-deps with: working-directory: ./solidity/random-beacon - - name: Run Slither run: slither . contracts-build-and-test: needs: contracts-detect-changes + if: | + needs.contracts-detect-changes.outputs.path-filter == 'true' + || github.event_name != 'pull_request' runs-on: ubuntu-latest defaults: run: @@ -118,10 +142,10 @@ jobs: - uses: actions/setup-node@v3 with: - # Using fixed version, because 18.16 was sometimes causing issues with - # artifacts generation during `hardhat compile` - see - # https://github.com/NomicFoundation/hardhat/issues/3877 - node-version: "22.23.1" + # Pinned to match the Dockerfiles exactly so CI and the image cannot + # drift apart. Node 24 requires hardhat >= 2.26 - below it, the solc + # download fails with HH502 (see PR description for details). + node-version: "24.11.1" - uses: ./.github/actions/install-yarn-deps with: @@ -136,6 +160,9 @@ jobs: contracts-deployment-dry-run: needs: contracts-detect-changes + if: | + needs.contracts-detect-changes.outputs.path-filter == 'true' + || github.event_name != 'pull_request' runs-on: ubuntu-latest defaults: run: @@ -145,10 +172,10 @@ jobs: - uses: actions/setup-node@v3 with: - # Using fixed version, because 18.16 was sometimes causing issues with - # artifacts generation during `hardhat compile` - see - # https://github.com/NomicFoundation/hardhat/issues/3877 - node-version: "22.23.1" + # Pinned to match the Dockerfiles exactly so CI and the image cannot + # drift apart. Node 24 requires hardhat >= 2.26 - below it, the solc + # download fails with HH502 (see PR description for details). + node-version: "24.11.1" - uses: ./.github/actions/install-yarn-deps with: @@ -163,12 +190,134 @@ jobs: imageName: keep-random-beacon-hardhat context: ./solidity/random-beacon push: false + load: true + + - name: Verify non-root runtime user + run: | + docker run --rm --entrypoint sh "$IMAGE_NAME" -c 'test "$(id -u)" = 1000 && test "$(id -g)" = 1000' + docker run --rm --entrypoint sh "$IMAGE_NAME" -c 'test -w "$WORK_DIR"' + docker run --rm "$IMAGE_NAME" --help >/dev/null + + # Enforces the core safety constraint stated in issue #4216 for the + # hardhat-deploy v1 upgrade: `export/` and `export.json` (the deploy + # artifacts consumed downstream by @keep-network/tbtc-v2) must stay + # byte-identical across hardhat-deploy versions and future changes. + # Both paths are gitignored (no committed baseline to diff against in + # git), so this job regenerates them on every gated run and compares + # a checksum manifest against the committed baseline file. A mismatch + # means the deploy/export artifact shape changed; if intentional, + # regenerate solidity/random-beacon/export-baseline.sha256 with the + # same commands below and commit it alongside the change. + # + # The manifest includes the frozen legacy contracts and remaining external + # artifacts. Vendored sources/artifacts are committed; yarn.lock pins the + # installed dependencies. Regenerate this baseline when either changes. + contracts-export-byte-identity: + needs: contracts-detect-changes + if: github.event_name != 'pull_request' || needs.contracts-detect-changes.outputs.path-filter == 'true' + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./solidity/random-beacon + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-node@v3 + with: + # Pinned to match the Dockerfiles exactly so CI and the image cannot + # drift apart. Node 24 requires hardhat >= 2.26 - below it, the solc + # download fails with HH502 (see PR description for details). + node-version: "24.11.1" + + - uses: ./.github/actions/install-yarn-deps + with: + working-directory: ./solidity/random-beacon + + - name: Deploy and export contracts + run: yarn deploy:test --network hardhat --export export.json + + - name: Generate packed export artifacts + run: yarn prepack + + - name: Verify export byte-identity against baseline + run: | + set -e + sha256sum export.json > /tmp/manifest.txt + # Sort paths consistently across developer machines and CI locales. + find export -type f | LC_ALL=C sort | xargs sha256sum >> /tmp/manifest.txt + if ! diff -q export-baseline.sha256 /tmp/manifest.txt > /dev/null; then + echo '::error::export.json/export/ artifact byte-identity mismatch against solidity/random-beacon/export-baseline.sha256.' + echo '::error::If this change is intentional, regenerate the baseline locally (see the job comment above) and commit it alongside this change.' + diff export-baseline.sha256 /tmp/manifest.txt + exit 1 + fi + echo 'export byte-identity OK' + + # ECDSA bundles the compiled Beacon deployment scripts, tasks and utilities + # under solidity/ecdsa/external/random-beacon-export/ so it can deploy + # against a v6 Beacon while the published Beacon package is still ethers v5. + # That bundle is generated from this package's TypeScript sources, so any + # change under deploy/, tasks/ or utils/ silently makes it stale - until now + # only the manual + # solidity/scripts/ethers-v6-compatibility/pack-and-capture.cjs script + # checked it, and that script never runs in CI. This job regenerates the + # exports and byte-compares them against the committed bundle, so drift + # fails here instead of shipping. + bundled-beacon-export-freshness: + needs: contracts-detect-changes + if: github.event_name != 'pull_request' || needs.contracts-detect-changes.outputs.path-filter == 'true' + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./solidity/random-beacon + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-node@v3 + with: + # Pinned to match the Dockerfiles exactly so CI and the image cannot + # drift apart. Node 24 requires hardhat >= 2.26 - below it, the solc + # download fails with HH502 (see PR description for details). + node-version: "24.11.1" + + - uses: ./.github/actions/install-yarn-deps + with: + working-directory: ./solidity/random-beacon + + - name: Build solidity contracts + run: yarn build + + - name: Generate packed export artifacts + run: yarn prepack + + - name: Verify bundled Beacon export is up to date + run: | + set -e + bundle=../ecdsa/external/random-beacon-export + staging="$(mktemp -d)" + mkdir -p "$staging/deploy" "$staging/utils" "$staging/tasks/utils" + cp export/deploy/*.js "$staging/deploy/" + cp export/utils/wait-for-confirmations.js "$staging/utils/" + cp export/tasks/initialize.js export/tasks/unlock-eth-accounts.js "$staging/tasks/" + cp export/tasks/utils/*.js "$staging/tasks/utils/" + if ! diff -r --exclude=README.md --exclude=LICENSE --exclude=VENDOR.json --exclude=artifacts "$staging" "$bundle"; then + echo '::error::solidity/ecdsa/external/random-beacon-export/ is stale - it no longer matches solidity/random-beacon/export/.' + echo '::error::Regenerate it with the commands documented in solidity/ecdsa/external/random-beacon-export/README.md and commit the result alongside this change.' + exit 1 + fi + echo 'bundled Beacon export freshness OK' contracts-deployment-testnet: needs: [contracts-build-and-test] - if: | - github.event_name == 'workflow_dispatch' - && github.ref != 'refs/heads/dapp-development' + # The ethers v6 deployment exports break existing ethers v5 consumers. + # Block workflow_dispatch publication to the `` tag; this + # gate replaces the original dispatch condition, kept here so it can be + # restored: + # github.event_name == 'workflow_dispatch' + # && github.ref != 'refs/heads/dapp-development' + # Re-enable only after the consumer migration and release pins are ready; + # see solidity/docs/ethers-v6-compatibility.md#limits-and-release-gates. + if: ${{ false }} runs-on: ubuntu-latest defaults: run: @@ -178,10 +327,10 @@ jobs: - uses: actions/setup-node@v3 with: - # Using fixed version, because 18.16 was sometimes causing issues with - # artifacts generation during `hardhat compile` - see - # https://github.com/NomicFoundation/hardhat/issues/3877 - node-version: "22.23.1" + # Pinned to match the Dockerfiles exactly so CI and the image cannot + # drift apart. Node 24 requires hardhat >= 2.26 - below it, the solc + # download fails with HH502 (see PR description for details). + node-version: "24.11.1" registry-url: "https://registry.npmjs.org" - uses: ./.github/actions/install-yarn-deps @@ -199,16 +348,7 @@ jobs: - name: Resolve latest contracts run: | yarn up \ - @threshold-network/solidity-contracts@${{ steps.upstream-builds-query.outputs.threshold-contracts-version }} \ - @keep-network/sortition-pools - - # TODO: Remove this step. We replace sortition pools for deployment on testnet - # with forked contracts that were tweaked to make operators joining the pool - # easier. This should never be used outside of the test environment. On - # test environment it should be used temporarily only. - - name: Use Sortition Pool forked contracts - run: | - yarn up @keep-network/sortition-pools@github:keep-network/sortition-pools#test-fork + @threshold-network/solidity-contracts@${{ steps.upstream-builds-query.outputs.threshold-contracts-version }} - name: Configure tenderly env: @@ -264,9 +404,15 @@ jobs: # `dapp-development`. contracts-dapp-development-deployment-testnet: needs: [contracts-build-and-test] - if: | - github.event_name == 'workflow_dispatch' - && github.ref == 'refs/heads/dapp-development' + # The ethers v6 deployment exports break existing ethers v5 consumers. + # Block workflow_dispatch publication to the + # `dapp-development-` tag; this gate replaces the original + # dispatch condition, kept here so it can be restored: + # github.event_name == 'workflow_dispatch' + # && github.ref == 'refs/heads/dapp-development' + # Re-enable only after the consumer migration and release pins are ready; + # see solidity/docs/ethers-v6-compatibility.md#limits-and-release-gates. + if: ${{ false }} runs-on: ubuntu-latest defaults: run: @@ -276,10 +422,10 @@ jobs: - uses: actions/setup-node@v3 with: - # Using fixed version, because 18.16 was sometimes causing issues with - # artifacts generation during `hardhat compile` - see - # https://github.com/NomicFoundation/hardhat/issues/3877 - node-version: "22.23.1" + # Pinned to match the Dockerfiles exactly so CI and the image cannot + # drift apart. Node 24 requires hardhat >= 2.26 - below it, the solc + # download fails with HH502 (see PR description for details). + node-version: "24.11.1" registry-url: "https://registry.npmjs.org" - uses: ./.github/actions/install-yarn-deps @@ -297,9 +443,8 @@ jobs: - name: Resolve latest contracts run: | yarn up \ - @threshold-network/solidity-contracts@${{ steps.upstream-builds-query.outputs.threshold-contracts-version }} \ - @keep-network/sortition-pools - + @threshold-network/solidity-contracts@${{ steps.upstream-builds-query.outputs.threshold-contracts-version }} + - name: Deploy contracts env: CHAIN_API_URL: ${{ secrets.SEPOLIA_ETH_HOSTNAME_HTTP }} @@ -341,3 +486,81 @@ jobs: upstream_builds: ${{ github.event.inputs.upstream_builds }} upstream_ref: dapp-development version: ${{ steps.npm-version-bump.outputs.version }} + + + # R8 aggregator gate for the Solidity Random Beacon workflow: closes the + # fail-open edge of the dorny/paths-filter stub pattern - a + # `dorny/paths-filter` crash in `contracts-detect-changes` would + # otherwise propagate as a Success on every downstream required + # context (skipped jobs report Success), letting a PR reach main with + # the contract checks never run. This job runs on every outcome and + # FAILS unless `contracts-detect-changes` succeeded AND each gated + # job succeeded, or was skipped only because the path filter was + # 'false' on a pull request; on non-PR events every gated job must + # have succeeded. The required-check context swap is time-gated by + # decision D2 and lands in a follow-up on protected main; the original + # required contexts stay in place. + contracts-gate-random-beacon: + if: always() + needs: + - contracts-detect-changes + - contracts-build-and-test + - contracts-lint + - contracts-deployment-dry-run + - contracts-slither + runs-on: ubuntu-latest + steps: + - name: Evaluate contracts gate + env: + EVENT: ${{ github.event_name }} + PATH_FILTER: ${{ needs.contracts-detect-changes.outputs.path-filter }} + DETECT: ${{ needs.contracts-detect-changes.result }} + BUILD_TEST: ${{ needs.contracts-build-and-test.result }} + LINT: ${{ needs.contracts-lint.result }} + DRY_RUN: ${{ needs.contracts-deployment-dry-run.result }} + SLITHER: ${{ needs.contracts-slither.result }} + run: | + # Skipped jobs report Success for required-check purposes, so + # this aggregator is the only place where a skip can be told + # apart from a genuine success. + normalize() { + case "$1" in + success) echo success ;; + skipped) echo skipped ;; + *) echo failed ;; + esac + } + echo "gate: detect=$DETECT build-test=$BUILD_TEST lint=$LINT dry-run=$DRY_RUN slither=$SLITHER" + if [ "$(normalize "$DETECT")" != "success" ]; then + echo "::error::contracts-gate: contracts-detect-changes did not succeed ($DETECT); required contract checks cannot be trusted" + exit 1 + fi + skip_allowed="false" + if [ "$EVENT" = "pull_request" ] && [ "$PATH_FILTER" = "false" ]; then + skip_allowed="true" + fi + for pair in "contracts-build-and-test:$BUILD_TEST" \ + "contracts-lint:$LINT" \ + "contracts-deployment-dry-run:$DRY_RUN" \ + "contracts-slither:$SLITHER"; do + name="${pair%%:*}" + state="$(normalize "${pair#*:}")" + case "$state" in + success) + echo "contracts-gate: $name succeeded" + ;; + skipped) + if [ "$skip_allowed" = "true" ]; then + echo "contracts-gate: $name skipped by path-filter (allowed on pull_request)" + else + echo "::error::contracts-gate: $name was skipped but no path-filter skip is allowed (event=$EVENT, path-filter=$PATH_FILTER)" + exit 1 + fi + ;; + *) + echo "::error::contracts-gate: $name did not succeed (${pair#*:})" + exit 1 + ;; + esac + done + echo "contracts-gate: all required contract checks succeeded" diff --git a/.github/workflows/monitoring-rules.yml b/.github/workflows/monitoring-rules.yml new file mode 100644 index 0000000000..d51f0edf6f --- /dev/null +++ b/.github/workflows/monitoring-rules.yml @@ -0,0 +1,37 @@ +name: Monitoring Rules + +on: + push: + branches: + - main + - dev + paths: + - "infrastructure/monitoring/**" + pull_request: + paths: + - "infrastructure/monitoring/**" + +jobs: + promtool-validate: + name: Validate Prometheus alert rules + runs-on: ubuntu-latest + defaults: + run: + working-directory: infrastructure/monitoring/maintainer + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Download and install promtool + run: | + curl -sSL -o prometheus.tar.gz \ + https://github.com/prometheus/prometheus/releases/download/v2.55.1/prometheus-2.55.1.linux-amd64.tar.gz + tar xzf prometheus.tar.gz + sudo mv prometheus-2.55.1.linux-amd64/promtool /usr/local/bin/promtool + promtool --version + + - name: Check Prometheus config + run: promtool check config prometheus.example.yml + + - name: Test Prometheus alert rules + run: promtool test rules rules.test.yml \ No newline at end of file diff --git a/.github/workflows/npm-ecdsa.yml b/.github/workflows/npm-ecdsa.yml index 760157d750..f9d4fa8a90 100644 --- a/.github/workflows/npm-ecdsa.yml +++ b/.github/workflows/npm-ecdsa.yml @@ -8,14 +8,24 @@ on: - "solidity/ecdsa/contracts/**" - "solidity/ecdsa/deploy/**" - "solidity/ecdsa/tasks/**" + - "solidity/ecdsa/utils/**" + - "solidity/ecdsa/external/**" - "solidity/ecdsa/hardhat.config.ts" - "solidity/ecdsa/package.json" - "solidity/ecdsa/yarn.lock" + - "solidity/ecdsa/.nvmrc" + - "solidity/ecdsa/.yarnrc.yml" + - "solidity/ecdsa/.yarn/patches/**" - ".github/workflows/npm-ecdsa.yml" workflow_dispatch: jobs: npm-compile-publish-contracts: + # The ethers v6 deployment exports break existing ethers v5 consumers. + # Block both push and workflow_dispatch publication, including latest. + # Re-enable only after the consumer migration and release pins are ready; + # see solidity/docs/ethers-v6-compatibility.md#limits-and-release-gates. + if: ${{ false }} runs-on: ubuntu-latest defaults: run: @@ -25,10 +35,10 @@ jobs: - uses: actions/setup-node@v3 with: - # Using fixed version, because 18.16 may cause issues with the - # artifacts generation during `hardhat compile` - see - # https://github.com/NomicFoundation/hardhat/issues/3877. - node-version: "22.23.1" + # Pinned to match the Dockerfiles exactly so CI and the image cannot + # drift apart. Node 24 requires hardhat >= 2.26 - below it, the solc + # download fails with HH502 (see PR description for details). + node-version: "24.11.1" registry-url: "https://registry.npmjs.org" - uses: ./.github/actions/install-yarn-deps diff --git a/.github/workflows/npm-random-beacon.yml b/.github/workflows/npm-random-beacon.yml index 00635ca9db..7e8cb00dc3 100644 --- a/.github/workflows/npm-random-beacon.yml +++ b/.github/workflows/npm-random-beacon.yml @@ -8,14 +8,23 @@ on: - "solidity/random-beacon/contracts/**" - "solidity/random-beacon/deploy/**" - "solidity/random-beacon/tasks/**" + - "solidity/random-beacon/utils/**" - "solidity/random-beacon/hardhat.config.ts" - "solidity/random-beacon/package.json" - "solidity/random-beacon/yarn.lock" + - "solidity/random-beacon/.nvmrc" + - "solidity/random-beacon/.yarnrc.yml" + - "solidity/random-beacon/.yarn/patches/**" - ".github/workflows/npm-random-beacon.yml" workflow_dispatch: jobs: npm-compile-publish-contracts: + # The ethers v6 deployment exports break existing ethers v5 consumers. + # Block both push and workflow_dispatch publication, including latest. + # Re-enable only after the consumer migration and release pins are ready; + # see solidity/docs/ethers-v6-compatibility.md#limits-and-release-gates. + if: ${{ false }} runs-on: ubuntu-latest defaults: run: @@ -25,31 +34,19 @@ jobs: - uses: actions/setup-node@v3 with: - # Using fixed version, because 18.16 may cause issues with the - # artifacts generation during `hardhat compile` - see - # https://github.com/NomicFoundation/hardhat/issues/3877. - node-version: "22.23.1" + # Pinned to match the Dockerfiles exactly so CI and the image cannot + # drift apart. Node 24 requires hardhat >= 2.26 - below it, the solc + # download fails with HH502 (see PR description for details). + node-version: "24.11.1" registry-url: "https://registry.npmjs.org" - - uses: ./.github/actions/setup-git-for-yarn - - - name: Enable Yarn 4 (packageManager) - run: | - corepack enable - yarn --version + - uses: ./.github/actions/install-yarn-deps + with: + working-directory: ./solidity/random-beacon - - name: Resolve latest contracts - # `@threshold-network/solidity-contracts` is pinned to 1.3.0-dev.11 - # (the version used by the last successful publish, 2.1.0-dev.18) - # because the `development` dist-tag was bumped to 1.3.0-dev.16, - # which refactored `TokenStaking` and removed `approveApplication` - # (called by `deploy/05_approve_random_beacon_in_token_staking.ts`). - # Unpin once the deploy scripts and Go ABI bindings are migrated - # to the new TokenStaking API. - run: | - yarn up --exact \ - @keep-network/sortition-pools \ - @threshold-network/solidity-contracts@1.3.0-dev.11 + - name: Install locked dependencies + # Preserve the tested Threshold version and its local ethers v6 patch. + run: yarn install --immutable # Deploy contracts to a local network to generate deployment artifacts that # are required by dashboard and client compilation. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7df458d649..43c26f7d62 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -67,6 +67,17 @@ jobs: push: false context: . + - name: Verify Linux release compatibility + run: | + release_dir=$(mktemp -d) + trap 'rm -rf "$release_dir"' EXIT + tar -xzf out/bin/*-linux-amd64.tar.gz -C "$release_dir" + for image in debian:bullseye-slim ubuntu:20.04; do + docker run --rm --platform linux/amd64 \ + --mount "type=bind,src=$release_dir,dst=/release,readonly" \ + "$image" sh -ec 'getconf GNU_LIBC_VERSION; /release/keep-client --version' + done + - name: Generate release notes id: release_notes run: | @@ -172,4 +183,4 @@ jobs: - name: Move Docker cache run: | rm -rf /tmp/.buildx-cache - mv /tmp/.buildx-cache-docker-new /tmp/.buildx-cache \ No newline at end of file + mv /tmp/.buildx-cache-docker-new /tmp/.buildx-cache diff --git a/.github/workflows/reusable-solidity-docs.yml b/.github/workflows/reusable-solidity-docs.yml index b56f256103..b287e3c86c 100644 --- a/.github/workflows/reusable-solidity-docs.yml +++ b/.github/workflows/reusable-solidity-docs.yml @@ -125,7 +125,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: "22.23.1" + node-version: "24.11.1" - uses: ./.github/actions/install-yarn-deps with: diff --git a/.gitignore b/.gitignore index 0c2c04268b..dc42dcb3f6 100644 --- a/.gitignore +++ b/.gitignore @@ -12,9 +12,6 @@ *.swp *.swo -# Infrastructure -/infrastructure/gcp/service-accounts* - # Secret directory used in Kubernetes configurations /infrastructure/kube/**/.secret/ /infrastructure/kube/**/*.secret diff --git a/Dockerfile b/Dockerfile index dce9eba139..fc3de655aa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,5 @@ -FROM golang:1.24-alpine3.21 AS build-sources +# Keep both builders aligned with the toolchain directive in go.mod. +FROM golang:1.26.8-alpine3.23 AS build-sources ENV GOPATH=/go \ GOBIN=/go/bin \ @@ -57,6 +58,11 @@ COPY ./pkg/tecdsa/gen $APP_DIR/pkg/tecdsa/gen COPY ./pkg/protocol/announcer/gen $APP_DIR/pkg/protocol/announcer/gen COPY ./pkg/protocol/inactivity/gen $APP_DIR/pkg/protocol/inactivity/gen +# The vendored code generators used by `make generate` (see +# tools/generators/ethereum, invoked from +# pkg/chain/ethereum/common/gen/Makefile) must be present before +# generation runs. +COPY ./tools $APP_DIR/tools # Install code generators. RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.32.0 @@ -91,7 +97,7 @@ RUN GOOS=linux make build \ version=$VERSION \ revision=$REVISION -FROM alpine:3.21 as runtime-docker +FROM alpine:3.23 as runtime-docker ENV APP_NAME=keep-client \ APP_DIR=/go/src/github.com/keep-network/keep-core \ @@ -111,9 +117,15 @@ CMD [] # # Build Binaries # -FROM golang:1.24-bullseye AS build-bins +# Keep cgo release binaries compatible with glibc 2.31 (Debian 11/Ubuntu 20.04). +# Copy only Go so the C compiler and libc still come from Bullseye. +FROM buildpack-deps:bullseye AS build-bins -ENV APP_DIR=/go/src/github.com/keep-network/keep-core +COPY --from=golang:1.26.8-bookworm /usr/local/go /usr/local/go + +ENV PATH=/usr/local/go/bin:$PATH \ + GOTOOLCHAIN=local \ + APP_DIR=/go/src/github.com/keep-network/keep-core WORKDIR $APP_DIR diff --git a/Makefile b/Makefile index ab468ae08f..6dc591d2f3 100644 --- a/Makefile +++ b/Makefile @@ -146,4 +146,7 @@ cmd-help: build @echo '$$ $(app_name) start --help' > docs/resources/client-start-help ./$(app_name) start --help >> docs/resources/client-start-help -.PHONY: all development sepolia download_artifacts generate gen_proto build cmd-help release build_multi +bench: + go test -bench=. -benchmem -count=10 -run='^$$' ./pkg/... + +.PHONY: all development sepolia mainnet local get_artifacts generate gen_proto build cmd-help release build_multi bench diff --git a/cmd/flags.go b/cmd/flags.go index 7a67ad5df8..6f466dcdb8 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -6,17 +6,17 @@ import ( "github.com/spf13/cobra" - commonEthereum "github.com/keep-network/keep-common/pkg/chain/ethereum" - "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/cmd/flag" - "github.com/keep-network/keep-common/pkg/rate" "github.com/keep-network/keep-core/config" "github.com/keep-network/keep-core/config/network" "github.com/keep-network/keep-core/pkg/bitcoin/electrum" chainEthereum "github.com/keep-network/keep-core/pkg/chain/ethereum" + commonEthereum "github.com/keep-network/keep-core/pkg/chain/ethereumutil" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" "github.com/keep-network/keep-core/pkg/clientinfo" + "github.com/keep-network/keep-core/pkg/cmd/flag" "github.com/keep-network/keep-core/pkg/maintainer/spv" "github.com/keep-network/keep-core/pkg/net/libp2p" + "github.com/keep-network/keep-core/pkg/rate" "github.com/keep-network/keep-core/pkg/tbtc" ) @@ -164,6 +164,17 @@ func initBitcoinElectrumFlags(cmd *cobra.Command, cfg *config.Config) { "URL to the Electrum server in format: `scheme://hostname:port`.", ) + cmd.Flags().StringSliceVar( + &cfg.Bitcoin.Electrum.FallbackURLs, + "bitcoin.electrum.fallbackURLs", + []string{}, + "Comma-separated list of alternate Electrum server URLs used for "+ + "failover when the primary server becomes unavailable. When no "+ + "primary URL is configured, these are appended behind the "+ + "auto-selected embedded primary; an explicitly configured "+ + "primary URL remains preferred, with these tried on failure.", + ) + cmd.Flags().DurationVar( &cfg.Bitcoin.Electrum.ConnectTimeout, "bitcoin.electrum.connectTimeout", @@ -310,6 +321,56 @@ func initTbtcFlags(cmd *cobra.Command, cfg *config.Config) { tbtc.DefaultKeyGenerationConcurrency, "tECDSA key generation concurrency.", ) + + cmd.Flags().IntVar( + &cfg.Tbtc.WalletTxSatPerVByteFloor, + "tbtc.walletTxSatPerVByteFloor", + tbtc.DefaultWalletTxSatPerVByteFloor, + "Minimum fee rate (sat/vByte) applied to wallet Bitcoin transactions "+ + "(deposit sweeps, redemptions, moving funds, moved funds sweeps). "+ + "Applies to both the leader-side floor in tbtcpg and the "+ + "follower-side soft check; 0 means use the default.", + ) + + cmd.Flags().IntVar( + &cfg.Tbtc.WalletTxFeeBufferPercent, + "tbtc.walletTxFeeBufferPercent", + tbtc.DefaultWalletTxFeeBufferPercent, + "Safety-buffer percentage applied over the per-vByte fee rate "+ + "(bufferedRate = ceil(rawRate * (100+Percent) / 100)); "+ + "0 means use the default.", + ) + + cmd.Flags().DurationVar( + &cfg.Tbtc.TransactionMonitor.StuckThreshold, + "tbtc.transactionMonitor.stuckThreshold", + tbtc.DefaultTransactionMonitorStuckThreshold, + "Unconfirmed transaction age before a stuck-transaction alert; 0 uses the default.", + ) + cmd.Flags().DurationVar( + &cfg.Tbtc.TransactionMonitor.CheckInterval, + "tbtc.transactionMonitor.checkInterval", + tbtc.DefaultTransactionMonitorCheckInterval, + "Polling interval for wallet transaction confirmations; 0 uses the default.", + ) + cmd.Flags().IntVar( + &cfg.Tbtc.TransactionMonitor.MaxTracked, + "tbtc.transactionMonitor.maxTracked", + tbtc.DefaultTransactionMonitorMaxTracked, + "Maximum number of wallet transactions tracked in memory; must not exceed 100000; 0 uses the default.", + ) + cmd.Flags().DurationVar( + &cfg.Tbtc.TransactionMonitor.MaxTrackingAge, + "tbtc.transactionMonitor.maxTrackingAge", + tbtc.DefaultTransactionMonitorMaxTrackingAge, + "Maximum age of a tracked transaction; must be at least stuckThreshold; 0 uses the default.", + ) + cmd.Flags().DurationVar( + &cfg.Tbtc.TransactionMonitor.CheckBudget, + "tbtc.transactionMonitor.checkBudget", + tbtc.DefaultTransactionMonitorCheckBudget, + "Time budget for one transaction confirmation-check pass; 0 uses the default.", + ) } // Initialize flags for Maintainer configuration. @@ -373,6 +434,15 @@ func initMaintainerFlags(command *cobra.Command, cfg *config.Config) { "The wait time which should be applied when there are no more "+ "transaction proofs to submit.", ) + command.Flags().UintVar( + &cfg.Maintainer.Spv.MaxProofHeaders, + "spv.maxProofHeaders", + spv.DefaultMaxProofHeaders, + "The maximum number of block headers allowed when assembling an SPV "+ + "proof. Bounds the forward walk over headers and so the number of "+ + "consecutive leading minimum-difficulty (DIFF1) headers a proof "+ + "can absorb before it becomes unprovable.", + ) } // Initialize flags for Developer configuration. diff --git a/cmd/flags_test.go b/cmd/flags_test.go index bb313cf50c..be86612dda 100644 --- a/cmd/flags_test.go +++ b/cmd/flags_test.go @@ -15,13 +15,14 @@ import ( "github.com/spf13/cobra" "golang.org/x/exp/slices" - commonEthereum "github.com/keep-network/keep-common/pkg/chain/ethereum" "github.com/keep-network/keep-core/config" chainEthereum "github.com/keep-network/keep-core/pkg/chain/ethereum" ethereumBeacon "github.com/keep-network/keep-core/pkg/chain/ethereum/beacon/gen" ethereumEcdsa "github.com/keep-network/keep-core/pkg/chain/ethereum/ecdsa/gen" ethereumTbtc "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen" ethereumThreshold "github.com/keep-network/keep-core/pkg/chain/ethereum/threshold/gen" + commonEthereum "github.com/keep-network/keep-core/pkg/chain/ethereumutil" + "github.com/keep-network/keep-core/pkg/tbtc" ) var cmdFlagsTests = map[string]struct { @@ -87,6 +88,13 @@ var cmdFlagsTests = map[string]struct { expectedValueFromFlag: "tcp://url.to.electrum:18332", defaultValue: "", }, + "bitcoin.electrum.fallbackURLs": { + readValueFunc: func(c *config.Config) interface{} { return c.Bitcoin.Electrum.FallbackURLs }, + flagName: "--bitcoin.electrum.fallbackURLs", + flagValue: "wss://one.example:443,wss://two.example:443", + expectedValueFromFlag: []string{"wss://one.example:443", "wss://two.example:443"}, + defaultValue: []string{}, + }, "bitcoin.electrum.connectTimeout": { readValueFunc: func(c *config.Config) interface{} { return c.Bitcoin.Electrum.ConnectTimeout }, flagName: "--bitcoin.electrum.connectTimeout", @@ -225,6 +233,55 @@ var cmdFlagsTests = map[string]struct { expectedValueFromFlag: 101, defaultValue: runtime.GOMAXPROCS(0), }, + "tbtc.walletTxSatPerVByteFloor": { + readValueFunc: func(c *config.Config) interface{} { return c.Tbtc.WalletTxSatPerVByteFloor }, + flagName: "--tbtc.walletTxSatPerVByteFloor", + flagValue: "7", + expectedValueFromFlag: 7, + defaultValue: tbtc.DefaultWalletTxSatPerVByteFloor, + }, + "tbtc.walletTxFeeBufferPercent": { + readValueFunc: func(c *config.Config) interface{} { return c.Tbtc.WalletTxFeeBufferPercent }, + flagName: "--tbtc.walletTxFeeBufferPercent", + flagValue: "30", + expectedValueFromFlag: 30, + defaultValue: tbtc.DefaultWalletTxFeeBufferPercent, + }, + "tbtc.transactionMonitor.stuckThreshold": { + readValueFunc: func(c *config.Config) interface{} { return c.Tbtc.TransactionMonitor.StuckThreshold }, + flagName: "--tbtc.transactionMonitor.stuckThreshold", + flagValue: "1h", + expectedValueFromFlag: time.Hour, + defaultValue: tbtc.DefaultTransactionMonitorStuckThreshold, + }, + "tbtc.transactionMonitor.checkInterval": { + readValueFunc: func(c *config.Config) interface{} { return c.Tbtc.TransactionMonitor.CheckInterval }, + flagName: "--tbtc.transactionMonitor.checkInterval", + flagValue: "1m", + expectedValueFromFlag: time.Minute, + defaultValue: tbtc.DefaultTransactionMonitorCheckInterval, + }, + "tbtc.transactionMonitor.maxTracked": { + readValueFunc: func(c *config.Config) interface{} { return c.Tbtc.TransactionMonitor.MaxTracked }, + flagName: "--tbtc.transactionMonitor.maxTracked", + flagValue: "25", + expectedValueFromFlag: 25, + defaultValue: tbtc.DefaultTransactionMonitorMaxTracked, + }, + "tbtc.transactionMonitor.maxTrackingAge": { + readValueFunc: func(c *config.Config) interface{} { return c.Tbtc.TransactionMonitor.MaxTrackingAge }, + flagName: "--tbtc.transactionMonitor.maxTrackingAge", + flagValue: "12h", + expectedValueFromFlag: 12 * time.Hour, + defaultValue: tbtc.DefaultTransactionMonitorMaxTrackingAge, + }, + "tbtc.transactionMonitor.checkBudget": { + readValueFunc: func(c *config.Config) interface{} { return c.Tbtc.TransactionMonitor.CheckBudget }, + flagName: "--tbtc.transactionMonitor.checkBudget", + flagValue: "30s", + expectedValueFromFlag: 30 * time.Second, + defaultValue: tbtc.DefaultTransactionMonitorCheckBudget, + }, "maintainer.bitcoinDifficulty": { readValueFunc: func(c *config.Config) interface{} { return c.Maintainer.BitcoinDifficulty.Enabled }, flagName: "--bitcoinDifficulty", @@ -432,6 +489,7 @@ func TestFlags_Mixed(t *testing.T) { "--bitcoin.electrum.url", "ssl://url.to.electrum:18332", "--network.port", "7469", "--bitcoinDifficulty", + "--tbtc.transactionMonitor.stuckThreshold", "30m", } testCommand.SetArgs(args) @@ -465,6 +523,16 @@ func TestFlags_Mixed(t *testing.T) { readValueFunc: func(c *config.Config) interface{} { return c.ClientInfo.Port }, expectedValue: 3097, }, + "tbtc.transactionMonitor": { + readValueFunc: func(c *config.Config) interface{} { return c.Tbtc.TransactionMonitor }, + expectedValue: tbtc.TransactionMonitorConfig{ + StuckThreshold: 30 * time.Minute, + CheckInterval: 45 * time.Second, + MaxTracked: 50, + MaxTrackingAge: 12 * time.Hour, + CheckBudget: tbtc.DefaultTransactionMonitorCheckBudget, + }, + }, "storage.dir": { readValueFunc: func(c *config.Config) interface{} { return c.Storage.Dir }, expectedValue: "/my/secure/location", diff --git a/cmd/helpers.go b/cmd/helpers.go index ee3fa35416..9b64613809 100644 --- a/cmd/helpers.go +++ b/cmd/helpers.go @@ -5,9 +5,9 @@ import ( "strconv" "strings" - commonEthereum "github.com/keep-network/keep-common/pkg/chain/ethereum" "github.com/keep-network/keep-core/build" chainEthereum "github.com/keep-network/keep-core/pkg/chain/ethereum" + commonEthereum "github.com/keep-network/keep-core/pkg/chain/ethereumutil" ) func nodeHeader(addrStrings []string, operator string, port int, ethereumConfig commonEthereum.Config) { diff --git a/cmd/maintainer.go b/cmd/maintainer.go index b8d81e2aa5..96457a0bcd 100644 --- a/cmd/maintainer.go +++ b/cmd/maintainer.go @@ -6,10 +6,15 @@ import ( "github.com/spf13/cobra" + "github.com/keep-network/keep-core/build" "github.com/keep-network/keep-core/config" + "github.com/keep-network/keep-core/pkg/bitcoin" "github.com/keep-network/keep-core/pkg/bitcoin/electrum" + "github.com/keep-network/keep-core/pkg/chain" "github.com/keep-network/keep-core/pkg/chain/ethereum" + "github.com/keep-network/keep-core/pkg/clientinfo" "github.com/keep-network/keep-core/pkg/maintainer" + "github.com/keep-network/keep-core/pkg/maintainer/spv" ) // MaintainerCommand contains the definition of the maintainer command-line @@ -39,11 +44,30 @@ func init() { ) } +// validateMaintainerConfig checks the maintainer configuration before any +// chain connection is attempted, so a misconfiguration fails fast and loudly +// at startup instead of degrading into silent runtime behavior. It delegates +// to maintainer.Config.Validate so the command-level check and the +// config-load check (config.ReadConfig) share one rule: SPV settings are +// validated only when the SPV maintainer will actually run (explicitly +// enabled, or neither maintainer enabled). +func validateMaintainerConfig(cfg *config.Config) error { + if err := cfg.Maintainer.Validate(); err != nil { + return fmt.Errorf("invalid maintainer configuration: [%v]", err) + } + + return nil +} + // maintainers initializes maintainer tasks specified by flags passed to the // maintainer command. func maintainers(cmd *cobra.Command, args []string) error { ctx := context.Background() + if err := validateMaintainerConfig(clientConfig); err != nil { + return err + } + btcChain, err := electrum.Connect(ctx, clientConfig.Bitcoin.Electrum) if err != nil { return fmt.Errorf("could not connect to Electrum chain: [%v]", err) @@ -61,7 +85,7 @@ func maintainers(cmd *cobra.Command, args []string) error { ) } - _, tbtcChain, _, _, _, err := ethereum.Connect( + _, tbtcChain, blockCounter, _, _, err := ethereum.Connect( ctx, clientConfig.Ethereum, ) @@ -72,14 +96,63 @@ func maintainers(cmd *cobra.Command, args []string) error { ) } - maintainer.Initialize( + metricsRecorder := initializeMaintainerMetrics(ctx, blockCounter, tbtcChain, btcChain) + + err = maintainer.Initialize( ctx, clientConfig.Maintainer, btcChain, btcDiffChain, tbtcChain, + metricsRecorder, ) + if err != nil { + return fmt.Errorf("could not initialize maintainer tasks: [%v]", err) + } <-ctx.Done() return fmt.Errorf("unexpected context cancellation") } + +// initializeMaintainerMetrics sets up the client info registry and performance +// metrics for the maintainer command. It returns a metrics recorder wired to +// the SPV maintainer, or nil when the client info endpoint is not configured +// (in which case metrics recording is disabled). +func initializeMaintainerMetrics( + ctx context.Context, + blockCounter chain.BlockCounter, + ethRPC clientinfo.EthereumRPC, + btcChain bitcoin.Chain, +) spv.MetricsRecorder { + registry, isConfigured := clientinfo.Initialize( + ctx, + clientConfig.ClientInfo, + ) + if !isConfigured { + logger.Infof("client info endpoint not configured") + return nil + } + + perfMetrics := clientinfo.NewPerformanceMetrics(ctx, registry) + + registry.RegisterMetricClientInfo(build.Version) + registry.ObserveEthConnectivity( + blockCounter, + clientConfig.ClientInfo.EthereumMetricsTick, + ) + registry.RegisterEthChainInfoSource(blockCounter) + registry.ObserveBtcConnectivity(btcChain, clientConfig.ClientInfo.BitcoinMetricsTick) + registry.RegisterBtcChainInfoSource(btcChain) + healthChecker := clientinfo.NewRPCHealthChecker( + registry, ethRPC, btcChain, clientConfig.ClientInfo.RPCHealthCheckInterval, + ) + // An unavailable RPC must not delay starting the maintainer's control loop. + go healthChecker.Start(ctx) + + logger.Infof( + "enabled client info endpoint on port [%v]", + clientConfig.ClientInfo.Port, + ) + + return perfMetrics +} diff --git a/cmd/maintainer_test.go b/cmd/maintainer_test.go new file mode 100644 index 0000000000..1edee53850 --- /dev/null +++ b/cmd/maintainer_test.go @@ -0,0 +1,218 @@ +package cmd + +import ( + "context" + "net" + "testing" + + "github.com/keep-network/keep-core/pkg/bitcoin" + "github.com/keep-network/keep-core/pkg/clientinfo" +) + +// stubBlockCounter is a minimal chain.BlockCounter implementation used to +// exercise the enabled path of initializeMaintainerMetrics without wiring a +// real Ethereum connection. Only CurrentBlock is ever invoked (from the +// registry's background eth-connectivity observer goroutine); the other +// methods exist solely to satisfy the interface. +type stubBlockCounter struct{} + +func (stubBlockCounter) WaitForBlockHeight(blockNumber uint64) error { + return nil +} + +func (stubBlockCounter) BlockHeightWaiter( + blockNumber uint64, +) (<-chan uint64, error) { + ch := make(chan uint64) + close(ch) + return ch, nil +} + +func (stubBlockCounter) CurrentBlock() (uint64, error) { + return 0, nil +} + +func (stubBlockCounter) WatchBlocks(ctx context.Context) <-chan uint64 { + ch := make(chan uint64) + close(ch) + return ch +} + +// stubEthereumRPC is a minimal clientinfo.EthereumRPC implementation used to +// exercise the enabled path of initializeMaintainerMetrics without wiring a +// real Ethereum RPC client. The background RPC health checker goroutine +// invokes LatestBlockNumber; a nil interface would panic there instead. +type stubEthereumRPC struct{} + +func (stubEthereumRPC) LatestBlockNumber(context.Context) (uint64, error) { + return 0, nil +} + +// stubBitcoinChain is a minimal bitcoin.Chain implementation used to +// exercise the enabled path of initializeMaintainerMetrics without wiring a +// real Bitcoin chain connection. Only GetLatestBlockHeight is ever invoked +// (from the registry's background btc-connectivity observer and the RPC +// health checker); the other methods exist solely to satisfy the interface. +type stubBitcoinChain struct{} + +func (stubBitcoinChain) GetTransaction(bitcoin.Hash) (*bitcoin.Transaction, error) { + panic("unsupported") +} + +func (stubBitcoinChain) GetTransactionConfirmations( + context.Context, + bitcoin.Hash, +) (uint, error) { + panic("unsupported") +} + +func (stubBitcoinChain) BroadcastTransaction(*bitcoin.Transaction) error { + panic("unsupported") +} + +func (stubBitcoinChain) GetLatestBlockHeight() (uint, error) { + return 0, nil +} + +func (stubBitcoinChain) GetBlockHeader(uint) (*bitcoin.BlockHeader, error) { + panic("unsupported") +} + +func (stubBitcoinChain) GetTransactionMerkleProof( + bitcoin.Hash, + uint, +) (*bitcoin.TransactionMerkleProof, error) { + panic("unsupported") +} + +func (stubBitcoinChain) GetTransactionsForPublicKeyHash( + [20]byte, + int, +) ([]*bitcoin.Transaction, error) { + panic("unsupported") +} + +func (stubBitcoinChain) GetTxHashesForPublicKeyHash( + [20]byte, +) ([]bitcoin.Hash, error) { + panic("unsupported") +} + +func (stubBitcoinChain) GetMempoolForPublicKeyHash( + [20]byte, +) ([]*bitcoin.Transaction, error) { + panic("unsupported") +} + +func (stubBitcoinChain) GetUtxosForPublicKeyHash( + [20]byte, +) ([]*bitcoin.UnspentTransactionOutput, error) { + panic("unsupported") +} + +func (stubBitcoinChain) GetMempoolUtxosForPublicKeyHash( + [20]byte, +) ([]*bitcoin.UnspentTransactionOutput, error) { + panic("unsupported") +} + +func (stubBitcoinChain) EstimateSatPerVByteFee(uint32) (int64, error) { + panic("unsupported") +} + +func (stubBitcoinChain) GetCoinbaseTxHash(uint) (bitcoin.Hash, error) { + panic("unsupported") +} + +// TestInitializeMaintainerMetricsDisabledWhenPortUnset verifies the metrics +// on/off gate: when the client info port is 0 (unset), the maintainer boot path +// must report the endpoint as not configured and return a genuinely nil +// recorder, leaving SPV metrics recording disabled. This is the sole production +// switch that turns the SPV proof-submission counters on or off, so inverting +// the gate would silently change maintainer behavior. +func TestInitializeMaintainerMetricsDisabledWhenPortUnset(t *testing.T) { + // clientConfig is a package-level global; restore it so the test does not + // leak state into other tests in this package. + originalPort := clientConfig.ClientInfo.Port + defer func() { clientConfig.ClientInfo.Port = originalPort }() + + clientConfig.ClientInfo.Port = 0 + + // blockCounter, ethRPC, and btcChain are only touched on the configured + // (enabled) path, so nil values are safe for the disabled path under test. + recorder := initializeMaintainerMetrics(context.Background(), nil, nil, nil) + + if recorder != nil { + t.Errorf( + "expected a nil recorder when the client info port is unset, got [%v]", + recorder, + ) + } +} + +// TestInitializeMaintainerMetricsEnabledWhenPortSet is the enabled-path +// counterpart to TestInitializeMaintainerMetricsDisabledWhenPortUnset: when +// the client info port is set, initializeMaintainerMetrics must return a +// live *clientinfo.PerformanceMetrics recorder wired to the registry it just +// created. A regression such as a dropped `return perfMetrics`, an early +// return after registry.RegisterMetricClientInfo, or constructing the +// recorder against the wrong registry would silently disable all production +// SPV proof-submission metrics, while every other test in the codebase +// (which construct fake recorders directly, bypassing this function) would +// keep passing. +func TestInitializeMaintainerMetricsEnabledWhenPortSet(t *testing.T) { + // clientConfig is a package-level global; restore it so the test does not + // leak state into other tests in this package. + originalPort := clientConfig.ClientInfo.Port + defer func() { clientConfig.ClientInfo.Port = originalPort }() + + // Reserve a genuinely free ephemeral port from the OS and release it + // immediately. clientinfo.Initialize binds this port on a private + // per-registry ServeMux via an unowned ListenAndServe goroutine with no + // shutdown handle, so a hardcoded port risks colliding with another + // process or a parallel test run. + listener, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatalf("could not reserve a free port: [%v]", err) + } + port := listener.Addr().(*net.TCPAddr).Port + if err := listener.Close(); err != nil { + t.Fatalf("could not release reserved port: [%v]", err) + } + + clientConfig.ClientInfo.Port = port + + // Stub block counter, RPC, and chain are used instead of nil: the enabled + // path starts background goroutines that immediately call + // blockCounter.CurrentBlock, ethRPC.LatestBlockNumber, and + // btcChain.GetLatestBlockHeight, which would panic on nil interfaces. + recorder := initializeMaintainerMetrics( + context.Background(), + stubBlockCounter{}, + stubEthereumRPC{}, + stubBitcoinChain{}, + ) + + if recorder == nil { + t.Fatal("expected a non-nil recorder when the client info port is set") + } + + perfMetrics, ok := recorder.(*clientinfo.PerformanceMetrics) + if !ok { + t.Fatalf( + "expected recorder to be a *clientinfo.PerformanceMetrics, got [%T]", + recorder, + ) + } + + perfMetrics.IncrementCounter(clientinfo.MetricDepositSweepProofSubmissionsTotal, 1) + + if value := perfMetrics.GetCounterValue( + clientinfo.MetricDepositSweepProofSubmissionsTotal, + ); value != 1 { + t.Errorf( + "expected counter value [1] after increment, got [%v]", + value, + ) + } +} diff --git a/cmd/maintainercli.go b/cmd/maintainercli.go index e674375fc3..87cda788bf 100644 --- a/cmd/maintainercli.go +++ b/cmd/maintainercli.go @@ -354,6 +354,7 @@ var submitDepositSweepProofCommand = cobra.Command{ requiredConfirmations, btcChain, tbtcChain, + nil, ); err != nil { return fmt.Errorf("failed to submit deposit sweep proof [%v]", err) } @@ -444,6 +445,7 @@ var submitRedemptionProofCommand = cobra.Command{ requiredConfirmations, btcChain, tbtcChain, + nil, ); err != nil { return fmt.Errorf("failed to submit redemption proof [%v]", err) } diff --git a/cmd/maxproofheaders_flag_test.go b/cmd/maxproofheaders_flag_test.go new file mode 100644 index 0000000000..bac7af4f85 --- /dev/null +++ b/cmd/maxproofheaders_flag_test.go @@ -0,0 +1,108 @@ +package cmd + +import ( + "strings" + "testing" + + "github.com/spf13/cobra" + + "github.com/keep-network/keep-core/config" +) + +// TestMaintainerConfig_RejectsExplicitZeroMaxProofHeaders asserts that an +// explicit `--spv.maxProofHeaders 0` is rejected by the same validation the +// maintainer command runs at startup. +// +// The flag is registered with cobra's UintVar, which accepts 0 as a valid +// unsigned value, so the 144 default only protects the case where the flag is +// omitted entirely. Without validation a zero bound reaches the proof +// assembly loop, where getProofInfo skips every transaction, disabling SPV +// proving. A test exercising only the omitted-flag default would pass +// regardless and mask this. +// +// The test drives validateMaintainerConfig, which delegates to +// maintainer.Config.Validate - the same rule the config-load pass applies. +// A fresh flag-initialized config has neither maintainer enabled, so the +// launch-all branch validates the SPV settings and reports the offending +// field. +func TestMaintainerConfig_RejectsExplicitZeroMaxProofHeaders(t *testing.T) { + command := &cobra.Command{Use: "maintainer-test"} + cfg := &config.Config{} + initMaintainerFlags(command, cfg) + + if err := command.Flags().Parse( + []string{"--spv.maxProofHeaders", "0"}, + ); err != nil { + t.Fatalf("failed to parse flags: [%v]", err) + } + + // Establishes that zero is genuinely reachable through the CLI rather than + // being rejected by flag parsing itself. + if got := cfg.Maintainer.Spv.MaxProofHeaders; got != 0 { + t.Fatalf("expected the flag to parse zero into config, got [%d]", got) + } + + err := validateMaintainerConfig(cfg) + if err == nil { + t.Fatal( + "expected startup validation to reject --spv.maxProofHeaders 0, got no error", + ) + } + if !strings.Contains(err.Error(), "maxProofHeaders") { + t.Errorf( + "expected the error to name the offending setting, got: [%v]", + err, + ) + } +} + +// TestMaintainerConfig_AcceptsDefaultMaxProofHeaders asserts the validation +// added above does not reject a normally-configured maintainer. +func TestMaintainerConfig_AcceptsDefaultMaxProofHeaders(t *testing.T) { + command := &cobra.Command{Use: "maintainer-test"} + cfg := &config.Config{} + initMaintainerFlags(command, cfg) + + if err := command.Flags().Parse([]string{}); err != nil { + t.Fatalf("failed to parse flags: [%v]", err) + } + + if err := validateMaintainerConfig(cfg); err != nil { + t.Errorf( + "expected the default configuration to be accepted, got error: [%v]", + err, + ) + } +} + +// TestMaintainerConfig_AcceptsCustomMaxProofHeaders asserts that explicitly +// provided positive values flow through the flag -> config -> validation path, +// not just the omitted-flag default. Without these cases a regression that +// breaks non-default values (e.g. a type conversion or off-by-one in +// validation) would only surface when an operator actually deviates from the +// 144 default. +func TestMaintainerConfig_AcceptsCustomMaxProofHeaders(t *testing.T) { + values := []string{"1", "288"} + + for _, value := range values { + t.Run(value, func(t *testing.T) { + command := &cobra.Command{Use: "maintainer-test"} + cfg := &config.Config{} + initMaintainerFlags(command, cfg) + + if err := command.Flags().Parse( + []string{"--spv.maxProofHeaders", value}, + ); err != nil { + t.Fatalf("failed to parse flags: [%v]", err) + } + + if err := validateMaintainerConfig(cfg); err != nil { + t.Errorf( + "expected --spv.maxProofHeaders %s to be accepted, got error: [%v]", + value, + err, + ) + } + }) + } +} diff --git a/cmd/start.go b/cmd/start.go index c5bc8902f2..8a8a5e0a46 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -7,10 +7,10 @@ import ( "github.com/keep-network/keep-core/pkg/tbtcpg" - "github.com/keep-network/keep-common/pkg/persistence" "github.com/keep-network/keep-core/build" "github.com/keep-network/keep-core/pkg/bitcoin/electrum" "github.com/keep-network/keep-core/pkg/operator" + "github.com/keep-network/keep-core/pkg/persistence" "github.com/keep-network/keep-core/pkg/storage" "github.com/spf13/cobra" @@ -139,11 +139,13 @@ func start(cmd *cobra.Command) error { rpcHealthChecker := clientinfo.NewRPCHealthChecker( clientInfoRegistry, - blockCounter, + tbtcChain, btcChain, clientConfig.ClientInfo.RPCHealthCheckInterval, ) - rpcHealthChecker.Start(ctx) + // An unavailable RPC must not delay starting the node's + // initialization (beacon and tbtc). + go rpcHealthChecker.Start(ctx) } err = beacon.Initialize( @@ -231,7 +233,7 @@ func initializeClientInfo( signing chain.Signing, blockCounter chain.BlockCounter, ) *clientinfo.Registry { - registry, isConfigured := clientinfo.Initialize(ctx, config.ClientInfo.Port) + registry, isConfigured := clientinfo.Initialize(ctx, config.ClientInfo) if !isConfigured { logger.Infof("client info endpoint not configured") return nil diff --git a/config/category.go b/config/category.go index f6b3f2ab0c..3fadf3ab35 100644 --- a/config/category.go +++ b/config/category.go @@ -30,6 +30,7 @@ var StartCmdCategories = []Category{ var MaintainerCategories = []Category{ Ethereum, BitcoinElectrum, + ClientInfo, Maintainer, } diff --git a/config/config.go b/config/config.go index 92081b2f10..89ce99cdfb 100644 --- a/config/config.go +++ b/config/config.go @@ -18,8 +18,8 @@ import ( "github.com/spf13/viper" "golang.org/x/term" - commonEthereum "github.com/keep-network/keep-common/pkg/chain/ethereum" "github.com/keep-network/keep-core/pkg/bitcoin/electrum" + commonEthereum "github.com/keep-network/keep-core/pkg/chain/ethereumutil" "github.com/keep-network/keep-core/pkg/clientinfo" "github.com/keep-network/keep-core/pkg/maintainer" "github.com/keep-network/keep-core/pkg/net/libp2p" @@ -227,6 +227,14 @@ func validateConfig(config *Config, categories ...Category) error { "missing value for storage.dir; see storage section in configuration", )) } + case Tbtc: + if err := config.Tbtc.TransactionMonitor.Validate(); err != nil { + result = multierror.Append(result, err) + } + case Maintainer: + if err := config.Maintainer.Validate(); err != nil { + result = multierror.Append(result, err) + } } } diff --git a/config/config_test.go b/config/config_test.go index f8de558c4e..cd270468da 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -11,6 +11,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/spf13/viper" "golang.org/x/exp/slices" "github.com/keep-network/keep-core/pkg/chain/ethereum" @@ -18,8 +19,159 @@ import ( ethereumEcdsa "github.com/keep-network/keep-core/pkg/chain/ethereum/ecdsa/gen" ethereumTbtc "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen" ethereumThreshold "github.com/keep-network/keep-core/pkg/chain/ethereum/threshold/gen" + "github.com/keep-network/keep-core/pkg/maintainer" + "github.com/keep-network/keep-core/pkg/maintainer/btcdiff" + "github.com/keep-network/keep-core/pkg/maintainer/spv" + "github.com/keep-network/keep-core/pkg/tbtc" ) +func TestValidateConfig_TransactionMonitor(t *testing.T) { + cfg := &Config{ + Tbtc: tbtc.Config{TransactionMonitor: tbtc.TransactionMonitorConfig{ + StuckThreshold: time.Hour, + MaxTrackingAge: 30 * time.Minute, + }}, + Maintainer: maintainer.Config{ + Spv: spv.Config{ + HistoryDepth: spv.DefaultHistoryDepth, + TransactionLimit: spv.DefaultTransactionLimit, + RestartBackoffTime: spv.DefaultRestartBackoffTime, + IdleBackoffTime: spv.DefaultIdleBackOffTime, + MaxProofHeaders: spv.DefaultMaxProofHeaders, + }, + }, + } + if err := validateConfig(cfg, Tbtc); err == nil || !strings.Contains(err.Error(), "maxTrackingAge") { + t.Fatalf("expected invalid monitoring settings to fail configuration validation, got %v", err) + } + if err := validateConfig(cfg, Maintainer); err != nil { + t.Fatalf("a command that does not start tBTC should ignore its monitor settings: %v", err) + } +} + +func TestValidateConfig_Maintainer(t *testing.T) { + tests := map[string]struct { + config *Config + expectErr bool + }{ + "launch-all with zero SPV maxProofHeaders fails": { + config: &Config{ + Maintainer: maintainer.Config{ + BitcoinDifficulty: btcdiff.Config{Enabled: false}, + Spv: spv.Config{Enabled: false, MaxProofHeaders: 0}, + }, + }, + expectErr: true, + }, + "enabled SPV with zero maxProofHeaders fails": { + config: &Config{ + Maintainer: maintainer.Config{ + BitcoinDifficulty: btcdiff.Config{Enabled: false}, + Spv: spv.Config{Enabled: true, MaxProofHeaders: 0}, + }, + }, + expectErr: true, + }, + "difficulty-only with zero SPV maxProofHeaders passes": { + config: &Config{ + Maintainer: maintainer.Config{ + BitcoinDifficulty: btcdiff.Config{Enabled: true}, + Spv: spv.Config{Enabled: false, MaxProofHeaders: 0}, + }, + }, + expectErr: false, + }, + "launch-all with positive SPV maxProofHeaders passes": { + config: &Config{ + Maintainer: maintainer.Config{ + BitcoinDifficulty: btcdiff.Config{Enabled: false}, + Spv: spv.Config{ + Enabled: false, + HistoryDepth: spv.DefaultHistoryDepth, + TransactionLimit: spv.DefaultTransactionLimit, + RestartBackoffTime: spv.DefaultRestartBackoffTime, + IdleBackoffTime: spv.DefaultIdleBackOffTime, + MaxProofHeaders: spv.DefaultMaxProofHeaders, + }, + }, + }, + expectErr: false, + }, + "enabled SPV with positive maxProofHeaders passes": { + config: &Config{ + Maintainer: maintainer.Config{ + BitcoinDifficulty: btcdiff.Config{Enabled: false}, + Spv: spv.Config{ + Enabled: true, + HistoryDepth: spv.DefaultHistoryDepth, + TransactionLimit: spv.DefaultTransactionLimit, + RestartBackoffTime: spv.DefaultRestartBackoffTime, + IdleBackoffTime: spv.DefaultIdleBackOffTime, + MaxProofHeaders: spv.DefaultMaxProofHeaders, + }, + }, + }, + expectErr: false, + }, + "enabled SPV with zero historyDepth fails": { + config: &Config{ + Maintainer: maintainer.Config{ + BitcoinDifficulty: btcdiff.Config{Enabled: false}, + Spv: spv.Config{ + Enabled: true, + TransactionLimit: spv.DefaultTransactionLimit, + RestartBackoffTime: spv.DefaultRestartBackoffTime, + IdleBackoffTime: spv.DefaultIdleBackOffTime, + MaxProofHeaders: spv.DefaultMaxProofHeaders, + }, + }, + }, + expectErr: true, + }, + "enabled SPV with zero transactionLimit fails": { + config: &Config{ + Maintainer: maintainer.Config{ + BitcoinDifficulty: btcdiff.Config{Enabled: false}, + Spv: spv.Config{ + Enabled: true, + HistoryDepth: spv.DefaultHistoryDepth, + RestartBackoffTime: spv.DefaultRestartBackoffTime, + IdleBackoffTime: spv.DefaultIdleBackOffTime, + MaxProofHeaders: spv.DefaultMaxProofHeaders, + }, + }, + }, + expectErr: true, + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + err := validateConfig(test.config, Maintainer) + + if test.expectErr { + if err == nil { + t.Fatal("expected error, got nil") + } + } else { + if err != nil { + t.Fatalf("expected no error, got: %v", err) + } + } + }) + } + + // Commands not running the Maintainer category should ignore Maintainer settings. + cfgZeroLaunchAll := &Config{ + Maintainer: maintainer.Config{ + Spv: spv.Config{MaxProofHeaders: 0}, + }, + } + if err := validateConfig(cfgZeroLaunchAll, Tbtc); err != nil { + t.Fatalf("a command that does not start Maintainer should ignore its settings: %v", err) + } +} + func TestReadConfigFromFile(t *testing.T) { filePaths := []string{ "../test/config.toml", @@ -233,6 +385,10 @@ func TestReadConfigFromFile(t *testing.T) { readValueFunc: func(c *Config) interface{} { return c.Maintainer.Spv.IdleBackoffTime }, expectedValue: 15 * time.Minute, }, + "Maintainer.Spv.MaxProofHeaders": { + readValueFunc: func(c *Config) interface{} { return c.Maintainer.Spv.MaxProofHeaders }, + expectedValue: uint(144), + }, } for _, filePath := range filePaths { @@ -410,3 +566,53 @@ func TestReadConfig_ReadContracts(t *testing.T) { }) } } + +// TestUnmarshalElectrumFallbackURLs guards the operator arm path for the +// Electrum failover feature: the fallbackURLs config key must reach +// electrum.Config.FallbackURLs through the production viper decode path +// (with the same decode hooks unmarshalConfig applies). +func TestUnmarshalElectrumFallbackURLs(t *testing.T) { + t.Run("string slice form", func(t *testing.T) { + viper.Set("bitcoin.electrum.fallbackURLs", []string{ + "wss://one.example:443", + "wss://two.example:443", + }) + defer viper.Set("bitcoin.electrum.fallbackURLs", nil) + + cfg := &Config{} + if err := unmarshalConfig(cfg); err != nil { + t.Fatalf("failed to unmarshal config: [%v]", err) + } + + expected := []string{"wss://one.example:443", "wss://two.example:443"} + if !reflect.DeepEqual(cfg.Bitcoin.Electrum.FallbackURLs, expected) { + t.Errorf( + "unexpected FallbackURLs\nexpected: %v\nactual: %v", + expected, + cfg.Bitcoin.Electrum.FallbackURLs, + ) + } + }) + + t.Run("comma-separated string form", func(t *testing.T) { + viper.Set( + "bitcoin.electrum.fallbackURLs", + "wss://three.example:443,wss://four.example:443", + ) + defer viper.Set("bitcoin.electrum.fallbackURLs", nil) + + cfg := &Config{} + if err := unmarshalConfig(cfg); err != nil { + t.Fatalf("failed to unmarshal config: [%v]", err) + } + + expected := []string{"wss://three.example:443", "wss://four.example:443"} + if !reflect.DeepEqual(cfg.Bitcoin.Electrum.FallbackURLs, expected) { + t.Errorf( + "unexpected FallbackURLs\nexpected: %v\nactual: %v", + expected, + cfg.Bitcoin.Electrum.FallbackURLs, + ) + } + }) +} diff --git a/config/contracts.go b/config/contracts.go index aea80e1f61..a6f229514e 100644 --- a/config/contracts.go +++ b/config/contracts.go @@ -7,8 +7,8 @@ import ( "github.com/spf13/viper" - commonEthereum "github.com/keep-network/keep-common/pkg/chain/ethereum" chainEthereum "github.com/keep-network/keep-core/pkg/chain/ethereum" + commonEthereum "github.com/keep-network/keep-core/pkg/chain/ethereumutil" ethereumBeacon "github.com/keep-network/keep-core/pkg/chain/ethereum/beacon/gen" ethereumEcdsa "github.com/keep-network/keep-core/pkg/chain/ethereum/ecdsa/gen" diff --git a/config/electrum.go b/config/electrum.go index 2d3b763e4c..fd6db183d3 100644 --- a/config/electrum.go +++ b/config/electrum.go @@ -30,7 +30,7 @@ func readElectrumUrls(network bitcoin.Network) ( // resolveElectrum checks if Electrum is already configured. If the Electrum URL // is empty it reads the Electrum configs from the embedded list for the given -// network and picks up one randomly. +// network, picks one randomly, and retains the others for automatic failover. func (c *Config) resolveElectrum(rng *rand.Rand) error { network := c.Bitcoin.Network @@ -70,15 +70,59 @@ func (c *Config) resolveElectrum(rng *rand.Rand) error { return fmt.Errorf("failed to read default Electrum URLs: [%v]", err) } + return c.selectElectrumServer(urls, rng) +} + +func (c *Config) selectElectrumServer(urls []string, rng *rand.Rand) error { + if len(urls) == 0 { + return fmt.Errorf("default Electrum URL list is empty") + } + // #nosec G404 (insecure random number source (rand)) // Picking up an Electrum server does not require secure randomness. selectedURL := urls[rng.Intn(len(urls))] logger.Infof("auto-selecting Electrum server: [%v]", selectedURL) - // Set only the URL in the original config. Other fields may be already set, - // and we don't want to override them. + // Retain the other connection settings while configuring the server pool. c.Bitcoin.Electrum.URL = selectedURL + // Operator-supplied fallbacks are explicit configuration and take + // precedence over the embedded candidates: honor them as-is (minus the + // selected primary) and do not append the embedded remainder on top of + // them. Without operator fallbacks, retain the embedded remainder for + // automatic failover in a per-process shuffled order. + fallbackURLs := c.Bitcoin.Electrum.FallbackURLs + if len(fallbackURLs) > 0 { + filtered := fallbackURLs[:0] + for _, url := range fallbackURLs { + if url != selectedURL { + filtered = append(filtered, url) + } + } + c.Bitcoin.Electrum.FallbackURLs = filtered + } else { + for _, url := range urls { + if url != selectedURL { + fallbackURLs = append(fallbackURLs, url) + } + } + c.Bitcoin.Electrum.FallbackURLs = fallbackURLs + + // Shuffle the embedded fallback candidates using the injected rng so + // each process derives its own independent rotation order instead of + // always retaining the embedded list order. + // #nosec G404 (insecure random number source (rand)) + // Ordering fallback candidates does not require secure randomness. + rng.Shuffle(len(fallbackURLs), func(i, j int) { + fallbackURLs[i], fallbackURLs[j] = fallbackURLs[j], fallbackURLs[i] + }) + } + + logger.Infof( + "using Electrum fallback servers: [%v]", + c.Bitcoin.Electrum.FallbackURLs, + ) + return nil } diff --git a/config/electrum_test.go b/config/electrum_test.go index 30b9166fee..c998951a63 100644 --- a/config/electrum_test.go +++ b/config/electrum_test.go @@ -2,8 +2,13 @@ package config import ( "math/rand" + "os" + "path/filepath" "reflect" + "sort" + "strings" "testing" + "time" "github.com/go-test/deep" @@ -97,3 +102,219 @@ func (s *fakeRandSource) Int63() int64 { func (s *fakeRandSource) Seed(expectedValue int64) { s.expectedValue = expectedValue } + +func TestSelectElectrumServerRetainsAlternatives(t *testing.T) { + cfg := &Config{} + cfg.Bitcoin.Electrum.RequestTimeout = time.Second + err := cfg.selectElectrumServer([]string{"first", "second", "third"}, rand.New(&fakeRandSource{1})) + if err != nil { + t.Fatal(err) + } + if cfg.Bitcoin.Electrum.URL != "second" { + t.Fatalf("unexpected selected server: %+v", cfg.Bitcoin.Electrum) + } + gotFallbacks := append([]string{}, cfg.Bitcoin.Electrum.FallbackURLs...) + sort.Strings(gotFallbacks) + if !reflect.DeepEqual(gotFallbacks, []string{"first", "third"}) { + t.Fatalf("unexpected server pool: %+v", cfg.Bitcoin.Electrum) + } + if cfg.Bitcoin.Electrum.RequestTimeout != time.Second { + t.Fatal("connection settings were overwritten") + } +} + +// TestSelectElectrumServerShufflesFallbacks proves that the fallback order is +// derived from the injected rng instead of always retaining the embedded +// list order. With a fixed seed the resulting order is deterministic. +func TestSelectElectrumServerShufflesFallbacks(t *testing.T) { + cfg := &Config{} + err := cfg.selectElectrumServer([]string{"first", "second", "third"}, rand.New(&fakeRandSource{1})) + if err != nil { + t.Fatal(err) + } + // The un-shuffled list order (excluding the selected primary "second") + // would be ["first", "third"]; the seeded rng shuffles it to + // ["third", "first"]. + if !reflect.DeepEqual(cfg.Bitcoin.Electrum.FallbackURLs, []string{"third", "first"}) { + t.Fatalf("expected shuffled fallback order, got: %v", cfg.Bitcoin.Electrum.FallbackURLs) + } +} + +func TestResolveElectrumExplicitURL(t *testing.T) { + cfg := &Config{} + cfg.Bitcoin.Network = bitcoin.Mainnet + cfg.Bitcoin.Electrum.URL = "ssl://private.example:50002" + if err := cfg.resolveElectrum(rand.New(&fakeRandSource{})); err != nil { + t.Fatal(err) + } + if cfg.Bitcoin.Electrum.URL != "ssl://private.example:50002" || len(cfg.Bitcoin.Electrum.FallbackURLs) != 0 { + t.Fatalf("explicit URL acquired automatic fallbacks: %+v", cfg.Bitcoin.Electrum) + } +} + +func TestSelectElectrumServerEmptyList(t *testing.T) { + if err := new(Config).selectElectrumServer(nil, rand.New(&fakeRandSource{})); err == nil { + t.Fatal("expected error for empty server pool") + } +} + +// TestResolveElectrumMultiURLFile exercises the same parsing pipeline +// readElectrumUrls uses (split-on-newline plus cleanStrings) against a +// temporary file modeled on config/_electrum_urls/testnet4's format (leading +// comments and a blank line), then resolves it through selectElectrumServer +// exactly as resolveElectrum would. +func TestResolveElectrumMultiURLFile(t *testing.T) { + content := "# Default Electrum URLs for Bitcoin testnet4 (one is chosen at random at startup).\n" + + "# Override with --bitcoin.electrum.url or bitcoin.electrum.url in the config file.\n" + + "\n" + + "ssl://first.example:50002\n" + + "ssl://second.example:50002\n" + + "ssl://third.example:50002\n" + + path := filepath.Join(t.TempDir(), "testnet4") + if err := os.WriteFile(path, []byte(content), 0o600); err != nil { + t.Fatal(err) + } + + file, err := os.ReadFile(path) + if err != nil { + t.Fatal(err) + } + urls := cleanStrings(strings.Split(string(file), "\n")) + + expectedURLs := []string{ + "ssl://first.example:50002", + "ssl://second.example:50002", + "ssl://third.example:50002", + } + if !reflect.DeepEqual(urls, expectedURLs) { + t.Fatalf("comments/blank lines leaked into parsed URLs: %v", urls) + } + + cfg := &Config{} + cfg.Bitcoin.Network = bitcoin.Testnet4 + if err := cfg.selectElectrumServer(urls, rand.New(&fakeRandSource{1})); err != nil { + t.Fatal(err) + } + + if cfg.Bitcoin.Electrum.URL == "" { + t.Fatal("no primary URL was selected") + } + pool := append([]string{cfg.Bitcoin.Electrum.URL}, cfg.Bitcoin.Electrum.FallbackURLs...) + sort.Strings(pool) + if !reflect.DeepEqual(pool, expectedURLs) { + t.Fatalf( + "selected server pool does not match parsed URLs: url=%s fallback=%v", + cfg.Bitcoin.Electrum.URL, cfg.Bitcoin.Electrum.FallbackURLs, + ) + } + if len(cfg.Bitcoin.Electrum.FallbackURLs) != len(expectedURLs)-1 { + t.Fatalf("unexpected fallback count: %v", cfg.Bitcoin.Electrum.FallbackURLs) + } +} + +// TestSelectElectrumServerHonorsOperatorFallbacks guards the operator arm path +// for failover: an operator-supplied fallback list must survive auto-selection +// instead of being overwritten by the embedded candidate remainder. +func TestSelectElectrumServerHonorsOperatorFallbacks(t *testing.T) { + t.Run("operator list replaces embedded remainder", func(t *testing.T) { + cfg := &Config{} + cfg.Bitcoin.Electrum.FallbackURLs = []string{ + "wss://op1.example:443", + "wss://op2.example:443", + } + + embedded := []string{ + "wss://embedded1.example:443", + "wss://embedded2.example:443", + } + if err := cfg.selectElectrumServer(embedded, rand.New(&fakeRandSource{1})); err != nil { + t.Fatal(err) + } + + expected := []string{"wss://op1.example:443", "wss://op2.example:443"} + if !reflect.DeepEqual(cfg.Bitcoin.Electrum.FallbackURLs, expected) { + t.Fatalf( + "operator fallbacks were not retained\nexpected: %v\nactual: %v", + expected, + cfg.Bitcoin.Electrum.FallbackURLs, + ) + } + }) + + t.Run("selected primary is deduped from operator list", func(t *testing.T) { + cfg := &Config{} + cfg.Bitcoin.Electrum.FallbackURLs = []string{ + "wss://embedded1.example:443", // equals the only embedded candidate + "wss://op1.example:443", + } + + if err := cfg.selectElectrumServer( + []string{"wss://embedded1.example:443"}, + rand.New(&fakeRandSource{1}), + ); err != nil { + t.Fatal(err) + } + + expected := []string{"wss://op1.example:443"} + if !reflect.DeepEqual(cfg.Bitcoin.Electrum.FallbackURLs, expected) { + t.Fatalf( + "selected primary not deduped from operator fallbacks\nexpected: %v\nactual: %v", + expected, + cfg.Bitcoin.Electrum.FallbackURLs, + ) + } + }) +} + +// TestResolveElectrumKeepsOperatorFallbacks covers the full resolution path: +// operator fallbacks set with no explicit URL survive auto-selection, and an +// explicit URL keeps both itself (pinned) and the operator fallbacks. +func TestResolveElectrumKeepsOperatorFallbacks(t *testing.T) { + t.Run("auto-selected primary keeps operator fallbacks", func(t *testing.T) { + cfg := &Config{} + cfg.Bitcoin.Network = bitcoin.Mainnet + cfg.Bitcoin.Electrum.FallbackURLs = []string{"wss://op1.example:443"} + + if err := cfg.resolveElectrum(rand.New(&fakeRandSource{1})); err != nil { + t.Fatal(err) + } + + if cfg.Bitcoin.Electrum.URL != "wss://electrum.boar.network:2083" { + t.Fatalf("unexpected primary: %v", cfg.Bitcoin.Electrum.URL) + } + + expected := []string{"wss://op1.example:443"} + if !reflect.DeepEqual(cfg.Bitcoin.Electrum.FallbackURLs, expected) { + t.Fatalf( + "operator fallbacks lost in auto-select path\nexpected: %v\nactual: %v", + expected, + cfg.Bitcoin.Electrum.FallbackURLs, + ) + } + }) + + t.Run("explicit URL stays pinned with operator fallbacks", func(t *testing.T) { + cfg := &Config{} + cfg.Bitcoin.Network = bitcoin.Mainnet + cfg.Bitcoin.Electrum.URL = "ssl://explicit.example:50002" + cfg.Bitcoin.Electrum.FallbackURLs = []string{"ssl://backup.example:50002"} + + if err := cfg.resolveElectrum(rand.New(&fakeRandSource{1})); err != nil { + t.Fatal(err) + } + + if cfg.Bitcoin.Electrum.URL != "ssl://explicit.example:50002" { + t.Fatalf("explicit URL was unpinned: %v", cfg.Bitcoin.Electrum.URL) + } + + expected := []string{"ssl://backup.example:50002"} + if !reflect.DeepEqual(cfg.Bitcoin.Electrum.FallbackURLs, expected) { + t.Fatalf( + "operator fallbacks lost with explicit URL\nexpected: %v\nactual: %v", + expected, + cfg.Bitcoin.Electrum.FallbackURLs, + ) + } + }) +} diff --git a/config/network/network.go b/config/network/network.go index 28274f966d..0935990d09 100644 --- a/config/network/network.go +++ b/config/network/network.go @@ -1,8 +1,8 @@ package network import ( - "github.com/keep-network/keep-common/pkg/chain/ethereum" "github.com/keep-network/keep-core/pkg/bitcoin" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil" ) // Type is a type used for networks enumeration. diff --git a/configs/config.toml.SAMPLE b/configs/config.toml.SAMPLE index 9ef7e220e9..1f79b65920 100644 --- a/configs/config.toml.SAMPLE +++ b/configs/config.toml.SAMPLE @@ -52,6 +52,12 @@ KeyFile = "/Users/someuser/ethereum/data/keystore/UTC--2018-03-11T01-37-33.20276 # one of the default embedded servers is selected randomly at startup. # URL = "tcp://electrumx.server.io:50001" +# List of alternate Electrum server URLs used for automatic failover. When +# URL is omitted, these are appended behind the auto-selected embedded +# primary; when URL is explicit, it remains the preferred primary and these +# are tried on failure. +# FallbackURLs = ["ssl://backup1.example:50002", "ssl://backup2.example:50002"] + # Timeout for a single attempt of Electrum connection establishment. # ConnectTimeout = "10s" @@ -118,6 +124,20 @@ Port = 9601 # PreParamsGenerationConcurrency = 1 # KeyGenerationConcurrency = 1 +# Stuck wallet transaction monitoring. Values shown are the defaults. +# Zero selects the default; negative values are rejected. MaxTracked must +# not exceed 100000. MaxTrackingAge must be at least StuckThreshold. These +# settings apply when the node starts. +# Command-line overrides use --tbtc.transactionMonitor., for example +# --tbtc.transactionMonitor.stuckThreshold=30m. +# +# [tbtc.transactionMonitor] +# StuckThreshold = "6h" +# CheckInterval = "5m" +# MaxTracked = 1000 +# MaxTrackingAge = "24h" +# CheckBudget = "2m" + # Developer options to work with locally deployed contracts # # [developer] diff --git a/docs/dev-ops.adoc b/docs/dev-ops.adoc index 1908b4312e..60e182ece1 100644 --- a/docs/dev-ops.adoc +++ b/docs/dev-ops.adoc @@ -7,7 +7,7 @@ = Kubernetes -At Keep we run on GCP + Kubernetes. To accommodate the aforementioned +At Keep we run on GCP and Kubernetes. To accommodate the xref:./run-keep-node.adoc#system-considerations[System Considerations] we use the following pattern for each of our environments: @@ -16,4 +16,3 @@ we use the following pattern for each of our environments: - A LoadBalancer Service for each client. - A StatefulSet for each client. -You can see our Testnet Kubernetes configurations link:https://github.com/threshold-network/keep-core/tree/main/infrastructure/kube/keep-test[here]. diff --git a/docs/development/README.adoc b/docs/development/README.adoc index e556878d1b..d2343182ab 100644 --- a/docs/development/README.adoc +++ b/docs/development/README.adoc @@ -254,3 +254,61 @@ Development ``` make ``` + +== Electrum server pool and failover + +The Bitcoin Electrum client connects through a pool of server URLs: an +optional explicit `bitcoin.electrum.url` (or, if omitted, a URL chosen +randomly from the embedded list under `config/_electrum_urls/`), +plus any `bitcoin.electrum.fallbackURLs` an operator supplies alongside it. + +Failover is active once the effective pool holds two or more URLs, whether +the second URL comes from operator-supplied fallbacks or from a second +vetted entry in the embedded list. + +NOTE: Each network's embedded list currently holds a single entry, so +failover across embedded servers becomes active only once a second server +is added to that network's list. + +When the pool holds a single URL, the client stays pinned to it: on a +transport failure it retires and re-dials that same server rather than +switching, so it never wedges on a half-open socket. An explicit +`bitcoin.electrum.url` also stays pinned as the pool's primary -- the +client keeps preferring it and only falls back to `fallbackURLs` on +failure. + +=== What triggers a switch + +Only transport-level failures move the client to the next candidate in the +pool: + +* dial failures and connection resets +* server-initiated shutdowns +* request timeouts +* a failed server-version or server-features verification + +Authoritative JSON-RPC responses from a server -- a rejected or not-found +transaction, a height out of range, a fee-oracle error such as `-32603` -- +are treated as valid answers from a healthy server and never trigger a +switch. Missing fee estimates retry against the other confirmation targets +on the current server using a single retry budget shared across all +targets, rather than a separate budget per target; caller cancellation +never marks a server unhealthy. + +=== Keepalive and healing back to the primary + +Keepalive is a single-shot ping bounded by +`bitcoin.electrum.requestTimeout`: a failed ping fails over to the next +candidate immediately rather than retrying for minutes. Once the client has +failed over to a non-primary server, it keeps probing the primary in the +background. After two consecutive successful keepalive ticks on the +current server, it dials and verifies the primary and, if healthy, swaps +the live connection back to it -- so the client migrates back to its +preferred server without operator intervention. + +=== Chain identity + +The first successfully verified server that reports a non-empty features.genesis_hash establishes the pool's chain identity. Every later candidate must +report a matching genesis hash or it is rejected as unsuitable for the +pool; a candidate that omits the field is still accepted, but the client +logs a warning since its chain identity cannot be confirmed. diff --git a/docs/development/go-guidelines.adoc b/docs/development/go-guidelines.adoc index 64b55cc389..f8783ab44f 100644 --- a/docs/development/go-guidelines.adoc +++ b/docs/development/go-guidelines.adoc @@ -67,3 +67,46 @@ There are a few common patterns for testing in the Keep codebase: information is deemed useful, it can be included before the initial newline. See `pkg/internal/testutils` for an example of an assert helper that uses this style. + +=== Integer conversions + +Keep numeric validation and narrowing in the same function. A checked conversion +should return the converted value and an error, so callers cannot accidentally +validate one value and cast another. Use `group.MemberIndexFromUint32` for +member indices decoded from protocol messages or persisted signers. It checks +the type range; wire/protocol messages get their membership re-checked +downstream, but persisted signer records do not, so persisted-signer callers +must reject zero at decode time instead. Note: `MemberIndex` is currently a +type alias, not a defined type, so this helper is a convention, not a +compiler-enforced guarantee; a future refactor to a defined type would close +this gap. + +Use `new(big.Int).SetUint64(value)` to construct a nonnegative `big.Int` from an +unsigned block number or transaction index. When serializing a `big.Int` into a +fixed-width unsigned field, check `IsUint64` first. For narrower unsigned +destinations, also check the destination type's upper bound before converting. +For signed Bitcoin amounts, reject negative inputs before converting to +unsigned ABI fields and check the upper bound before converting unsigned +responses to `int64`. Check arithmetic before it can overflow; a check on an +already-wrapped fee cannot recover the original value. + +Some conversions intentionally preserve a bit pattern rather than a numeric +value. Existing deterministic retry and coordination seeds use all 64 bits, +including the sign bit, and Bitcoin version fields preserve their signed 32-bit +wire encoding. Do not reject, mask, or clamp these values: doing so would change +protocol behavior. Such conversions use a local `#nosec G115` comment explaining +the representation contract. Other local exceptions identify the concrete +upstream-library, domain, or test-only range guarantee that makes the +conversion safe. Do not exclude G115 globally or +annotate a conversion without checking its callers and bounds. + +Run the G115 check with the same generated-code exclusions used by CI: + +[source,shell] +---- +gosec -include=G115 \ + -exclude-dir=pkg/chain/ethereum/beacon/gen \ + -exclude-dir=pkg/chain/ethereum/ecdsa/gen \ + -exclude-dir=pkg/chain/ethereum/threshold/gen \ + -exclude-dir=pkg/chain/ethereum/tbtc/gen ./... +---- diff --git a/docs/index.adoc b/docs/index.adoc index c54fe111c2..4d8622438c 100644 --- a/docs/index.adoc +++ b/docs/index.adoc @@ -4,5 +4,6 @@ * xref:./registration.adoc[Registration] * xref:./run-keep-node.adoc[Run Keep Client Node] +* xref:./profiling.md[Profiling & pprof runbook] * xref:./development/README.adoc[Developers] * xref:./dev-ops.adoc[DevOps] \ No newline at end of file diff --git a/docs/performance-metrics.adoc b/docs/performance-metrics.adoc index af2a7132bc..74789c20dc 100644 --- a/docs/performance-metrics.adoc +++ b/docs/performance-metrics.adoc @@ -197,6 +197,80 @@ For each action type, the following metrics are available: *Description*: Total count of coordination duration samples *Labels*: None +=== Redemption Proposal Metrics + +These counters are recorded only by the node acting as coordination leader +for a given wallet and coordination window; a node with no leader elections +in the observed window will show no increase on these counters. + +==== `performance_redemption_proposal_generation_total` +*Type*: Counter +*Description*: Total number of redemption proposal generation task invocations, including retries (leader-only) +*Labels*: None + +==== `performance_redemption_proposal_generation_failed_total` +*Type*: Counter +*Description*: Total number of failed redemption proposal generation tasks, even when a later action succeeds or returns no-op (leader-only) +*Labels*: None + +==== `performance_redemption_proposal_generation_success_total` +*Type*: Counter +*Description*: Total number of redemption proposal generation tasks that produced a proposal (leader-only) +*Labels*: None + +==== `performance_redemption_proposal_broadcast_total` +*Type*: Counter +*Description*: Total number of generated redemption proposals accepted by the local broadcast channel (leader-only) +*Labels*: None + +==== `performance_redemption_proposal_broadcast_failed_total` +*Type*: Counter +*Description*: Total number of failed attempts to broadcast a generated redemption proposal (leader-only) +*Labels*: None + +See docs/redemption-proposal-monitoring.adoc for alerting guidance. + +=== SPV Proof Submission Metrics (Maintainer) + +These metrics are recorded by the SPV maintainer (the `maintainer` command) when +it submits Bitcoin SPV proofs to the host chain. They require the client info +endpoint to be configured. + +NOTE: Running the `maintainer` command starts the client-info HTTP endpoint on +all interfaces on port `9601` by default. Set `ClientInfo.Port` to `0` in +configuration, or pass `--clientInfo.port=0`, to disable the endpoint and +these metrics. + +==== `performance_deposit_sweep_proof_submissions_total` +*Type*: Counter +*Description*: Total number of deposit sweep proof submissions attempted +*Labels*: None + +==== `performance_deposit_sweep_proof_submissions_success_total` +*Type*: Counter +*Description*: Total number of successful deposit sweep proof submissions +*Labels*: None + +==== `performance_deposit_sweep_proof_submissions_failed_total` +*Type*: Counter +*Description*: Total number of failed deposit sweep proof submissions +*Labels*: None + +==== `performance_redemption_proof_submissions_total` +*Type*: Counter +*Description*: Total number of redemption proof submissions attempted +*Labels*: None + +==== `performance_redemption_proof_submissions_success_total` +*Type*: Counter +*Description*: Total number of successful redemption proof submissions +*Labels*: None + +==== `performance_redemption_proof_submissions_failed_total` +*Type*: Counter +*Description*: Total number of failed redemption proof submissions +*Labels*: None + === Network Metrics ==== `performance_incoming_message_queue_size` @@ -276,4 +350,70 @@ For each action type, the following metrics are available: ==== `performance_relay_entry_timeout_reported_total` *Type*: Counter *Description*: Total number of relay entry timeouts reported on-chain -*Labels*: None \ No newline at end of file +*Labels*: None + +== Maintainer health + +The `maintainer` command exposes client-info metrics when `clientInfo.port` is +nonzero (default `9601`). Ethereum and Bitcoin connectivity checks run alongside +the SPV loop. Initial RPC probes run asynchronously so an unavailable endpoint +does not prevent the maintainer from starting. Set `clientInfo.port=0` to disable +the endpoint and metric recording. + +Ethereum health probes fetch the latest header through the chain's RPC client +on every check. They do not use the subscription-backed block counter, which +can retain a height after disconnecting. Probes pass cancellation and a +30-second deadline to the RPC; queuing in the client's rate limiter can delay +completion. The last-check timestamp advances only after the probe returns. +A successful response confirms connectivity, not synchronization with chain tip. + +All names below have the `performance_` prefix on `/metrics`: + +[%header,cols="1,2"] +|=== +|Metric |Meaning +|`rpc_eth_healthy`, `rpc_btc_healthy` +|1 after a successful probe; 0 before the first probe or after a failed probe. +|`rpc_eth_last_check_timestamp_seconds`, `rpc_btc_last_check_timestamp_seconds` +|Unix time of the last completed probe, including failures. Zero means no probe +has completed. Combine freshness with the health value to detect a hung RPC. +|`rpc_health_check_interval_seconds` +|Configured probe interval (60 seconds by default). +|`rpc_eth_response_time_seconds`, `rpc_btc_response_time_seconds` +|Duration in seconds of the most recent successful probe; not updated on +failure. +|`rpc_btc_health_check_benign_errors_total` +|Count of known-benign -32602 (`cp_height` not supported) `GetBlockHeader` +responses. These still mark `rpc_btc_healthy` unhealthy; the counter only +distinguishes benign header-support gaps from other RPC failures. +|`spv_maintainer_active` +|1 while the SPV control loop is running, including its normal backoff; 0 when +disabled or stopped. Use scrape availability to detect a stopped process. +|`spv_maintainer_last_activity_timestamp_seconds` +|Updated at loop startup and at the start and end of each proof task. A timestamp +that stops advancing indicates stalled processing, even if the HTTP server works. +|`spv_maintainer_last_success_timestamp_seconds` +|Time of the last complete successful pass over all proof tasks. A pass with no +pending proofs is successful; this metric does not imply a proof was submitted. +|`spv_maintainer_last_failure_timestamp_seconds` +|Time of the most recent failed proof task; zero if none has failed yet. +Compare against the last-success timestamp to see whether the most recent +cycle failed or succeeded. +|`spv_maintainer_max_backoff_seconds` +|The larger of the configured restart and idle backoffs. Allow this interval plus +a processing margin when alerting on stale activity. +|`spv_proof_task_failures_total`, `redemption_proof_task_failures_total` +|Failed proof tasks, including discovery and proof-info errors before submission. +The second counter includes redemption tasks only. A failed submission increments +both its existing submission-failure counter and these task counters, so do not +sum them as independent failures. +|=== + +Relay-range skips and proof-header-limit skips retain their separate +`spv_proof_skipped_outside_relay_range_total` and +`spv_proof_skipped_exceeded_max_headers_total` counters. They are not task failures. +These counters count attempts, so the same transaction can be counted again in a +later cycle. Check logs for the affected transaction hashes. All SPV maintainer +gauges and counters update immediately when the underlying event occurs, with +no polling delay. Only the `rpc_*` health-status metrics above are sampled on +a 1-minute poll; allow for that delay when alerting on RPC health. diff --git a/docs/profiling.md b/docs/profiling.md new file mode 100644 index 0000000000..fdc0d6c077 --- /dev/null +++ b/docs/profiling.md @@ -0,0 +1,149 @@ +# Go Profiling Runbook + +## Overview + +The keep-core binary exposes Go runtime profiling endpoints via the +`clientinfo` HTTP server. The `/debug/pprof/...` endpoints are gated by +`EnablePprof` in configuration: they are only registered when +`EnablePprof: true` is set explicitly under `[ClientInfo]`, and are +not served otherwise. Profiles are served at `/debug/pprof/` on the +same port as metrics and diagnostics (`ClientInfo.Port`). + +## Security Warning + +The clientinfo HTTP server binds to all interfaces (`0.0.0.0`). The +`EnablePprof` flag is the only thing that prevents the `/debug/pprof/` +endpoints from being reachable on that port: **leave `EnablePprof` +unset or `false` on any node whose `ClientInfo.Port` is reachable +beyond a trusted network.** Leaving the flag at its default (off) is +the secure posture; flipping it on a node exposed to untrusted +networks exposes CPU profiles, heap dumps, and goroutine traces that +can leak sensitive runtime state. + +Safe access patterns when profiling is genuinely needed: +- Run on a private/firewalled network +- Use an SSH tunnel: `ssh -L 9601:localhost:9601 node-host` +- Restrict at the network layer (security group, firewall rule) +- Profile briefly (e.g. `-seconds=` on the CPU profile endpoint) and + set `EnablePprof: false` again when finished + +## Enabling Profiling + +Profiling is disabled by default. To enable it, set `EnablePprof: true` +in your config (TOML example): + +```toml +[ClientInfo] + Port = 9601 + EnablePprof = true +``` + +Or pass via environment / flag if your deployment uses those overrides. +Set `EnablePprof` back to `false` (or remove it) as soon as you are +finished profiling so the endpoints stop being served. + +## Standard Commands + +Replace `9601` with your configured `ClientInfo.Port`. + +### CPU profile (30 seconds) + +```sh +go tool pprof http://localhost:9601/debug/pprof/profile?seconds=30 +``` + +### Heap profile + +```sh +go tool pprof http://localhost:9601/debug/pprof/heap +``` + +### Goroutine dump (text) + +```sh +curl -s http://localhost:9601/debug/pprof/goroutine?debug=2 +``` + +### Trace (5 seconds) + +```sh +curl -o /tmp/trace.out http://localhost:9601/debug/pprof/trace?seconds=5 +go tool trace /tmp/trace.out +``` + +### Mutex contention + +```sh +# Enable mutex profiling first (runtime call or startup flag): +# runtime.SetMutexProfileFraction(1) +go tool pprof http://localhost:9601/debug/pprof/mutex +``` + +## Benchmark + Profile Workflow + +To identify hot paths found by benchmarks: + +Note: `-bench=` accepts a Go regular expression that substring-matches +benchmark names; the patterns below intentionally match every +size-suffixed variant of the named benchmark (e.g. +`BenchmarkGetRecentWindows_100Windows`, `BenchmarkComputeSignatureHashes_5Inputs`). + +```sh +# Run benchmark and write CPU profile +go test ./pkg/tbtc/... -run=^$ -bench=BenchmarkGetRecentWindows \ + -cpuprofile=/tmp/cpu.pprof -benchtime=5s + +# Inspect interactively +go tool pprof /tmp/cpu.pprof +(pprof) top10 +(pprof) web # requires graphviz +``` + +For memory allocation hot paths: + +```sh +go test ./pkg/bitcoin/... -run=^$ -bench=BenchmarkComputeSignatureHashes \ + -memprofile=/tmp/mem.pprof -benchtime=5s +go tool pprof /tmp/mem.pprof +(pprof) alloc_space +(pprof) top10 +``` + +## Comparing Benchmarks Across Commits + +```sh +# Baseline (main branch) +git stash +go test ./pkg/... -run=^$ -bench=. -count=6 | tee /tmp/baseline.txt + +# Candidate (your branch) +git stash pop +go test ./pkg/... -run=^$ -bench=. -count=6 | tee /tmp/candidate.txt + +benchstat /tmp/baseline.txt /tmp/candidate.txt +``` + +Install `benchstat`: `go install golang.org/x/perf/cmd/benchstat@latest` + +## Available Endpoints + +| Endpoint | Description | +|----------|-------------| +| `/debug/pprof/` | Index of available profiles | +| `/debug/pprof/cmdline` | Process command line | +| `/debug/pprof/profile` | CPU profile (30s default) | +| `/debug/pprof/symbol` | Symbol lookup | +| `/debug/pprof/trace` | Execution trace | +| `/debug/pprof/goroutine` | Goroutine stacks | +| `/debug/pprof/heap` | Heap allocations | +| `/debug/pprof/allocs` | Allocation samples | +| `/debug/pprof/block` | Goroutine blocking events | +| `/debug/pprof/mutex` | Mutex contention | + +## Notes + +- CPU profiling adds ~5% overhead to the profiled binary during the sampling + window. It is safe to run against a live node for short durations. +- Heap and goroutine profiles are sampled snapshots; a single sample may + miss transient allocations. Take multiple profiles under load. + diff --git a/docs/redemption-proposal-monitoring.adoc b/docs/redemption-proposal-monitoring.adoc new file mode 100644 index 0000000000..ddad1bd813 --- /dev/null +++ b/docs/redemption-proposal-monitoring.adoc @@ -0,0 +1,47 @@ += Redemption proposal monitoring + +Wallet nodes generate redemption proposals off-chain and broadcast them through +the wallet coordination channel. There is no Ethereum proposal-submitted event +for the on-chain redemption monitor to observe. Scrape wallet nodes running the +`start` command to observe this stage; the SPV maintainer runs after the wallet +has produced the Bitcoin transaction. + +The client-info `/metrics` endpoint exposes these counters with the +`performance_` prefix: + +[cols="1,2",options="header"] +|=== +| Counter | Meaning +| `redemption_proposal_generation_total` | Redemption task invocations, including retries. +| `redemption_proposal_generation_failed_total` | Failed redemption tasks, even when a later action succeeds or returns no-op. +| `redemption_proposal_generation_success_total` | Tasks that produced a redemption proposal. +| `redemption_proposal_broadcast_total` | Generated redemption proposals accepted by the local broadcast channel. +| `redemption_proposal_broadcast_failed_total` | Failed attempts to send a generated redemption proposal. +|=== + +A successful check with no pending requests increments only the attempt counter. +Other wallet actions do not increment these counters. Broadcast success does not +prove peer receipt, signing, Bitcoin confirmation, or Ethereum proof acceptance. +Counters aggregate across wallets on the node and reset on process restart; +they do not add wallet or redemption IDs as metric labels. +These counters are recorded only by the node acting as coordination leader for a given wallet and coordination window, so a node with no leader elections in the observed window reports no attempts/successes; absence of increase on a single node is not itself a signal. Alerting must key on the failure counters (as the doc already does) rather than on missing successes. + +For a notification for each proposal, consume the structured `keep-tbtc` log +event `event="redemption_proposal_broadcast"`. It includes `walletPKH` and +`coordinationBlock`; deduplicate using network, wallet PKH, and coordination +block before forwarding an informational notification to the existing receiver. +The event is emitted only after the first broadcast succeeds, independently of +whether metrics are enabled. Retransmissions do not produce additional events. +Enable JSON logging (`GOLOG_LOG_FMT=json`) in the collector's deployment. + +For failure alerts, evaluate +`increase(performance_redemption_proposal_generation_failed_total[15m]) > 0` +and +`increase(performance_redemption_proposal_broadcast_failed_total[15m]) > 0` +per node, and route them to the existing on-call receiver. Tune the window to +the coordination schedule and retain `instance` and network labels. Counter +alerts require an observed increase; inspect initial values during rollout. +Use the structured log event for individual proposal notifications because an +aggregate counter alert cannot identify each proposal. + +See issue #3664 for rollout verification. diff --git a/docs/release-process.md b/docs/release-process.md index 3d1ed5b74a..457aeda15c 100644 --- a/docs/release-process.md +++ b/docs/release-process.md @@ -9,6 +9,29 @@ Keep Core now supports fully automated releases through GitHub Actions. When you 3. Creates a GitHub release with artifacts 4. Generates release notes +## Release Tracking PR (dev → main) + +When a release cycle accumulates a large or interconnected set of +changes, the project uses a long-lived aggregation PR instead of +landing everything via normal `feature → main` PRs: + +- **Base:** `main` +- **Head:** a moving `dev` branch that accumulates the cycle's work by + merging each sub-PR into `dev` before the sub-PR closes. Sub-PRs are + not merged into `main` — `main` advances only when the aggregation + PR itself merges at the end of the cycle. +- **State:** the PR stays open across the whole cycle. Its diff + against `main` is the live view of "what is still queued for the + next release." + +Sub-PRs are still reviewed and CI'd independently — the aggregation +PR is just the place to watch the cumulative state. Sub-PRs target `dev` +as their base branch; maintainers merge them into `dev` after review. +When the cycle is ready to ship, fast-forward `dev` to the latest `main`, +resolve any final conflicts, and merge the aggregation PR into `main` +as a single merge commit. The version tag is then cut from `main` per +"Creating a Release" below. + ## Creating a Release ### 1. Prepare the Release diff --git a/docs/resources/client-start-help b/docs/resources/client-start-help index 76fcba6f86..2c1a0b3db1 100644 --- a/docs/resources/client-start-help +++ b/docs/resources/client-start-help @@ -13,6 +13,7 @@ Flags: --ethereum.concurrencyLimit int The maximum number of concurrent requests which can be executed against Ethereum client. (default 30) --ethereum.balanceAlertThreshold wei The minimum balance of operator account below which client starts reporting errors in logs. (default 500000000 gwei) --bitcoin.electrum.url scheme://hostname:port URL to the Electrum server in format: scheme://hostname:port. + --bitcoin.electrum.fallbackURLs strings Comma-separated list of alternate Electrum server URLs used for failover when the primary server becomes unavailable. When no primary URL is configured, these are appended behind the auto-selected embedded primary; an explicitly configured primary URL remains preferred, with these tried on failure. --bitcoin.electrum.connectTimeout duration Timeout for a single attempt of Electrum connection establishment. (default 10s) --bitcoin.electrum.connectRetryTimeout duration Timeout for Electrum connection establishment retries. (default 1m0s) --bitcoin.electrum.requestTimeout duration Timeout for a single attempt of Electrum protocol request. (default 30s) diff --git a/docs/retired-components.md b/docs/retired-components.md index 3f524cd8cf..caf174088a 100644 --- a/docs/retired-components.md +++ b/docs/retired-components.md @@ -12,7 +12,7 @@ below are the original locations under the now-extracted v1 tree (formerly - `token-stakedrop/` - `solidity-v1/scripts/withdraw-old-rewards.js` - `solidity-v1/dashboard/` -- KEEP token dashboard Kubernetes manifests under `infrastructure/kube/keep-*` +- the `./infrastructure/` tree, with the exceptions noted below: KEEP-era GKE manifests under `kube/{keep-test,keep-dev,keep-prd,lcl}`, Terraform modules sourcing from the now-defunct `thesis/infrastructure` repository, the `provision-keep-client` initcontainer that consumed `solidity-v1/` contract JSONs (since extracted to `keep-core-v1`), and other private-testnet / Goerli-era assets - `scripts/start_dashboard.sh` These components were removed because they are no longer part of supported @@ -20,7 +20,35 @@ operations, were tied to deprecated KEEP-token workflows, and had accumulated unmaintained security risk. In particular, the old rewards withdrawal helper contained a committed mainnet private key (since rotated and no longer active), and the retired staking escrow had no remaining ETH, KEEP, or T balance on -Ethereum mainnet when checked before removal. +Ethereum mainnet when checked before removal. The removed `infrastructure/` +tree also contained low-sensitivity testnet/dev credential material now +recoverable only via git history: a private Ethereum testnet keystore +passphrase and a hardcoded local-dev dashboard `WS_SECRET`. Neither is a +production credential. + +**Exceptions: three Kubernetes overlays under `infrastructure/kube/` were +kept.** Unlike the rest of the tree, these overlays are actively deployed +(`kubectl apply -k ./`, independent of the retired Terraform) and remain in +the repository at their original paths: + +- `infrastructure/kube/keep-test/tbtc-v2-maintainer/`: the tBTC v2 testnet + maintainer, last patched to fix its Electrum endpoint shortly before this + cleanup +- `infrastructure/kube/keep-prd/tbtc-v2-monitoring/`: tBTC v2 mainnet + monitoring +- `infrastructure/kube/keep-prd/keep-maintainer/`: the keep-client + maintainer StatefulSet on mainnet + +The two `keep-prd/` overlays build on shared bases under +`infrastructure/kube/templates/{keep-maintainer,tbtc-v2-monitoring}/`, which +were kept with them. + +**GCP projects referenced by the retired Terraform remain live.** +`keep-test-f3e0` and `keep-prd-210b` (see `.github/workflows/client.yml`, +`docs/run-keep-node.adoc`, and `docs/registration.adoc`) are still used for +CI image publishing and client-binary distribution. They are managed +out-of-band from the removed Terraform, which had not been applied since +2020 and sourced from the same now-defunct `thesis/infrastructure` remote. Historical documents under the `docs/` tree of `keep-core-v1` (formerly `docs-v1/` here) may still mention these components for release history and diff --git a/go.mod b/go.mod index be68423897..c3efb0f839 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module github.com/keep-network/keep-core -go 1.24.0 +go 1.25.7 -toolchain go1.24.1 +toolchain go1.26.8 replace ( github.com/bnb-chain/tss-lib => github.com/threshold-network/tss-lib v0.0.0-20230901144531-2e712689cfbe @@ -18,8 +18,9 @@ replace ( // (GO-2022-1098, GO-2024-2818, GO-2024-3189) into the Bitcoin consensus, // wire, and script packages. github.com/btcsuite/btcd/btcec => ./third_party/btcsuite/btcec - github.com/checksum0/go-electrum => github.com/keep-network/go-electrum v0.0.0-20240206170935-6038cb594daa - github.com/keep-network/keep-common => github.com/threshold-network/keep-common v1.7.1-tlabs.0 + // The pinned fork needs a concurrency-safe transport abort for cancellation. + // See third_party/go-electrum/VENDOR.md for provenance and local changes. + github.com/checksum0/go-electrum => ./third_party/go-electrum // Temporary replacement until v1.28.2 is released containing `protodelim` package. // See https://github.com/protocolbuffers/protobuf-go/commit/fb0abd915897428ccfdd6b03b48ad8219751ee54 google.golang.org/protobuf/dev => google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8 @@ -45,8 +46,8 @@ require ( github.com/btcsuite/btcd/btcutil v1.1.5 github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 github.com/checksum0/go-electrum v0.0.0-20220912200153-b862ac442cf9 - github.com/ethereum/go-ethereum v1.13.15 - github.com/ferranbt/fastssz v0.1.2 + github.com/ethereum/go-ethereum v1.17.3 + github.com/ferranbt/fastssz v0.1.4 github.com/go-test/deep v1.0.8 github.com/google/gofuzz v1.2.0 github.com/graph-gophers/graphql-go v1.3.0 @@ -58,7 +59,6 @@ require ( github.com/ipfs/go-log v1.0.5 github.com/ipfs/go-log/v2 v2.5.1 github.com/jbenet/goprocess v0.1.4 - github.com/keep-network/keep-common v1.7.1-0.20240424094333-bd36cd25bb74 github.com/libp2p/go-addr-util v0.2.0 github.com/libp2p/go-libp2p v0.38.2 github.com/libp2p/go-libp2p-kad-dht v0.29.0 @@ -66,22 +66,26 @@ require ( github.com/mitchellh/mapstructure v1.5.0 github.com/multiformats/go-multiaddr v0.14.0 github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 - github.com/spf13/cobra v1.5.0 - github.com/spf13/pflag v1.0.5 + github.com/spf13/cobra v1.8.1 + github.com/spf13/pflag v1.0.6 github.com/spf13/viper v1.12.0 go.uber.org/zap v1.27.0 - golang.org/x/crypto v0.32.0 + golang.org/x/crypto v0.47.0 golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 - golang.org/x/sync v0.10.0 - golang.org/x/term v0.28.0 - google.golang.org/protobuf v1.36.3 + golang.org/x/sync v0.19.0 + golang.org/x/term v0.39.0 + google.golang.org/protobuf v1.36.11 google.golang.org/protobuf/dev v0.0.0-00010101000000-000000000000 ) require ( + github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 // indirect github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d // indirect + github.com/crate-crypto/go-eth-kzg v1.5.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect + github.com/emicklei/dot v1.6.2 // indirect + github.com/ethereum/c-kzg-4844/v2 v2.1.6 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pion/datachannel v1.5.10 // indirect @@ -105,31 +109,29 @@ require ( github.com/stretchr/objx v0.5.2 // indirect github.com/stretchr/testify v1.11.1 // indirect github.com/wlynxg/anet v0.0.5 // indirect + golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc // indirect ) require ( - github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/StackExchange/wmi v1.2.1 // indirect github.com/aead/siphash v1.0.1 // indirect github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bits-and-blooms/bitset v1.10.0 // indirect + github.com/bits-and-blooms/bitset v1.20.0 // indirect github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/consensys/bavard v0.1.13 // indirect - github.com/consensys/gnark-crypto v0.12.1 // indirect + github.com/consensys/gnark-crypto v0.18.1 // indirect github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect - github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect - github.com/deckarep/golang-set/v2 v2.1.0 // indirect + github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/decred/dcrd/dcrec/edwards/v2 v2.0.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/deepmap/oapi-codegen v1.6.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/elastic/gosigar v0.14.3 // indirect - github.com/ethereum/c-kzg-4844 v0.4.0 // indirect github.com/flynn/noise v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect @@ -146,9 +148,9 @@ require ( github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/holiman/uint256 v1.2.4 // indirect + github.com/holiman/uint256 v1.3.2 // indirect github.com/huin/goupnp v1.3.0 // indirect - github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect github.com/ipfs/boxo v0.27.2 // indirect github.com/ipfs/go-cid v0.5.0 // indirect @@ -183,7 +185,6 @@ require ( github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/multiformats/go-base32 v0.1.0 // indirect github.com/multiformats/go-base36 v0.2.0 // indirect @@ -220,7 +221,7 @@ require ( github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/subosito/gotenv v1.3.0 // indirect - github.com/supranational/blst v0.3.11 // indirect + github.com/supranational/blst v0.3.16 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect @@ -233,16 +234,15 @@ require ( go.uber.org/fx v1.23.0 // indirect go.uber.org/mock v0.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/mod v0.22.0 // indirect - golang.org/x/net v0.34.0 // indirect - golang.org/x/sys v0.29.0 // indirect - golang.org/x/text v0.21.0 // indirect - golang.org/x/time v0.5.0 - golang.org/x/tools v0.29.0 // indirect + golang.org/x/mod v0.31.0 // indirect + golang.org/x/net v0.49.0 // indirect + golang.org/x/sys v0.40.0 // indirect + golang.org/x/text v0.33.0 // indirect + golang.org/x/time v0.9.0 + golang.org/x/tools v0.40.0 gonum.org/v1/gonum v0.15.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.3.0 // indirect - rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/go.sum b/go.sum index bb707cd1cd..6fe4cc9b4e 100644 --- a/go.sum +++ b/go.sum @@ -49,12 +49,14 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 h1:1zYrtlhrZ6/b6SAjLSfKzWtdgqK0U+HtH/VcBWh1BaU= +github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= -github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= -github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= +github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0= +github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU= github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7ISrnJIXKzwaspym5BTKGx93EI= @@ -67,8 +69,8 @@ github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZx github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= -github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU= +github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= github.com/btcsuite/btcd v0.0.0-20190629003639-c26ffa870fd8/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= @@ -103,8 +105,8 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU= -github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= +github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= +github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -115,22 +117,20 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cockroachdb/errors v1.8.1 h1:A5+txlVZfOqFBDa4mGz2bUWSp0aHElvHX2bKkdbQu+Y= -github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= -github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 h1:aPEJyR4rPBvDmeyi+l/FS/VtA00IWvjeFvjen1m1l1A= -github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593/go.mod h1:6hk1eMY/u5t+Cf18q5lFMUA1Rc+Sm5I6Ra1QuPyxXCo= -github.com/cockroachdb/redact v1.0.8 h1:8QG/764wK+vmEYoOlfobpe12EQcS81ukx/a4hdVMxNw= -github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= -github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM= -github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= +github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= +github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/pebble v1.1.5 h1:5AAWCBWbat0uE0blr8qzufZP5tBjkRyy/jWe1QWLnvw= +github.com/cockroachdb/pebble v1.1.5/go.mod h1:17wO9el1YEigxkP/YtV8NtCivQDgoCyBg5c4VR/eOWo= +github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= +github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= -github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= -github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= -github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= +github.com/consensys/gnark-crypto v0.18.1 h1:RyLV6UhPRoYYzaFnPQA4qK3DyuDgkTgskDdoGqFt3fI= +github.com/consensys/gnark-crypto v0.18.1/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= @@ -140,12 +140,11 @@ github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8 github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ= -github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= -github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA= -github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crate-crypto/go-eth-kzg v1.5.0 h1:FYRiJMJG2iv+2Dy3fi14SVGjcPteZ5HAAUe4YWlJygc= +github.com/crate-crypto/go-eth-kzg v1.5.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -153,8 +152,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= -github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= -github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA= +github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc= +github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= +github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= @@ -174,21 +175,23 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/elastic/gosigar v0.14.3 h1:xwkKwPia+hSfg9GqrCUKYdId102m9qTJIIr7egmK/uo= github.com/elastic/gosigar v0.14.3/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= +github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A= +github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= -github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/ethereum/go-ethereum v1.13.15 h1:U7sSGYGo4SPjP6iNIifNoyIAiNjrmQkz6EwQG+/EZWo= -github.com/ethereum/go-ethereum v1.13.15/go.mod h1:TN8ZiHrdJwSe8Cb6x+p0hs5CxhJZPbqB7hHkaUXcmIU= +github.com/ethereum/c-kzg-4844/v2 v2.1.6 h1:xQymkKCT5E2Jiaoqf3v4wsNgjZLY0lRSkZn27fRjSls= +github.com/ethereum/c-kzg-4844/v2 v2.1.6/go.mod h1:8HMkUZ5JRv4hpw/XUrYWSQNAUzhHMg2UDb/U+5m+XNw= +github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab h1:rvv6MJhy07IMfEKuARQ9TKojGqLVNxQajaXEp/BoqSk= +github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab/go.mod h1:IuLm4IsPipXKF7CW5Lzf68PIbZ5yl7FFd74l/E0o9A8= +github.com/ethereum/go-ethereum v1.17.3 h1:Ev/sQHH+UdKZHWjuVzhu2pxhi/sXaPZl23Q+Q5LDd4Q= +github.com/ethereum/go-ethereum v1.17.3/go.mod h1:f2EhRwqewIZkGoQekywI2Y2RZAMTSavLNkD9qItFy1A= github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5/go.mod h1:JpoxHjuQauoxiFMl1ie8Xc/7TfLuMZ5eOCONd1sUBHg= -github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk= -github.com/ferranbt/fastssz v0.1.2/go.mod h1:X5UPrE2u1UJjxHA8X54u04SBwdAQjG2sFtWs39YxyWs= -github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA= -github.com/fjl/memsize v0.0.2/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeDY= +github.com/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= @@ -200,11 +203,11 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= -github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= -github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE= -github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= +github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= +github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= @@ -231,15 +234,15 @@ github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= -github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= +github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -270,8 +273,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= -github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= +github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -310,7 +313,6 @@ github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -327,6 +329,10 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7 github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grafana/pyroscope-go v1.2.7 h1:VWBBlqxjyR0Cwk2W6UrE8CdcdD80GOFNutj0Kb1T8ac= +github.com/grafana/pyroscope-go v1.2.7/go.mod h1:o/bpSLiJYYP6HQtvcoVKiE9s5RiNgjYTj1DhiddP2Pc= +github.com/grafana/pyroscope-go/godeltaprof v0.1.9 h1:c1Us8i6eSmkW+Ez05d3co8kasnuOY813tbMN8i/a3Og= +github.com/grafana/pyroscope-go/godeltaprof v0.1.9/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU= github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY41SORZyNJ0= github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= @@ -349,19 +355,19 @@ github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6wn4Ej8vjuVGxeHdan+bRb2ebyv4= -github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= +github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db h1:IZUYC/xb3giYwBLMnr8d0TGTzPKFGNTCGgGLoyeX330= +github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db/go.mod h1:xTEYN9KCHxuYHs+NmrmzFcnvHMzLLNiGFafCb1n3Mfg= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= -github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= -github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA= +github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/influxdb-client-go/v2 v2.4.0 h1:HGBfZYStlx3Kqvsv1h2pJixbCl/jhnFtxpKFAv9Tu5k= github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= @@ -414,8 +420,6 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/keep-network/go-electrum v0.0.0-20240206170935-6038cb594daa h1:AKTJr+STc4rP9NcN2ppP9Zft3GbYechFW8q/S8UNQrQ= -github.com/keep-network/go-electrum v0.0.0-20240206170935-6038cb594daa/go.mod h1:eiMFzdvS+x8Voi0bmiZtVfJ3zMNRUnPNDnhCQR0tudo= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -442,8 +446,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= -github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= -github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= +github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= +github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= github.com/libp2p/go-addr-util v0.2.0 h1:nwPtbrJEujbrmQm7tMxjsFY+PjZ0YWFeb9jVdpjjiuc= github.com/libp2p/go-addr-util v0.2.0/go.mod h1:lsJiu306BQNNAUWgzNiwNGFunP1/swKhRvTLzpPveD0= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= @@ -532,9 +536,6 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= -github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= -github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= -github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= @@ -582,8 +583,6 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= @@ -646,6 +645,8 @@ github.com/pion/srtp/v2 v2.0.20 h1:HNNny4s+OUmG280ETrCdgFndp4ufx3/uy85EawYEhTk= github.com/pion/srtp/v2 v2.0.20/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= +github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0= +github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ= github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= @@ -680,8 +681,8 @@ github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkq github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/prysmaticlabs/gohashtree v0.0.1-alpha.0.20220714111606-acbb2962fb48 h1:cSo6/vk8YpvkLbk9v3FO97cakNmUoxwi2KMP8hd5WIw= -github.com/prysmaticlabs/gohashtree v0.0.1-alpha.0.20220714111606-acbb2962fb48/go.mod h1:4pWaT30XoEx1j8KNJf3TV+E3mQkaufn7mf+jRNb/Fuk= +github.com/prysmaticlabs/gohashtree v0.0.4-beta h1:H/EbCuXPeTV3lpKeXGPpEV9gsUpkqOOVnWapUyeWro4= +github.com/prysmaticlabs/gohashtree v0.0.4-beta/go.mod h1:BFdtALS+Ffhg3lGQIHv9HDWuHS8cTvHZzrHWxwOtGOs= github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE= @@ -745,16 +746,15 @@ github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= -github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= -github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= -github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -775,26 +775,22 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= -github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= -github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/supranational/blst v0.3.16 h1:bTDadT+3fK497EvLdWRQEjiGnUtzJ7jjIUMF0jqwYhE= +github.com/supranational/blst v0.3.16/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= -github.com/threshold-network/keep-common v1.7.1-tlabs.0 h1:E3Qy3yoeA3+9Ybi08Bb1Xm1D2fFxoberQwUjw+UEK8k= -github.com/threshold-network/keep-common v1.7.1-tlabs.0/go.mod h1:OmaZrnZODf6RJ95yUn2kBjy8Z4u2npPJQkSiyimluto= github.com/threshold-network/tss-lib v0.0.0-20230901144531-2e712689cfbe h1:dOKhoYxZjXwFIyGnxgU+Sa1obZPMHRhu6e44oOLkzU4= github.com/threshold-network/tss-lib v0.0.0-20230901144531-2e712689cfbe/go.mod h1:o3zAAo7A88ZJnCE1qpjy1hTqPn+GPQlxRsj8soz14UU= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= -github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= -github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.10 h1:p8Fspmz3iTctJstry1PYS3HVdllxnEzTEsgIgtxTrCk= github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= -github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= +github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= +github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= @@ -808,8 +804,8 @@ github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1 github.com/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU= github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -831,6 +827,8 @@ go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c= go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE= go.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ= go.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps= +go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= +go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0= go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -877,8 +875,8 @@ golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= -golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= +golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -918,8 +916,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= -golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -968,8 +966,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= -golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -995,8 +993,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1065,8 +1063,10 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc h1:bH6xUXay0AIFMElXG2rQ4uiE+7ncwtiOdPfYK1NK2XA= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1075,8 +1075,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= -golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= +golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= +golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1089,16 +1089,16 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= +golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1158,8 +1158,8 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= -golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1270,8 +1270,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8 h1:KR8+MyP7/qOlV+8Af01LtjL04bu7on42eVsxT4EyBQk= google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= -google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1282,8 +1282,8 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1310,7 +1310,5 @@ lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= -rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/infrastructure/docker/ethereum/dashboard-node/Dockerfile b/infrastructure/docker/ethereum/dashboard-node/Dockerfile deleted file mode 100644 index 7f97a1f7a8..0000000000 --- a/infrastructure/docker/ethereum/dashboard-node/Dockerfile +++ /dev/null @@ -1,30 +0,0 @@ -FROM ubuntu -MAINTAINER "Markus Fix - -RUN apt-get update && apt-get upgrade -y -RUN apt-get install -y build-essential -RUN apt-get install -y nodejs npm git curl - -RUN npm install -g grunt -RUN npm install -g pm2 - -RUN git clone https://github.com/lispmeister/eth-netstats.git /var/lib/eth-netstats -WORKDIR /var/lib/eth-netstats -RUN npm install -RUN grunt all - -RUN git clone https://github.com/lispmeister/bootnode-registrar.git /var/lib/bootnode -WORKDIR /var/lib/bootnode -RUN npm install - -RUN useradd -ms /bin/bash dashboard -USER dashboard - -WORKDIR /home/dashboard -COPY app.json /home/dashboard/app.json -COPY run.sh /home/dashboard/run.sh - -COPY updateNode.sh /home/dashboard/updateNode.sh -RUN /bin/bash /home/dashboard/updateNode.sh - -ENTRYPOINT ["/bin/bash", "run.sh"] diff --git a/infrastructure/docker/ethereum/dashboard-node/README.adoc b/infrastructure/docker/ethereum/dashboard-node/README.adoc deleted file mode 100644 index bcf3c034b1..0000000000 --- a/infrastructure/docker/ethereum/dashboard-node/README.adoc +++ /dev/null @@ -1,22 +0,0 @@ -= Build Dashboard Node image - -To build the docker image -``` -docker build --pull --squash --no-cache --rm -t $DOCKER_ID_USER/eth-stats-dashboard . -``` - -You can list your new image with this command: -``` -docker images |grep eth-stats-dashboard -``` - -Push the image to Docker Hub: -``` -docker push $DOCKER_ID_USER/eth-stats-dashboard -``` - -Start a single node as a Docker container without Kubernetes -mapping the HTTP interface to `localhost:3000`: -``` -docker run -it -p 3000:3000 $DOCKER_ID_USER/eth-stats-dashboard -``` diff --git a/infrastructure/docker/ethereum/dashboard-node/app.json b/infrastructure/docker/ethereum/dashboard-node/app.json deleted file mode 100644 index 6b1cef986c..0000000000 --- a/infrastructure/docker/ethereum/dashboard-node/app.json +++ /dev/null @@ -1,18 +0,0 @@ -[ - { - "name" : "bootNodeRegistrar", - "script" : "/var/lib/bootnode/app.js", - "log_date_format" : "YYYY-MM-DD HH:mm Z", - "merge_logs" : false, - "watch" : true, - "max_restarts" : 0, - "exec_interpreter" : "node", - "exec_mode" : "fork_mode", - "env": - { - "PORT" : 3001, - "NODE_ENV" : "production", - "VERBOSITY" : 2 - } - } -] diff --git a/infrastructure/docker/ethereum/dashboard-node/run.sh b/infrastructure/docker/ethereum/dashboard-node/run.sh deleted file mode 100644 index e31faef6cb..0000000000 --- a/infrastructure/docker/ethereum/dashboard-node/run.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -export NVM_DIR="$HOME/.nvm" -[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" - -cd /home/dashboard -pm2 start app.json -cd /var/lib/eth-netstats -npm start diff --git a/infrastructure/docker/ethereum/dashboard-node/updateNode.sh b/infrastructure/docker/ethereum/dashboard-node/updateNode.sh deleted file mode 100644 index 0d2af792be..0000000000 --- a/infrastructure/docker/ethereum/dashboard-node/updateNode.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -# install Node Version Manager -curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.1/install.sh | bash - -export NVM_DIR="$HOME/.nvm" -[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" -# install long-term support version of node -nvm install --lts -nvm use --lts diff --git a/infrastructure/docker/ethereum/geth-node/Dockerfile b/infrastructure/docker/ethereum/geth-node/Dockerfile deleted file mode 100644 index 11b0951562..0000000000 --- a/infrastructure/docker/ethereum/geth-node/Dockerfile +++ /dev/null @@ -1,58 +0,0 @@ -# Be explicit about the ethereum go client version installed -# This version should be used to tag the resulting image that's pushed -# to Keeps container registry -FROM ethereum/client-go:v1.9.6 -MAINTAINER "Thesis.co" - -# Install dependencies required for downstream commands -# These dependencies can be used here, in geth-init.sh, or run-geth.sh - -RUN apk add --no-cache --update python -RUN apk add --no-cache --update build-base -RUN apk add --no-cache --update nodejs npm -RUN apk add --no-cache --update bash -RUN apk add --no-cache --update jq -RUN apk add --no-cache --update curl -RUN apk add --no-cache --update git - -# Configure log rotation - -RUN npm install pm2 -g -RUN pm2 install pm2-logrotate -RUN pm2 set pm2-logrotate:max_size 100M -RUN pm2 set pm2-logrotate:compress true -RUN pm2 set pm2-logrotate:rotateInterval '23 * * *' - -# Install code to report in at the registry of the bootnode (dashboard) -RUN git clone https://github.com/lispmeister/bootnode-registrar.git /root/lib/bootnode -WORKDIR /root/lib/bootnode -RUN npm install - -# Install ethStatsApi to report local stats to dashboard -RUN git clone https://github.com/lispmeister/eth-net-intelligence-api.git /root/lib/ethStatsApi -WORKDIR /root/lib/ethStatsApi -RUN npm install - -# Change to /root before provisioning our services -WORKDIR /root - -# Setup target dir for geth data -RUN mkdir .geth - -# Copy passphrase file -COPY testnet-account-passphrase.txt passphrase - -# Copy keystore -# If you need a copy of the keystore it's in /keep-core/private-testnet/keyfles -ADD keystore .geth/keystore - -# Create genesis file -COPY genesis-template.json genesis-template.json -COPY geth-init.sh geth-init.sh -RUN /root/geth-init.sh - -# Provision our three services (check app.json for details) -COPY app.json app.json -COPY run-geth.sh run-geth.sh - -ENTRYPOINT ["pm2", "start", "--no-daemon", "app.json"] diff --git a/infrastructure/docker/ethereum/geth-node/README.adoc b/infrastructure/docker/ethereum/geth-node/README.adoc deleted file mode 100644 index 7642f248f5..0000000000 --- a/infrastructure/docker/ethereum/geth-node/README.adoc +++ /dev/null @@ -1,37 +0,0 @@ -= Build Geth Node Image - -== WARNING == - -We are currently storing the passphrase for all accounts that we create on -the testnet in the file `passphrase` that lives in the same directory as this -README file. This is HORRIBLY INSECURE and only OK for the internal testnet. - -== Build -To build the docker image: -``` -docker build --pull --squash --no-cache --rm -t $DOCKER_ID_USER/geth-node . -``` - -Build an image with five Keep client accounts: -``` -docker build --build-arg KEEP_ACCOUNTS=5 --pull --squash --no-cache --rm -t $DOCKER_ID_USER/geth-node . -``` - -== List -You can list your new image with this command: -``` -docker images |grep geth-node -``` - -== Copy Keystore Files -You can copy the keystore files for the accounts created during the Docker run -with the following commands: -``` -docker run --entrypoint="" --rm -v `pwd`:/out $DOCKER_ID_USER/geth-node cp -rv /root/.geth/keystore /out -``` - -== Push Image -Push the image to Docker Hub: -``` -docker push $DOCKER_ID_USER/geth-node -``` diff --git a/infrastructure/docker/ethereum/geth-node/app.json b/infrastructure/docker/ethereum/geth-node/app.json deleted file mode 100644 index b47e831150..0000000000 --- a/infrastructure/docker/ethereum/geth-node/app.json +++ /dev/null @@ -1,50 +0,0 @@ -[ - { - "name" : "gethNode", - "script" : "/root/run-geth.sh", - "log_date_format" : "YYYY-MM-DD HH:mm Z", - "merge_logs" : false, - "watch" : true, - "max_restarts" : 0, - "exec_interpreter" : "/bin/bash", - "exec_mode" : "fork_mode", - "env": - { - "VERBOSITY" : 3 - } - }, - { - "name" : "ethStatsApi", - "script" : "/root/lib/ethStatsApi/app.js", - "log_date_format" : "YYYY-MM-DD HH:mm Z", - "merge_logs" : false, - "watch" : true, - "max_restarts" : 0, - "exec_interpreter" : "node", - "exec_mode" : "fork_mode", - "env": - { - "NODE_ENV" : "production", - "RPC_HOST" : "localhost", - "RPC_PORT" : "8545", - "LISTENING_PORT" : "30303", - "VERBOSITY" : 1 - } - }, - { - "name" : "bootNodeReporter", - "script" : "/root/lib/bootnode/client.js", - "log_date_format" : "YYYY-MM-DD HH:mm Z", - "merge_logs" : false, - "watch" : true, - "max_restarts" : 10, - "restart_delay" : 4000, - "exec_interpreter" : "node", - "exec_mode" : "fork_mode", - "env": - { - "NODE_ENV" : "production", - "VERBOSITY" : 1 - } - } -] diff --git a/infrastructure/docker/ethereum/geth-node/docker-entrypoint.sh b/infrastructure/docker/ethereum/geth-node/docker-entrypoint.sh deleted file mode 100755 index bec45a1308..0000000000 --- a/infrastructure/docker/ethereum/geth-node/docker-entrypoint.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/sh -set -e - -# generate a random node id -export RANDOM_ID=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1) -echo "-- RANDOM_ID: $RANDOM_ID" -echo "" - -# create new account for this Keep client -/geth account new --password /root/passphrase | \ - cut -d "{" -f2 | cut -d "}" -f1 > /root/account0 -export GETH_ETH_ACCOUNT0=`cat /root/account0` -echo "-- GETH_ETH_ACCOUNT0: $GETH_ETH_ACCOUNT0" -echo "" - -# create new account for Keep peers -/geth account new --password /root/passphrase | \ - cut -d "{" -f2 | cut -d "}" -f1 > /root/account1 -export GETH_ETH_ACCOUNT1=`cat /root/account1` -echo "-- GETH_ETH_ACCOUNT1: $GETH_ETH_ACCOUNT1" -echo "" - -# Generate genesis.json and issue tokens to Keep peers account1 -cat <> /root/genesis.json -{ - "config": { - "chainId": 1101, - "homesteadBlock": 0, - "eip155Block": 0, - "eip158Block": 0 - }, - "difficulty" : "0x20000", - "gasLimit" : "0x493E00", - "alloc": { -EOF - -echo " \"0x$GETH_ETH_ACCOUNT1\": {" >> /root/genesis.json -echo " \"balance\": \"1000000000000000000000\"" >> /root/genesis.json -cat <> /root/genesis.json - } - } -} -EOF - -# dump genesis file -echo "-- Dump genesis.json:" -cat /root/genesis.json -echo "" - -# initialize chain with our genesis.json parameters -echo "-- Initialize geth" -/geth init /root/genesis.json -echo "" - -# start miner and allocate rewards to account0 -echo "-- Start geth mining for account0: $GETH_ETH_ACCOUNT0" -echo "" - -exec "/geth" --port 30303 --networkid 1101 \ - --ws --wsaddr "0.0.0.0" --wsport 8546 --wsorigins "*" \ - --rpc --rpcport 8545 --rpcaddr 0.0.0.0 --rpccorsdomain "" \ - --rpcapi "db,ssh,miner,admin,eth,net,web3,personal" \ - --syncmode "fast" \ - --mine --miner.threads=1 \ - --identity $RANDOM_ID \ - --miner.etherbase=$GETH_ETH_ACCOUNT0 diff --git a/infrastructure/docker/ethereum/geth-node/genesis-template.json b/infrastructure/docker/ethereum/geth-node/genesis-template.json deleted file mode 100644 index 207883e6c1..0000000000 --- a/infrastructure/docker/ethereum/geth-node/genesis-template.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "config": { - "chainId": 1101, - "eip150Block": 0, - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "homesteadBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "daoForkBlock": 0, - "istanbulBlock": 0, - "daoForkSupport": true - }, - "coinbase": "0x0000000000000000000000000000000000000000", - "difficulty": "0x20", - "extraData": "", - "gasLimit": "0x7A1200", - "nonce": "0x90F0050060078460", - "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp": "0x00", - "alloc": { - } -} \ No newline at end of file diff --git a/infrastructure/docker/ethereum/geth-node/geth-init.sh b/infrastructure/docker/ethereum/geth-node/geth-init.sh deleted file mode 100755 index 82f175a760..0000000000 --- a/infrastructure/docker/ethereum/geth-node/geth-init.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/bash - -DATADIR_DEFAULT=/root/.geth - -# feed keep ETH accounts into genesis -for keyfile in ${DATADIR_DEFAULT}/keystore/*; -do - ACCOUNT=`cat $keyfile | jq .address | tr -d '"'` - echo "0x${ACCOUNT}" >> /root/keep_accounts -done -echo "-- Keep client accounts populated:" -cat /root/keep_accounts - -# Generate genesis.json and issue tokens to Keep peers. -# We are setting mining difficulty to zero. -# Start with the preamble -# Generate genesis.json and issue tokens to Keep peers. -# We are setting mining difficulty to zero. -GENESIS=/root/genesis.json -GENESIS_TEMPLATE=/root/genesis-template.json -RESULT=`cat $GENESIS_TEMPLATE` -# add Keep client accounts and fund them -while read -r ACCOUNT; do - LINE=".alloc += {\"${ACCOUNT}\": {"balance": \"1000000000000000000000\"}}" - RESULT=`echo $RESULT | jq "$LINE"` -done < /root/keep_accounts -echo $RESULT | jq . > $GENESIS - -## genesis.json generation done ------- - -## set miner account -echo "-- Setting miner account:" -head -1 /root/keep_accounts > /root/mining_account -cat /root/mining_account - -# dump genesis file -echo "-- Dump genesis.json:" -cat $GENESIS -echo "" - -# List the keystore directory -echo "-- KEYSTORE directory" -ls -la ${DATADIR_DEFAULT}/keystore - -# List the .geth directory -echo "-- .geth directory" -ls -la $DATADIR_DEFAULT - -# List the /root directory -echo "-- /root directory" -ls -la /root diff --git a/infrastructure/docker/ethereum/geth-node/run-geth.sh b/infrastructure/docker/ethereum/geth-node/run-geth.sh deleted file mode 100755 index e89f76cf34..0000000000 --- a/infrastructure/docker/ethereum/geth-node/run-geth.sh +++ /dev/null @@ -1,111 +0,0 @@ -#!/bin/bash - -DATADIR_DEFAULT=/root/.geth -ETH_IPC_PATH_DEFAULT=/root/.geth/geth.ipc - -RPCPORT=8545 -RPCHOST=0.0.0.0 -RPCAPI=db,ssh,miner,admin,eth,net,web3,personal -WSPORT=8546 -#WSHOST=0.0.0.0 -#WSORIGINS="*" -GETHPORT=30303 -GETHARGS= -BOOTNODE_URL="$BOOTNODE_URL/staticenodes?network=$BOOTNODE_NETWORK" -BOOTNODES=$(curl --connect-timeout 1 --retry 10 --retry-max-time 10 -f -s $BOOTNODE_URL) - -# fetch accounts -export GETH_ETH_MINING_ACCOUNT=`cat /root/mining_account` -echo "-- GETH_ETH_MINING_ACCOUNT: $GETH_ETH_MINING_ACCOUNT" - -# dump genesis file -echo "-- Dump genesis.json:" -GENESIS=/root/genesis.json -cat $GENESIS -echo "" - -if [ -z "$HOSTVOLUME" ]; then - DATADIR="$DATADIR_DEFAULT" - echo "-- No HOSTVOLUME was supplied. Using default DATADIR: $DATADIR" -else - DATADIR="$HOSTVOLUME" # GCP: each pod has a private volume attached - echo "-- Setting DATADIR to: $DATADIR" - # check if we need to create the directory - if [ ! -d "$DATADIR" ]; then - echo "-- Creating $DATADIR" - mkdir -p $DATADIR - fi - echo "-- Copying keystore to DATADIR" - cp -rv $DATADIR_DEFAULT/keystore $DATADIR - echo "-- List DATADIR/keystore:" - ls -la $DATADIR/keystore -fi - -if [ -z "$ETH_IPC_PATH" ]; then - ETH_IPC_PATH="$ETH_IPC_PATH_DEFAULT" - echo "-- No ETH_IPC_PATH was supplied. Using default ETH_IPC_PATH: $ETH_IPC_PATH" -fi - -if [ -z "$NETWORKID" ]; then - echo "-- No NETWORKID was supplied" - exit 1 -fi - -if [ -z "$GENESIS" ]; then - echo "-- No GENESIS was supplied" - exit 1 -fi - -if [ -z "$NODE_NAME" ]; then - echo "-- No NODE_NAME was supplied" - exit 1 -fi - -if [ "$ENABLE_MINER" ]; then - MINER_ADDRESS=$GETH_ETH_MINING_ACCOUNT - echo "-- MINER_ADDRESS: $MINER_ADDRESS" - - while [ -z "$BOOTNODES" ] - do - BOOTNODES=$(curl --connect-timeout 1 --retry 10 --retry-delay 0 --retry-max-time 10 -f -s $BOOTNODE_URL) - done - - GETHARGS="--mine --miner.etherbase=$MINER_ADDRESS" - - if [ "$MINER_THREADS" ]; then - GETHARGS="$GETHARGS --minerthreads $MINER_THREADS" - fi -else - GETHARGS="" -fi - - -if [ "$BOOTNODES" ]; then - echo "-- Adding bootnodes:" - mkdir -p $DATADIR - echo $BOOTNODES > $DATADIR/static-nodes.json - cat $DATADIR/static-nodes.json -fi - -# TODO: only initialize if DATADIR has no chain data -if [ ! -d "$DATADIR/geth/chaindata" ]; then - echo "-- No chaindata directory. Neet to Initialize. Writing genesis block..." - geth --datadir $DATADIR init $GENESIS -fi - -echo "-- BOOTNODES: $BOOTNODES" -echo "-- GETHARGS: $GETHARGS" - -echo "-- Starting geth..." - -geth --datadir $DATADIR --ethash.dagdir $DATADIR --ipcpath $ETH_IPC_PATH \ - --nodiscover \ - --port $GETHPORT --networkid $NETWORKID \ - --ws --wsaddr "0.0.0.0" --wsport $WSPORT --wsorigins "*" \ - --rpc --rpcport $RPCPORT --rpcaddr $RPCHOST --rpccorsdomain "*" --rpcvhosts "*" \ - --rpcapi $RPCAPI \ - --identity $NODE_NAME \ - --syncmode "fast" \ - --allow-insecure-unlock \ - --targetgaslimit "7000000" \ - $GETHARGS diff --git a/infrastructure/docker/ethereum/geth-node/testnet-account-passphrase.txt b/infrastructure/docker/ethereum/geth-node/testnet-account-passphrase.txt deleted file mode 100644 index ce79aaf6a2..0000000000 --- a/infrastructure/docker/ethereum/geth-node/testnet-account-passphrase.txt +++ /dev/null @@ -1 +0,0 @@ -doughnut_armenian_parallel_firework_backbite_employer_singlet diff --git a/infrastructure/eth-networks/private-testnet/.gitignore b/infrastructure/eth-networks/private-testnet/.gitignore deleted file mode 100644 index 17ce0d765e..0000000000 --- a/infrastructure/eth-networks/private-testnet/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -# Local NPM Command Installation -package.json -package-lock.json -node_modules/ - -# Secrets -bundles/*/secret/ - -# Generated Documentation -bundles/*/index.html - -# Bundles -*.tgz diff --git a/infrastructure/eth-networks/private-testnet/README.adoc b/infrastructure/eth-networks/private-testnet/README.adoc deleted file mode 100644 index 8cfa31a1ef..0000000000 --- a/infrastructure/eth-networks/private-testnet/README.adoc +++ /dev/null @@ -1,38 +0,0 @@ -= Keep Network Private Testnet - -We set up a Keep Network Private Testnet that is accessible by the permitted parties. -Here we hold the code helping us to create bundles for the parties. - -The network runs against the link:https://goerli.net/[Ethereum Görli Testnet]. - -The generated bundles contain a preinitialized Ethereum Account details. The account -receives a stake delegation to the Staking Provider Account with authorized `beacon` and -`tbtc` application. This is a production-like experience for the Staking Providers, -where they will receive stakes from their customers. - -== Scripts - -=== Prerequisites - -The scripts require the following tools to be installed: - -- `npx` - link:https://nodejs.org/en/download/package-manager/#macos[macOS install] -- `geth` - link:https://geth.ethereum.org/docs/install-and-build/installing-geth#macos-via-homebrew[macOS install] -- `asciidoctor` - link:https://asciidoctor.org/docs/install-asciidoctor-macos/#homebrew-procedure[macOS install] -- `docker` - link:https://docs.docker.com/desktop/install/mac-install/[macOS install] - -=== Create New Bundle - -To create a new bundle run: - -```bash -./scripts/new-bundle.sh -``` - -=== Initialize Staking Provider - -To simulate a Staker delegation to a Staking Provider and authorize the applications run: - -```bash -./scripts/init-provider.sh -``` diff --git a/infrastructure/eth-networks/private-testnet/bundles/bundle-guide.adoc b/infrastructure/eth-networks/private-testnet/bundles/bundle-guide.adoc deleted file mode 100644 index 0ef60af252..0000000000 --- a/infrastructure/eth-networks/private-testnet/bundles/bundle-guide.adoc +++ /dev/null @@ -1,98 +0,0 @@ -:toc: left -:toclevels: 3 -:sectanchors: true -:sectids: true -:source-highlighter: rouge -:icons: font - -ifdef::env-github[] -:tip-caption: :bulb: -:note-caption: :information_source: -:important-caption: :heavy_exclamation_mark: -:caution-caption: :fire: -:warning-caption: :warning: -endif::[] - -= Keep Network Private Testnet Bundle - -Use this bundle to setup Keep Network node running on Keep Network Private Testnet. -The Keep Network Private Testnet is running against the -link:https://goerli.net/[Ethereum Görli Testnet]. - -This is a quickstart guide, for the full documentation please visit -link:https://docs.keep.network/run-keep-node.html[Run Keep Node documentation]. - -== Stake and Register - -This bundle comes with a Staking Provider Ethereum Account that was already staked and -authorized, similar to what a Staker would do in the production. - -IMPORTANT: Delivering the Staking Provider Account details in the bundle is a -simplification for testnet. On mainnet, the Staking Provider will have -to provide the address for the Staker. See <<#staking-provider-account>> section. - -[#staking-provider-account] -=== Staking Provider Account - -A Staking Provider is responsible for providing a Staker with a Staking Provider -Account address where the stake should be delegated to. - -The Staking Provider Account is controlled by the Staking Provider. - -The Staking Provider Account can be an Ethereum account managed by any kind of -a wallet that can sign transactions (i.e. it doesn't have to be a Key File). - -=== Operator Account - -The Operator Account is an Ethereum account that the Keep Client runs with. The -client requires an encrypted Ethereum Key File along with the Password for the -Operator Account to run. - -The Operator Account is controlled by the Staking Provider. - -The Staking Provider has to register an Operator Account address for the stake delegation -received to the Staking Provider Account. - -To generate an Ethereum Account Key File you can use `geth account new` command. - -[source,shell] ----- -geth account new --keystore ./keystore ----- - -Keep the password used for the Key File encryption as it will -have to be passed to the Keep Client start command. - -Once the Operator Account address is known it should be registered with a transaction -submitted from the Staking Provider Account, please refer to -link:https://docs.keep.network/registration.html#register-operator[Register Operator] -documentation. - -TIP: When starting the client, remember about running the `keep-client start` -command with the `--goerli` flag. - -IMPORTANT: The Operator Account has to be funded with Goerli ETH (GöETH) so the -client can submit transactions to the Ethereum chain. This bundle doesn't fund -the account, please do it on your own. - -== Configuration - -For details on the Keep Client Node configuration visit -link:https://docs.keep.network/run-keep-node.html#configuration[Configuration documentation]. - -== Running - -For details on running the Keep Client Node on Testnet visit -link:https://docs.keep.network/run-keep-node.html#testnet[Testnet documentation]. - -=== Validate - -To validate the running client check the metrics for the number of connected peers -(`connected_peers_count`). - -The client should connect to the bootstrap nodes (at least 2) and other nodes that -are working in the network. There should be at least 10 connections. - -``` -curl localhost:9601/metrics -``` diff --git a/infrastructure/eth-networks/private-testnet/scripts/init-provider.sh b/infrastructure/eth-networks/private-testnet/scripts/init-provider.sh deleted file mode 100755 index 981717eefc..0000000000 --- a/infrastructure/eth-networks/private-testnet/scripts/init-provider.sh +++ /dev/null @@ -1,101 +0,0 @@ -#!/bin/bash -set -eou pipefail - -ROOT_DIR="$(realpath "$(dirname $0)/../bundles")" - -if [ -z "${CHAIN_API_URL+x}" ]; then - read -p "Provide Ethereum API URL: " CHAIN_API_URL -fi - -if [ -z "${PURSE_PRIVATE_KEY+x}" ]; then - read -p "Provide ETH Purse Private Key: " PURSE_PRIVATE_KEY -fi - -if [ -z "${GOERLI_DEPLOYER_PRIVATE_KEY+x}" ]; then - read -p "Provide GOERLI_DEPLOYER_PRIVATE_KEY: " GOERLI_DEPLOYER_PRIVATE_KEY -fi - -STAKING_PROVIDER=${1-} -if [ -z "$STAKING_PROVIDER" ]; then - read -p "Provide Staking Provider name: " STAKING_PROVIDER -fi - -STAKING_PROVIDER_DIR="$(realpath "$ROOT_DIR/$STAKING_PROVIDER")" - -if [ ! -d "$STAKING_PROVIDER_DIR" ]; then - echo "Directory for $STAKING_PROVIDER does not exists." - exit 1 -fi - -CONFIG_DIR="$STAKING_PROVIDER_DIR/config" -SECRETS_DIR="$STAKING_PROVIDER_DIR/secret" - -KEY_FILE_PATH="$CONFIG_DIR/staking-provider-eth-account-key-file.json" -KEY_FILE_PASSWORD_PATH="$SECRETS_DIR/staking-provider-eth-account-password" -PRIVATE_KEY_FILE_PATH="$SECRETS_DIR/staking-provider-eth-account-private-key" - -ACCOUNT_ADDRESS=$(jq -jr .address $KEY_FILE_PATH) -ACCOUNT_PRIVATE_KEY=$(cat $PRIVATE_KEY_FILE_PATH) - -[[ $ACCOUNT_ADDRESS == 0x* ]] || ACCOUNT_ADDRESS="0x$ACCOUNT_ADDRESS" - -printf "Staking Provider Account Address: $ACCOUNT_ADDRESS\n" - -printf "Pull the latest images...\n" - -docker pull gcr.io/keep-test-f3e0/keep-random-beacon-hardhat:latest -docker pull gcr.io/keep-test-f3e0/keep-ecdsa-hardhat:latest - -printf "Fund Staking Provider Account Address with ether from purse...\n" - -docker run \ - --rm \ - --env "CHAIN_API_URL=$CHAIN_API_URL" \ - --env "ACCOUNTS_PRIVATE_KEYS=$PURSE_PRIVATE_KEY" \ - --platform linux/amd64 \ - gcr.io/keep-test-f3e0/keep-random-beacon-hardhat:latest \ - ensure-eth-balance \ - --network goerli \ - --target-balance "0.1 ether" \ - $ACCOUNT_ADDRESS - -printf "Initialize staking...\n" - -docker run \ - --rm \ - --env "CHAIN_API_URL=$CHAIN_API_URL" \ - --env "ACCOUNTS_PRIVATE_KEYS=$GOERLI_DEPLOYER_PRIVATE_KEY,$ACCOUNT_PRIVATE_KEY" \ - --platform linux/amd64 \ - gcr.io/keep-test-f3e0/keep-random-beacon-hardhat:latest \ - initialize:staking \ - --network goerli \ - --owner $ACCOUNT_ADDRESS \ - --provider $ACCOUNT_ADDRESS - -printf "Authorize the Random Beacon...\n" - -docker run \ - --rm \ - --env "CHAIN_API_URL=$CHAIN_API_URL" \ - --env "ACCOUNTS_PRIVATE_KEYS=$GOERLI_DEPLOYER_PRIVATE_KEY,$ACCOUNT_PRIVATE_KEY" \ - --platform linux/amd64 \ - gcr.io/keep-test-f3e0/keep-random-beacon-hardhat:latest \ - authorize:beacon \ - --network goerli \ - --owner $ACCOUNT_ADDRESS \ - --provider $ACCOUNT_ADDRESS - -printf "Authorize the ECDSA...\n" - -docker run \ - --rm \ - --env "CHAIN_API_URL=$CHAIN_API_URL" \ - --env "ACCOUNTS_PRIVATE_KEYS=$GOERLI_DEPLOYER_PRIVATE_KEY,$ACCOUNT_PRIVATE_KEY" \ - --platform linux/amd64 \ - gcr.io/keep-test-f3e0/keep-ecdsa-hardhat:latest \ - authorize:ecdsa \ - --network goerli \ - --owner $ACCOUNT_ADDRESS \ - --provider $ACCOUNT_ADDRESS - -printf "\n\e[1;32mDONE!\n\n\e[0m" diff --git a/infrastructure/eth-networks/private-testnet/scripts/new-bundle.sh b/infrastructure/eth-networks/private-testnet/scripts/new-bundle.sh deleted file mode 100755 index 8f34594f09..0000000000 --- a/infrastructure/eth-networks/private-testnet/scripts/new-bundle.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash -set -eou pipefail - -ROOT_DIR="$(realpath "$(dirname $0)/../bundles")" - -if ! npx eth-helper --version &>/dev/null; then - printf "eth-helper could not be found; installing... \n" - npm install nkuba/eth-helper -fi - -STAKING_PROVIDER=${1-} -if [ -z "${STAKING_PROVIDER}" ]; then - read -p "Provide Staking Provider name: " STAKING_PROVIDER -fi - -STAKING_PROVIDER_DIR="$(realpath "$ROOT_DIR/$STAKING_PROVIDER")" - -if [ -d "$STAKING_PROVIDER_DIR" ]; then - echo "Directory for $STAKING_PROVIDER already exists." - exit 1 -fi - -if [ -z "${KEYFILE_PASSWORD+x}" ]; then - read -s -r -p "Provide password for key file encryption: " KEYFILE_PASSWORD - if [ -z "$KEYFILE_PASSWORD" ]; then - printf "KEYFILE_PASSWORD not set\n" - exit 1 - fi - printf "\n" -fi - -CONFIG_DIR="$STAKING_PROVIDER_DIR/config" -SECRETS_DIR="$STAKING_PROVIDER_DIR/secret" - -KEY_FILE_PATH="$CONFIG_DIR/staking-provider-eth-account-key-file.json" -KEY_FILE_PASSWORD_PATH="$SECRETS_DIR/staking-provider-eth-account-password" -PRIVATE_KEY_FILE_PATH="$SECRETS_DIR/staking-provider-eth-account-private-key" - -mkdir $STAKING_PROVIDER_DIR -mkdir $SECRETS_DIR -mkdir $CONFIG_DIR - -cd $STAKING_PROVIDER_DIR - -echo -n "$KEYFILE_PASSWORD" >"$KEY_FILE_PASSWORD_PATH" - -geth account new \ - --keystore ./ \ - --password "$KEY_FILE_PASSWORD_PATH" - -mv UTC-* $KEY_FILE_PATH - -npx eth-helper extract-private-key \ - -k "$KEY_FILE_PATH" \ - -p "$KEY_FILE_PASSWORD_PATH" \ - -o "$PRIVATE_KEY_FILE_PATH" - -asciidoctor ../bundle-guide.adoc -o index.html --doctype book - -tar -zcvf keep-test-bundle-$STAKING_PROVIDER.tgz --exclude *.tgz . - -printf "A bundle was saved: keep-test-bundle-$STAKING_PROVIDER.tgz" - -printf "\n\e[1;32mDONE!\n\n\e[0m" diff --git a/infrastructure/kube/keep-dev/.gitignore b/infrastructure/kube/keep-dev/.gitignore deleted file mode 100644 index ce71aabd5c..0000000000 --- a/infrastructure/kube/keep-dev/.gitignore +++ /dev/null @@ -1 +0,0 @@ -secrets/* diff --git a/infrastructure/kube/keep-dev/atlantis-ingress-https.yaml b/infrastructure/kube/keep-dev/atlantis-ingress-https.yaml deleted file mode 100644 index b9aa18e455..0000000000 --- a/infrastructure/kube/keep-dev/atlantis-ingress-https.yaml +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: atlantis-https - annotations: - kubernetes.io/ingress.class: "gce" - kubernetes.io/ingress.allow-http: "false" - kubernetes.io/ingress.global-static-ip-name: "keep-dev-atlantis-external-ip-0" -spec: - tls: - - hosts: - # This assumes tls-secret exists and the SSL - # certificate contains a CN for foo.bar.com - secretName: atlantis-tls - backend: - # This assumes http-svc exists and routes to healthy endpoints - serviceName: atlantis-https - servicePort: 8443 diff --git a/infrastructure/kube/keep-dev/atlantis-service-https.yaml b/infrastructure/kube/keep-dev/atlantis-service-https.yaml deleted file mode 100644 index 5d3ee762f3..0000000000 --- a/infrastructure/kube/keep-dev/atlantis-service-https.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: atlantis-https - annotations: - service.alpha.kubernetes.io/app-protocols: '{"atlantis-https-port":"HTTPS"}' -spec: - type: NodePort - ports: - - name: atlantis-https-port - port: 8443 - targetPort: 8443 - selector: - app: atlantis \ No newline at end of file diff --git a/infrastructure/kube/keep-dev/atlantis-statefulset.yaml b/infrastructure/kube/keep-dev/atlantis-statefulset.yaml deleted file mode 100644 index c087d10249..0000000000 --- a/infrastructure/kube/keep-dev/atlantis-statefulset.yaml +++ /dev/null @@ -1,114 +0,0 @@ -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: atlantis -spec: - serviceName: atlantis - replicas: 1 - updateStrategy: - type: RollingUpdate - rollingUpdate: - partition: 0 - selector: - matchLabels: - app: atlantis - template: - metadata: - labels: - app: atlantis - spec: - securityContext: - fsGroup: 1000 # Atlantis group (1000) read/write access to volumes. - containers: - - name: atlantis - image: runatlantis/atlantis:latest - env: - - name: GOOGLE_APPLICATION_CREDENTIALS - value: /mnt/terraform-admin-service-account/thesis-terraform-admin-service-account-creds.json - - name: ATLANTIS_ALLOW_REPO_CONFIG - value: "true" - - name: ATLANTIS_ATLANTIS_URL - value: https://atlantis.keep-dev.com - - name: ATLANTIS_SSL_CERT_FILE - value: /atlantis/tls/tls.crt - - name: ATLANTIS_SSL_KEY_FILE - value: /atlantis/tls/tls.key - - name: ATLANTIS_REPO_WHITELIST - value: github.com/keep-network/keep-core - - name: ATLANTIS_GH_USER - value: thesis-heimdall - - name: ATLANTIS_GH_TOKEN - valueFrom: - secretKeyRef: - name: atlantis-git - key: gh-access-token - - name: ATLANTIS_GH_WEBHOOK_SECRET - valueFrom: - secretKeyRef: - name: atlantis-git - key: gh-webhook-secret - - name: ATLANTIS_DATA_DIR - value: /atlantis - - name: ATLANTIS_PORT - value: "8443" - - name: TF_VAR_gcp_thesis_org_id - valueFrom: - secretKeyRef: - name: terraform-env-vars - key: org-id - - name: TF_VAR_gcp_thesis_billing_account - valueFrom: - secretKeyRef: - name: terraform-env-vars - key: billing-account - volumeMounts: - - name: atlantis-data - mountPath: /atlantis - - name: atlantis-tls-files - mountPath: /atlantis/tls - - name: atlantis-gitconfig - mountPath: /home/atlantis/ - - name: terraform-admin-service-account - mountPath: /mnt/terraform-admin-service-account - ports: - - name: atlantis - containerPort: 8443 - resources: - requests: - memory: 256Mi - cpu: 100m - limits: - memory: 256Mi - cpu: 100m - livenessProbe: - periodSeconds: 60 - httpGet: - path: /healthz - port: 8443 - scheme: HTTPS - readinessProbe: - periodSeconds: 60 - httpGet: - path: /healthz - port: 8443 - scheme: HTTPS - volumes: - - name: atlantis-tls-files - secret: - secretName: atlantis-tls - - name: atlantis-gitconfig - secret: - secretName: atlantis-gitconfig - - name: terraform-admin-service-account - secret: - secretName: terraform-admin-service-account - volumeClaimTemplates: - - metadata: - name: atlantis-data - spec: - accessModes: ["ReadWriteOnce"] # Volume should not be shared by multiple nodes. - resources: - requests: - # The biggest thing Atlantis stores is the Git repo when it checks it out. - # It deletes the repo after the pull request is merged. - storage: 1Gi diff --git a/infrastructure/kube/keep-dev/eth-account-info-configmap.yaml b/infrastructure/kube/keep-dev/eth-account-info-configmap.yaml deleted file mode 100644 index 0b9fc8c22a..0000000000 --- a/infrastructure/kube/keep-dev/eth-account-info-configmap.yaml +++ /dev/null @@ -1,20 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: eth-account-info - namespace: default -data: - account-0-keyfile: | - {"address":"0ec14bc7cca82c942cf276f6bbd0413216ddb2be","crypto":{"cipher":"aes-128-ctr","ciphertext":"d1e1885d30a2c25a54664487db4d69da496951733de6ceb4d5f565fe62eaba79","cipherparams":{"iv":"8cacad8a1b79982f568948b7f97b3dd3"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"00bfb9f49e54e6dba5b1b0c5b09904998fcfa10d0381b90bf26d45904a4e2636"},"mac":"9038c2a02d7837e448088fb19fc76e9d6c5063e8f1cb0addb40dc9df061b4928"},"id":"afb99070-073f-4dc6-b0d7-92b41fcf0afb","version":3} - - account-1-keyfile: | - {"address":"cab2a402bac470686d14956fb310d51bbef9fa31","crypto":{"cipher":"aes-128-ctr","ciphertext":"50193ab419aa322ceb556d4c073d1727763e5d873cce4e0735e6690194432665","cipherparams":{"iv":"6f869f3bd192d80981435016cc19afff"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"b72fe3dfd4d7419baa4d9a8ed7e27bf509fb9e1557a5d73c9c4879bf3a19abe9"},"mac":"5d3093a7b0160a8c2187efd4ab7ec168226e561ff7a0d714886c5dff28c405e7"},"id":"d43da5de-511f-4a1d-8ba8-0e0c24bf33e6","version":3} - - account-2-keyfile: | - {"address":"ac049223397e2f25ea9fe56d5ee0896f6d8e8cb7","crypto":{"cipher":"aes-128-ctr","ciphertext":"42f6463f021f631ffbaf04989c107d784f0e1ba3a3b469073af4cc928d90bd5b","cipherparams":{"iv":"a533352b5ceb005cd730153f26e2f710"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"5716b94200ea2500fd257d28c1fd58e92ea991a4642813c91f66ae81fbc088bd"},"mac":"09b1e0857562a20ef0d25f41687095cdf246295a9dba82fee7e46756b0437bdc"},"id":"3819c68b-bc9d-4f54-867a-1ea7955c3cff","version":3} - - account-3-keyfile: | - {"address":"3ff855895ef4ac833c32ab6a0d6c7fbfa137e26e","crypto":{"cipher":"aes-128-ctr","ciphertext":"3cb866a0a1c0db6ca8accfc3c3036d9ee93b5dbca98f89dcf8f293e8b0134146","cipherparams":{"iv":"50e06549568b995a76190673e1643635"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"ee2164b8525571024704eaa976c3ac80fb41b74bcaa7d7788f7ac94dd1b6878b"},"mac":"408bf7c097e905019e25b4c82b4c988b03a607469f77bdbe0e9ca6d870fa9055"},"id":"93a1dc32-f80a-400a-99be-c478f72a6630","version":3} - - account-4-keyfile: | - {"address":"0954efefeb970d317a51736201b4eb2de75ff5de","crypto":{"cipher":"aes-128-ctr","ciphertext":"ad2d8baa3626a7ffd0040a09dbbe73e179aa125e1677987524e1c5593f03c645","cipherparams":{"iv":"856e9d869aaa40e994bda72f969505ac"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"a83d0582c376744e44cb982a90a5512a6570e046ea7ee0fd571e2fbda0cb762b"},"mac":"83ea2018f56bdd4967e8bd32c60cc7b3021bab59c72e4292c2e0ff20fc3b37e6"},"id":"666be636-2a15-4563-b78f-1ab704ec606c","version":3} diff --git a/infrastructure/kube/keep-dev/eth-dashboard-internal-deployment.yaml b/infrastructure/kube/keep-dev/eth-dashboard-internal-deployment.yaml deleted file mode 100644 index e6b71b220b..0000000000 --- a/infrastructure/kube/keep-dev/eth-dashboard-internal-deployment.yaml +++ /dev/null @@ -1,31 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: eth-dashboard - namespace: default -spec: - replicas: 1 - strategy: - type: RollingUpdate - selector: - matchLabels: - app: eth-dashboard - template: - metadata: - labels: - app: eth-dashboard - spec: - securityContext: - fsGroup: 1000 - containers: - - name: eth-dashboard - image: gcr.io/keep-dev-fe24/eth-dashboard-node - ports: - - containerPort: 3000 - - containerPort: 3001 - env: - - name: WS_SECRET - value: BANZAI!!!! - - name: BOOTNODE_URL - value: http://eth-dashboard.default.svc.cluster.local:3001 diff --git a/infrastructure/kube/keep-dev/eth-dashboard-internal-ingress.yaml b/infrastructure/kube/keep-dev/eth-dashboard-internal-ingress.yaml deleted file mode 100644 index 2b2fbd33b1..0000000000 --- a/infrastructure/kube/keep-dev/eth-dashboard-internal-ingress.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: eth-dashboard-http - annotations: - kubernetes.io/ingress.class: "gce" - kubernetes.io/ingress.allow-http: "true" -spec: - backend: - # This assumes service eth-dashboard-http exists and routes to healthy endpoints - serviceName: eth-dashboard-http - servicePort: 8080 diff --git a/infrastructure/kube/keep-dev/eth-dashboard-internal-service.yaml b/infrastructure/kube/keep-dev/eth-dashboard-internal-service.yaml deleted file mode 100644 index 009bef4d1e..0000000000 --- a/infrastructure/kube/keep-dev/eth-dashboard-internal-service.yaml +++ /dev/null @@ -1,30 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: eth-dashboard-http -spec: - type: NodePort - ports: - - name: eth-dashboard-http-port - port: 8080 - targetPort: 3000 - selector: - app: eth-dashboard ---- -apiVersion: v1 -kind: Service -metadata: - name: eth-dashboard - labels: - app: eth-dashboard -spec: - ports: - - port: 3000 - targetPort: 3000 - name: tcp-3000 - - port: 3001 - targetPort: 3001 - name: tcp-3001 - selector: - app: eth-dashboard diff --git a/infrastructure/kube/keep-dev/eth-miner-internal-daemonset.yaml b/infrastructure/kube/keep-dev/eth-miner-internal-daemonset.yaml deleted file mode 100644 index 8ca5e1abd1..0000000000 --- a/infrastructure/kube/keep-dev/eth-miner-internal-daemonset.yaml +++ /dev/null @@ -1,56 +0,0 @@ ---- -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: eth-miner-node - namespace: default -spec: - selector: - matchLabels: - app: geth - type: miner - template: - metadata: - labels: - app: geth - type: miner - spec: - securityContext: - fsGroup: 1000 - containers: - - name: miner - image: gcr.io/keep-dev-fe24/eth-geth-node:1.9.6 - ports: - - containerPort: 8545 - - containerPort: 8546 - - containerPort: 30303 - volumeMounts: - env: - - name: INSTANCE_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: HOST_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - - name: NETWORKID - value: "1101" - - name: WS_SERVER - value: ws://eth-dashboard.default.svc.cluster.local:3000 - - name: WS_SECRET - value: BANZAI!!!! - - name: BOOTNODE_URL - value: http://eth-dashboard.default.svc.cluster.local:3001 - - name: BOOTNODE_NETWORK - value: network_1 - - name: ENABLE_MINER - value: "1" - - name: MINER_THREADS - value: "1" - - name: ETH_IPC_PATH - value: /tmp/geth.ipc diff --git a/infrastructure/kube/keep-dev/eth-miner-internal-service.yaml b/infrastructure/kube/keep-dev/eth-miner-internal-service.yaml deleted file mode 100644 index 9fbdb5e690..0000000000 --- a/infrastructure/kube/keep-dev/eth-miner-internal-service.yaml +++ /dev/null @@ -1,26 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: eth-miner-node - labels: - app: geth - type: miner -spec: - ports: - - port: 8545 - targetPort: 8545 - name: tcp-8545 - - port: 8546 - targetPort: 8546 - name: tcp-8546 - - port: 30303 - targetPort: 30303 - name: tcp-30303 - - port: 30303 - targetPort: 30303 - name: udp-30303 - protocol: UDP - selector: - app: geth - type: miner diff --git a/infrastructure/kube/keep-dev/eth-network-internal-configmap.yaml b/infrastructure/kube/keep-dev/eth-network-internal-configmap.yaml deleted file mode 100644 index 50511759c4..0000000000 --- a/infrastructure/kube/keep-dev/eth-network-internal-configmap.yaml +++ /dev/null @@ -1,10 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: eth-network-internal - namespace: default -data: - rpc-url: http://eth-tx-node.default.svc.cluster.local:8545 - ws-url: ws://eth-tx-node.default.svc.cluster.local:8546 - network-id: '1101' - contract-owner-eth-account-address: '0x923c5dbf353e99394a21aa7b67f3327ca111c67d' diff --git a/infrastructure/kube/keep-dev/eth-tx-internal-deployment.yaml b/infrastructure/kube/keep-dev/eth-tx-internal-deployment.yaml deleted file mode 100644 index 147c0b313f..0000000000 --- a/infrastructure/kube/keep-dev/eth-tx-internal-deployment.yaml +++ /dev/null @@ -1,56 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: eth-tx-node - namespace: default -spec: - replicas: 1 - strategy: - type: RollingUpdate - selector: - matchLabels: - app: geth - type: tx - template: - metadata: - labels: - app: geth - type: tx - spec: - securityContext: - fsGroup: 1000 - containers: - - name: tx - image: gcr.io/keep-dev-fe24/eth-geth-node:1.9.6 - ports: - - containerPort: 8545 - - containerPort: 8546 - - containerPort: 30303 - env: - - name: INSTANCE_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: HOST_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - - name: NETWORKID - value: "1101" - - name: WS_SERVER - value: ws://eth-dashboard.default.svc.cluster.local:3000 - - name: WS_SECRET - value: BANZAI!!!! - - name: BOOTNODE_URL - value: http://eth-dashboard.default.svc.cluster.local:3001 - - name: BOOTNODE_NETWORK - value: network_1 - - name: BOOTNODE_PUBLIC_IP - value: eth-dashboard.default.svc.cluster.local - - name: ETH_IPC_PATH - value: /tmp/geth.ipc diff --git a/infrastructure/kube/keep-dev/eth-tx-internal-service.yaml b/infrastructure/kube/keep-dev/eth-tx-internal-service.yaml deleted file mode 100644 index 9c8bef2e16..0000000000 --- a/infrastructure/kube/keep-dev/eth-tx-internal-service.yaml +++ /dev/null @@ -1,26 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: eth-tx-node - labels: - app: geth - type: tx -spec: - ports: - - port: 8545 - targetPort: 8545 - name: tcp-8545 - - port: 8546 - targetPort: 8546 - name: tcp-8546 - - port: 30303 - targetPort: 30303 - name: tcp-30303 - - port: 30303 - targetPort: 30303 - name: udp-30303 - protocol: UDP - selector: - app: geth - type: tx \ No newline at end of file diff --git a/infrastructure/kube/keep-dev/keep-client-0-service.yaml b/infrastructure/kube/keep-dev/keep-client-0-service.yaml deleted file mode 100644 index 44b23b5734..0000000000 --- a/infrastructure/kube/keep-dev/keep-client-0-service.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: keep-client-0 - namespace: default - labels: - app: keep - type: beacon - id: '0' -spec: - ports: - - port: 3919 - targetPort: 3919 - name: tcp-3919 - selector: - app: keep - type: beacon - id: '0' \ No newline at end of file diff --git a/infrastructure/kube/keep-dev/keep-client-0-statefulset.yaml b/infrastructure/kube/keep-dev/keep-client-0-statefulset.yaml deleted file mode 100644 index 2ca4df8b06..0000000000 --- a/infrastructure/kube/keep-dev/keep-client-0-statefulset.yaml +++ /dev/null @@ -1,124 +0,0 @@ ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: keep-client-0 - namespace: default - labels: - keel.sh/policy: all - app: keep - type: beacon - id: '0' -spec: - replicas: 1 - selector: - matchLabels: - app: keep - type: beacon - id: '0' - serviceName: keep-client-0 - volumeClaimTemplates: - - metadata: - name: keep-client-data - spec: - accessModes: [ReadWriteOnce] - resources: - requests: - storage: 512Mi - - metadata: - name: keep-client-config - spec: - accessModes: [ReadWriteOnce] - resources: - requests: - storage: 5Mi - template: - metadata: - labels: - app: keep - type: beacon - id: '0' - spec: - volumes: - - name: keep-client-config - persistentVolumeClaim: - claimName: keep-client-config - - name: keep-client-data - persistentVolumeClaim: - claimName: keep-client-data - - name: eth-account-keyfile - configMap: - name: eth-account-info - items: - - key: account-0-keyfile - path: account-0-keyfile - containers: - - name: keep-client-0 - image: gcr.io/keep-dev-fe24/keep-client - imagePullPolicy: Always - ports: - - containerPort: 3919 - env: - - name: KEEP_ETHEREUM_PASSWORD - valueFrom: - secretKeyRef: - name: eth-account-passphrases - key: account-0 - - name: LOG_LEVEL - value: debug - - name: IPFS_LOGGING_FMT - value: nocolor - volumeMounts: - - name: keep-client-config - mountPath: /mnt/keep-client/config - - name: keep-client-data - mountPath: /mnt/keep-client/data - - name: eth-account-keyfile - mountPath: /mnt/keep-client/keyfile - command: ["keep-client", "-config", "/mnt/keep-client/config/keep-client-config.toml", "start"] - initContainers: - - name: initcontainer-provision-keep-client - image: gcr.io/keep-dev-fe24/initcontainer-provision-keep-client-ethereum - imagePullPolicy: Always - env: - - name: ETH_RPC_URL - valueFrom: - configMapKeyRef: - name: eth-network-internal - key: rpc-url - - name: ETH_WS_URL - valueFrom: - configMapKeyRef: - name: eth-network-internal - key: ws-url - - name: ETH_NETWORK_ID - valueFrom: - configMapKeyRef: - name: eth-network-internal - key: network-id - - name: CONTRACT_OWNER_ETH_ACCOUNT_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-network-internal - key: contract-owner-eth-account-address - - name: CONTRACT_OWNER_ETH_ACCOUNT_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-internal - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_KEYFILE_PATH - value: /mnt/keep-client/keyfile/account-0-keyfile - - name: KEEP_CLIENT_PEERS - value: /ip4/10.102.100.40/tcp/3919/ipfs/16Uiu2HAm3eJtyFKAttzJ85NLMromHuRg4yyum3CREMf6CHBBV6KY - - name: KEEP_CLIENT_ANNOUNCED_ADDRESSES - value: '' - - name: KEEP_CLIENT_PORT - value: '3919' - - name: KEEP_CLIENT_DATA_DIR - value: /mnt/keep-client/data - volumeMounts: - - name: keep-client-config - mountPath: /mnt/keep-client/config - - name: eth-account-keyfile - mountPath: /mnt/keep-client/keyfile - command: ["node", "/tmp/provision-keep-client.js"] diff --git a/infrastructure/kube/keep-dev/keep-client-1-service.yaml b/infrastructure/kube/keep-dev/keep-client-1-service.yaml deleted file mode 100644 index d9fd231f70..0000000000 --- a/infrastructure/kube/keep-dev/keep-client-1-service.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: keep-client-1 - namespace: default - labels: - app: keep - type: beacon - id: '1' -spec: - ports: - - port: 3919 - targetPort: 3919 - name: tcp-3919 - selector: - app: keep - type: beacon - id: '1' \ No newline at end of file diff --git a/infrastructure/kube/keep-dev/keep-client-1-statefulset.yaml b/infrastructure/kube/keep-dev/keep-client-1-statefulset.yaml deleted file mode 100644 index 57b6e662b5..0000000000 --- a/infrastructure/kube/keep-dev/keep-client-1-statefulset.yaml +++ /dev/null @@ -1,124 +0,0 @@ ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: keep-client-1 - namespace: default - labels: - keel.sh/policy: all - app: keep - type: beacon - id: '1' -spec: - replicas: 1 - selector: - matchLabels: - app: keep - type: beacon - id: '1' - serviceName: keep-client-1 - volumeClaimTemplates: - - metadata: - name: keep-client-data - spec: - accessModes: [ReadWriteOnce] - resources: - requests: - storage: 512Mi - - metadata: - name: keep-client-config - spec: - accessModes: [ReadWriteOnce] - resources: - requests: - storage: 5Mi - template: - metadata: - labels: - app: keep - type: beacon - id: '1' - spec: - volumes: - - name: keep-client-config - persistentVolumeClaim: - claimName: keep-client-config - - name: keep-client-data - persistentVolumeClaim: - claimName: keep-client-data - - name: eth-account-keyfile - configMap: - name: eth-account-info - items: - - key: account-1-keyfile - path: account-1-keyfile - containers: - - name: keep-client-1 - image: gcr.io/keep-dev-fe24/keep-client - imagePullPolicy: Always - ports: - - containerPort: 3919 - env: - - name: KEEP_ETHEREUM_PASSWORD - valueFrom: - secretKeyRef: - name: eth-account-passphrases - key: account-1 - - name: LOG_LEVEL - value: debug - - name: IPFS_LOGGING_FMT - value: nocolor - volumeMounts: - - name: keep-client-config - mountPath: /mnt/keep-client/config - - name: keep-client-data - mountPath: /mnt/keep-client/data - - name: eth-account-keyfile - mountPath: /mnt/keep-client/keyfile - command: ["keep-client", "-config", "/mnt/keep-client/config/keep-client-config.toml", "start"] - initContainers: - - name: initcontainer-provision-keep-client - image: gcr.io/keep-dev-fe24/initcontainer-provision-keep-client-ethereum - imagePullPolicy: Always - env: - - name: ETH_RPC_URL - valueFrom: - configMapKeyRef: - name: eth-network-internal - key: rpc-url - - name: ETH_WS_URL - valueFrom: - configMapKeyRef: - name: eth-network-internal - key: ws-url - - name: ETH_NETWORK_ID - valueFrom: - configMapKeyRef: - name: eth-network-internal - key: network-id - - name: CONTRACT_OWNER_ETH_ACCOUNT_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-network-internal - key: contract-owner-eth-account-address - - name: CONTRACT_OWNER_ETH_ACCOUNT_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-internal - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_KEYFILE_PATH - value: /mnt/keep-client/keyfile/account-1-keyfile - - name: KEEP_CLIENT_PEERS - value: /ip4/10.102.100.165/tcp/3919/ipfs/16Uiu2HAmCcfVpHwfBKNFbQuhvGuFXHVLQ65gB4sJm7HyrcZuLttH - - name: KEEP_CLIENT_ANNOUNCED_ADDRESSES - value: '' - - name: KEEP_CLIENT_PORT - value: '3919' - - name: KEEP_CLIENT_DATA_DIR - value: /mnt/keep-client/data - volumeMounts: - - name: keep-client-config - mountPath: /mnt/keep-client/config - - name: eth-account-keyfile - mountPath: /mnt/keep-client/keyfile - command: ["node", "/tmp/provision-keep-client.js"] diff --git a/infrastructure/kube/keep-dev/keep-client-2-service.yaml b/infrastructure/kube/keep-dev/keep-client-2-service.yaml deleted file mode 100644 index 06e2672748..0000000000 --- a/infrastructure/kube/keep-dev/keep-client-2-service.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: keep-client-2 - namespace: default - labels: - app: keep - type: beacon - id: '2' -spec: - ports: - - port: 3919 - targetPort: 3919 - name: tcp-3919 - selector: - app: keep - type: beacon - id: '2' \ No newline at end of file diff --git a/infrastructure/kube/keep-dev/keep-client-2-statefulset.yaml b/infrastructure/kube/keep-dev/keep-client-2-statefulset.yaml deleted file mode 100644 index 92827cffe6..0000000000 --- a/infrastructure/kube/keep-dev/keep-client-2-statefulset.yaml +++ /dev/null @@ -1,124 +0,0 @@ ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: keep-client-2 - namespace: default - labels: - keel.sh/policy: all - app: keep - type: beacon - id: '2' -spec: - replicas: 1 - selector: - matchLabels: - app: keep - type: beacon - id: '2' - serviceName: keep-client-0 - volumeClaimTemplates: - - metadata: - name: keep-client-data - spec: - accessModes: [ReadWriteOnce] - resources: - requests: - storage: 512Mi - - metadata: - name: keep-client-config - spec: - accessModes: [ReadWriteOnce] - resources: - requests: - storage: 5Mi - template: - metadata: - labels: - app: keep - type: beacon - id: '2' - spec: - volumes: - - name: keep-client-config - persistentVolumeClaim: - claimName: keep-client-config - - name: keep-client-data - persistentVolumeClaim: - claimName: keep-client-data - - name: eth-account-keyfile - configMap: - name: eth-account-info - items: - - key: account-2-keyfile - path: account-2-keyfile - containers: - - name: keep-client-0 - image: gcr.io/keep-dev-fe24/keep-client - imagePullPolicy: Always - ports: - - containerPort: 3919 - env: - - name: KEEP_ETHEREUM_PASSWORD - valueFrom: - secretKeyRef: - name: eth-account-passphrases - key: account-2 - - name: LOG_LEVEL - value: debug - - name: IPFS_LOGGING_FMT - value: nocolor - volumeMounts: - - name: keep-client-config - mountPath: /mnt/keep-client/config - - name: keep-client-data - mountPath: /mnt/keep-client/data - - name: eth-account-keyfile - mountPath: /mnt/keep-client/keyfile - command: ["keep-client", "-config", "/mnt/keep-client/config/keep-client-config.toml", "start"] - initContainers: - - name: initcontainer-provision-keep-client - image: gcr.io/keep-dev-fe24/initcontainer-provision-keep-client-ethereum - imagePullPolicy: Always - env: - - name: ETH_RPC_URL - valueFrom: - configMapKeyRef: - name: eth-network-internal - key: rpc-url - - name: ETH_WS_URL - valueFrom: - configMapKeyRef: - name: eth-network-internal - key: ws-url - - name: ETH_NETWORK_ID - valueFrom: - configMapKeyRef: - name: eth-network-internal - key: network-id - - name: CONTRACT_OWNER_ETH_ACCOUNT_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-network-internal - key: contract-owner-eth-account-address - - name: CONTRACT_OWNER_ETH_ACCOUNT_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-internal - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_KEYFILE_PATH - value: /mnt/keep-client/keyfile/account-2-keyfile - - name: KEEP_CLIENT_PEERS - value: /ip4/10.102.100.40/tcp/3919/ipfs/16Uiu2HAm3eJtyFKAttzJ85NLMromHuRg4yyum3CREMf6CHBBV6KY - - name: KEEP_CLIENT_ANNOUNCED_ADDRESSES - value: '' - - name: KEEP_CLIENT_PORT - value: '3919' - - name: KEEP_CLIENT_DATA_DIR - value: /mnt/keep-client/data - volumeMounts: - - name: keep-client-config - mountPath: /mnt/keep-client/config - - name: eth-account-keyfile - mountPath: /mnt/keep-client/keyfile - command: ["node", "/tmp/provision-keep-client.js"] diff --git a/infrastructure/kube/keep-dev/keep-client-3-service.yaml b/infrastructure/kube/keep-dev/keep-client-3-service.yaml deleted file mode 100644 index 19e8050a9e..0000000000 --- a/infrastructure/kube/keep-dev/keep-client-3-service.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: keep-client-3 - namespace: default - labels: - app: keep - type: beacon - id: '3' -spec: - ports: - - port: 3919 - targetPort: 3919 - name: tcp-3919 - selector: - app: keep - type: beacon - id: '3' \ No newline at end of file diff --git a/infrastructure/kube/keep-dev/keep-client-3-statefulset.yaml b/infrastructure/kube/keep-dev/keep-client-3-statefulset.yaml deleted file mode 100644 index e5a88dfaeb..0000000000 --- a/infrastructure/kube/keep-dev/keep-client-3-statefulset.yaml +++ /dev/null @@ -1,124 +0,0 @@ ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: keep-client-3 - namespace: default - labels: - keel.sh/policy: all - app: keep - type: beacon - id: '3' -spec: - replicas: 1 - selector: - matchLabels: - app: keep - type: beacon - id: '3' - serviceName: keep-client-0 - volumeClaimTemplates: - - metadata: - name: keep-client-data - spec: - accessModes: [ReadWriteOnce] - resources: - requests: - storage: 512Mi - - metadata: - name: keep-client-config - spec: - accessModes: [ReadWriteOnce] - resources: - requests: - storage: 5Mi - template: - metadata: - labels: - app: keep - type: beacon - id: '3' - spec: - volumes: - - name: keep-client-config - persistentVolumeClaim: - claimName: keep-client-config - - name: keep-client-data - persistentVolumeClaim: - claimName: keep-client-data - - name: eth-account-keyfile - configMap: - name: eth-account-info - items: - - key: account-3-keyfile - path: account-3-keyfile - containers: - - name: keep-client-0 - image: gcr.io/keep-dev-fe24/keep-client - imagePullPolicy: Always - ports: - - containerPort: 3919 - env: - - name: KEEP_ETHEREUM_PASSWORD - valueFrom: - secretKeyRef: - name: eth-account-passphrases - key: account-3 - - name: LOG_LEVEL - value: debug - - name: IPFS_LOGGING_FMT - value: nocolor - volumeMounts: - - name: keep-client-config - mountPath: /mnt/keep-client/config - - name: keep-client-data - mountPath: /mnt/keep-client/data - - name: eth-account-keyfile - mountPath: /mnt/keep-client/keyfile - command: ["keep-client", "-config", "/mnt/keep-client/config/keep-client-config.toml", "start"] - initContainers: - - name: initcontainer-provision-keep-client - image: gcr.io/keep-dev-fe24/initcontainer-provision-keep-client-ethereum - imagePullPolicy: Always - env: - - name: ETH_RPC_URL - valueFrom: - configMapKeyRef: - name: eth-network-internal - key: rpc-url - - name: ETH_WS_URL - valueFrom: - configMapKeyRef: - name: eth-network-internal - key: ws-url - - name: ETH_NETWORK_ID - valueFrom: - configMapKeyRef: - name: eth-network-internal - key: network-id - - name: CONTRACT_OWNER_ETH_ACCOUNT_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-network-internal - key: contract-owner-eth-account-address - - name: CONTRACT_OWNER_ETH_ACCOUNT_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-internal - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_KEYFILE_PATH - value: /mnt/keep-client/keyfile/account-3-keyfile - - name: KEEP_CLIENT_PEERS - value: /ip4/10.102.100.149/tcp/3919/ipfs/16Uiu2HAmNNuCp45z5bgB8KiTHv1vHTNAVbBgxxtTFGAndageo9Dp - - name: KEEP_CLIENT_ANNOUNCED_ADDRESSES - value: '' - - name: KEEP_CLIENT_PORT - value: '3919' - - name: KEEP_CLIENT_DATA_DIR - value: /mnt/keep-client/data - volumeMounts: - - name: keep-client-config - mountPath: /mnt/keep-client/config - - name: eth-account-keyfile - mountPath: /mnt/keep-client/keyfile - command: ["node", "/tmp/provision-keep-client.js"] diff --git a/infrastructure/kube/keep-dev/keep-client-4-service.yaml b/infrastructure/kube/keep-dev/keep-client-4-service.yaml deleted file mode 100644 index 8b232d9507..0000000000 --- a/infrastructure/kube/keep-dev/keep-client-4-service.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: keep-client-4 - namespace: default - labels: - app: keep - type: beacon - id: '4' -spec: - ports: - - port: 3919 - targetPort: 3919 - name: tcp-3919 - selector: - app: keep - type: beacon - id: '4' \ No newline at end of file diff --git a/infrastructure/kube/keep-dev/keep-client-4-statefulset.yaml b/infrastructure/kube/keep-dev/keep-client-4-statefulset.yaml deleted file mode 100644 index ef6ea6b042..0000000000 --- a/infrastructure/kube/keep-dev/keep-client-4-statefulset.yaml +++ /dev/null @@ -1,124 +0,0 @@ ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: keep-client-4 - namespace: default - labels: - keel.sh/policy: all - app: keep - type: beacon - id: '4' -spec: - replicas: 1 - selector: - matchLabels: - app: keep - type: beacon - id: '4' - serviceName: keep-client-0 - volumeClaimTemplates: - - metadata: - name: keep-client-data - spec: - accessModes: [ReadWriteOnce] - resources: - requests: - storage: 512Mi - - metadata: - name: keep-client-config - spec: - accessModes: [ReadWriteOnce] - resources: - requests: - storage: 5Mi - template: - metadata: - labels: - app: keep - type: beacon - id: '4' - spec: - volumes: - - name: keep-client-config - persistentVolumeClaim: - claimName: keep-client-config - - name: keep-client-data - persistentVolumeClaim: - claimName: keep-client-data - - name: eth-account-keyfile - configMap: - name: eth-account-info - items: - - key: account-4-keyfile - path: account-4-keyfile - containers: - - name: keep-client-0 - image: gcr.io/keep-dev-fe24/keep-client - imagePullPolicy: Always - ports: - - containerPort: 3919 - env: - - name: KEEP_ETHEREUM_PASSWORD - valueFrom: - secretKeyRef: - name: eth-account-passphrases - key: account-4 - - name: LOG_LEVEL - value: debug - - name: IPFS_LOGGING_FMT - value: nocolor - volumeMounts: - - name: keep-client-config - mountPath: /mnt/keep-client/config - - name: keep-client-data - mountPath: /mnt/keep-client/data - - name: eth-account-keyfile - mountPath: /mnt/keep-client/keyfile - command: ["keep-client", "-config", "/mnt/keep-client/config/keep-client-config.toml", "start"] - initContainers: - - name: initcontainer-provision-keep-client - image: gcr.io/keep-dev-fe24/initcontainer-provision-keep-client-ethereum - imagePullPolicy: Always - env: - - name: ETH_RPC_URL - valueFrom: - configMapKeyRef: - name: eth-network-internal - key: rpc-url - - name: ETH_WS_URL - valueFrom: - configMapKeyRef: - name: eth-network-internal - key: ws-url - - name: ETH_NETWORK_ID - valueFrom: - configMapKeyRef: - name: eth-network-internal - key: network-id - - name: CONTRACT_OWNER_ETH_ACCOUNT_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-network-internal - key: contract-owner-eth-account-address - - name: CONTRACT_OWNER_ETH_ACCOUNT_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-internal - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_KEYFILE_PATH - value: /mnt/keep-client/keyfile/account-4-keyfile - - name: KEEP_CLIENT_PEERS - value: /ip4/10.102.100.66/tcp/3919/ipfs/16Uiu2HAm8KJX32kr3eYUhDuzwTucSfAfspnjnXNf9veVhB12t6Vf - - name: KEEP_CLIENT_ANNOUNCED_ADDRESSES - value: '' - - name: KEEP_CLIENT_PORT - value: '3919' - - name: KEEP_CLIENT_DATA_DIR - value: /mnt/keep-client/data - volumeMounts: - - name: keep-client-config - mountPath: /mnt/keep-client/config - - name: eth-account-keyfile - mountPath: /mnt/keep-client/keyfile - command: ["node", "/tmp/provision-keep-client.js"] diff --git a/infrastructure/kube/keep-dev/tenderly-agent-configmap.yaml b/infrastructure/kube/keep-dev/tenderly-agent-configmap.yaml deleted file mode 100644 index 65a228cfc2..0000000000 --- a/infrastructure/kube/keep-dev/tenderly-agent-configmap.yaml +++ /dev/null @@ -1,55 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: tenderly-agent - namespace: default -data: - config.yaml: | - agent: - database_path: .db - networks: - 1101: - name: keep-dev - address: 0.0.0.0:8555 - # the address and port of your local node - # note: this is the address from the perspective of the container - rpc_server: eth-tx-node.default.svc.cluster.local:8545 - node_type: geth - chain_config: - chainId: 1101 - homesteadBlock: 0 - eip150Block: 0 - eip155Block: 0 - eip158Block: 0 - byzantiumBlock: 0 - constantinopleBlock: 0 - petersburgBlock: 0 - istanbulBlock: 0 - clique: - period: 1 - epoch: 30000 - cert_file: ./.tenderly/cert/tenderly-agent.crt # optional - key_file: ./.tenderly/private/tenderly-agent.key # optional - tenderly-agent.crt: | - -----BEGIN CERTIFICATE----- - MIIDSTCCAjECCQDOwN/Y2oFDPDANBgkqhkiG9w0BAQsFADBfMRkwFwYDVQQDDBBk - ZXYua2VlcC5uZXR3b3JrMRAwDgYDVQQIDAdHZW9yZ2lhMRAwDgYDVQQHDAdBdGxh - bnRhMQ0wCwYDVQQKDARLZWVwMQ8wDQYDVQQLDAZEZXZPcHMwHhcNMjAwMzA5MjA0 - NzQ3WhcNMzAwMzA3MjA0NzQ3WjBuMSgwJgYDVQQDDB90ZW5kZXJseS1hZ2VudC5k - ZXYua2VlcC5uZXR3b3JrMRAwDgYDVQQIDAdHZW9yZ2lhMRAwDgYDVQQHDAdBdGxh - bnRhMQ0wCwYDVQQKDARLZWVwMQ8wDQYDVQQLDAZEZXZPcHMwggEiMA0GCSqGSIb3 - DQEBAQUAA4IBDwAwggEKAoIBAQDaJCPohw0cQXyzUinOW8cmGKpRtrwlvf/8pyUA - 1UPLTQ0h0QGFyba1ErceF3TAQLTmvoW5nmaQBkVlR++JynQIm4ZKQXlKNkBYM1qN - 5ce2sZpzIzJuatKA6BgFPh2R/p9YY9o+lMpeJCJ7wDnMuG5LrGk52g4Jb3zUu2XD - CdO9eZfUFnATlnBQ3UX5cbdyKmkTBPUijXezAevcFmdyoGCp/W0zdS1Slu25nRNd - EYKKBEfob/73aGWUuVdbnE01q9fguzzFAN5LEWewXDFCQ/sm8OdpvN62LvKmEXP7 - Dl4GHtkVq69bzQ1gGDwWr8GRkPKMnSALUETgQx8qBtA4JNQfAgMBAAEwDQYJKoZI - hvcNAQELBQADggEBAGEbIPTdTv6/LLf1y/rbFd/mYy2EbB5s7OcGXEDlUO00P7X3 - PcFZ88rVEWRc4eZxSFmPmwiDId5kEHXarsyM1yl2mG2Z08hNkTvq822GrgW+0dXy - EGuA512oQ491CLv+rIz0l/Cv0pMfICJXZsyiPArU2CPdA9JAfVEqQbGyd/TNr20p - p6fM4nqzd/m2gD7tFj9r3TJYNk5m1eiNsVV82SszaCgTK+ZagugWwXXd5snY4Zck - W1gG7eVF0RAMFjpAaquWGwAUtoqs2Wmx1w8cIp7Kw+3a8GEEUKxfNIXoWzs9tSEX - ApE5j9Uc3rETemy0x812OBR6iWj80TBPaaYyPzc= - -----END CERTIFICATE----- - - diff --git a/infrastructure/kube/keep-dev/tenderly-agent-deployment.yaml b/infrastructure/kube/keep-dev/tenderly-agent-deployment.yaml deleted file mode 100644 index 778aab8d33..0000000000 --- a/infrastructure/kube/keep-dev/tenderly-agent-deployment.yaml +++ /dev/null @@ -1,49 +0,0 @@ ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: tenderly-agent - labels: - app: tenderly - type: agent -spec: - replicas: 1 - selector: - matchLabels: - app: tenderly - type: agent - template: - metadata: - labels: - app: tenderly - type: agent - spec: - containers: - - name: tenderly-agent - image: gcr.io/tenderly-public/tenderly-agent:latest - volumeMounts: - - name: tenderly-agent-config - mountPath: /tenderly/config - - name: tenderly-agent-cert - mountPath: /tenderly/.tenderly/cert - - name: tenderly-agent-cert-key - mountPath: /tenderly/.tenderly/private - volumes: - - name: tenderly-agent-config - configMap: - name: tenderly-agent - items: - - key: config.yaml - path: config.yaml - - name: tenderly-agent-cert - configMap: - name: tenderly-agent - items: - - key: tenderly-agent.crt - path: tenderly-agent.crt - - name: tenderly-agent-cert-key - secret: - secretName: tenderly-agent - items: - - key: tenderly-agent.key - path: tenderly-agent.key \ No newline at end of file diff --git a/infrastructure/kube/keep-dev/tenderly-agent-service.yaml b/infrastructure/kube/keep-dev/tenderly-agent-service.yaml deleted file mode 100644 index 15f9574a2b..0000000000 --- a/infrastructure/kube/keep-dev/tenderly-agent-service.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: tenderly-agent - namespace: default - labels: - app: tenderly - type: agent -spec: - type: LoadBalancer - ports: - - name: agent-port - port: 8555 - targetPort: 8555 - selector: - app: tenderly - type: agent diff --git a/infrastructure/kube/keep-prd/.envrc b/infrastructure/kube/keep-prd/.envrc deleted file mode 100644 index 1f94e4483f..0000000000 --- a/infrastructure/kube/keep-prd/.envrc +++ /dev/null @@ -1 +0,0 @@ -export CLOUDSDK_ACTIVE_CONFIG_NAME=keep-prd diff --git a/infrastructure/kube/keep-prd/bitcoin/bitcoin-namespace.yaml b/infrastructure/kube/keep-prd/bitcoin/bitcoin-namespace.yaml deleted file mode 100644 index aa47d7b9e4..0000000000 --- a/infrastructure/kube/keep-prd/bitcoin/bitcoin-namespace.yaml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: bitcoin diff --git a/infrastructure/kube/keep-prd/bitcoin/bitcoind/bitcoind-data-bitcoind-1-pvc.yaml b/infrastructure/kube/keep-prd/bitcoin/bitcoind/bitcoind-data-bitcoind-1-pvc.yaml deleted file mode 100644 index 639281f2bc..0000000000 --- a/infrastructure/kube/keep-prd/bitcoin/bitcoind/bitcoind-data-bitcoind-1-pvc.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: bitcoind-data-bitcoind-1 - namespace: bitcoin - labels: - app: bitcoind - chain: bitcoin - network: mainnet -spec: - storageClassName: bitcoind - dataSource: - name: bitcoind-snapshot - kind: VolumeSnapshot - apiGroup: snapshot.storage.k8s.io - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 650Gi diff --git a/infrastructure/kube/keep-prd/bitcoin/bitcoind/bitcoind-volumesnapshot.yaml b/infrastructure/kube/keep-prd/bitcoin/bitcoind/bitcoind-volumesnapshot.yaml deleted file mode 100644 index 5182f14be1..0000000000 --- a/infrastructure/kube/keep-prd/bitcoin/bitcoind/bitcoind-volumesnapshot.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: snapshot.storage.k8s.io/v1 -kind: VolumeSnapshot -metadata: - name: bitcoind-snapshot -spec: - volumeSnapshotClassName: bitcoind - source: - persistentVolumeClaimName: bitcoind-data-bitcoind-0 diff --git a/infrastructure/kube/keep-prd/bitcoin/bitcoind/kustomization.yaml b/infrastructure/kube/keep-prd/bitcoin/bitcoind/kustomization.yaml deleted file mode 100644 index 726fc3cddf..0000000000 --- a/infrastructure/kube/keep-prd/bitcoin/bitcoind/kustomization.yaml +++ /dev/null @@ -1,31 +0,0 @@ -resources: - - ../../../templates/bitcoin/bitcoind - -namespace: bitcoin - -commonLabels: - network: mainnet - -configMapGenerator: - - name: bitcoind - behavior: merge - literals: - - chain=main - -secretGenerator: - - name: bitcoind - behavior: merge - envs: - - .env.secret - -patches: - - target: - kind: StatefulSet - name: bitcoind - patch: |- - apiVersion: apps/v1 - kind: StatefulSet - metadata: - name: bitcoind - spec: - replicas: 2 diff --git a/infrastructure/kube/keep-prd/bitcoin/electrumx/electrumx-compact-history-job.yaml b/infrastructure/kube/keep-prd/bitcoin/electrumx/electrumx-compact-history-job.yaml deleted file mode 100644 index f6f79363b9..0000000000 --- a/infrastructure/kube/keep-prd/bitcoin/electrumx/electrumx-compact-history-job.yaml +++ /dev/null @@ -1,67 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: electrumx-compact-history - namespace: bitcoin - labels: - chain: bitcoin - app: electrumx - network: mainnet -spec: - backoffLimit: 0 - completions: 1 - parallelism: 1 - template: - metadata: - labels: - chain: bitcoin - app: electrumx - network: mainnet - job-name: electrumx-compact-history - spec: - securityContext: - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - # https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#configure-volume-permission-and-ownership-change-policy-for-pods - fsGroupChangePolicy: "OnRootMismatch" - containers: - - name: electrumx - image: lukechilds/electrumx:v1.16.0 # TODO: switch to our image - imagePullPolicy: Always - command: - - /electrumx/electrumx_compact_history - env: - - name: COIN - value: BitcoinSegwit - - name: NET - value: mainnet - - name: DB_DIRECTORY - value: /mnt/electrum/data - - name: DAEMON_TOKEN - valueFrom: - secretKeyRef: - name: bitcoind - key: rpc-password - - name: DAEMON_HOST - valueFrom: - configMapKeyRef: - name: electrumx - key: daemon-host - - name: DAEMON_URL - value: http://$(DAEMON_USER):$(DAEMON_TOKEN)@$(DAEMON_HOST) - - name: COST_SOFT_LIMIT - value: "0" - - name: COST_HARD_LIMIT - value: "0" - - name: LOG_LEVEL - value: debug - volumeMounts: - - name: electrumx-data - mountPath: /mnt/electrum/data - restartPolicy: Never - volumes: - - name: electrumx-data - persistentVolumeClaim: - # Update to the desired replica's volume index. - claimName: electrumx-data-electrumx-2 diff --git a/infrastructure/kube/keep-prd/bitcoin/electrumx/electrumx-data-electrumx-1-pvc.yaml b/infrastructure/kube/keep-prd/bitcoin/electrumx/electrumx-data-electrumx-1-pvc.yaml deleted file mode 100644 index 9898a901a8..0000000000 --- a/infrastructure/kube/keep-prd/bitcoin/electrumx/electrumx-data-electrumx-1-pvc.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: electrumx-data-electrumx-1 - namespace: bitcoin - labels: - app: electrumx - chain: bitcoin - network: mainnet -spec: - storageClassName: electrumx-v2 - dataSource: - name: electrumx-snapshot - kind: VolumeSnapshot - apiGroup: snapshot.storage.k8s.io - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 450Gi diff --git a/infrastructure/kube/keep-prd/bitcoin/electrumx/electrumx-data-electrumx-2-pvc.yaml b/infrastructure/kube/keep-prd/bitcoin/electrumx/electrumx-data-electrumx-2-pvc.yaml deleted file mode 100644 index 4d311f6981..0000000000 --- a/infrastructure/kube/keep-prd/bitcoin/electrumx/electrumx-data-electrumx-2-pvc.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: electrumx-data-electrumx-2 - namespace: bitcoin - labels: - app: electrumx - chain: bitcoin - network: mainnet -spec: - storageClassName: electrumx-v2 - dataSource: - name: electrumx-snapshot - kind: VolumeSnapshot - apiGroup: snapshot.storage.k8s.io - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 450Gi diff --git a/infrastructure/kube/keep-prd/bitcoin/electrumx/electrumx-volumesnapshot.yaml b/infrastructure/kube/keep-prd/bitcoin/electrumx/electrumx-volumesnapshot.yaml deleted file mode 100644 index 36242a68ca..0000000000 --- a/infrastructure/kube/keep-prd/bitcoin/electrumx/electrumx-volumesnapshot.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: snapshot.storage.k8s.io/v1 -kind: VolumeSnapshot -metadata: - name: electrumx-snapshot -spec: - volumeSnapshotClassName: electrumx - source: - persistentVolumeClaimName: electrumx-data-electrumx-0 diff --git a/infrastructure/kube/keep-prd/bitcoin/electrumx/kustomization.yaml b/infrastructure/kube/keep-prd/bitcoin/electrumx/kustomization.yaml deleted file mode 100644 index d20f7bd6c5..0000000000 --- a/infrastructure/kube/keep-prd/bitcoin/electrumx/kustomization.yaml +++ /dev/null @@ -1,43 +0,0 @@ -resources: - - ../../../templates/bitcoin/electrumx - -namespace: bitcoin - -commonLabels: - network: mainnet - -secretGenerator: - - name: tbtc-network-cloudflare-origin-cert - type: kubernetes.io/tls - files: - - .secret/ca.crt - - .secret/tls.crt - - .secret/tls.key - -patches: - - target: - kind: Service - name: electrumx - patch: |- - apiVersion: v1 - kind: Service - metadata: - name: electrumx - spec: - type: LoadBalancer - loadBalancerIP: 35.223.16.19 - - target: - kind: StatefulSet - name: electrumx - patch: |- - apiVersion: apps/v1 - kind: StatefulSet - metadata: - name: electrumx - spec: - replicas: 3 - -generatorOptions: - disableNameSuffixHash: true - annotations: - note: generated diff --git a/infrastructure/kube/keep-prd/bitcoin/kustomization.yaml b/infrastructure/kube/keep-prd/bitcoin/kustomization.yaml deleted file mode 100644 index 03ec75721c..0000000000 --- a/infrastructure/kube/keep-prd/bitcoin/kustomization.yaml +++ /dev/null @@ -1,2 +0,0 @@ -resources: - - bitcoin-namespace.yaml diff --git a/infrastructure/kube/keep-prd/keep-maintainer/kustomization.yaml b/infrastructure/kube/keep-prd/keep-maintainer/kustomization.yaml index a74c65a959..33424f8422 100644 --- a/infrastructure/kube/keep-prd/keep-maintainer/kustomization.yaml +++ b/infrastructure/kube/keep-prd/keep-maintainer/kustomization.yaml @@ -10,7 +10,7 @@ commonLabels: images: - name: keep-maintainer - newName: thresholdnetwork/keep-client + newName: keepnetwork/keep-client newTag: v2.1.0 configMapGenerator: diff --git a/infrastructure/kube/keep-prd/monitoring/README.adoc b/infrastructure/kube/keep-prd/monitoring/README.adoc deleted file mode 100644 index bc9f79b764..0000000000 --- a/infrastructure/kube/keep-prd/monitoring/README.adoc +++ /dev/null @@ -1,37 +0,0 @@ -:icons: font - -ifdef::env-github[] -:tip-caption: :bulb: -:note-caption: :information_source: -:important-caption: :heavy_exclamation_mark: -:caution-caption: :fire: -:warning-caption: :warning: -endif::[] - -# Monitoring - -The monitoring stack has the following components: - -1. Prometheus -2. Trickster -3. Grafana - -The production monitoring is based on the configuration described in the link:../../keep-test/monitoring/README.adoc[keep-test monitoring documentation]. - -Resources are exposed publicly under the following URLs: - -[cols="^1s,2m"] -|=== -^h|Service -^h|Address - -|Public Dashboard -|link:https://public.monitoring.threshold.network[] - -|Grafana -|link:https://monitoring.threshold.network/grafana[] - -|Prometheus -|link:https://monitoring.threshold.network/prometheus[] - -|=== diff --git a/infrastructure/kube/keep-prd/monitoring/grafana/config/dashboards.yaml b/infrastructure/kube/keep-prd/monitoring/grafana/config/dashboards.yaml deleted file mode 100644 index 54bf65f56f..0000000000 --- a/infrastructure/kube/keep-prd/monitoring/grafana/config/dashboards.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: 1 -providers: - - name: dashboards-provider - type: file - disableDeletion: true - updateIntervalSeconds: 10 - allowUiUpdates: true - options: - path: "/var/lib/grafana/dashboards" - foldersFromFilesStructure: true diff --git a/infrastructure/kube/keep-prd/monitoring/grafana/config/datasources.yaml b/infrastructure/kube/keep-prd/monitoring/grafana/config/datasources.yaml deleted file mode 100644 index ef00731e62..0000000000 --- a/infrastructure/kube/keep-prd/monitoring/grafana/config/datasources.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: 1 -datasources: - - name: Trickster - type: prometheus - access: proxy - editable: true - orgId: 1 - url: http://trickster:8480/prometheus - version: 1 - isDefault: true diff --git a/infrastructure/kube/keep-prd/monitoring/grafana/config/grafana.ini b/infrastructure/kube/keep-prd/monitoring/grafana/config/grafana.ini deleted file mode 100644 index 66e6511968..0000000000 --- a/infrastructure/kube/keep-prd/monitoring/grafana/config/grafana.ini +++ /dev/null @@ -1,9 +0,0 @@ -[auth.google] -enabled = true -scopes = https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email -auth_url = https://accounts.google.com/o/oauth2/auth -token_url = https://accounts.google.com/o/oauth2/token -allow_sign_up = true - -[feature_toggles] -publicDashboards = true diff --git a/infrastructure/kube/keep-prd/monitoring/grafana/dashboards/keep/keep-nodes-public.json b/infrastructure/kube/keep-prd/monitoring/grafana/dashboards/keep/keep-nodes-public.json deleted file mode 100644 index eb91d379db..0000000000 --- a/infrastructure/kube/keep-prd/monitoring/grafana/dashboards/keep/keep-nodes-public.json +++ /dev/null @@ -1,911 +0,0 @@ -{ - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "grafana", - "uid": "-- Grafana --" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "target": { - "limit": 100, - "matchAny": false, - "tags": [], - "type": "dashboard" - }, - "type": "dashboard" - } - ] - }, - "description": "", - "editable": true, - "fiscalYearStartMonth": 0, - "graphTooltip": 0, - "id": 2, - "links": [], - "liveNow": false, - "panels": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "min": 0, - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "orange", - "value": 30 - }, - { - "color": "green", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 11, - "x": 0, - "y": 0 - }, - "id": 8, - "interval": "1m", - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.2.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "expr": "sum by(job) (sum by(chain_address) (up{job=\"keep-discovered-nodes\"}))", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Nodes Up", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "super-light-red", - "value": null - }, - { - "color": "super-light-yellow", - "value": 30 - }, - { - "color": "super-light-green", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 16, - "w": 13, - "x": 11, - "y": 0 - }, - "id": 3, - "interval": "1m", - "options": { - "legend": { - "calcs": [ - "last" - ], - "displayMode": "table", - "placement": "right", - "showLegend": true, - "sortBy": "Last", - "sortDesc": true - }, - "tooltip": { - "mode": "multi", - "sort": "desc" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "exemplar": false, - "expr": "min by(chain_address) (connected_wellknown_peers_count{job=\"keep-discovered-nodes\"})", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "C" - } - ], - "title": "Connected Bootstraps", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "log": 2, - "type": "log" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "area" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "orange", - "value": 100 - }, - { - "color": "light-yellow", - "value": 300 - }, - { - "color": "green", - "value": 900 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 28, - "w": 11, - "x": 0, - "y": 8 - }, - "id": 4, - "interval": "1m", - "options": { - "legend": { - "calcs": [ - "last" - ], - "displayMode": "table", - "placement": "bottom", - "showLegend": true, - "sortBy": "Last", - "sortDesc": true - }, - "tooltip": { - "mode": "multi", - "sort": "asc" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "exemplar": false, - "expr": "min by(chain_address) (tbtc_pre_params_count{job=\"keep-discovered-nodes\"})", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "C" - } - ], - "title": "TBTC PreParams Count", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "super-light-yellow", - "value": 50 - }, - { - "color": "super-light-green", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 20, - "w": 13, - "x": 11, - "y": 16 - }, - "id": 2, - "interval": "1m", - "options": { - "legend": { - "calcs": [ - "last" - ], - "displayMode": "table", - "placement": "right", - "showLegend": true, - "sortBy": "Last", - "sortDesc": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "expr": "min by(chain_address) (connected_peers_count{job=\"keep-discovered-nodes\"})", - "hide": false, - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "Discovered Keep Nodes" - } - ], - "title": "Connected Peers", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "align": "auto", - "displayMode": "auto", - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 25, - "w": 11, - "x": 0, - "y": 36 - }, - "id": 10, - "options": { - "footer": { - "fields": "", - "reducer": [ - "sum" - ], - "show": false - }, - "frameIndex": 1, - "showHeader": true, - "sortBy": [ - { - "desc": false, - "displayName": "chain_address" - } - ] - }, - "pluginVersion": "9.2.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "exemplar": false, - "expr": "up{job=\"keep-discovered-nodes\"}", - "format": "table", - "hide": false, - "instant": true, - "interval": "", - "legendFormat": "__auto", - "range": false, - "refId": "Nodes" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "exemplar": false, - "expr": "client_info{job=\"keep-discovered-nodes\"}", - "format": "table", - "hide": false, - "instant": true, - "legendFormat": "", - "range": false, - "refId": "Client Info" - } - ], - "title": "Client Versions (experimental)", - "transformations": [ - { - "id": "seriesToColumns", - "options": { - "byField": "chain_address" - } - }, - { - "id": "organize", - "options": { - "excludeByName": { - "Time": true, - "Time 1": false, - "Time 2": true, - "Value": true, - "Value #A": true, - "Value #B": true, - "Value #Client Info": true, - "Value #Nodes": true, - "__name__": true, - "__name__ 1": true, - "__name__ 2": true, - "app": true, - "controller_revision_hash": true, - "id": true, - "instance": false, - "instance 1": false, - "instance 2": true, - "job": true, - "job 1": true, - "job 2": true, - "kubernetes_namespace": true, - "kubernetes_pod_name": true, - "kubernetes_pod_name_monitoring": true, - "network": true, - "network_id": true, - "network_id 1": true, - "network_id 2": true, - "statefulset_kubernetes_io_pod_name": true, - "type": true - }, - "indexByName": { - "Time 1": 3, - "Time 2": 8, - "Value #Client Info": 13, - "Value #Nodes": 7, - "__name__ 1": 4, - "__name__ 2": 9, - "chain_address": 0, - "instance 1": 1, - "instance 2": 10, - "job 1": 5, - "job 2": 11, - "network_id 1": 6, - "network_id 2": 12, - "version": 2 - }, - "renameByName": { - "chain_address": "Chain Address", - "instance 1": "Instance", - "version": "Client Version" - } - } - } - ], - "type": "table" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "description": "Provides information on whether the node is connected to the Bitcoin network.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "super-light-yellow", - "value": 50 - }, - { - "color": "super-light-green", - "value": 80 - } - ] - }, - "unit": "bool" - }, - "overrides": [] - }, - "gridPos": { - "h": 20, - "w": 13, - "x": 11, - "y": 36 - }, - "id": 11, - "interval": "1m", - "options": { - "legend": { - "calcs": [ - "last" - ], - "displayMode": "table", - "placement": "right", - "showLegend": true, - "sortBy": "Last", - "sortDesc": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "expr": "min by(chain_address) (btc_connectivity{job=\"keep-discovered-nodes\"})", - "hide": false, - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "Discovered Keep Nodes" - } - ], - "title": "BTC Connectivity", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "description": "Provides information on whether the node is connected to the Ethereum network.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "super-light-yellow", - "value": 50 - }, - { - "color": "super-light-green", - "value": 80 - } - ] - }, - "unit": "bool" - }, - "overrides": [] - }, - "gridPos": { - "h": 20, - "w": 13, - "x": 11, - "y": 56 - }, - "id": 12, - "interval": "1m", - "options": { - "legend": { - "calcs": [ - "last" - ], - "displayMode": "table", - "placement": "right", - "showLegend": true, - "sortBy": "Last", - "sortDesc": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "expr": "min by(chain_address) (eth_connectivity{job=\"keep-discovered-nodes\"})", - "hide": false, - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "Discovered Keep Nodes" - } - ], - "title": "ETH Connectivity", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "fillOpacity": 70, - "lineWidth": 0, - "spanNulls": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 25, - "w": 13, - "x": 11, - "y": 76 - }, - "id": 6, - "options": { - "alignValue": "left", - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "mergeValues": true, - "rowHeight": 0.9, - "showValue": "auto", - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "9.1.2", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "expr": "min by(chain_address) (up{job=\"keep-discovered-nodes\"})", - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "A" - } - ], - "title": "Uptime (experimental)", - "type": "state-timeline" - } - ], - "refresh": false, - "schemaVersion": 37, - "style": "dark", - "tags": [ - "tbtc", - "keep", - "public" - ], - "templating": { - "list": [] - }, - "time": { - "from": "now-2d", - "to": "now" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ] - }, - "timezone": "", - "title": "Keep Nodes (Public)", - "uid": "hhDyYDI4z", - "version": 17, - "weekStart": "" -} \ No newline at end of file diff --git a/infrastructure/kube/keep-prd/monitoring/grafana/dashboards/keep/keep-nodes.json b/infrastructure/kube/keep-prd/monitoring/grafana/dashboards/keep/keep-nodes.json deleted file mode 100644 index e794fd0650..0000000000 --- a/infrastructure/kube/keep-prd/monitoring/grafana/dashboards/keep/keep-nodes.json +++ /dev/null @@ -1,1223 +0,0 @@ -{ - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "grafana", - "uid": "-- Grafana --" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "target": { - "limit": 100, - "matchAny": false, - "tags": [], - "type": "dashboard" - }, - "type": "dashboard" - } - ] - }, - "description": "", - "editable": true, - "fiscalYearStartMonth": 0, - "graphTooltip": 0, - "id": 3, - "links": [], - "liveNow": false, - "panels": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "min": 0, - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "orange", - "value": 30 - }, - { - "color": "green", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 11, - "x": 0, - "y": 0 - }, - "id": 8, - "interval": "1m", - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.2.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "exemplar": false, - "expr": "sum by(job) (sum by(chain_address) (up{job=\"keep-discovered-nodes\"}))", - "format": "time_series", - "instant": false, - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Nodes Up", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "super-light-red", - "value": null - }, - { - "color": "super-light-yellow", - "value": 30 - }, - { - "color": "super-light-green", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 16, - "w": 13, - "x": 11, - "y": 0 - }, - "id": 3, - "interval": "1m", - "options": { - "legend": { - "calcs": [ - "last" - ], - "displayMode": "table", - "placement": "right", - "showLegend": true, - "sortBy": "Last", - "sortDesc": true - }, - "tooltip": { - "mode": "multi", - "sort": "desc" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "exemplar": false, - "expr": "min by(chain_address) (connected_wellknown_peers_count{job=\"keep-discovered-nodes\"})", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "C" - } - ], - "title": "Connected Bootstraps", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "log": 2, - "type": "log" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "area" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "orange", - "value": 100 - }, - { - "color": "light-yellow", - "value": 300 - }, - { - "color": "green", - "value": 900 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 28, - "w": 11, - "x": 0, - "y": 8 - }, - "id": 4, - "interval": "1m", - "options": { - "legend": { - "calcs": [ - "last" - ], - "displayMode": "table", - "placement": "bottom", - "showLegend": true, - "sortBy": "Last", - "sortDesc": true - }, - "tooltip": { - "mode": "multi", - "sort": "asc" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "exemplar": false, - "expr": "min by(chain_address) (tbtc_pre_params_count{job=\"keep-discovered-nodes\"})", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "C" - } - ], - "title": "TBTC PreParams Count", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "super-light-yellow", - "value": 50 - }, - { - "color": "super-light-green", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 20, - "w": 13, - "x": 11, - "y": 16 - }, - "id": 2, - "interval": "1m", - "options": { - "legend": { - "calcs": [ - "last" - ], - "displayMode": "table", - "placement": "right", - "showLegend": true, - "sortBy": "Last", - "sortDesc": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "expr": "min by(chain_address) (connected_peers_count{job=\"keep-discovered-nodes\"})", - "hide": false, - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "Discovered Keep Nodes" - } - ], - "title": "Connected Peers", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "align": "auto", - "displayMode": "auto", - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 25, - "w": 11, - "x": 0, - "y": 36 - }, - "id": 10, - "options": { - "footer": { - "fields": "", - "reducer": [ - "sum" - ], - "show": false - }, - "frameIndex": 1, - "showHeader": true, - "sortBy": [ - { - "desc": false, - "displayName": "chain_address" - } - ] - }, - "pluginVersion": "9.2.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "exemplar": false, - "expr": "up{job=\"keep-discovered-nodes\"}", - "format": "table", - "hide": false, - "instant": true, - "interval": "", - "legendFormat": "__auto", - "range": false, - "refId": "Nodes" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "exemplar": false, - "expr": "client_info{job=\"keep-discovered-nodes\"}", - "format": "table", - "hide": false, - "instant": true, - "legendFormat": "", - "range": false, - "refId": "Client Info" - } - ], - "title": "Client Versions", - "transformations": [ - { - "id": "seriesToColumns", - "options": { - "byField": "chain_address" - } - }, - { - "id": "organize", - "options": { - "excludeByName": { - "Time": true, - "Time 1": false, - "Time 2": true, - "Value": true, - "Value #A": true, - "Value #B": true, - "Value #Client Info": true, - "Value #Nodes": true, - "__name__": true, - "__name__ 1": true, - "__name__ 2": true, - "app": true, - "controller_revision_hash": true, - "id": true, - "instance": false, - "instance 1": false, - "instance 2": true, - "job": true, - "job 1": true, - "job 2": true, - "kubernetes_namespace": true, - "kubernetes_pod_name": true, - "kubernetes_pod_name_monitoring": true, - "network": true, - "network_id": true, - "network_id 1": true, - "network_id 2": true, - "statefulset_kubernetes_io_pod_name": true, - "type": true - }, - "indexByName": { - "Time 1": 3, - "Time 2": 8, - "Value #Client Info": 13, - "Value #Nodes": 7, - "__name__ 1": 4, - "__name__ 2": 9, - "chain_address": 0, - "instance 1": 1, - "instance 2": 10, - "job 1": 5, - "job 2": 11, - "network_id 1": 6, - "network_id 2": 12, - "version": 2 - }, - "renameByName": { - "chain_address": "Chain Address", - "instance 1": "Instance", - "version": "Client Version" - } - } - } - ], - "type": "table" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "description": "Provides information on whether the node is connected to the Bitcoin network", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "super-light-yellow", - "value": 50 - }, - { - "color": "super-light-green", - "value": 80 - } - ] - }, - "unit": "bool" - }, - "overrides": [ - { - "__systemRef": "hideSeriesFrom", - "matcher": { - "id": "byNames", - "options": { - "mode": "exclude", - "names": [ - "0x0f115091c3909048BA336C76Fd30ca616c1A2bB8" - ], - "prefix": "All except:", - "readOnly": true - } - }, - "properties": [ - { - "id": "custom.hideFrom", - "value": { - "legend": false, - "tooltip": false, - "viz": true - } - } - ] - } - ] - }, - "gridPos": { - "h": 20, - "w": 13, - "x": 11, - "y": 36 - }, - "id": 13, - "interval": "1m", - "options": { - "legend": { - "calcs": [ - "last" - ], - "displayMode": "table", - "placement": "right", - "showLegend": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "expr": "min by(chain_address) (btc_connectivity{job=\"keep-discovered-nodes\"})", - "hide": false, - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "Discovered Keep Nodes" - } - ], - "title": "BTC Connectivity", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "description": "Provides information on whether the node is connected to the Ethereum network", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "red" - }, - { - "color": "super-light-yellow", - "value": 50 - }, - { - "color": "super-light-green", - "value": 80 - } - ] - }, - "unit": "bool" - }, - "overrides": [] - }, - "gridPos": { - "h": 20, - "w": 13, - "x": 11, - "y": 56 - }, - "id": 14, - "interval": "1m", - "options": { - "legend": { - "calcs": [ - "last" - ], - "displayMode": "table", - "placement": "right", - "showLegend": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "expr": "min by(chain_address) (eth_connectivity{job=\"keep-discovered-nodes\"})", - "hide": false, - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "Discovered Keep Nodes" - } - ], - "title": "ETH Connectivity", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "description": "A number of running instances for each operator address.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "fillOpacity": 60, - "lineWidth": 0, - "spanNulls": false - }, - "mappings": [], - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "super-light-orange" - }, - { - "color": "super-light-green", - "value": 1 - }, - { - "color": "super-light-red", - "value": 2 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 20, - "w": 11, - "x": 0, - "y": 61 - }, - "id": 12, - "options": { - "alignValue": "center", - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "mergeValues": true, - "rowHeight": 0.9, - "showValue": "auto", - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "9.1.2", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "expr": "count by(chain_address) (up{job=\"keep-discovered-nodes\"})", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Node Instances", - "type": "state-timeline" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "fillOpacity": 70, - "lineWidth": 0, - "spanNulls": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 25, - "w": 13, - "x": 11, - "y": 76 - }, - "id": 6, - "options": { - "alignValue": "left", - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "mergeValues": true, - "rowHeight": 0.9, - "showValue": "auto", - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "9.1.2", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "expr": "min by(chain_address) (up{job=\"keep-discovered-nodes\"})", - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "A" - } - ], - "title": "Uptime (experimental)", - "type": "state-timeline" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "description": "Inbound network join requests across all monitored nodes, with the failure-reason breakdown. A high failure share is expected: unrecognized peers probing the network are rejected by the on-chain firewall check. Investigate when the mix shifts (e.g. firewall rpc error or timeout growth) or when bursts coincide with peer loss.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 20, - "w": 11, - "x": 0, - "y": 81 - }, - "id": 15, - "interval": "1m", - "options": { - "legend": { - "calcs": [ - "last" - ], - "displayMode": "table", - "placement": "right", - "showLegend": true, - "sortBy": "Last", - "sortDesc": true - }, - "tooltip": { - "mode": "multi", - "sort": "desc" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "code", - "exemplar": false, - "expr": "sum(increase(performance_network_join_requests_total{job=\"keep-discovered-nodes\"}[10m]))", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "total", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "code", - "exemplar": false, - "expr": "sum(increase(performance_network_join_requests_success_total{job=\"keep-discovered-nodes\"}[10m]))", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "success", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "code", - "exemplar": false, - "expr": "sum(increase(performance_network_join_requests_failed_total{job=\"keep-discovered-nodes\"}[10m]))", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "failed", - "range": true, - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "code", - "exemplar": false, - "expr": "sum(increase(performance_network_join_requests_failed_timeout_total{job=\"keep-discovered-nodes\"}[10m]))", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "failed: timeout", - "range": true, - "refId": "D" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "code", - "exemplar": false, - "expr": "sum(increase(performance_network_join_requests_failed_eof_reset_total{job=\"keep-discovered-nodes\"}[10m]))", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "failed: eof/reset", - "range": true, - "refId": "E" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "code", - "exemplar": false, - "expr": "sum(increase(performance_network_join_requests_failed_protocol_crypto_total{job=\"keep-discovered-nodes\"}[10m]))", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "failed: protocol/crypto", - "range": true, - "refId": "F" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "code", - "exemplar": false, - "expr": "sum(increase(performance_network_join_requests_failed_firewall_unrecognized_total{job=\"keep-discovered-nodes\"}[10m]))", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "failed: firewall unrecognized", - "range": true, - "refId": "G" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "code", - "exemplar": false, - "expr": "sum(increase(performance_network_join_requests_failed_firewall_rpc_error_total{job=\"keep-discovered-nodes\"}[10m]))", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "failed: firewall rpc error", - "range": true, - "refId": "H" - } - ], - "title": "Network Join Requests (per 10m)", - "type": "timeseries" - } - ], - "refresh": false, - "schemaVersion": 37, - "style": "dark", - "tags": [ - "tbtc", - "keep" - ], - "templating": { - "list": [] - }, - "time": { - "from": "now-7d", - "to": "now" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ] - }, - "timezone": "", - "title": "Keep Nodes", - "uid": "tMgEvbnVk", - "version": 13, - "weekStart": "" -} \ No newline at end of file diff --git a/infrastructure/kube/keep-prd/monitoring/grafana/grafana-deployment.yaml b/infrastructure/kube/keep-prd/monitoring/grafana/grafana-deployment.yaml deleted file mode 100644 index d9d39b4acd..0000000000 --- a/infrastructure/kube/keep-prd/monitoring/grafana/grafana-deployment.yaml +++ /dev/null @@ -1,99 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: grafana -spec: - replicas: 1 - selector: - matchLabels: - app: grafana - template: - spec: - securityContext: - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - runAsNonRoot: true - containers: - - name: grafana - image: grafana/grafana:9.2.5 - env: - - name: GF_SERVER_DOMAIN - value: monitoring.threshold.network - - name: GF_SERVER_ROOT_URL - value: "https://%(domain)s/grafana/" - - name: GF_SERVER_SERVE_FROM_SUB_PATH - value: "true" - - name: GF_FEATURE_TOGGLES_PUBLICDASHBOARDS - value: "true" - - name: GF_AUTH_GOOGLE_CLIENT_ID - valueFrom: - secretKeyRef: - name: grafana-auth-google - key: client_id - - name: GF_AUTH_GOOGLE_CLIENT_SECRET - valueFrom: - secretKeyRef: - name: grafana-auth-google - key: client_secret - ports: - - name: grafana - containerPort: 3000 - readinessProbe: - httpGet: - path: /api/health - port: grafana - initialDelaySeconds: 10 - periodSeconds: 30 - timeoutSeconds: 2 - livenessProbe: - initialDelaySeconds: 30 - tcpSocket: - port: grafana - resources: - limits: - cpu: 1000m - memory: 1Gi - requests: - cpu: 250m - memory: 512Mi - volumeMounts: - - name: grafana-grafana-ini - mountPath: /etc/grafana/grafana.ini - subPath: grafana.ini - - name: grafana-config-datasources - mountPath: /etc/grafana/provisioning/datasources - - name: grafana-config-dashboards - mountPath: /etc/grafana/provisioning/dashboards - - name: grafana-storage - mountPath: /var/lib/grafana - - name: grafana-dashboards-keep - mountPath: /var/lib/grafana/dashboards/keep - securityContext: - readOnlyRootFilesystem: true - volumes: - - name: grafana-storage - persistentVolumeClaim: - claimName: grafana-pvc - - name: grafana-dashboards-keep - configMap: - name: grafana-dashboards-keep - - name: grafana-config-datasources - configMap: - name: grafana-config - items: - - key: datasources.yaml - path: datasources.yaml - - name: grafana-config-dashboards - configMap: - name: grafana-config - items: - - key: dashboards.yaml - path: dashboards.yaml - - name: grafana-grafana-ini - configMap: - name: grafana-config - items: - - key: grafana.ini - path: grafana.ini diff --git a/infrastructure/kube/keep-prd/monitoring/grafana/grafana-pvc.yaml b/infrastructure/kube/keep-prd/monitoring/grafana/grafana-pvc.yaml deleted file mode 100644 index 46b9de4205..0000000000 --- a/infrastructure/kube/keep-prd/monitoring/grafana/grafana-pvc.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: grafana-pvc - namespace: monitoring - labels: - app: grafana -spec: - storageClassName: monitoring-storage - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 5Gi diff --git a/infrastructure/kube/keep-prd/monitoring/grafana/grafana-service.yaml b/infrastructure/kube/keep-prd/monitoring/grafana/grafana-service.yaml deleted file mode 100644 index 2db62dbeda..0000000000 --- a/infrastructure/kube/keep-prd/monitoring/grafana/grafana-service.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: grafana -spec: - selector: - app: grafana - type: NodePort - ports: - - port: 3000 - targetPort: grafana diff --git a/infrastructure/kube/keep-prd/monitoring/grafana/kustomization.yaml b/infrastructure/kube/keep-prd/monitoring/grafana/kustomization.yaml deleted file mode 100644 index e1ca15444f..0000000000 --- a/infrastructure/kube/keep-prd/monitoring/grafana/kustomization.yaml +++ /dev/null @@ -1,26 +0,0 @@ -resources: - - grafana-deployment.yaml - - grafana-pvc.yaml - - grafana-service.yaml - -namespace: monitoring - -commonLabels: - app: grafana - type: monitoring - -configMapGenerator: - - name: grafana-config - files: - - config/grafana.ini - - config/dashboards.yaml - - config/datasources.yaml - - name: grafana-dashboards-keep - files: - - dashboards/keep/keep-nodes-public.json - - dashboards/keep/keep-nodes.json - -generatorOptions: - disableNameSuffixHash: true - annotations: - note: generated diff --git a/infrastructure/kube/keep-prd/monitoring/monitoring-ingress.yaml b/infrastructure/kube/keep-prd/monitoring/monitoring-ingress.yaml deleted file mode 100644 index bfa25808cb..0000000000 --- a/infrastructure/kube/keep-prd/monitoring/monitoring-ingress.yaml +++ /dev/null @@ -1,50 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: monitoring - namespace: monitoring - annotations: - kubernetes.io/ingress.class: "gce" - # The static IP has to be created with the following command: - # `gcloud compute addresses create keep-monitoring-ingress --global` - kubernetes.io/ingress.global-static-ip-name: "keep-monitoring-ingress" - networking.gke.io/managed-certificates: monitoring-cert -spec: - defaultBackend: - service: - name: grafana - port: - number: 3000 - rules: - - http: - paths: - - path: "/grafana" - pathType: Prefix - backend: - service: - name: grafana - port: - number: 3000 - - path: "/prometheus" - pathType: Prefix - backend: - service: - name: trickster - port: - number: 8480 - - path: "/trickster" - pathType: Prefix - backend: - service: - name: trickster - port: - number: 8480 ---- -apiVersion: networking.gke.io/v1 -kind: ManagedCertificate -metadata: - name: monitoring-cert - namespace: monitoring -spec: - domains: - - monitoring.threshold.network diff --git a/infrastructure/kube/keep-prd/monitoring/prometheus/config/config.yaml b/infrastructure/kube/keep-prd/monitoring/prometheus/config/config.yaml deleted file mode 100644 index caafb7470f..0000000000 --- a/infrastructure/kube/keep-prd/monitoring/prometheus/config/config.yaml +++ /dev/null @@ -1,30 +0,0 @@ -global: - scrape_interval: 1m - scrape_timeout: 10s - evaluation_interval: 1m -rule_files: - - /etc/prometheus/rules.yaml -scrape_configs: - - job_name: keep-discovered-nodes - honor_timestamps: true - metrics_path: /metrics - scheme: http - follow_redirects: true - enable_http2: true - relabel_configs: - - source_labels: [__meta_chain_address] - separator: ; - regex: (.*) - target_label: chain_address - replacement: $1 - action: replace - - source_labels: [__meta_network_id] - separator: ; - regex: (.*) - target_label: network_id - replacement: $1 - action: replace - file_sd_configs: - - files: - - /etc/prometheus/sd/keep-sd.json - refresh_interval: 5m diff --git a/infrastructure/kube/keep-prd/monitoring/prometheus/config/rules.yaml b/infrastructure/kube/keep-prd/monitoring/prometheus/config/rules.yaml deleted file mode 100644 index 668044bd92..0000000000 --- a/infrastructure/kube/keep-prd/monitoring/prometheus/config/rules.yaml +++ /dev/null @@ -1,52 +0,0 @@ -groups: - - name: keep-network-join-requests - rules: - # Fires only when an abnormal burst of inbound join-request failures - # coincides with peer loss or coordination degradation on the same - # node. A high failure ratio alone is expected behavior (unrecognized - # peers probing the network are rejected by the on-chain firewall - # check) and intentionally does not fire this alert. - - alert: KeepNodeJoinFailureBurstWithConnectivityDegradation - expr: | - ( - sum by (chain_address) ( - rate(performance_network_join_requests_failed_total{job="keep-discovered-nodes"}[30m]) - ) - > - 4 * sum by (chain_address) ( - rate(performance_network_join_requests_failed_total{job="keep-discovered-nodes"}[6h] offset 30m) - ) + 0.05 - ) - and on (chain_address) - ( - min by (chain_address) ( - connected_wellknown_peers_count{job="keep-discovered-nodes"} - ) == 0 - or - min by (chain_address) ( - delta(connected_peers_count{job="keep-discovered-nodes"}[30m]) - ) < -5 - or - sum by (chain_address) ( - increase(performance_coordination_failed_total{job="keep-discovered-nodes"}[1h]) - ) > 0 - or - sum by (chain_address) ( - increase(performance_coordination_leader_timeout_total{job="keep-discovered-nodes"}[1h]) - ) > 2 - ) - for: 15m - labels: - severity: warning - annotations: - summary: >- - Join-request failure burst with connectivity degradation on - {{ $labels.chain_address }} - description: >- - Inbound network join-request failures on node - {{ $labels.chain_address }} spiked to more than 4x their 6h - baseline while the node also shows well-known peer isolation, - peer loss, or coordination degradation. Check the per-reason - breakdown (performance_network_join_requests_failed_*_total) - to tell genuine non-recognition (firewall_unrecognized) apart - from firewall RPC errors, timeouts, and connection resets. diff --git a/infrastructure/kube/keep-prd/monitoring/prometheus/kustomization.yaml b/infrastructure/kube/keep-prd/monitoring/prometheus/kustomization.yaml deleted file mode 100644 index c70e76bef9..0000000000 --- a/infrastructure/kube/keep-prd/monitoring/prometheus/kustomization.yaml +++ /dev/null @@ -1,21 +0,0 @@ -resources: - - prometheus-deployment.yaml - - prometheus-pvc.yaml - - prometheus-service.yaml - -namespace: monitoring - -commonLabels: - app: prometheus - type: monitoring - -configMapGenerator: - - name: prometheus-config - files: - - config/config.yaml - - config/rules.yaml - -generatorOptions: - disableNameSuffixHash: true - annotations: - note: generated diff --git a/infrastructure/kube/keep-prd/monitoring/prometheus/prometheus-deployment.yaml b/infrastructure/kube/keep-prd/monitoring/prometheus/prometheus-deployment.yaml deleted file mode 100644 index 227e85b42f..0000000000 --- a/infrastructure/kube/keep-prd/monitoring/prometheus/prometheus-deployment.yaml +++ /dev/null @@ -1,91 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: prometheus -spec: - replicas: 1 - strategy: - type: Recreate - selector: - matchLabels: - app: prometheus - type: monitoring - template: - spec: - securityContext: - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - runAsNonRoot: true - containers: - - name: prometheus - image: prom/prometheus:v2.43.1 - args: - - --config.file=/etc/prometheus/config.yaml - - --storage.tsdb.path=/etc/prometheus/data - - --storage.tsdb.retention.time=1y - - --web.external-url=/prometheus/ - ports: - - name: prometheus - containerPort: 9090 - readinessProbe: - httpGet: - path: "/prometheus/-/ready" - port: prometheus - initialDelaySeconds: 10 - periodSeconds: 30 - timeoutSeconds: 2 - livenessProbe: - httpGet: - path: "/prometheus/-/healthy" - port: prometheus - initialDelaySeconds: 10 - periodSeconds: 30 - timeoutSeconds: 2 - resources: - limits: - cpu: 1000m - memory: 1Gi - requests: - cpu: 500m - memory: 512Mi - volumeMounts: - - name: prometheus-config-volume - mountPath: /etc/prometheus/ - - name: prometheus-storage-volume - mountPath: /etc/prometheus/data/ - - name: prometheus-sd-volume - mountPath: /etc/prometheus/sd/ - securityContext: - readOnlyRootFilesystem: true - - name: keep-sd - image: keepnetwork/keep-prometheus-sd - args: - - --output.file=/etc/prometheus/sd/keep-sd.json - - --source.address=bst-a01.tbtc.boar.network:9601 - - --source.address=bst-b01.tbtc.boar.network:9601 - - --refresh.interval=5m - - --scan.timeout=3s - - --log.json - resources: - limits: - cpu: 1000m - memory: 1Gi - requests: - cpu: 250m - memory: 256Mi - volumeMounts: - - name: prometheus-sd-volume - mountPath: /etc/prometheus/sd/ - securityContext: - readOnlyRootFilesystem: true - volumes: - - name: prometheus-config-volume - configMap: - name: prometheus-config - - name: prometheus-storage-volume - persistentVolumeClaim: - claimName: prometheus-pvc - - name: prometheus-sd-volume - emptyDir: {} diff --git a/infrastructure/kube/keep-prd/monitoring/prometheus/prometheus-pvc.yaml b/infrastructure/kube/keep-prd/monitoring/prometheus/prometheus-pvc.yaml deleted file mode 100644 index 6ca54ca443..0000000000 --- a/infrastructure/kube/keep-prd/monitoring/prometheus/prometheus-pvc.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: prometheus-pvc -spec: - storageClassName: monitoring-storage - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 100Gi diff --git a/infrastructure/kube/keep-prd/monitoring/prometheus/prometheus-service.yaml b/infrastructure/kube/keep-prd/monitoring/prometheus/prometheus-service.yaml deleted file mode 100644 index ef83e37517..0000000000 --- a/infrastructure/kube/keep-prd/monitoring/prometheus/prometheus-service.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: prometheus -spec: - selector: - app: prometheus - ports: - - port: 9090 - targetPort: prometheus diff --git a/infrastructure/kube/keep-prd/monitoring/storage-class.yaml b/infrastructure/kube/keep-prd/monitoring/storage-class.yaml deleted file mode 100644 index bf375bd8c0..0000000000 --- a/infrastructure/kube/keep-prd/monitoring/storage-class.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: storage.k8s.io/v1 -kind: StorageClass -metadata: - name: monitoring-storage -provisioner: kubernetes.io/gce-pd -parameters: - type: pd-ssd - replication-type: none -reclaimPolicy: Retain -allowVolumeExpansion: true -mountOptions: - - debug -volumeBindingMode: Immediate diff --git a/infrastructure/kube/keep-prd/monitoring/trickster/config/trickster.yaml b/infrastructure/kube/keep-prd/monitoring/trickster/config/trickster.yaml deleted file mode 100644 index 0c4b5797c5..0000000000 --- a/infrastructure/kube/keep-prd/monitoring/trickster/config/trickster.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# Trickster Configuration File. -# -# A full configuration file example can be found here: -# https://github.com/trickstercache/trickster/blob/main/examples/conf/example.full.yaml - -frontend: - listen_port: 8480 - -backends: - default: - provider: prometheus - origin_url: http://prometheus:9090 - is_default: true - healthcheck: - path: /prometheus/-/ready - upstream_path: /prometheus/-/ready - interval_ms: 5000 - expected_body: "Prometheus Server is Ready.\n" - -metrics: - listen_port: 8481 - listen_address: "" - -logging: - log_level: info diff --git a/infrastructure/kube/keep-prd/monitoring/trickster/kustomization.yaml b/infrastructure/kube/keep-prd/monitoring/trickster/kustomization.yaml deleted file mode 100644 index 0ca82fb0a6..0000000000 --- a/infrastructure/kube/keep-prd/monitoring/trickster/kustomization.yaml +++ /dev/null @@ -1,19 +0,0 @@ -resources: - - trickster-deployment.yaml - - trickster-service.yaml - -namespace: monitoring - -commonLabels: - app: trickster - type: monitoring - -configMapGenerator: - - name: trickster-config - files: - - config/trickster.yaml - -generatorOptions: - disableNameSuffixHash: true - annotations: - note: generated diff --git a/infrastructure/kube/keep-prd/monitoring/trickster/trickster-deployment.yaml b/infrastructure/kube/keep-prd/monitoring/trickster/trickster-deployment.yaml deleted file mode 100644 index f63c615dad..0000000000 --- a/infrastructure/kube/keep-prd/monitoring/trickster/trickster-deployment.yaml +++ /dev/null @@ -1,58 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: trickster -spec: - replicas: 1 - selector: - matchLabels: - app: trickster - type: monitoring - template: - spec: - securityContext: - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - runAsNonRoot: true - containers: - - name: trickster - image: trickstercache/trickster:2 - ports: - - name: trickster - containerPort: 8480 - - name: metrics - containerPort: 8481 - readinessProbe: - httpGet: - path: "/trickster/health/default" - port: metrics - livenessProbe: - httpGet: - path: "/trickster/ping" - port: trickster - resources: - limits: - cpu: 1000m - memory: 1Gi - requests: - cpu: 500m - memory: 512Mi - volumeMounts: - - name: trickster-config - mountPath: /etc/trickster - env: - - name: NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - securityContext: - readOnlyRootFilesystem: true - volumes: - - name: trickster-config - configMap: - name: trickster-config - items: - - key: trickster.yaml - path: trickster.yaml diff --git a/infrastructure/kube/keep-prd/monitoring/trickster/trickster-service.yaml b/infrastructure/kube/keep-prd/monitoring/trickster/trickster-service.yaml deleted file mode 100644 index cdcb0f9030..0000000000 --- a/infrastructure/kube/keep-prd/monitoring/trickster/trickster-service.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: trickster -spec: - selector: - app: trickster - ports: - - name: trickster - port: 8480 - targetPort: trickster - - name: metrics - port: 8481 - targetPort: metrics diff --git a/infrastructure/kube/keep-test/.envrc b/infrastructure/kube/keep-test/.envrc deleted file mode 100644 index 4d732771d6..0000000000 --- a/infrastructure/kube/keep-test/.envrc +++ /dev/null @@ -1 +0,0 @@ -export CLOUDSDK_ACTIVE_CONFIG_NAME=keep-test diff --git a/infrastructure/kube/keep-test/bitcoin/testnet/bitcoin-namespace.yaml b/infrastructure/kube/keep-test/bitcoin/testnet/bitcoin-namespace.yaml deleted file mode 100644 index 28b32f048a..0000000000 --- a/infrastructure/kube/keep-test/bitcoin/testnet/bitcoin-namespace.yaml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: bitcoin-testnet diff --git a/infrastructure/kube/keep-test/bitcoin/testnet/bitcoind/bitcoind-data-bitcoind-1-pvc.yaml b/infrastructure/kube/keep-test/bitcoin/testnet/bitcoind/bitcoind-data-bitcoind-1-pvc.yaml deleted file mode 100644 index d1e4bbb76e..0000000000 --- a/infrastructure/kube/keep-test/bitcoin/testnet/bitcoind/bitcoind-data-bitcoind-1-pvc.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: bitcoind-data-bitcoind-1 - namespace: bitcoin-testnet - labels: - app: bitcoind - chain: bitcoin - network: testnet -spec: - storageClassName: bitcoind - dataSource: - name: bitcoind-snapshot - kind: VolumeSnapshot - apiGroup: snapshot.storage.k8s.io - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 50Gi diff --git a/infrastructure/kube/keep-test/bitcoin/testnet/bitcoind/bitcoind-volumesnapshot.yaml b/infrastructure/kube/keep-test/bitcoin/testnet/bitcoind/bitcoind-volumesnapshot.yaml deleted file mode 100644 index 5182f14be1..0000000000 --- a/infrastructure/kube/keep-test/bitcoin/testnet/bitcoind/bitcoind-volumesnapshot.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: snapshot.storage.k8s.io/v1 -kind: VolumeSnapshot -metadata: - name: bitcoind-snapshot -spec: - volumeSnapshotClassName: bitcoind - source: - persistentVolumeClaimName: bitcoind-data-bitcoind-0 diff --git a/infrastructure/kube/keep-test/bitcoin/testnet/bitcoind/kustomization.yaml b/infrastructure/kube/keep-test/bitcoin/testnet/bitcoind/kustomization.yaml deleted file mode 100644 index 5e140ca5cd..0000000000 --- a/infrastructure/kube/keep-test/bitcoin/testnet/bitcoind/kustomization.yaml +++ /dev/null @@ -1,46 +0,0 @@ -resources: - - ../../../../templates/bitcoin/bitcoind - -namespace: bitcoin-testnet - -commonLabels: - network: testnet - -configMapGenerator: - - name: bitcoind - behavior: merge - literals: - - chain=test - -secretGenerator: - - name: bitcoind - behavior: merge - envs: - - .env.secret - -patches: - # Patch bitcoind StatefulSet by setting a storage request specific for testnet. - - target: - kind: StatefulSet - name: bitcoind - patch: |- - apiVersion: apps/v1 - kind: StatefulSet - metadata: - name: bitcoind - spec: - replicas: 2 - volumeClaimTemplates: - - metadata: - name: bitcoind-data - labels: - chain: bitcoin - app: bitcoind - network: testnet - spec: - storageClassName: bitcoind - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 50Gi diff --git a/infrastructure/kube/keep-test/bitcoin/testnet/electrumx/electrumx-data-electrumx-1-pvc.yaml b/infrastructure/kube/keep-test/bitcoin/testnet/electrumx/electrumx-data-electrumx-1-pvc.yaml deleted file mode 100644 index 8db8802fed..0000000000 --- a/infrastructure/kube/keep-test/bitcoin/testnet/electrumx/electrumx-data-electrumx-1-pvc.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: electrumx-data-electrumx-1 - namespace: bitcoin-testnet - labels: - app: electrumx - chain: bitcoin - network: testnet -spec: - storageClassName: electrumx-v2 - dataSource: - name: electrumx-snapshot - kind: VolumeSnapshot - apiGroup: snapshot.storage.k8s.io - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 40Gi diff --git a/infrastructure/kube/keep-test/bitcoin/testnet/electrumx/electrumx-volumesnapshot.yaml b/infrastructure/kube/keep-test/bitcoin/testnet/electrumx/electrumx-volumesnapshot.yaml deleted file mode 100644 index 36242a68ca..0000000000 --- a/infrastructure/kube/keep-test/bitcoin/testnet/electrumx/electrumx-volumesnapshot.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: snapshot.storage.k8s.io/v1 -kind: VolumeSnapshot -metadata: - name: electrumx-snapshot -spec: - volumeSnapshotClassName: electrumx - source: - persistentVolumeClaimName: electrumx-data-electrumx-0 diff --git a/infrastructure/kube/keep-test/bitcoin/testnet/electrumx/kustomization.yaml b/infrastructure/kube/keep-test/bitcoin/testnet/electrumx/kustomization.yaml deleted file mode 100644 index 55063a72d5..0000000000 --- a/infrastructure/kube/keep-test/bitcoin/testnet/electrumx/kustomization.yaml +++ /dev/null @@ -1,67 +0,0 @@ -resources: - - ../../../../templates/bitcoin/electrumx - -namespace: bitcoin-testnet - -commonLabels: - network: testnet - -secretGenerator: - - name: test-tbtc-network-cloudflare-origin-cert - type: kubernetes.io/tls - files: - - .secret/tls.crt - - .secret/tls.key - -patches: - - target: - kind: Service - name: electrumx - patch: |- - apiVersion: v1 - kind: Service - metadata: - name: electrumx - spec: - type: LoadBalancer - loadBalancerIP: 34.70.22.39 - - target: - kind: StatefulSet - name: electrumx - patch: |- - apiVersion: apps/v1 - kind: StatefulSet - metadata: - name: electrumx - spec: - replicas: 2 - template: - spec: - containers: - - name: electrumx - env: - - name: NET - value: testnet - volumes: - - name: tbtc-network-cloudflare-origin-cert - secret: - secretName: test-tbtc-network-cloudflare-origin-cert - volumeClaimTemplates: - - metadata: - name: electrumx-data - labels: - chain: bitcoin - app: electrumx - network: testnet - spec: - storageClassName: electrumx-v2 - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 40Gi - -generatorOptions: - disableNameSuffixHash: true - annotations: - note: generated diff --git a/infrastructure/kube/keep-test/bitcoin/testnet/kustomization.yaml b/infrastructure/kube/keep-test/bitcoin/testnet/kustomization.yaml deleted file mode 100644 index 03ec75721c..0000000000 --- a/infrastructure/kube/keep-test/bitcoin/testnet/kustomization.yaml +++ /dev/null @@ -1,2 +0,0 @@ -resources: - - bitcoin-namespace.yaml diff --git a/infrastructure/kube/keep-test/eth-account-info-configmap.yaml b/infrastructure/kube/keep-test/eth-account-info-configmap.yaml deleted file mode 100644 index 2bf17899d1..0000000000 --- a/infrastructure/kube/keep-test/eth-account-info-configmap.yaml +++ /dev/null @@ -1,309 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: eth-account-info - namespace: default -data: - relay-requester-address: "0xcd5524a79afd81f1a25c1298d41a8e9271a759e5" - relay-requester-keyfile: | - {"address":"cd5524a79afd81f1a25c1298d41a8e9271a759e5","crypto":{"cipher":"aes-128-ctr","ciphertext":"8218af1cb5da7eccd70ac1b7eae3a21df2130bf76e34ce146efe33e68c3f0984","cipherparams":{"iv":"bafa5af5602116398d8dc3c394b8460d"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"2cf504c3b85067d793c1e278dc51cf66d162fb485904b3c1536b5b30e9e73580"},"mac":"9e414c00af2dbf82c6cd2ab05f71b7525cae0b76a463cd0f82b0d8d6404c726d"},"id":"e4cb5dc2-82db-4577-b7ca-b196ab1d2264","version":3} - account-0-address: "0x0ec14bc7cca82c942cf276f6bbd0413216ddb2be" - account-0-keyfile: | - {"address":"0ec14bc7cca82c942cf276f6bbd0413216ddb2be","crypto":{"cipher":"aes-128-ctr","ciphertext":"d1e1885d30a2c25a54664487db4d69da496951733de6ceb4d5f565fe62eaba79","cipherparams":{"iv":"8cacad8a1b79982f568948b7f97b3dd3"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"00bfb9f49e54e6dba5b1b0c5b09904998fcfa10d0381b90bf26d45904a4e2636"},"mac":"9038c2a02d7837e448088fb19fc76e9d6c5063e8f1cb0addb40dc9df061b4928"},"id":"afb99070-073f-4dc6-b0d7-92b41fcf0afb","version":3} - account-1-address: "0xcab2a402bac470686d14956fb310d51bbef9fa31" - account-1-keyfile: | - {"address":"cab2a402bac470686d14956fb310d51bbef9fa31","crypto":{"cipher":"aes-128-ctr","ciphertext":"50193ab419aa322ceb556d4c073d1727763e5d873cce4e0735e6690194432665","cipherparams":{"iv":"6f869f3bd192d80981435016cc19afff"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"b72fe3dfd4d7419baa4d9a8ed7e27bf509fb9e1557a5d73c9c4879bf3a19abe9"},"mac":"5d3093a7b0160a8c2187efd4ab7ec168226e561ff7a0d714886c5dff28c405e7"},"id":"d43da5de-511f-4a1d-8ba8-0e0c24bf33e6","version":3} - account-2-address: "0xac049223397e2f25ea9fe56d5ee0896f6d8e8cb7" - account-2-keyfile: | - {"address":"ac049223397e2f25ea9fe56d5ee0896f6d8e8cb7","crypto":{"cipher":"aes-128-ctr","ciphertext":"42f6463f021f631ffbaf04989c107d784f0e1ba3a3b469073af4cc928d90bd5b","cipherparams":{"iv":"a533352b5ceb005cd730153f26e2f710"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"5716b94200ea2500fd257d28c1fd58e92ea991a4642813c91f66ae81fbc088bd"},"mac":"09b1e0857562a20ef0d25f41687095cdf246295a9dba82fee7e46756b0437bdc"},"id":"3819c68b-bc9d-4f54-867a-1ea7955c3cff","version":3} - account-3-address: "0x3ff855895ef4ac833c32ab6a0d6c7fbfa137e26e" - account-3-keyfile: | - {"address":"3ff855895ef4ac833c32ab6a0d6c7fbfa137e26e","crypto":{"cipher":"aes-128-ctr","ciphertext":"3cb866a0a1c0db6ca8accfc3c3036d9ee93b5dbca98f89dcf8f293e8b0134146","cipherparams":{"iv":"50e06549568b995a76190673e1643635"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"ee2164b8525571024704eaa976c3ac80fb41b74bcaa7d7788f7ac94dd1b6878b"},"mac":"408bf7c097e905019e25b4c82b4c988b03a607469f77bdbe0e9ca6d870fa9055"},"id":"93a1dc32-f80a-400a-99be-c478f72a6630","version":3} - account-4-address: "0x0954efefeb970d317a51736201b4eb2de75ff5de" - account-4-keyfile: | - {"address":"0954efefeb970d317a51736201b4eb2de75ff5de","crypto":{"cipher":"aes-128-ctr","ciphertext":"ad2d8baa3626a7ffd0040a09dbbe73e179aa125e1677987524e1c5593f03c645","cipherparams":{"iv":"856e9d869aaa40e994bda72f969505ac"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"a83d0582c376744e44cb982a90a5512a6570e046ea7ee0fd571e2fbda0cb762b"},"mac":"83ea2018f56bdd4967e8bd32c60cc7b3021bab59c72e4292c2e0ff20fc3b37e6"},"id":"666be636-2a15-4563-b78f-1ab704ec606c","version":3} - account-5-address: "0xd12a53056b74d96f89910ad3485da69a662f7930" - account-5-keyfile: | - {"address":"d12a53056b74d96f89910ad3485da69a662f7930","crypto":{"cipher":"aes-128-ctr","ciphertext":"02569d09ce9bd7371844dc60117bfd3ce97829a28d4c812cd7b30187047abd39","cipherparams":{"iv":"58b6a3e2cbc560323bebb81ebff1ca2c"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"8c28d3ece5b9e268ef73a148158dfe89f963ecf96e76fae41bda3ed2917b1331"},"mac":"9a9e29ebfd8712d70791df38b14e9de7aecdffdb858405f961966d65de843012"},"id":"0fdef51c-dd68-40e0-80d1-c038e800e511","version":3} - account-6-address: "0x677753a3cb8f3575be626f6a1f26e5c027c0af29" - account-6-keyfile: | - {"address":"677753a3cb8f3575be626f6a1f26e5c027c0af29","crypto":{"cipher":"aes-128-ctr","ciphertext":"cca77c25f7ea03abc65f154ef56bc712f4f3c4e21734e3ffc979615bc3d4b430","cipherparams":{"iv":"a94134c6c64db813aedb193d8d27c08e"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"9f9722abaf81affdbe6dc1573e97305a234cf4f3cba7dde985f45acff7a5b4f0"},"mac":"472e17c5d4660f669a09d724dbe0dbafb1cb8dc272e422e31654a300d2fc89ac"},"id":"66f810fc-7e95-4f1d-a490-792e0b8452ec","version":3} - account-7-address: "0x1aa7a9de6bd5a5802a98be50ff12f5a024a5abe0" - account-7-keyfile: | - {"address":"1aa7a9de6bd5a5802a98be50ff12f5a024a5abe0","crypto":{"cipher":"aes-128-ctr","ciphertext":"86279536ed5efaeb02b3a689cab7f7bb1a1d0554a36097164e499792d5d2b1fb","cipherparams":{"iv":"ee76fa919405a1fcd22311c181da4f70"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"3791fe112eab42db3721293556ca8a70431143462bedf0a320019c1626ac4a89"},"mac":"489181ff7b99ff1f1e40feef41f7099f4390da1064c4377e2e0946d705696f80"},"id":"0ae13709-5f10-4f42-a474-903353474732","version":3} - account-8-address: "0x76bc6bad38728329fe1c0e57d2555726f26a0399" - account-8-keyfile: | - {"address":"76bc6bad38728329fe1c0e57d2555726f26a0399","crypto":{"cipher":"aes-128-ctr","ciphertext":"40b3d9aae76bad5d8c61651adbad20c8b39a86e465e3e49b228ede63a615f549","cipherparams":{"iv":"10e8d87e8a6740fb1424fce23cee9fd7"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"db64fc334131708c0501b0fa5c90a41f10a47c1fb485e1b1c9cf3c625ade0781"},"mac":"19261b5cb3c73747a50884f4987a3ce31373af19e5970b19ea5da0ae17cbc8d1"},"id":"ff1f7c67-520a-45d5-90e4-f99d9303f327","version":3} - account-9-address: "0x5cd847903bb7f29de77eecc135628ca5b104a355" - account-9-keyfile: | - {"address":"5cd847903bb7f29de77eecc135628ca5b104a355","crypto":{"cipher":"aes-128-ctr","ciphertext":"306a0fa382c0f7a27dced0ca467a9664638a87ac1757f25819f4c7da45a9542b","cipherparams":{"iv":"606ff921f2474b0fcf53bdb3a2de5e14"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"85fa0683ece0df0e763956816220287b7d902b51157b74f2e05ea342d5a44ff7"},"mac":"c53de6511e7baccbbf0e99ab68743d09008c90af6ffd4a8087ea350e44640935"},"id":"821565f0-f8d0-4508-8409-89b0a19c9bfa","version":3} - account-10-address: "0xcc0123cb642ab7d24c1de153418cc7a1b42f8595" - account-10-keyfile: | - {"address":"cc0123cb642ab7d24c1de153418cc7a1b42f8595","crypto":{"cipher":"aes-128-ctr","ciphertext":"7eb604aa36c47222a0aab1e6591770789c5427d092290a2269e653d20b734bb6","cipherparams":{"iv":"f2e295eef926b71042b9ed08734c5968"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"9d30f2896d1f6ee7bd19576c0f922dc4b4db98715ffb27b90e0ad200993ce74e"},"mac":"7d0275617c128819569d0062d579dea1afe9afe94f13ba39e5677564af51da70"},"id":"6d52a7aa-c2a2-46b4-ad2d-f145e805836e","version":3} - account-11-address: "0x2150a36177fced7a5b6d8840eb76a8c09cba1601" - account-11-keyfile: | - {"address":"2150a36177fced7a5b6d8840eb76a8c09cba1601","crypto":{"cipher":"aes-128-ctr","ciphertext":"b6f9a6cf0815e83bf11120d8dc51df0cc8ece3c0434ac56353e34d40a457703b","cipherparams":{"iv":"9a929dd1183f151bdf19a5d685fb2075"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"66299b29b303e63324a2fa3c365f87f3a51b7ec3a02d109a34c70f798dbca819"},"mac":"64ad5823a83652f987fd188a70b790b6d5f03829d9f604c2a0b17fc455a309ab"},"id":"983b30f6-1920-43c5-8e83-08c72c68174c","version":3} - account-12-address: "0x6213cacb40c83447503e8e177137cffdacc59ee6" - account-12-keyfile: | - {"address":"6213cacb40c83447503e8e177137cffdacc59ee6","crypto":{"cipher":"aes-128-ctr","ciphertext":"4426d345bd619655ad2138847bc88c0a72afe4faa4ac38f69a099b62101f17c5","cipherparams":{"iv":"0cf40b99e00a65aa6325a07fd69b916e"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"3472ea2351b6236af54434e510e76cb9b50bf639898522a6c420c31e3e17e342"},"mac":"5595eba3025437d54a9e04613ee3dc219a0baba947bdac5b046a08b5df79835a"},"id":"7c487ef0-806e-40f9-a6d8-cf25aa44a38b","version":3} - account-13-address: "0xef52aada7c474d67aaede102c030522547001a46" - account-13-keyfile: | - {"address":"ef52aada7c474d67aaede102c030522547001a46","crypto":{"cipher":"aes-128-ctr","ciphertext":"9db579c5a39279dc91fab604a08a8c160b99fc92b694c0190c3fd2713d952b28","cipherparams":{"iv":"83428b6dd0673a1bca03009ecc0b7fcf"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"b9b5d319ec98dff0f783bb17bfa23b62a1e6bfe3f6e66bd42fa37a48b952b55e"},"mac":"3c87298445dd58d7c11196099f1cfdc1a6e7bb7055eb72f1abedc93cca7fab65"},"id":"0b7e9d2e-8a0d-4d9a-95b6-6a7e1f828f4a","version":3} - account-14-address: "0xbbfd3adc60e4d82a063442adf21294f16f0ae4a8" - account-14-keyfile: | - {"address":"bbfd3adc60e4d82a063442adf21294f16f0ae4a8","crypto":{"cipher":"aes-128-ctr","ciphertext":"63eb6083de9db291d86f4baa30265e12b21c5e99f5c6379a44b7fab382f5d848","cipherparams":{"iv":"cc4e44f79b3ce1fa703c7d6f2fbf8975"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"c7ae81ea0de51ad5b5856c16502db06a79596d27d077e6a778b1b2cf3956811a"},"mac":"f91f2016c57a245207013eac5484b62dfec5bfe19573198187a6057427541889"},"id":"731ff860-6c6f-445d-9fdd-a93c7a54fbcc","version":3} - account-15-address: "0xf8b07ea64379845bb172b1bfb5064c2f6e73faf7" - account-15-keyfile: | - {"address":"f8b07ea64379845bb172b1bfb5064c2f6e73faf7","crypto":{"cipher":"aes-128-ctr","ciphertext":"b3e15d0c80adce83b36af2da24c297d041efcd799389781cc873fdfc3eba8af1","cipherparams":{"iv":"5a4c0cad0c9178f4a4dc65e5065cb9b3"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"ec6abac88520b87bc398c11e589fb982b6c9b4aa3f8716148ae9f6a9c43e853c"},"mac":"3e2e69a1ca4c5cf1b7b5ab4932d8e6bbf46c69f66837505c968c61768a079285"},"id":"20662e3f-25f6-436f-afc7-396f78c98073","version":3} - account-16-address: "0x22c109baa3f47bae309211195d9a5c79fd32f6c5" - account-16-keyfile: | - {"address":"22c109baa3f47bae309211195d9a5c79fd32f6c5","crypto":{"cipher":"aes-128-ctr","ciphertext":"daba6da04153932b3821e423549c7679643b6ac87cf5399b3249d89a2bf6ff67","cipherparams":{"iv":"ced83eabfec9dcc1a77231e17780410a"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"fb209482da530eba29d3a81a51a794872125e9a6b6625afac5c7498ed31e781f"},"mac":"49ea6834a65a917f3cc924926870f1b7e3c0cf6948202da254422c5bd5e1f1f5"},"id":"13904fe7-4a16-49f5-8163-1d572d112afb","version":3} - account-17-address: "0x5fe83ab703a7e3bcc2b8c9c86be71ccd7cdadeb3" - account-17-keyfile: | - {"address":"5fe83ab703a7e3bcc2b8c9c86be71ccd7cdadeb3","crypto":{"cipher":"aes-128-ctr","ciphertext":"56918dfd8e2bd4cc34a7d2adb38ef4d6739b45798a6f2a27212be3a335427d9b","cipherparams":{"iv":"4b246c6cf8e68a5962899ed8bf4dd43f"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"bc7460e1a7e18b3252ddd1a3ca05f398bbe72fe3a1b4d10f8e4f4228f8a75653"},"mac":"4f85c40f459a44cb3a1106187dc7b79678b7d0f4277ae54405b7cfdbe88c5f50"},"id":"91e45287-832e-47a4-92bb-085a586ba1e4","version":3} - account-18-address: "0xaf3bcf9c3fbba388200cd8d098f8b73461e08c5f" - account-18-keyfile: | - {"address":"af3bcf9c3fbba388200cd8d098f8b73461e08c5f","crypto":{"cipher":"aes-128-ctr","ciphertext":"d26f9a376b9a55d3cb972afe741500110123f2a8c40335b12dc9ee0f214aa1c8","cipherparams":{"iv":"4d1db4ace91e9b1e60eef37c6b694953"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"e08f620cc2fda7cb6b681385652dbec47c34d278803753bdce2ddfa69a3e48ff"},"mac":"b5d22b4064db5c1eab8f6475bd485fa341df72a6e7919e57f8bd00665d608958"},"id":"79ebcb1d-2c59-4e52-baf3-a77c82e7fd56","version":3} - account-19-address: "0xf33153e1020881d52cbe6db06b801824480c325b" - account-19-keyfile: | - {"address":"f33153e1020881d52cbe6db06b801824480c325b","crypto":{"cipher":"aes-128-ctr","ciphertext":"5a4f702509eea6ff4630fcaefb7f8d7971094344435a7841d29ee7f6baaaa821","cipherparams":{"iv":"6d2c082a8071371ec16683d6da07a296"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"ccba1ef481ea7fd6cb2286cd6c163354bdc649f00deb7f342876c8977b6041b5"},"mac":"6cff490e45eb00e415414a4976ce8b147791c03648088f74917739a234abe351"},"id":"8ec0519c-890e-400c-84d9-38519659b1e3","version":3} - account-20-address: "0xb4a78b27007cee374403681ffacdace76909f913" - account-20-keyfile: | - {"address":"b4a78b27007cee374403681ffacdace76909f913","crypto":{"cipher":"aes-128-ctr","ciphertext":"825634adfa65bb79da672fb19377456d06264519c409d532199e2bffc99a7aa5","cipherparams":{"iv":"d882cd05d6e0f96c7d6b93083864d2a5"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"293029c5a27de4a6f33fae8b459568c2d2e93d3b7a1ac49122256f670f9acbd9"},"mac":"da7318ee1893afd857d36071d2e0e01fbbe9f75fe9adb4265ceb7f02c49a922f"},"id":"732154e6-145b-4700-bddd-797ac11d9f25","version":3} - account-21-address: "0xe44391df208629cc4f42a6e4cb17ba8c1fbbf0e3" - account-21-keyfile: | - {"address":"e44391df208629cc4f42a6e4cb17ba8c1fbbf0e3","crypto":{"cipher":"aes-128-ctr","ciphertext":"8840bf60888c27149f8ae59c862a35095a1b112e69aaa474be5d2820e9b9732e","cipherparams":{"iv":"b07626a490f2c649bc1a9ce20ea9931b"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"f750e37fc4fc5c5d5d6116c074c666c88e2c71bc73383c68f9f7368036c3feca"},"mac":"0788c27a8d49a81c576a3832f3272b015e8caad1f9b418064a6085e95723b7de"},"id":"014399a3-b14b-4dba-89d6-f36cc325ffb7","version":3} - account-22-address: "0xdb7af39b6d8754b5dadad29bef43945bdd487806" - account-22-keyfile: | - {"address":"db7af39b6d8754b5dadad29bef43945bdd487806","crypto":{"cipher":"aes-128-ctr","ciphertext":"76cfb216f5b40d78f1f70f28210f48846c86f6c8204245f4e415e32da30bda88","cipherparams":{"iv":"47bf995d1dbd2a0cd070df2f23fe3de7"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"1ddc490e6e9a6b249e0bdb753dffe8f377c09ce7ed365c1cce72b5a674b39d63"},"mac":"8f8cf27fa11523db97f5342fac2d92edb6962f21eaaf7d011aa30a26eeccab60"},"id":"101c8d5d-3f3f-477c-a0bf-991b4b868a48","version":3} - account-23-address: "0x2c1e150bed83ecea9cb111ba9bf485f0ac19c683" - account-23-keyfile: | - {"address":"2c1e150bed83ecea9cb111ba9bf485f0ac19c683","crypto":{"cipher":"aes-128-ctr","ciphertext":"9bddac5144b118ead6a8fb6b9c1087a81bfbe356a98df3b9a6658db3468291e8","cipherparams":{"iv":"0fb3a7d72b64243b08c2fbcb8744f85e"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"ef2155aafc128413f3f45738a2159bab308a7773332435f4b45fbe862d8d9c72"},"mac":"8d860f9c01e4676dd9d4c448a1dbca27e00fe5241cdec070f0422edddcac54ad"},"id":"bbc3d7c0-9905-4115-bebf-cfd01d18f54e","version":3} - account-24-address: "0xd7b1b5e78efcb2bf425bb109c2bed6d14b8009fb" - account-24-keyfile: | - {"address":"d7b1b5e78efcb2bf425bb109c2bed6d14b8009fb","crypto":{"cipher":"aes-128-ctr","ciphertext":"a9c9110f71175e690f0af51fe3bf9a7d9cfcaaa776ac6207a0b0448dded399dc","cipherparams":{"iv":"6fac01bf5e006dc2bf158044976f4bfa"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"623fd2b3010bea5e678caae3f4d9fc1ae54787b98753b4a7619285456551ca2d"},"mac":"54e9247d5631e0b30f1801e72b46c615af08810d64761f73e5383c65d79a9076"},"id":"d86b436d-3066-4cc1-bea0-0effc2c2aa6f","version":3} - account-25-address: "0xe1165cef25bfbebe98b534ef6224223cf4580570" - account-25-keyfile: | - {"address":"e1165cef25bfbebe98b534ef6224223cf4580570","crypto":{"cipher":"aes-128-ctr","ciphertext":"30b40293db73af288d8c79c2b7afb89e8660c1837ef11f159d01a3537f678170","cipherparams":{"iv":"43936e17120eb83a7c8313bc535460d0"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"c56314526991328040ffa9c2bee8a360f320394ec7b31d2426f24c9addc8376a"},"mac":"d7cc65ff7f720a1a26e6038645491b300454930228a37507d7565c84e326c3e7"},"id":"534d81be-108d-4e30-b18a-a83607773be2","version":3} - account-26-address: "0xf86ab3c084912d4cd57982cad97fbb22d74f3c98" - account-26-keyfile: | - {"address":"f86ab3c084912d4cd57982cad97fbb22d74f3c98","crypto":{"cipher":"aes-128-ctr","ciphertext":"ebd249f20090df75b746b81401afb53960c5a07ce069b6286dd8d553bdef5cd9","cipherparams":{"iv":"616a7201eadfd59909581b17dc0384bd"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"ad0fb8882696c7c1c19f4a206ac0939ad3a66fef288e23df2dd28d9d2dca138b"},"mac":"48c2c3b1daaa353115995ff38755bba48bf97851a1068bf7ac18ecc019891f57"},"id":"ae93dee1-32ba-4d30-b684-b0a116e3e8f4","version":3} - account-27-address: "0x0a556970d79d924f5532507b8f4a899f26d16e90" - account-27-keyfile: | - {"address":"0a556970d79d924f5532507b8f4a899f26d16e90","crypto":{"cipher":"aes-128-ctr","ciphertext":"9be0f38d053e69f28d5bbfa1a8e7f25c434016edd5fd48f8eea15a5c00101714","cipherparams":{"iv":"da2f69448d5f5b5fb46c849e25c9374e"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"f8a38e4cec22a03a3fed5f008953a55d664005b0296f057b520d107d65c90583"},"mac":"4e6d0ef26b309b905d621329c8b850bcb21032d8d9e48916b27f1b22aa0243ad"},"id":"46a6bd1a-5a53-4cce-a48a-15d8964a4bd8","version":3} - account-28-address: "0x06915e6471f7d12ebe317bed11c4c9e6afa8faf1" - account-28-keyfile: | - {"address":"06915e6471f7d12ebe317bed11c4c9e6afa8faf1","crypto":{"cipher":"aes-128-ctr","ciphertext":"233737bb511b7d9069e48735491636a91cd2edd5bd9819bd39eaa56e51ccbafb","cipherparams":{"iv":"4333f03889f922bcc0b49149e5c85e3f"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"6f1065459f74d4e4b1cabf1bbd017e36d87327eea7b53dba3273a242badd1b95"},"mac":"c6d30d39783a92a4d39b939da073e2dfcfb26faf39160e47be10e0c197a95504"},"id":"e20615d7-df15-4f82-a284-099a53c73648","version":3} - account-29-address: "0x12a9d4579c2cf9daedb3d8b6a844dc3a878222fb" - account-29-keyfile: | - {"address":"12a9d4579c2cf9daedb3d8b6a844dc3a878222fb","crypto":{"cipher":"aes-128-ctr","ciphertext":"7b9b686e539226dd9d85d33aa51cd87ff7dd5eb5c062a1954e5150e7bb5553c3","cipherparams":{"iv":"8f842bf10d11953f108ae88df527b4ba"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"21167fbc4d30c2da5253fd47ade4b94b1f66036f1e6edd4b3deaf5213c723d9e"},"mac":"40386f30dc04f60c682609ce8be44ec05a6a62e81f10884055fa173a60e305fe"},"id":"d3ee8030-2b45-4c4a-8360-f4455c73873e","version":3} - account-30-address: "0xc9f6a78167fcc9c1867b50c77c2a0aa003fd489c" - account-30-keyfile: | - {"address":"c9f6a78167fcc9c1867b50c77c2a0aa003fd489c","crypto":{"cipher":"aes-128-ctr","ciphertext":"2b5a72531a7394379c828704716aead63cbdf57010408552846e88be47d5c4ef","cipherparams":{"iv":"7755004c8c2caaecc57a4ff85fd03322"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"100ffdc13ffb773168d435758c0291fe38d7bb70f4fbd46da796ba63e3e41104"},"mac":"eb9e7aeb7aa237b3a525641165a52b67727265f2a9de172025aee152bc31c414"},"id":"1312b41c-d0be-4c82-ac8b-4ef772fa7b56","version":3} - account-31-address: "0x127d48d2536a85a97085d12eeff74ec244b153d6" - account-31-keyfile: | - {"address":"127d48d2536a85a97085d12eeff74ec244b153d6","crypto":{"cipher":"aes-128-ctr","ciphertext":"fff1243cab851041d84d00e778e21c92f218233ff12983e5c68c4ee49c30a47e","cipherparams":{"iv":"3f27900280b09de16a6494f515a1e5e4"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"e2fd43ee53400803f960875717f93658597492f161dd985921b13a8e97071b9c"},"mac":"c2ac84b499830d14855886b5f780dd5f4d9f64dbd131e9ac8b64a47fcedcb874"},"id":"248b7f5a-21cf-4568-b940-fb5ec4039cd4","version":3} - account-32-address: "0x765fbe861a8be3e3377047301dca87dcce3b7291" - account-32-keyfile: | - {"address":"765fbe861a8be3e3377047301dca87dcce3b7291","crypto":{"cipher":"aes-128-ctr","ciphertext":"183e8e2c81afb396893315ae29660a94aa85698a2ab4eefa6d23c4a21fc0a108","cipherparams":{"iv":"993966a6ab9078aa194839dd8a77d158"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"f59680509daf3e8313a4108cbe0378e559859bffbceeb583153fab044a764ab3"},"mac":"482d76539ee8b14878264594ffd8ad21690a3f72faaf91087ab7353604d718ac"},"id":"436c66e6-ef23-4892-bf61-fc3a5595665b","version":3} - account-33-address: "0xa723c7d91c3070a80e43f39b10d2e9d082bb4bdd" - account-33-keyfile: | - {"address":"a723c7d91c3070a80e43f39b10d2e9d082bb4bdd","crypto":{"cipher":"aes-128-ctr","ciphertext":"d88a20dcefa779c4f3b3b2e994a6212bf8a6e772c921709458348c503698780a","cipherparams":{"iv":"6d88802070f7d853ff520b33dcdb67a5"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"2b2fae61be6361748626ec6679a27d198d284123de8db4448abd4a4a95d8abd9"},"mac":"3ddd54dd23759fabf2d9154aeb8cab64f21cbb2091f5e17955d0506e05977e5e"},"id":"92dc2fd7-582e-4f70-b9a6-800525964589","version":3} - account-34-address: "0x98787a33e399361f2d6189c227b86a3025ee5688" - account-34-keyfile: | - {"address":"98787a33e399361f2d6189c227b86a3025ee5688","crypto":{"cipher":"aes-128-ctr","ciphertext":"1cac6f9371710d5bd3227d4da0983842f7a55ef54012cecacce5881c7e96357b","cipherparams":{"iv":"eb71eaa83c3e4cb73bc85380f5cfab83"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"ce8275197567fcf999ef1d28237a87229a6d308df3b012c439a0a757be5f6225"},"mac":"c9596d85010336bcb8197e0b51521b26f5507b18cf57fe3e5c8d541cfd24b91b"},"id":"fe9cc520-238e-454d-acba-e11838d5ee3d","version":3} - account-35-address: "0xbd38bbbde29fc5ffadaa40e339eda2abc51c11e8" - account-35-keyfile: | - {"address":"bd38bbbde29fc5ffadaa40e339eda2abc51c11e8","crypto":{"cipher":"aes-128-ctr","ciphertext":"18381ac7daa0b1b221f9e182ee9958fd88330ecddfc34b173687b150e19bb262","cipherparams":{"iv":"aa1823a585f545d86f3e9578599a369c"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"6409c0de3648e9f79c8205e129f20b361763c0368d08c6d133dc584962b522e9"},"mac":"4e84123df5933568cb5e4b048c1a15b44ac1762f91990f6a93d20e5b8e1364d2"},"id":"31d5c73e-3d2e-4e90-b875-a6566986197c","version":3} - account-36-address: "0x6eeabbb3bf02bbd51779994ee0a16b0a27118041" - account-36-keyfile: | - {"address":"6eeabbb3bf02bbd51779994ee0a16b0a27118041","crypto":{"cipher":"aes-128-ctr","ciphertext":"e3dbcf0bc5c9e1aa651e0d7ff0927d4b9861ceecc9405d52b667c172c3b6aa73","cipherparams":{"iv":"66eeddfa89cbe9bfc298c7b33dab5a82"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"0db71cf1e3f9ec8cd7071e0fee80efb5c7c845254b1a11bd19f83e22196980d3"},"mac":"15ae5bafb285e6e860ff32f0324af74c6bb5213b6ff7633d0260da45bf381e9e"},"id":"6616b3a0-eccf-4c29-9448-709a27b5a573","version":3} - account-37-address: "0xb325305f4dc4018982838b7599589a4acc82e348" - account-37-keyfile: | - {"address":"b325305f4dc4018982838b7599589a4acc82e348","crypto":{"cipher":"aes-128-ctr","ciphertext":"a0af3a150f30878f7909b0a97baf408b188a39ef86a1759c07a33da687752e9c","cipherparams":{"iv":"4e6e7a6708fca5c8131897a17e411e07"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"ca7cf158d65221f5d0941002e1e5afe81431fd3c442c61baa24a949fabd22c97"},"mac":"d74bc7a434e625f0d35247ec1ff7d6fd58f21bd9a41f2b536ef1bf9ec3d468cc"},"id":"793089b8-ef61-4564-922e-48a23fb74269","version":3} - account-38-address: "0x3f069271b7279d6d5384dd3bc3fede1855518d4c" - account-38-keyfile: | - {"address":"3f069271b7279d6d5384dd3bc3fede1855518d4c","crypto":{"cipher":"aes-128-ctr","ciphertext":"9097759452619cc7d27cfa80f3b85a32d1da54105af41397b08f20ef3b1bbdf3","cipherparams":{"iv":"d0eb8a436fbe1a0bc597af430a5ab0fb"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"856bd3545142f569033c234f2f536e4bf973dcfa947df194cf7eac8559bd9d7a"},"mac":"66198225fc42b75bd84b84d84872ac1e65851a457f33fdf356483b34418c6d54"},"id":"ca591401-d92a-4438-ad95-d2b421dd8b76","version":3} - account-39-address: "0x9d95667b6e9bf6e84019f6514c6cef11bfa6cbdf" - account-39-keyfile: | - {"address":"9d95667b6e9bf6e84019f6514c6cef11bfa6cbdf","crypto":{"cipher":"aes-128-ctr","ciphertext":"f5a9f90b9505c7c534bc84ae1d56a3abc8b9b32275e3f2b3880f8c9c172d863f","cipherparams":{"iv":"868c49fd8e8dff254b241a143fa6eeb1"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"fc37d202bc12bfbd13dfd1e68fb3e7119cfe8d6a9e8d85babf683e3f9658ba33"},"mac":"cecdf8d872aca5f436104b7973deff7b600cc3e9815a9f676de1fe61821c5b3e"},"id":"43beb89f-3780-4886-9c82-920efa074ad1","version":3} - account-40-address: "0x06ecd74b4b949e32ec2378515d9ae278c8bf2b43" - account-40-keyfile: | - {"address":"06ecd74b4b949e32ec2378515d9ae278c8bf2b43","crypto":{"cipher":"aes-128-ctr","ciphertext":"8dc38dab7acef366f26600ae4cd143db08d0f13603e84e23cf19e7c5ba10a384","cipherparams":{"iv":"c9bfff41b4abd1b2fc5815000a014d3d"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"f6d4125128fcab3ba1b60f698ee29949814030dae82726bc074a8d7a114e66f4"},"mac":"be98f18689d3a64273bca6f9a9af8e89b855c7239bce696469344783c07fd20f"},"id":"4dcd8016-f2f4-4719-b7bb-0e73df8e84a9","version":3} - account-41-address: "0x1363223b0acfa2fb58e1c7f374f011be2333db96" - account-41-keyfile: | - {"address":"1363223b0acfa2fb58e1c7f374f011be2333db96","crypto":{"cipher":"aes-128-ctr","ciphertext":"95b8832967d4fc453e3287bc51ba6bec8e3a11e84e2b8dc54bc501e9dc222b7c","cipherparams":{"iv":"b9ed108524d25630798e56583dae4131"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"1ebc1c5df10650592179e3e19a6133750ca9f225fa54e33d99f82065bd986494"},"mac":"6267013080fa2ceb42964fa60e1041096ede40d1eb06aa4838e3d0cd5d5bfbf9"},"id":"c8633238-28a2-4208-a5f1-b477e459d203","version":3} - account-42-address: "0x5a6e4ed97aa97924e415ff22d42d2a0acc04f0d5" - account-42-keyfile: | - {"address":"5a6e4ed97aa97924e415ff22d42d2a0acc04f0d5","crypto":{"cipher":"aes-128-ctr","ciphertext":"f05ddf65790ae143e772fd9da7f26392b62937c30ba7716a3c8bef7c5dfa8fed","cipherparams":{"iv":"f4a9f62f81d9d56d3d5e2417ba3740ef"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"15bb60f1b5f4b33ff7ceadbfa5da132e7dda7d8c6ddb0c26ab77264ff217eaf9"},"mac":"fa8cb34ee8512d8fc72b387fa69b4419bf0531c76e61589980cc8e9100e8dca7"},"id":"ea463da1-f94b-47b9-90fd-c1eff5ebad80","version":3} - account-43-address: "0xb4b48cb7338bfd72bb92f314b8af0737b15de529" - account-43-keyfile: | - {"address":"b4b48cb7338bfd72bb92f314b8af0737b15de529","crypto":{"cipher":"aes-128-ctr","ciphertext":"bd87427c816f7727510c984d6d55ada88d5dfa0393210dbbbd5bbfc3028ea885","cipherparams":{"iv":"fd95be87ef3e48e80c7e8535c72e4a35"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"65ebb3e27a6438246fb17f121e3af89ffaaff4edbabe2bc251b044aeed4f1d3b"},"mac":"772ae2000d0f67d6a189ae9b3c32339091f8f03bfb1df527f9717d66500d58de"},"id":"787f0ee0-9b04-4950-ae9a-180b9f2e1140","version":3} - account-44-address: "0xb182da6013ffa83ede34c0f621f08ec1dc11fabc" - account-44-keyfile: | - {"address":"b182da6013ffa83ede34c0f621f08ec1dc11fabc","crypto":{"cipher":"aes-128-ctr","ciphertext":"321a2e23557b8ab33c60a669e8049edf7270dcfc2057956ec7ffd9f6ae0037fa","cipherparams":{"iv":"242584dd8c87bc8036a25c059f7dc52c"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"b59c0f963083ef979db83b224df6b0b0adf43a2ca286425376b12f980a1f94df"},"mac":"c88c7dee2166996f05da9f0c9fd21ff5ee9f6b9be8c084b5dc91a2bd487187d8"},"id":"aa9ece81-9eb2-44a1-a296-3a1b0d2a461d","version":3} - account-45-address: "0x1e3cc42656ba98ddec729c1cbea514dae25d0de9" - account-45-keyfile: | - {"address":"1e3cc42656ba98ddec729c1cbea514dae25d0de9","crypto":{"cipher":"aes-128-ctr","ciphertext":"de26281b1b2eb37366ad2868579d877e14f11a82197a2ee446db35e89093d299","cipherparams":{"iv":"b1d3c177190435a731b064cac5cd3739"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"d18e18b322f2a8eb4acacc36749ba897ae0a99dccbd56240a2ae4d32d0cb5c02"},"mac":"dbaf7a8886d2469516e13c933f17139d42f270955417bc56d9709e4934e9503a"},"id":"e7a4264a-ecdc-450b-b0ff-2a155f9bf5ea","version":3} - account-46-address: "0x881edb9fa7bb70ad6adeb903bb5bb960c981ec95" - account-46-keyfile: | - {"address":"881edb9fa7bb70ad6adeb903bb5bb960c981ec95","crypto":{"cipher":"aes-128-ctr","ciphertext":"e192dfefae980cccb0dcd5215559b5b5cf06647b1ceeded1603775d3a3ce94d6","cipherparams":{"iv":"2a566c350912f29768164cdad722716d"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"f80bf34d97a61a815e1d8388619bddf1483bf9ef4162e7515d15b7de77d9a454"},"mac":"874cb0f7cb033f246d01d38fb1c997a4e30e9e627edaebb4d3d47f5611fea35c"},"id":"089277a2-1ffa-4658-931c-4a4c29a8219e","version":3} - account-47-address: "0x0f1ffbafc315df3bb0ff566d880baeb5757fa12b" - account-47-keyfile: | - {"address":"0f1ffbafc315df3bb0ff566d880baeb5757fa12b","crypto":{"cipher":"aes-128-ctr","ciphertext":"a2bbb40b28bb7b90ceed72de064738d76fcba2b76e0c7a2f9281c89c71f38a77","cipherparams":{"iv":"02590a460b9784c3335b00ad57a48eb9"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"d66acc05e36af2d5aae8feb9dff59641c9a021d3fe0c877dd762b86244128473"},"mac":"6490ca9077f686057033a1562a28911c3c5a669bdddc41d0912e7976138af592"},"id":"55c33815-007b-4664-b590-146afdd954e1","version":3} - account-48-address: "0xc9b138bfcae72cf69dbeb3d418aede58fdb7cede" - account-48-keyfile: | - {"address":"c9b138bfcae72cf69dbeb3d418aede58fdb7cede","crypto":{"cipher":"aes-128-ctr","ciphertext":"73ab913054e91994f92b9701e4e6b43fb591dfcee603c76056909f85f368a6a9","cipherparams":{"iv":"5ba2015007fd54b523952fde2e39f7a1"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"49b1f83026d38e0faa35075d932c41ebcb6854668e0f1e0806d0dd000ab339ee"},"mac":"09feff10b41cb0fd72bcb28b5c390e97d6a07bb5b554318bf6de8d453b2cc3f4"},"id":"881646d9-2ee3-4adb-bf87-5d91c88de35f","version":3} - account-49-address: "0xa78c127157b6aa89079e5e3666d51856a3553bdd" - account-49-keyfile: | - {"address":"a78c127157b6aa89079e5e3666d51856a3553bdd","crypto":{"cipher":"aes-128-ctr","ciphertext":"11ebb4684cc5534471ca651fa97044b48fcccbe01771688c36ea019bf5632f6b","cipherparams":{"iv":"f0646bf3be80088f001a50f1d23d1393"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"bca01ec05d2fe9d92af877403ee2fe1dde27cef4db4913055d775b5f03c820ad"},"mac":"4355a10abba4f468af039e0b4d7362078bb9808cb08400e70db986706d4f9122"},"id":"7bb60055-b602-409a-9c00-ff486d4c3290","version":3} - account-50-address: "0xdd21e3d887d923667e84b71ec9244338f0882022" - account-50-keyfile: | - {"address":"dd21e3d887d923667e84b71ec9244338f0882022","crypto":{"cipher":"aes-128-ctr","ciphertext":"3b20224bd8cb497dfd425eed28ac44748c268e9bc9dcbbb3074e5068540a49fa","cipherparams":{"iv":"c025c17a11e41d10940f47798982f668"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"ce57b9219c492ed09b61e14af0f4e3ca0d0c28aeba08425bc91bb01a444d5de9"},"mac":"7423adb79573c618f840da8b7e3bf31d8d254b9d4c0ad1948dcfa68c599ac7f9"},"id":"fe7f813b-b187-4dff-a914-ebe0b24812d5","version":3} - account-51-address: "0x7f7633e1b86c54c94f25b5ec8d1fd11ece4b1181" - account-51-keyfile: | - {"address":"7f7633e1b86c54c94f25b5ec8d1fd11ece4b1181","crypto":{"cipher":"aes-128-ctr","ciphertext":"5fd706557deec406a46f063d5bfdc15ca144a0af5ef96d1a9135c7fd71d32b8a","cipherparams":{"iv":"1cda57ca99bc0927354c00be0d9e1508"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"87a481ede6f72d9350cd4b7ab4f0455df0c35e70b5847b2b03b1cec84ca46eb4"},"mac":"e65e1d1fec514527d884813e6ef7cb4939c743088e7b0d8aac504d884f64e31b"},"id":"7bd051ed-cd22-4779-9aa7-a7a45ff2c977","version":3} - account-52-address: "0x713a114a5e620938f93cef33ca6362bbd7be7aa2" - account-52-keyfile: | - {"address":"713a114a5e620938f93cef33ca6362bbd7be7aa2","crypto":{"cipher":"aes-128-ctr","ciphertext":"e8997ad7140debe133a1b573b0a3e4c511bfcaeac8cb3b4f59d57db0403fe7ff","cipherparams":{"iv":"fd9dd64b6fa425057bbff040ba2c596e"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"bf0833cb883d6ecc04a404f6f22be2e6db6d4ac871585b54f0578ffe315db55a"},"mac":"63393a31a1571954d440028cb709676285b5e964205aa5f4049ac12900615846"},"id":"37c558de-2d07-46df-bd43-4e1d3bd3f791","version":3} - account-53-address: "0xe7f76f6eeae7dc754280d4d5a8e15426138525d9" - account-53-keyfile: | - {"address":"e7f76f6eeae7dc754280d4d5a8e15426138525d9","crypto":{"cipher":"aes-128-ctr","ciphertext":"3c76c5c2a2b497a849cdcf43abcf376ffae2d6a971025deb21aff845136f6a78","cipherparams":{"iv":"53b016b728dc2f38e3ea73521751a166"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"a203d92e0c77ce2c3d334da0ae6c3c245ba857ae02e1a16db41d4bcf6460fcc0"},"mac":"394a20572ad42635c282fa063ad20097f20ea41212915bef3cdfd1e6d9f32f18"},"id":"4b1aa6b0-d115-44f5-be1d-0bd6c7cc7df4","version":3} - account-54-address: "0xb3a06e0ef0c16899abb0ea95a5171ea2cb06f4d7" - account-54-keyfile: | - {"address":"b3a06e0ef0c16899abb0ea95a5171ea2cb06f4d7","crypto":{"cipher":"aes-128-ctr","ciphertext":"87c3bd7c66cf6d5c0fef009a67b6c6663d63869ba72fd75752c1234ff846a2a1","cipherparams":{"iv":"024f6cc468f249a9cebb02819d732cbc"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"936b0e4854ac3a4622cf120fbc24154a6fdceddb723dab27c16a0088a9f2f8e0"},"mac":"0ae8b566bc73e4bfadb936972bb5e529aa450c209a2864f83d3add34f9e890df"},"id":"ed566df4-9990-48ec-b489-ac56ff0140c9","version":3} - account-55-address: "0xb702d04773d6fd3fcc066cf130717d681cdd8c5b" - account-55-keyfile: | - {"address":"b702d04773d6fd3fcc066cf130717d681cdd8c5b","crypto":{"cipher":"aes-128-ctr","ciphertext":"2684f7913301c183e9ebaea9c6b22a8458dc379230828b1f8e058f5f0d0538e8","cipherparams":{"iv":"58a5a5f10bb9de8b2bcc44d4a592e742"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"c538a8c893ac897c86e7d52346939d8870d7d7b4dcff07472584e28925607002"},"mac":"0cd5e986f11b77c221de5a7eae6b53a8677c3f99e10bc37b78aa730c878ef251"},"id":"accc72a3-94c5-4387-bca4-20b4604e282e","version":3} - account-56-address: "0x5b53745ce2f533aa05e4c14e33daec411d9576fe" - account-56-keyfile: | - {"address":"5b53745ce2f533aa05e4c14e33daec411d9576fe","crypto":{"cipher":"aes-128-ctr","ciphertext":"30bce9457eeaf58caad23ef9b8927fa0642d134b646d1af68543719297d4b69e","cipherparams":{"iv":"be232415bf3d22445c62209b80bddaec"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"a62b09281a0dca289794b5a2f4c66eaec82f662a595642fb9cb4c0eb4eb4a882"},"mac":"d6e3415a1cedfbb30149da5fff5efc4bf2b9dab3a806ec1713696a6ef674af42"},"id":"46dbb35d-8f94-48aa-90b0-e753e5ba8d1a","version":3} - account-57-address: "0x3bd569b9a3172991bf15ceb318a170ca7923b737" - account-57-keyfile: | - {"address":"3bd569b9a3172991bf15ceb318a170ca7923b737","crypto":{"cipher":"aes-128-ctr","ciphertext":"9703c10e4dea5629caedfce60402754aabbca973620cf97e5d25d585ef8ad760","cipherparams":{"iv":"0b38e6aa34aa407caa6f1953ae0044af"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"8ba3e8a4aec494c64d64f7a2ec079ff0fdd6a8df037ddb48be4653e83b1eaeba"},"mac":"ded691b6da2d227521f957b1ce28334ffd0b26f31048f3eaf6387d47103f6143"},"id":"103a3df5-c613-49ed-9f0f-e0d1ee2a970d","version":3} - account-58-address: "0x4ae4ff81fbdb6ff6aa7a71ade1fe735023bf55cb" - account-58-keyfile: | - {"address":"4ae4ff81fbdb6ff6aa7a71ade1fe735023bf55cb","crypto":{"cipher":"aes-128-ctr","ciphertext":"2ba7fab603a489fa2bc1c0d071935506c2ce9fd1601eeea6c22f741a8648188c","cipherparams":{"iv":"f009814e69b32dfd2371bb1d6e225a56"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"240a234eb77fd58b3c3c4fad0353c5ccf585b0e71ebd1686de765b09e432ffcf"},"mac":"84eace34590bc58240e43b5d9f49bcffc08001a298decb0d68b1d89442a6ed34"},"id":"c59c8874-3af8-4471-aef4-11c5cf78937e","version":3} - account-59-address: "0x215c9275417fc94ad2d1ef368e126b968772fb27" - account-59-keyfile: | - {"address":"215c9275417fc94ad2d1ef368e126b968772fb27","crypto":{"cipher":"aes-128-ctr","ciphertext":"6b2ec8e75ee8d241efbee1f9cfee8b6f74b8b63149dd5e929e7a978cb8c04423","cipherparams":{"iv":"c7efc204d57096631de9a5bda34ef976"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"c2f7467c65836dfad77a24b7fb165b02eb000b482b82bccd1f1ff1ae3123db5b"},"mac":"bb6ae1c04e14809f959e9fdb7ae687a253bb5c5b35b23108211f05334a5d25e3"},"id":"f7dd8579-b8fe-41a9-b9d7-ef5e0dfffa7e","version":3} - account-60-address: "0xc2a93865f2451455174e4af0757be4ae0eb4efad" - account-60-keyfile: | - {"address":"c2a93865f2451455174e4af0757be4ae0eb4efad","crypto":{"cipher":"aes-128-ctr","ciphertext":"8f7483ccb88887aa5655a8c096d2d59de1f777519c5626b0eefbabc4f5803993","cipherparams":{"iv":"e55fadab5162533fe0ebd5ac1d08f910"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"85fa26e6465a2ab8ab86372e03bf79fc1b59ed43374788cba88250260a04bc0e"},"mac":"1483b790a0980058e0e355aa34a6351aa36cd3a0fb4f276096524fbe9505ac2a"},"id":"38acae56-9673-4039-ad75-bf30116c1904","version":3} - account-61-address: "0x5d3f80feed09f0013afd5e2e77f0c96884c4cbaf" - account-61-keyfile: | - {"address":"5d3f80feed09f0013afd5e2e77f0c96884c4cbaf","crypto":{"cipher":"aes-128-ctr","ciphertext":"7e78e1bf39a76911137ab59dbb7a560227e26341c2f8e8a1fa5a67992247d75c","cipherparams":{"iv":"b1d41597e2fe5c24b167e4714d4c7934"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"c638f717664c2c466bf1f2c7a4f1c46afe65ba2738413791c2682da3291f21f3"},"mac":"db20b371940937f885eb4af4dc825a6c77846a43f8440ce11be2712937e1033c"},"id":"58bedcfc-42d0-4f49-8a7e-26407e029d5a","version":3} - account-62-address: "0x5fc57afc4779bfc73cf9df11e243c50c8cbaf2a4" - account-62-keyfile: | - {"address":"5fc57afc4779bfc73cf9df11e243c50c8cbaf2a4","crypto":{"cipher":"aes-128-ctr","ciphertext":"fb91c015451108783ef7dac55abbe937aa96d2487dc26d358cefdb72700b4075","cipherparams":{"iv":"8669788d98dbf78c65a6aeec3efe62aa"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"56f5c472a98dbdbef2710f7738f7d589bc636e307088e8f294f93f2567b7f5fd"},"mac":"8021f4f71c984e53638b167a0e7c7306aec581a079fe62995562957f6b9e8b1c"},"id":"ab4f6cb5-8c46-4534-bfde-363e5792226f","version":3} - account-63-address: "0xec4e9ccc33a28d3c6adbdf80200fa97a38f4d3ce" - account-63-keyfile: | - {"address":"ec4e9ccc33a28d3c6adbdf80200fa97a38f4d3ce","crypto":{"cipher":"aes-128-ctr","ciphertext":"c331c31c1f538db1a6350818c957ae041bef5aabfdff7ea85e72188b73bee9ed","cipherparams":{"iv":"b4f93453327bcfb6c3bb6c2b75abea62"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"2bc9b74d70786be2faf2212d14088876ab1407e89823ff471ca2c8fd038e4e57"},"mac":"99fd049b79450f467a7683f15ab6ecd0d1b371f06f95adc8e398db25109cc7c2"},"id":"2b7bbce4-5ecf-4206-a10f-5f7f544e5051","version":3} - account-64-address: "0x8d516f40ab30bb6c20df8feffdb888349234f015" - account-64-keyfile: | - {"address":"8d516f40ab30bb6c20df8feffdb888349234f015","crypto":{"cipher":"aes-128-ctr","ciphertext":"9fa794a83d6e3bd164b5edcdb1237db7bbac00e1540567568f90de825752b318","cipherparams":{"iv":"0fefa2313ecca5184cfce818ce99ecb1"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"70d30be31c3d4b303087a72a25a065aa36ae779da9d8b24a38764f26adadd6e5"},"mac":"f157e4aa072a2fe454ed02f626397b190aba6a62b1c5e170d1c10962ae5c2b32"},"id":"ea7dea45-6fa9-4d24-83ea-5fd5ba4877e3","version":3} - account-65-address: "0x894242f10b55a0c397cd76cf37913c5ab24ab7b3" - account-65-keyfile: | - {"address":"894242f10b55a0c397cd76cf37913c5ab24ab7b3","crypto":{"cipher":"aes-128-ctr","ciphertext":"6511b0c6b9979996f647a19cbb9f3ce1235416cf54b7c8e1ce53d4e901e09c23","cipherparams":{"iv":"363216dcfe40c53563d4bdb95a1d77e8"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"c30dc6044e39e5c4bd50a3bcf3442a24c5da2f4390906bb5f9f9a88f4c95e999"},"mac":"6c7b2ea9e4fe84ba0fe2683e44e04cee7904cdb6b3a539fa254e7a47e78be80b"},"id":"9b45b951-9d89-4df5-8641-b248a45e47e3","version":3} - account-66-address: "0xbb78ce192add31a8335e381c52a88175bcd0798d" - account-66-keyfile: | - {"address":"bb78ce192add31a8335e381c52a88175bcd0798d","crypto":{"cipher":"aes-128-ctr","ciphertext":"8118b9ed9cb3abafd22cc246b69b64ac2f8b59dd2176269953573dba386bfd5d","cipherparams":{"iv":"b5c98ba464b6fde0c2d0d3bb66a59252"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"429360476c31d58f17cfb3967521950307fba6ad7977cf95b0cfb125e8339c9b"},"mac":"ac94c759481ad7f08d3641466606d0fd79bc670267eb3d567f0228bfa874bb0b"},"id":"16ce236b-f8dd-4c4a-a9ef-3ca23602e3bb","version":3} - account-67-address: "0x64a7d3084d8ae4c6d3a20758bcb1248d5293dfed" - account-67-keyfile: | - {"address":"64a7d3084d8ae4c6d3a20758bcb1248d5293dfed","crypto":{"cipher":"aes-128-ctr","ciphertext":"dc87d6983081339a5ecba864fb13fbf4edc9f639a52cedd224f76b21d7ffb430","cipherparams":{"iv":"5cd51cdaec7461eaf965e39ae0afbb7c"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"9415ce9074d492bf5fabe91cd23abb3511ec60da442ed43b0e99935d4d00762f"},"mac":"622809350d55d7477c9b69ae695ff75c9c5218a5c251790855fdb152a15007d8"},"id":"c4f0c5b1-cd42-47b7-87d6-8a7d587d8a46","version":3} - account-68-address: "0x21382f74a6ada375682a4282614d6004a167de7c" - account-68-keyfile: | - {"address":"21382f74a6ada375682a4282614d6004a167de7c","crypto":{"cipher":"aes-128-ctr","ciphertext":"86e3a1609dcab1c0b6680f21370d73b007a92b11fed8f4217183238275829d48","cipherparams":{"iv":"0584f079c8304bc93436e74b956de051"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"9a7e5ff576c26d892f0860ce3453b51b398f470b1003f044eaa15c0e27e1107f"},"mac":"9456e2c7a6b871bd96721adcc9251ac019a82d9b01482fabe797b580ed27837a"},"id":"70a6e86d-3317-49af-adc1-e4fd808a2220","version":3} - account-69-address: "0x9bed51d95f77b29eb07e2a720679c48849f1df0a" - account-69-keyfile: | - {"address":"9bed51d95f77b29eb07e2a720679c48849f1df0a","crypto":{"cipher":"aes-128-ctr","ciphertext":"c59e3729680aec16cf52f04adcd7f94fbdadc492b60fcdfec77d23e8725284f8","cipherparams":{"iv":"4f93a8d6746444fa34040ff1aeebed38"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"d9e4a4dbffa3f0dc36848615f23a00cfd8c894d4d961a3a3db12d2cd2cf1c6ca"},"mac":"40f0bc17eee3907e387e8a9c0a4bfd0e28438e02788c1cb8fd56a5558dfdaba1"},"id":"da3a8d8e-0895-4ca5-a44d-15696b2861da","version":3} - account-70-address: "0xccb77a8dacab6b6e1fd26dfc0b893561e05ff73b" - account-70-keyfile: | - {"address":"ccb77a8dacab6b6e1fd26dfc0b893561e05ff73b","crypto":{"cipher":"aes-128-ctr","ciphertext":"c0a1a71dd1e46b1e1bc71c3d8b34d7f8823276b2af31d807ff435a234f5e9209","cipherparams":{"iv":"7cee0d70fc20292617ad2788f5920452"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"c1979e98bd2d9b05d5537e76b231ab7ac76fbbe594f21f6d8a3fc6873a4cc747"},"mac":"47558de5c3b6ed74e810f1b79e557fe96f3fc6d3ade0c9598d43f01aedfdd021"},"id":"8eb31a8b-efb4-4f50-a54b-fd2083e57b4f","version":3} - account-71-address: "0x223f7abce664d1b2619c8684341ee276272dca40" - account-71-keyfile: | - {"address":"223f7abce664d1b2619c8684341ee276272dca40","crypto":{"cipher":"aes-128-ctr","ciphertext":"f886f710a91fe2bd208fab8c3685513a014573f18a65ac516f42b25102d70f67","cipherparams":{"iv":"381155b50b2011d01382a54735806b0e"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"e6026f95bf36ae607c5cdb0981a108f1d8854f7ce043917c882f17c4c9825b5a"},"mac":"269e86b5811341c572919ac18b09da22869400febe987fccb399232413a22fac"},"id":"f343ae86-3e9a-46b2-b5ec-9dce41aea78e","version":3} - account-72-address: "0x92a50483402886dd2d3e6bb07b77940560779c49" - account-72-keyfile: | - {"address":"92a50483402886dd2d3e6bb07b77940560779c49","crypto":{"cipher":"aes-128-ctr","ciphertext":"66ab4264c34151cb6a179cb2e4d580226fbf75b11a667aa19adca07d1d91810c","cipherparams":{"iv":"1d635cdb883e16b078f1ec1c27b1d115"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"19183df4866fd2127d274458629dd1f927d72a81f017d8854a57c08abff65425"},"mac":"384722f9a9d0a0a5dd03bff95dee16b43a0254dd8f2f6dbe0cfe0d0b09846b2d"},"id":"071a8cd4-d071-417a-a31f-58e4f4306552","version":3} - account-73-address: "0xce7ef6140350acb104950540286fd082e25ca806" - account-73-keyfile: | - {"address":"ce7ef6140350acb104950540286fd082e25ca806","crypto":{"cipher":"aes-128-ctr","ciphertext":"02d2406eeec8bcbbce92d4ce275fc48fb7ec71ae96a573f566197ba561f0722e","cipherparams":{"iv":"3742490d6e33b3512fa63e9edd1bb017"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"41f95626f96902d191ec2f8098b2297190df996979df04f1ad589bfe9b3dba6a"},"mac":"b456ef0f326271aefd674142333828725ec12726e97fd407118792a9554e8e08"},"id":"69fe139a-c451-450f-8197-f1a6a8a0ab24","version":3} - account-74-address: "0x89c46eafe8f81bd3a804f6d8534e1771a69baaed" - account-74-keyfile: | - {"address":"89c46eafe8f81bd3a804f6d8534e1771a69baaed","crypto":{"cipher":"aes-128-ctr","ciphertext":"d4d513750fcd7ecbd54a00cd8dc6d87eda8b5fc381901723998b62002d5f4c3d","cipherparams":{"iv":"80b11dd856e9fcca928468ae85da4935"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"90a712a2db8546175b1fe41725ba5d4db25cfec87a61c42b9b84f7c50cb95844"},"mac":"e149a029453e0300e8f7b0682030e6ee7c079f1b782f4f7af5d165bf7775a466"},"id":"b28aeec7-1ad6-4547-a03d-f820a3e1416b","version":3} - account-75-address: "0x8569ec5e73c66b40b43b9f39cc35f258aa74b06f" - account-75-keyfile: | - {"address":"8569ec5e73c66b40b43b9f39cc35f258aa74b06f","crypto":{"cipher":"aes-128-ctr","ciphertext":"0b4a4bf5b62906bbbf8e843e1d13e95a0877a949ad504be9bdee179a01aacf67","cipherparams":{"iv":"99b66d57aeadafd2aa0d9f77c7a1042c"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"f556f7b630ec1cd981600e251ab25fed30cb268ab237c21159a820d44490fca5"},"mac":"96e6539d139d18cb16d47cdd2cd54be6b51fbd360eb113e53d0de82ef1efa207"},"id":"c5412766-de1c-411a-9282-0594849c3167","version":3} - account-76-address: "0x71dae2f3a3f58dd58d4687d1d1d94f6947571f08" - account-76-keyfile: | - {"address":"71dae2f3a3f58dd58d4687d1d1d94f6947571f08","crypto":{"cipher":"aes-128-ctr","ciphertext":"de99d17c98decc84f9470dd1bf569a01f3d5ae1d07dfc76f52ed3ce671f8f934","cipherparams":{"iv":"55c327788f1c997f94f770bc282f769a"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"41f38e89e3a8f9530f0d0e050b3e8d3e76de1cbe9946f7017f1ec80f26932276"},"mac":"07feb0ea3b25ee62c53ee49eb4efa34de82a4aa0968a80341ba24c0b891a5269"},"id":"84350a8b-e90b-48c5-8283-1d386eb0a056","version":3} - account-77-address: "0x8914c585b4f825a7a4ee67208e34d525fa3b90e4" - account-77-keyfile: | - {"address":"8914c585b4f825a7a4ee67208e34d525fa3b90e4","crypto":{"cipher":"aes-128-ctr","ciphertext":"0f75741ed9782d1fe9e08621a07476f7347bfc6e9cff579e40f9475f1554c8f7","cipherparams":{"iv":"bd59462bae3702004f98a58cb2e994bc"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"61dfcadb00239f8c6550f1169309cd3a76eee047b342b228ccb54a3bb25369d2"},"mac":"1e610cbd9a19dfeb86f13fa46e925b9933af65a7658e74f468307840c36284ef"},"id":"3f6e9bee-17c4-4b0a-b9cd-eeb253883dff","version":3} - account-78-address: "0xf9b978d9c0b253638368230a0a0efa1c811df371" - account-78-keyfile: | - {"address":"f9b978d9c0b253638368230a0a0efa1c811df371","crypto":{"cipher":"aes-128-ctr","ciphertext":"ea5a9a95453b2a750422a70fc043cbc15c8f9a300d1f9cfd217a9fda2ae7e83d","cipherparams":{"iv":"b40075a44e73a49629c26bd10e0fd214"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"6a596deb5b2b038823d1d5afa822bfecef01cbc61a975bddc71dbf403e0a7926"},"mac":"bf7bf1426186753fe6ab77ddfb2d18f4a972b1d37387a47107188494fa74a1d0"},"id":"7ae256fb-cc81-454d-a618-f2d01812285d","version":3} - account-79-address: "0x696738ce105743a2950a7729bad66c8cda78552d" - account-79-keyfile: | - {"address":"696738ce105743a2950a7729bad66c8cda78552d","crypto":{"cipher":"aes-128-ctr","ciphertext":"6b8951356ca1da0823cc99eb71178e24075d825b6c29a271353950014fddd04a","cipherparams":{"iv":"7c78bc250d7e55ea9898b82d1addbaa9"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"a21c7658e0c8bbec363b5f3c06c589bfb6d3072a4570ce415d16093803d221ea"},"mac":"9f68670f36de4c9f6e3bfc4a6518c0c1583cd2121d9a84bbafab06d29b6d572b"},"id":"85c9ce46-1873-4269-bc61-2f664077a25c","version":3} - account-80-address: "0x5c266973ee88a23ca96cc4d429d8d386f32d7f23" - account-80-keyfile: | - {"address":"5c266973ee88a23ca96cc4d429d8d386f32d7f23","crypto":{"cipher":"aes-128-ctr","ciphertext":"69a85a32347d603e868609a7a7ad12dee2075f93e66061da38d13aded91579ae","cipherparams":{"iv":"32f071510a15e09b2e3556f4c871cfdd"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"23ede4763eaf0e76509b7c7b5360cd59ffe6b93f07ed56db6263694faf01f275"},"mac":"548c1cb13b0ba43684d3514216b9a5ce56aa46b170a23067079687def80b73ed"},"id":"a2527fe2-a54b-4838-bca4-886bf552fa5e","version":3} - account-81-address: "0x86022171aaf9657766d543b06bc30e7f2086acb9" - account-81-keyfile: | - {"address":"86022171aaf9657766d543b06bc30e7f2086acb9","crypto":{"cipher":"aes-128-ctr","ciphertext":"a61c1f7f95b85e0dc57d868c290755b3ac53f6a24bebe9621aabcfa68155329a","cipherparams":{"iv":"d8020d609f33cfe284c1804421adefcb"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"69371f68c0ac65c5ba4348afea6f56a9ecf346055d1dcc7d7251bef0fab107f9"},"mac":"150680f2207235d67d507255aaa5c648794ce22d3b910657c27a4c8b422271de"},"id":"17f7d6d1-3640-4165-ad95-728bfa8490d8","version":3} - account-82-address: "0xb5e467d166cd1d1da2f9345c5ef3e81f07b73b53" - account-82-keyfile: | - {"address":"b5e467d166cd1d1da2f9345c5ef3e81f07b73b53","crypto":{"cipher":"aes-128-ctr","ciphertext":"1842ee9cc83ba9d21fd78873a60be88e869e9b24558c6e03ae64effe8dfe07e6","cipherparams":{"iv":"d6f643913e8431d142c4913efeac1d23"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"5d527570bfcd94a8bc10786e8993aab069327f5974632cadf15e5a087d42bfa4"},"mac":"4546d24f7b0f8b685b05c710f5c081102156faa5ed9b0f14990e76bbd25d1d87"},"id":"a6694e0a-8353-4579-b654-7b8f03a2ee0d","version":3} - account-83-address: "0x84d7da05d5dc1e47b0c5075c7ff456d0d3be1424" - account-83-keyfile: | - {"address":"84d7da05d5dc1e47b0c5075c7ff456d0d3be1424","crypto":{"cipher":"aes-128-ctr","ciphertext":"9580c625b60f77e502dbf594cf6efd96b3de9acd4e9ca914fb01c8ddca40fcbe","cipherparams":{"iv":"08fad98bb032eff831db7364ae4b24b0"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"ce77b1999c25b29fea7bed481899d7e7cc884fad7d2a830eaf9fd435c3b26b09"},"mac":"366b7834b51e9fc651cc19e76411289e8045e588ee750b63b49b69f92b8ca034"},"id":"a7a45c88-f8bc-4f5a-bc10-c11f506bc88a","version":3} - account-84-address: "0xbf4d20f0a40aa1627c4dc03e2eca26dc76cdcb2f" - account-84-keyfile: | - {"address":"bf4d20f0a40aa1627c4dc03e2eca26dc76cdcb2f","crypto":{"cipher":"aes-128-ctr","ciphertext":"2819591308a416302380fd0757d50075acacdee56fd76cdeb3227a678ea5623b","cipherparams":{"iv":"9a32860b243a185d2d7bd537227231bf"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"ca6c84dc59a9f6678630ef67761ea1be3429234e06e4094a163b36b22a3745f2"},"mac":"589e1ef0daea168f8c1d50ae26ffb6a9245e90d43480773304cf101a679cc24e"},"id":"c6f5974a-cf96-4277-8f4d-7e52fbd29f0d","version":3} - account-85-address: "0x891b55a7559147f2a141d34ff9e002d9e93dc519" - account-85-keyfile: | - {"address":"891b55a7559147f2a141d34ff9e002d9e93dc519","crypto":{"cipher":"aes-128-ctr","ciphertext":"8854e8ea8f8c1b766f528c6acfea778c0f1f571396a181dba5d1644d1986a3a1","cipherparams":{"iv":"91c4ad32acbb3edd8a597aceea0576f1"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"e5060339906fd09e283793007c56997da5123f948f799d0501f35d1c9cdabb65"},"mac":"8e6b22ef3e505930e16521436cb51e21199a4318fc915608798384d6b9ae6377"},"id":"ccf81ae0-0991-4dba-acd9-120f27b24d92","version":3} - account-86-address: "0x14fcea2a1305a4c71c02c3d57fe1e8f77a6b57d3" - account-86-keyfile: | - {"address":"14fcea2a1305a4c71c02c3d57fe1e8f77a6b57d3","crypto":{"cipher":"aes-128-ctr","ciphertext":"1736a5db71803485def5be896784ac57d3c27c0d911be68440a36339fc0f4045","cipherparams":{"iv":"231f64338fb2a9fbf896a7a117b23bf3"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"26eb1e24f4c5259fbf7ffff00f6a750c6a59baa6e9ee5be2df01b2782b4554e3"},"mac":"0ef57e90c814f380a897d04ae2c884f0798ba3d96af73194d17b30f7d1c19ee4"},"id":"84ea004f-5c50-4cf5-b99d-dc8c88f66500","version":3} - account-87-address: "0xfd7e16d89be981db1db54e2605ac59552f7ef5f2" - account-87-keyfile: | - {"address":"fd7e16d89be981db1db54e2605ac59552f7ef5f2","crypto":{"cipher":"aes-128-ctr","ciphertext":"0775c7eeec8767f4a9f12fcb74edf333ac7fc6875f936b6b4bd61611418261ef","cipherparams":{"iv":"4237ca78789d4576970e40ac71ef157c"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"50ca92eacfbdc9148c787b9254fd29ef23afa6f0b617f6a38a051e902983aecb"},"mac":"393ce842535a3e3195d000a0ddc888e1b97e67477d7775fdb46a028d491d893c"},"id":"8f262b20-3f77-442b-8b47-29747730696b","version":3} - account-88-address: "0xe4034b30e70643f6216cd7f6ffec1f5bab818bae" - account-88-keyfile: | - {"address":"e4034b30e70643f6216cd7f6ffec1f5bab818bae","crypto":{"cipher":"aes-128-ctr","ciphertext":"3e651dd0f290f0a4620651d27b592f7db22b1ee2de832fba84f20bbe0feacb31","cipherparams":{"iv":"c405b5d329f7447160a8539ec61b7fb3"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"eae27b86b0180f25ad07fb2dbd973ed01ba1ccf4e4a2315304fb7d87dd31f4f1"},"mac":"35eaa69de5f9747ed83022f8628c6df8c8f63d13a8e963895f821c986f969317"},"id":"8a89a93b-fe62-454f-b0cc-7c94ca104a54","version":3} - account-89-address: "0xc1fd92ca4cd3634441b36966a7bb767fad88a1c8" - account-89-keyfile: | - {"address":"c1fd92ca4cd3634441b36966a7bb767fad88a1c8","crypto":{"cipher":"aes-128-ctr","ciphertext":"a14f021f73bee0479513d6c2781cceb982338921cc55bc460f61ded42bc4c42d","cipherparams":{"iv":"fd3c6f7c6eb730cde485ce772dddf6b8"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"43aab3b1b44288edfeabbd3d6c166d839dcaa98d4c00cd04006745c07cc81025"},"mac":"32c1ce100f68e525c44c22c1fc49bf3ea8af2459d946694bd9f3648f34e17bed"},"id":"8b8ed472-33d6-4d8e-8f5c-1085a4bf8dab","version":3} - account-90-address: "0x5d41ff2b042c89dcb79570f02971d3e7b449d7c0" - account-90-keyfile: | - {"address":"5d41ff2b042c89dcb79570f02971d3e7b449d7c0","crypto":{"cipher":"aes-128-ctr","ciphertext":"980613ae4416039559a23859fa6c25bd6db15543616642273358e0c044b19aeb","cipherparams":{"iv":"04163f5d2bb38534cc45242677354596"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"a348a527122195899075b512dda50e6372f55f2db341b399b6a845eccda3be9d"},"mac":"3c8b5f1c76f6f9f673f6ca33251a2e48e1c43f7e30f80d0ca523f7a7374a0593"},"id":"b495206d-5491-44db-aba1-f2de9aa2a88f","version":3} - account-91-address: "0x730c8670a01faf3a70a2788e16b2815c2b34db37" - account-91-keyfile: | - {"address":"730c8670a01faf3a70a2788e16b2815c2b34db37","crypto":{"cipher":"aes-128-ctr","ciphertext":"ddfdd1ad75e07c6d64208c5a30d982c1d6bfb3083dd6ebbbe27fd441630f5052","cipherparams":{"iv":"c5db1b2ac5992f0b71a4e54d48b590e0"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"7f5ff78423b37352388fa4c350222efac03c971ea0f5777d4f9f18aca66fa9dd"},"mac":"9e6d432edcac88054a714bb01b417635310308f0411d4a5897358bf79e12dfc5"},"id":"fdcf0d0f-c526-4d56-a2b9-894fbd80ec34","version":3} - account-92-address: "0x285fc27d49de57755e8040bbfcd141c13c5eb25a" - account-92-keyfile: | - {"address":"285fc27d49de57755e8040bbfcd141c13c5eb25a","crypto":{"cipher":"aes-128-ctr","ciphertext":"ca6d748e1277b16bcea91ffd4856434d27391b29910feb395e7d8fae41563b8d","cipherparams":{"iv":"07452b57375de5777f5921e72b129b6d"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"3d50f3d80f23051bf47b9504363c2b00347895198ce340b72340765dc0da7797"},"mac":"e998499876157511e7f94e8d239b10e2d7c90c5b0b517388b5bacb94265011d0"},"id":"1a239bdd-40df-4d2a-9aa9-00d648a10b76","version":3} - account-93-address: "0xf68e5f768d607280f1eab153ae6f27a021e33140" - account-93-keyfile: | - {"address":"f68e5f768d607280f1eab153ae6f27a021e33140","crypto":{"cipher":"aes-128-ctr","ciphertext":"6db5e25c05a2f28d6f5dabb16d51490b624d88e500cb5875e5378159a0a42fd0","cipherparams":{"iv":"2fc32736a73dc0c478897d97ed945ae9"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"0089d0a3c0699b76895a933c9e7c0ed03a1d31c2a0ab6c60b54bb0d60f204246"},"mac":"387163a78e8ca8b3ce953a11d990e0f58e850d834f058c90e1dcb7802c2214a6"},"id":"6cab197f-f523-4303-a8df-9d65bdb24625","version":3} - account-94-address: "0x1045581987377137a4be69c90744ad7cc486515d" - account-94-keyfile: | - {"address":"1045581987377137a4be69c90744ad7cc486515d","crypto":{"cipher":"aes-128-ctr","ciphertext":"5f726d6e6db0749e710a9fab3fe6c9a99d7e6a07fc83798d874611dc97952bb5","cipherparams":{"iv":"428c9bdd8da8fb0a2a703e8e9fc53ec0"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"f4c95b732c6b56ec9a388d8b974114bfeb5458e7c69ade4c742124e7e739783e"},"mac":"9996afcfe2ae5aec92f67045d0aa9acbd3847bb6fb20e1c59d36d5f0202b1001"},"id":"12533915-5e94-432d-9810-f508dd4af6cd","version":3} - account-95-address: "0x4fd6f76407a7f85eebca41d3e4571cf7414a0b5f" - account-95-keyfile: | - {"address":"4fd6f76407a7f85eebca41d3e4571cf7414a0b5f","crypto":{"cipher":"aes-128-ctr","ciphertext":"e0982a2226cdb00e7e3444446370b9a7a7c2e45d6313088c532ee53f077b4f46","cipherparams":{"iv":"4250e985fe85284dc522fef832b7f3dd"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"e883148a3b6bf773340f50329f62d9020e63422b6431d4ba951680b3590ede4e"},"mac":"e451c909197fd5b1774de330f4c54c68d2c0822bae6a0a9b1cf61464774caf0e"},"id":"b398cf6a-2fff-4ddc-a02e-9845f4f58845","version":3} - account-96-address: "0xbf0f3c029a8d7e57be721364bb0a43b61713918f" - account-96-keyfile: | - {"address":"bf0f3c029a8d7e57be721364bb0a43b61713918f","crypto":{"cipher":"aes-128-ctr","ciphertext":"b06bb050b83d2255339880e34305c57500ea834ce5179575b52fa46ef918dd2f","cipherparams":{"iv":"72a45f7738ad0e0d960e97a16b6331c6"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"a2d78db2608ec7081f373f99b2e2687efd4b90b9a2bad5ca13f22b5953b2d53c"},"mac":"c332f10204f770dd919dc2f0213c423730713855e8922b1e49626f3fa78ef54d"},"id":"f1e14e97-aa69-412e-9c1e-32ec189b75a0","version":3} - account-97-address: "0x28cc0f2b7398680b436a12ceca5cfef220640879" - account-97-keyfile: | - {"address":"28cc0f2b7398680b436a12ceca5cfef220640879","crypto":{"cipher":"aes-128-ctr","ciphertext":"aa6221589a8ad6254689726f3faa9ec7125bc0b8a26341591e4b86b16252c54c","cipherparams":{"iv":"3c655a548f02e27b42229673df37dc75"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"3515fa07e956be86a5090d579b1665d7ad74e06fedadc182dc9828e4b778887f"},"mac":"0b88b449867167af54414d6816b84009856e211f6551e9353c5ebb7d16d47e28"},"id":"89f4adf5-28f1-4dfc-bf98-064134c74c5a","version":3} - account-98-address: "0xf3254b90a0a771447037b627e355284bf0f4788f" - account-98-keyfile: | - {"address":"f3254b90a0a771447037b627e355284bf0f4788f","crypto":{"cipher":"aes-128-ctr","ciphertext":"7267877cece6c3efa2b7a7345184f36f4d7d1b2644eb48a541698296a3382cb9","cipherparams":{"iv":"382714a5e993f2daa6fea11c2974b159"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"f0c6ea1559ac59892c607daeba0c0caf8c68076b88e418177f58127200003448"},"mac":"a9ab2bdaf63cd8b6e3100e847bae33b01902bb1141579b8b1725dbc6e3ed33f1"},"id":"03ba879c-49ff-4056-84ce-890bd4ab20c5","version":3} - account-99-address: "0xd237c76e6902f71da0a66a8f5583d25cc64add6f" - account-99-keyfile: | - {"address":"d237c76e6902f71da0a66a8f5583d25cc64add6f","crypto":{"cipher":"aes-128-ctr","ciphertext":"3564f11313280f9b98a4f3256e19e0bff4c5d92a195a01204d33def1b372855b","cipherparams":{"iv":"a36914ce8d6028ed92450e9ff7ef69ce"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"1cd4244a2f8e96b67e62e81c83ee23e351427393950e509082138d7afb2f31e1"},"mac":"3ab600b5195143af4966f07f96ae4f96d99cc991b6d8538267c91fe6b171a188"},"id":"c86ab6c0-12d4-4e10-ab28-30e2af708571","version":3} diff --git a/infrastructure/kube/keep-test/geth-node/eth-goerli-node.yaml b/infrastructure/kube/keep-test/geth-node/eth-goerli-node.yaml deleted file mode 100644 index 289b360a12..0000000000 --- a/infrastructure/kube/keep-test/geth-node/eth-goerli-node.yaml +++ /dev/null @@ -1,89 +0,0 @@ ---- -apiVersion: storage.k8s.io/v1 -kind: StorageClass -metadata: - name: geth-goerli -provisioner: kubernetes.io/gce-pd -parameters: - type: pd-ssd - replication-type: none -reclaimPolicy: Retain -allowVolumeExpansion: true -mountOptions: - - debug -volumeBindingMode: Immediate ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: geth-goerli - labels: - app: geth - network: goerli -spec: - replicas: 1 - serviceName: geth-goerli - volumeClaimTemplates: - - metadata: - name: geth-goerli - spec: - accessModes: [ReadWriteOnce] - storageClassName: geth-goerli - resources: - requests: - storage: 200Gi - selector: - matchLabels: - app: geth - network: goerli - template: - metadata: - labels: - app: geth - network: goerli - spec: - containers: - - name: geth-goerli - image: ethereum/client-go:v1.10.20 - ports: - - containerPort: 8545 - - containerPort: 8546 - - containerPort: 30303 - volumeMounts: - - name: geth-goerli - mountPath: /root/.ethereum - args: - - "--http" - - "--http.addr=0.0.0.0" - - "--ws" - - "--ws.addr=0.0.0.0" - - "--goerli" - - "--syncmode=snap" ---- -apiVersion: v1 -kind: Service -metadata: - name: geth-goerli - labels: - app: geth - network: goerli -spec: - selector: - app: geth - network: goerli - ports: - - port: 8545 - targetPort: 8545 - name: tcp-8545 - - port: 8546 - targetPort: 8546 - name: tcp-8546 - - port: 30303 - targetPort: 30303 - name: tcp-30303 - - port: 30303 - targetPort: 30303 - name: udp-30303 - protocol: UDP - type: LoadBalancer - loadBalancerIP: "35.238.111.174" diff --git a/infrastructure/kube/keep-test/keep-client/README.md b/infrastructure/kube/keep-test/keep-client/README.md deleted file mode 100644 index 9ece10b201..0000000000 --- a/infrastructure/kube/keep-test/keep-client/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Keep Client - -## Configuration - -### Generation - -Keep Client Nodes manifests are generated with [`ytt`](https://carvel.dev/ytt/). - -To generate the YAML configuration for nodes run `./gen.sh`. - -ytt configuration consists of 3 files: - -- [`template.yaml`](.gen/template.yaml) - template for kubernetes manifest -- [`schema.yaml`](./gen/schema.yaml) - properties with default values -- [`data.yaml`](./gen/data.yaml) - values for generation - -### Resources - -Manifests for `StatefulSet` and `Service` for all the nodes are generated into the [`keep-clients.yaml`](./keep-clients.yaml) file. - -A node manifest reads values from following resources: - -Config Maps: - -- [`keep-client-config`](./keep-client-config.yaml) -- [`eth-account-info`](../eth-account-info-configmap.yaml) - -Secrets: - -- `eth-network-sepolia` -- `eth-account-passphrases` -- `eth-account-privatekeys` diff --git a/infrastructure/kube/keep-test/keep-client/gen.sh b/infrastructure/kube/keep-test/keep-client/gen.sh deleted file mode 100755 index 5f9cdeca85..0000000000 --- a/infrastructure/kube/keep-test/keep-client/gen.sh +++ /dev/null @@ -1,17 +0,0 @@ -#! /bin/bash - -if ! command -v ytt &> /dev/null -then - echo "ytt could not be found; for installation instruction visit https://carvel.dev/ytt/docs/latest/install" - exit -fi - - -ytt \ - -f gen/template.yaml \ - -f gen/data.yaml \ - -f gen/schema.yaml \ - --file-mark 'template.yaml:path=keep-clients.yaml' \ - --output-files . - -echo '# File generated with gen.sh - DO NOT EDIT' | cat - keep-clients.yaml > keep-clients.yaml.tmp && mv keep-clients.yaml.tmp keep-clients.yaml diff --git a/infrastructure/kube/keep-test/keep-client/gen/data.yaml b/infrastructure/kube/keep-test/keep-client/gen/data.yaml deleted file mode 100644 index 47dc4919f1..0000000000 --- a/infrastructure/kube/keep-test/keep-client/gen/data.yaml +++ /dev/null @@ -1,22 +0,0 @@ -#@data/values ---- -clients: - - id: 0 - publicAnnouncedAddress: "bootstrap-0.test.keep.network" - staticIP: "104.154.61.116" - - id: 1 - publicAnnouncedAddress: "bootstrap-1.test.keep.network" - staticIP: "35.223.100.87" - - id: 2 - - id: 3 - - id: 4 - - id: 5 - - id: 6 - - id: 7 - - id: 8 - - id: 9 -initContainers: - - name: initcontainer-beacon - image: gcr.io/keep-test-f3e0/keep-random-beacon-hardhat:latest - - name: initcontainer-ecdsa - image: gcr.io/keep-test-f3e0/keep-ecdsa-hardhat:latest diff --git a/infrastructure/kube/keep-test/keep-client/gen/schema.yaml b/infrastructure/kube/keep-test/keep-client/gen/schema.yaml deleted file mode 100644 index 6660088a9a..0000000000 --- a/infrastructure/kube/keep-test/keep-client/gen/schema.yaml +++ /dev/null @@ -1,14 +0,0 @@ -#@data/values-schema ---- -clients: - - id: 0 - #@schema/nullable - networkPeers: "" - #@schema/nullable - publicAnnouncedAddress: "" - #@schema/nullable - staticIP: "" - stakeAmount: 800_000 -initContainers: - - name: "" - image: "" diff --git a/infrastructure/kube/keep-test/keep-client/gen/template.yaml b/infrastructure/kube/keep-test/keep-client/gen/template.yaml deleted file mode 100644 index 2f5a569566..0000000000 --- a/infrastructure/kube/keep-test/keep-client/gen/template.yaml +++ /dev/null @@ -1,173 +0,0 @@ -#@ load("@ytt:data", "data") - -#@ for client in data.values.clients: - -#@ def labels(): -app: keep -type: client -id: #@ str(client.id) -network: sepolia -#@ end - -#@ def name(): -#@ return "keep-client-" + str(client.id) -#@ end - -#@ def account(): -#@ return "account-" + str(client.id) -#@ end ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: #@ name() - namespace: default - labels: #@ labels() -spec: - replicas: 1 - selector: - matchLabels: #@ labels() - serviceName: #@ name() - volumeClaimTemplates: - - metadata: - name: keep-client-data - spec: - accessModes: [ReadWriteOnce] - resources: - requests: - storage: 4096Mi - template: - metadata: - labels: #@ labels() - spec: - volumes: - - name: keep-client-data - persistentVolumeClaim: - claimName: keep-client-data - - name: eth-account-keyfile - configMap: - name: eth-account-info - items: - - key: #@ account() + "-keyfile" - path: #@ account() + "-keyfile" - containers: - - name: keep-client - image: "gcr.io/keep-test-f3e0/keep-client:latest" - imagePullPolicy: Always - resources: - requests: - cpu: 1500m - memory: 512M - ports: - - name: network - containerPort: 3919 - - name: client-info - containerPort: 9601 - env: - - name: KEEP_ETHEREUM_PASSWORD - valueFrom: - secretKeyRef: - name: eth-account-passphrases - key: #@ account() - #! Read secret to env variable to use it as arg. - - name: ETH_WS_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: ws-url - envFrom: - - configMapRef: - name: keep-client-config - volumeMounts: - - name: keep-client-data - mountPath: /mnt/keep-client/data - - name: eth-account-keyfile - mountPath: /mnt/keep-client/keyfile - command: ["keep-client", "start"] - args: - - --testnet - - --ethereum.url - - $(ETH_WS_URL) - - "--ethereum.keyFile" - - #@ "/mnt/keep-client/keyfile/" + account() + "-keyfile" - - --bitcoin.electrum.url - - $(ELECTRUM_TCP_URL) - - "--storage.dir" - - "/mnt/keep-client/data" - - "--network.port" - - "3919" - #@ if client.publicAnnouncedAddress: - - "--network.announcedAddresses" - - #@ "/dns4/" + client.publicAnnouncedAddress + "/tcp/3919" - #@ end - #@ if client.networkPeers: - - "--network.peers" - - #@ client.networkPeers - #@ end - - "--clientInfo.port" - - "9601" - - "--tbtc.keyGenerationConcurrency" - - "2" - initContainers: - #@ for/end initcontainer in data.values.initContainers: - - name: #@ initcontainer.name - image: #@ initcontainer.image - imagePullPolicy: Always - env: - - name: CHAIN_API_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: http-url - - name: CONTRACT_OWNER_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-account-privatekeys - key: #@ account() - - name: ACCOUNTS_PRIVATE_KEYS - value: $(CONTRACT_OWNER_ETH_PRIVATE_KEY),$(KEEP_CLIENT_ETH_PRIVATE_KEY) - - name: KEEP_CLIENT_ETH_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-account-info - key: #@ account() + "-address" - args: - - "initialize" - - "--network" - - "sepolia" - - "--owner" - - "$(KEEP_CLIENT_ETH_ADDRESS)" - - "--provider" - - "$(KEEP_CLIENT_ETH_ADDRESS)" - - "--operator" - - "$(KEEP_CLIENT_ETH_ADDRESS)" - #@ if client.stakeAmount: - - "--amount" - - #@ str(client.stakeAmount) - - "--authorization" - - #@ str(client.stakeAmount) - #@ end ---- -apiVersion: v1 -kind: Service -metadata: - name: #@ name() - namespace: default - labels: #@ labels() -spec: - type: LoadBalancer - ports: - - name: network - port: 3919 - targetPort: network - - name: client-info - port: 9601 - targetPort: client-info - selector: #@ labels() - loadBalancerIP: #@ client.staticIP -#@ end diff --git a/infrastructure/kube/keep-test/keep-client/keep-client-config.yaml b/infrastructure/kube/keep-test/keep-client/keep-client-config.yaml deleted file mode 100644 index dde3321712..0000000000 --- a/infrastructure/kube/keep-test/keep-client/keep-client-config.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: keep-client-config - namespace: default -data: - LOG_LEVEL: "keep*=info tss-lib=warn" - GOLOG_LOG_FMT: json - # GOLOG_OUTPUT: stdout - ELECTRUM_TCP_URL: tcp://electrumx.bitcoin-testnet:80 diff --git a/infrastructure/kube/keep-test/keep-client/keep-clients.yaml b/infrastructure/kube/keep-test/keep-client/keep-clients.yaml deleted file mode 100644 index d3f284bb8c..0000000000 --- a/infrastructure/kube/keep-test/keep-client/keep-clients.yaml +++ /dev/null @@ -1,2054 +0,0 @@ -# File generated with gen.sh - DO NOT EDIT -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: keep-client-0 - namespace: default - labels: - app: keep - type: client - id: "0" - network: sepolia -spec: - replicas: 1 - selector: - matchLabels: - app: keep - type: client - id: "0" - network: sepolia - serviceName: keep-client-0 - volumeClaimTemplates: - - metadata: - name: keep-client-data - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 4096Mi - template: - metadata: - labels: - app: keep - type: client - id: "0" - network: sepolia - spec: - volumes: - - name: keep-client-data - persistentVolumeClaim: - claimName: keep-client-data - - name: eth-account-keyfile - configMap: - name: eth-account-info - items: - - key: account-0-keyfile - path: account-0-keyfile - containers: - - name: keep-client - image: gcr.io/keep-test-f3e0/keep-client:latest - imagePullPolicy: Always - resources: - requests: - cpu: 1500m - memory: 512M - ports: - - name: network - containerPort: 3919 - - name: client-info - containerPort: 9601 - env: - - name: KEEP_ETHEREUM_PASSWORD - valueFrom: - secretKeyRef: - name: eth-account-passphrases - key: account-0 - - name: ETH_WS_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: ws-url - envFrom: - - configMapRef: - name: keep-client-config - volumeMounts: - - name: keep-client-data - mountPath: /mnt/keep-client/data - - name: eth-account-keyfile - mountPath: /mnt/keep-client/keyfile - command: - - keep-client - - start - args: - - --testnet - - --ethereum.url - - $(ETH_WS_URL) - - --ethereum.keyFile - - /mnt/keep-client/keyfile/account-0-keyfile - - --bitcoin.electrum.url - - $(ELECTRUM_TCP_URL) - - --storage.dir - - /mnt/keep-client/data - - --network.port - - "3919" - - --network.announcedAddresses - - /dns4/bootstrap-0.test.keep.network/tcp/3919 - - --clientInfo.port - - "9601" - - --tbtc.keyGenerationConcurrency - - "2" - initContainers: - - name: initcontainer-beacon - image: gcr.io/keep-test-f3e0/keep-random-beacon-hardhat:latest - imagePullPolicy: Always - env: - - name: CHAIN_API_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: http-url - - name: CONTRACT_OWNER_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-account-privatekeys - key: account-0 - - name: ACCOUNTS_PRIVATE_KEYS - value: $(CONTRACT_OWNER_ETH_PRIVATE_KEY),$(KEEP_CLIENT_ETH_PRIVATE_KEY) - - name: KEEP_CLIENT_ETH_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-account-info - key: account-0-address - args: - - initialize - - --network - - sepolia - - --owner - - $(KEEP_CLIENT_ETH_ADDRESS) - - --provider - - $(KEEP_CLIENT_ETH_ADDRESS) - - --operator - - $(KEEP_CLIENT_ETH_ADDRESS) - - --amount - - "800000" - - --authorization - - "800000" - - name: initcontainer-ecdsa - image: gcr.io/keep-test-f3e0/keep-ecdsa-hardhat:latest - imagePullPolicy: Always - env: - - name: CHAIN_API_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: http-url - - name: CONTRACT_OWNER_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-account-privatekeys - key: account-0 - - name: ACCOUNTS_PRIVATE_KEYS - value: $(CONTRACT_OWNER_ETH_PRIVATE_KEY),$(KEEP_CLIENT_ETH_PRIVATE_KEY) - - name: KEEP_CLIENT_ETH_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-account-info - key: account-0-address - args: - - initialize - - --network - - sepolia - - --owner - - $(KEEP_CLIENT_ETH_ADDRESS) - - --provider - - $(KEEP_CLIENT_ETH_ADDRESS) - - --operator - - $(KEEP_CLIENT_ETH_ADDRESS) - - --amount - - "800000" - - --authorization - - "800000" ---- -apiVersion: v1 -kind: Service -metadata: - name: keep-client-0 - namespace: default - labels: - app: keep - type: client - id: "0" - network: sepolia -spec: - type: LoadBalancer - ports: - - name: network - port: 3919 - targetPort: network - - name: client-info - port: 9601 - targetPort: client-info - selector: - app: keep - type: client - id: "0" - network: sepolia - loadBalancerIP: 104.154.61.116 ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: keep-client-1 - namespace: default - labels: - app: keep - type: client - id: "1" - network: sepolia -spec: - replicas: 1 - selector: - matchLabels: - app: keep - type: client - id: "1" - network: sepolia - serviceName: keep-client-1 - volumeClaimTemplates: - - metadata: - name: keep-client-data - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 4096Mi - template: - metadata: - labels: - app: keep - type: client - id: "1" - network: sepolia - spec: - volumes: - - name: keep-client-data - persistentVolumeClaim: - claimName: keep-client-data - - name: eth-account-keyfile - configMap: - name: eth-account-info - items: - - key: account-1-keyfile - path: account-1-keyfile - containers: - - name: keep-client - image: gcr.io/keep-test-f3e0/keep-client:latest - imagePullPolicy: Always - resources: - requests: - cpu: 1500m - memory: 512M - ports: - - name: network - containerPort: 3919 - - name: client-info - containerPort: 9601 - env: - - name: KEEP_ETHEREUM_PASSWORD - valueFrom: - secretKeyRef: - name: eth-account-passphrases - key: account-1 - - name: ETH_WS_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: ws-url - envFrom: - - configMapRef: - name: keep-client-config - volumeMounts: - - name: keep-client-data - mountPath: /mnt/keep-client/data - - name: eth-account-keyfile - mountPath: /mnt/keep-client/keyfile - command: - - keep-client - - start - args: - - --testnet - - --ethereum.url - - $(ETH_WS_URL) - - --ethereum.keyFile - - /mnt/keep-client/keyfile/account-1-keyfile - - --bitcoin.electrum.url - - $(ELECTRUM_TCP_URL) - - --storage.dir - - /mnt/keep-client/data - - --network.port - - "3919" - - --network.announcedAddresses - - /dns4/bootstrap-1.test.keep.network/tcp/3919 - - --clientInfo.port - - "9601" - - --tbtc.keyGenerationConcurrency - - "2" - initContainers: - - name: initcontainer-beacon - image: gcr.io/keep-test-f3e0/keep-random-beacon-hardhat:latest - imagePullPolicy: Always - env: - - name: CHAIN_API_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: http-url - - name: CONTRACT_OWNER_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-account-privatekeys - key: account-1 - - name: ACCOUNTS_PRIVATE_KEYS - value: $(CONTRACT_OWNER_ETH_PRIVATE_KEY),$(KEEP_CLIENT_ETH_PRIVATE_KEY) - - name: KEEP_CLIENT_ETH_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-account-info - key: account-1-address - args: - - initialize - - --network - - sepolia - - --owner - - $(KEEP_CLIENT_ETH_ADDRESS) - - --provider - - $(KEEP_CLIENT_ETH_ADDRESS) - - --operator - - $(KEEP_CLIENT_ETH_ADDRESS) - - --amount - - "800000" - - --authorization - - "800000" - - name: initcontainer-ecdsa - image: gcr.io/keep-test-f3e0/keep-ecdsa-hardhat:latest - imagePullPolicy: Always - env: - - name: CHAIN_API_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: http-url - - name: CONTRACT_OWNER_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-account-privatekeys - key: account-1 - - name: ACCOUNTS_PRIVATE_KEYS - value: $(CONTRACT_OWNER_ETH_PRIVATE_KEY),$(KEEP_CLIENT_ETH_PRIVATE_KEY) - - name: KEEP_CLIENT_ETH_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-account-info - key: account-1-address - args: - - initialize - - --network - - sepolia - - --owner - - $(KEEP_CLIENT_ETH_ADDRESS) - - --provider - - $(KEEP_CLIENT_ETH_ADDRESS) - - --operator - - $(KEEP_CLIENT_ETH_ADDRESS) - - --amount - - "800000" - - --authorization - - "800000" ---- -apiVersion: v1 -kind: Service -metadata: - name: keep-client-1 - namespace: default - labels: - app: keep - type: client - id: "1" - network: sepolia -spec: - type: LoadBalancer - ports: - - name: network - port: 3919 - targetPort: network - - name: client-info - port: 9601 - targetPort: client-info - selector: - app: keep - type: client - id: "1" - network: sepolia - loadBalancerIP: 35.223.100.87 ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: keep-client-2 - namespace: default - labels: - app: keep - type: client - id: "2" - network: sepolia -spec: - replicas: 1 - selector: - matchLabels: - app: keep - type: client - id: "2" - network: sepolia - serviceName: keep-client-2 - volumeClaimTemplates: - - metadata: - name: keep-client-data - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 4096Mi - template: - metadata: - labels: - app: keep - type: client - id: "2" - network: sepolia - spec: - volumes: - - name: keep-client-data - persistentVolumeClaim: - claimName: keep-client-data - - name: eth-account-keyfile - configMap: - name: eth-account-info - items: - - key: account-2-keyfile - path: account-2-keyfile - containers: - - name: keep-client - image: gcr.io/keep-test-f3e0/keep-client:latest - imagePullPolicy: Always - resources: - requests: - cpu: 1500m - memory: 512M - ports: - - name: network - containerPort: 3919 - - name: client-info - containerPort: 9601 - env: - - name: KEEP_ETHEREUM_PASSWORD - valueFrom: - secretKeyRef: - name: eth-account-passphrases - key: account-2 - - name: ETH_WS_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: ws-url - envFrom: - - configMapRef: - name: keep-client-config - volumeMounts: - - name: keep-client-data - mountPath: /mnt/keep-client/data - - name: eth-account-keyfile - mountPath: /mnt/keep-client/keyfile - command: - - keep-client - - start - args: - - --testnet - - --ethereum.url - - $(ETH_WS_URL) - - --ethereum.keyFile - - /mnt/keep-client/keyfile/account-2-keyfile - - --bitcoin.electrum.url - - $(ELECTRUM_TCP_URL) - - --storage.dir - - /mnt/keep-client/data - - --network.port - - "3919" - - --clientInfo.port - - "9601" - - --tbtc.keyGenerationConcurrency - - "2" - initContainers: - - name: initcontainer-beacon - image: gcr.io/keep-test-f3e0/keep-random-beacon-hardhat:latest - imagePullPolicy: Always - env: - - name: CHAIN_API_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: http-url - - name: CONTRACT_OWNER_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-account-privatekeys - key: account-2 - - name: ACCOUNTS_PRIVATE_KEYS - value: $(CONTRACT_OWNER_ETH_PRIVATE_KEY),$(KEEP_CLIENT_ETH_PRIVATE_KEY) - - name: KEEP_CLIENT_ETH_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-account-info - key: account-2-address - args: - - initialize - - --network - - sepolia - - --owner - - $(KEEP_CLIENT_ETH_ADDRESS) - - --provider - - $(KEEP_CLIENT_ETH_ADDRESS) - - --operator - - $(KEEP_CLIENT_ETH_ADDRESS) - - --amount - - "800000" - - --authorization - - "800000" - - name: initcontainer-ecdsa - image: gcr.io/keep-test-f3e0/keep-ecdsa-hardhat:latest - imagePullPolicy: Always - env: - - name: CHAIN_API_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: http-url - - name: CONTRACT_OWNER_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-account-privatekeys - key: account-2 - - name: ACCOUNTS_PRIVATE_KEYS - value: $(CONTRACT_OWNER_ETH_PRIVATE_KEY),$(KEEP_CLIENT_ETH_PRIVATE_KEY) - - name: KEEP_CLIENT_ETH_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-account-info - key: account-2-address - args: - - initialize - - --network - - sepolia - - --owner - - $(KEEP_CLIENT_ETH_ADDRESS) - - --provider - - $(KEEP_CLIENT_ETH_ADDRESS) - - --operator - - $(KEEP_CLIENT_ETH_ADDRESS) - - --amount - - "800000" - - --authorization - - "800000" ---- -apiVersion: v1 -kind: Service -metadata: - name: keep-client-2 - namespace: default - labels: - app: keep - type: client - id: "2" - network: sepolia -spec: - type: LoadBalancer - ports: - - name: network - port: 3919 - targetPort: network - - name: client-info - port: 9601 - targetPort: client-info - selector: - app: keep - type: client - id: "2" - network: sepolia - loadBalancerIP: null ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: keep-client-3 - namespace: default - labels: - app: keep - type: client - id: "3" - network: sepolia -spec: - replicas: 1 - selector: - matchLabels: - app: keep - type: client - id: "3" - network: sepolia - serviceName: keep-client-3 - volumeClaimTemplates: - - metadata: - name: keep-client-data - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 4096Mi - template: - metadata: - labels: - app: keep - type: client - id: "3" - network: sepolia - spec: - volumes: - - name: keep-client-data - persistentVolumeClaim: - claimName: keep-client-data - - name: eth-account-keyfile - configMap: - name: eth-account-info - items: - - key: account-3-keyfile - path: account-3-keyfile - containers: - - name: keep-client - image: gcr.io/keep-test-f3e0/keep-client:latest - imagePullPolicy: Always - resources: - requests: - cpu: 1500m - memory: 512M - ports: - - name: network - containerPort: 3919 - - name: client-info - containerPort: 9601 - env: - - name: KEEP_ETHEREUM_PASSWORD - valueFrom: - secretKeyRef: - name: eth-account-passphrases - key: account-3 - - name: ETH_WS_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: ws-url - envFrom: - - configMapRef: - name: keep-client-config - volumeMounts: - - name: keep-client-data - mountPath: /mnt/keep-client/data - - name: eth-account-keyfile - mountPath: /mnt/keep-client/keyfile - command: - - keep-client - - start - args: - - --testnet - - --ethereum.url - - $(ETH_WS_URL) - - --ethereum.keyFile - - /mnt/keep-client/keyfile/account-3-keyfile - - --bitcoin.electrum.url - - $(ELECTRUM_TCP_URL) - - --storage.dir - - /mnt/keep-client/data - - --network.port - - "3919" - - --clientInfo.port - - "9601" - - --tbtc.keyGenerationConcurrency - - "2" - initContainers: - - name: initcontainer-beacon - image: gcr.io/keep-test-f3e0/keep-random-beacon-hardhat:latest - imagePullPolicy: Always - env: - - name: CHAIN_API_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: http-url - - name: CONTRACT_OWNER_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-account-privatekeys - key: account-3 - - name: ACCOUNTS_PRIVATE_KEYS - value: $(CONTRACT_OWNER_ETH_PRIVATE_KEY),$(KEEP_CLIENT_ETH_PRIVATE_KEY) - - name: KEEP_CLIENT_ETH_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-account-info - key: account-3-address - args: - - initialize - - --network - - sepolia - - --owner - - $(KEEP_CLIENT_ETH_ADDRESS) - - --provider - - $(KEEP_CLIENT_ETH_ADDRESS) - - --operator - - $(KEEP_CLIENT_ETH_ADDRESS) - - --amount - - "800000" - - --authorization - - "800000" - - name: initcontainer-ecdsa - image: gcr.io/keep-test-f3e0/keep-ecdsa-hardhat:latest - imagePullPolicy: Always - env: - - name: CHAIN_API_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: http-url - - name: CONTRACT_OWNER_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-account-privatekeys - key: account-3 - - name: ACCOUNTS_PRIVATE_KEYS - value: $(CONTRACT_OWNER_ETH_PRIVATE_KEY),$(KEEP_CLIENT_ETH_PRIVATE_KEY) - - name: KEEP_CLIENT_ETH_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-account-info - key: account-3-address - args: - - initialize - - --network - - sepolia - - --owner - - $(KEEP_CLIENT_ETH_ADDRESS) - - --provider - - $(KEEP_CLIENT_ETH_ADDRESS) - - --operator - - $(KEEP_CLIENT_ETH_ADDRESS) - - --amount - - "800000" - - --authorization - - "800000" ---- -apiVersion: v1 -kind: Service -metadata: - name: keep-client-3 - namespace: default - labels: - app: keep - type: client - id: "3" - network: sepolia -spec: - type: LoadBalancer - ports: - - name: network - port: 3919 - targetPort: network - - name: client-info - port: 9601 - targetPort: client-info - selector: - app: keep - type: client - id: "3" - network: sepolia - loadBalancerIP: null ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: keep-client-4 - namespace: default - labels: - app: keep - type: client - id: "4" - network: sepolia -spec: - replicas: 1 - selector: - matchLabels: - app: keep - type: client - id: "4" - network: sepolia - serviceName: keep-client-4 - volumeClaimTemplates: - - metadata: - name: keep-client-data - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 4096Mi - template: - metadata: - labels: - app: keep - type: client - id: "4" - network: sepolia - spec: - volumes: - - name: keep-client-data - persistentVolumeClaim: - claimName: keep-client-data - - name: eth-account-keyfile - configMap: - name: eth-account-info - items: - - key: account-4-keyfile - path: account-4-keyfile - containers: - - name: keep-client - image: gcr.io/keep-test-f3e0/keep-client:latest - imagePullPolicy: Always - resources: - requests: - cpu: 1500m - memory: 512M - ports: - - name: network - containerPort: 3919 - - name: client-info - containerPort: 9601 - env: - - name: KEEP_ETHEREUM_PASSWORD - valueFrom: - secretKeyRef: - name: eth-account-passphrases - key: account-4 - - name: ETH_WS_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: ws-url - envFrom: - - configMapRef: - name: keep-client-config - volumeMounts: - - name: keep-client-data - mountPath: /mnt/keep-client/data - - name: eth-account-keyfile - mountPath: /mnt/keep-client/keyfile - command: - - keep-client - - start - args: - - --testnet - - --ethereum.url - - $(ETH_WS_URL) - - --ethereum.keyFile - - /mnt/keep-client/keyfile/account-4-keyfile - - --bitcoin.electrum.url - - $(ELECTRUM_TCP_URL) - - --storage.dir - - /mnt/keep-client/data - - --network.port - - "3919" - - --clientInfo.port - - "9601" - - --tbtc.keyGenerationConcurrency - - "2" - initContainers: - - name: initcontainer-beacon - image: gcr.io/keep-test-f3e0/keep-random-beacon-hardhat:latest - imagePullPolicy: Always - env: - - name: CHAIN_API_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: http-url - - name: CONTRACT_OWNER_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-account-privatekeys - key: account-4 - - name: ACCOUNTS_PRIVATE_KEYS - value: $(CONTRACT_OWNER_ETH_PRIVATE_KEY),$(KEEP_CLIENT_ETH_PRIVATE_KEY) - - name: KEEP_CLIENT_ETH_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-account-info - key: account-4-address - args: - - initialize - - --network - - sepolia - - --owner - - $(KEEP_CLIENT_ETH_ADDRESS) - - --provider - - $(KEEP_CLIENT_ETH_ADDRESS) - - --operator - - $(KEEP_CLIENT_ETH_ADDRESS) - - --amount - - "800000" - - --authorization - - "800000" - - name: initcontainer-ecdsa - image: gcr.io/keep-test-f3e0/keep-ecdsa-hardhat:latest - imagePullPolicy: Always - env: - - name: CHAIN_API_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: http-url - - name: CONTRACT_OWNER_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-account-privatekeys - key: account-4 - - name: ACCOUNTS_PRIVATE_KEYS - value: $(CONTRACT_OWNER_ETH_PRIVATE_KEY),$(KEEP_CLIENT_ETH_PRIVATE_KEY) - - name: KEEP_CLIENT_ETH_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-account-info - key: account-4-address - args: - - initialize - - --network - - sepolia - - --owner - - $(KEEP_CLIENT_ETH_ADDRESS) - - --provider - - $(KEEP_CLIENT_ETH_ADDRESS) - - --operator - - $(KEEP_CLIENT_ETH_ADDRESS) - - --amount - - "800000" - - --authorization - - "800000" ---- -apiVersion: v1 -kind: Service -metadata: - name: keep-client-4 - namespace: default - labels: - app: keep - type: client - id: "4" - network: sepolia -spec: - type: LoadBalancer - ports: - - name: network - port: 3919 - targetPort: network - - name: client-info - port: 9601 - targetPort: client-info - selector: - app: keep - type: client - id: "4" - network: sepolia - loadBalancerIP: null ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: keep-client-5 - namespace: default - labels: - app: keep - type: client - id: "5" - network: sepolia -spec: - replicas: 1 - selector: - matchLabels: - app: keep - type: client - id: "5" - network: sepolia - serviceName: keep-client-5 - volumeClaimTemplates: - - metadata: - name: keep-client-data - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 4096Mi - template: - metadata: - labels: - app: keep - type: client - id: "5" - network: sepolia - spec: - volumes: - - name: keep-client-data - persistentVolumeClaim: - claimName: keep-client-data - - name: eth-account-keyfile - configMap: - name: eth-account-info - items: - - key: account-5-keyfile - path: account-5-keyfile - containers: - - name: keep-client - image: gcr.io/keep-test-f3e0/keep-client:latest - imagePullPolicy: Always - resources: - requests: - cpu: 1500m - memory: 512M - ports: - - name: network - containerPort: 3919 - - name: client-info - containerPort: 9601 - env: - - name: KEEP_ETHEREUM_PASSWORD - valueFrom: - secretKeyRef: - name: eth-account-passphrases - key: account-5 - - name: ETH_WS_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: ws-url - envFrom: - - configMapRef: - name: keep-client-config - volumeMounts: - - name: keep-client-data - mountPath: /mnt/keep-client/data - - name: eth-account-keyfile - mountPath: /mnt/keep-client/keyfile - command: - - keep-client - - start - args: - - --testnet - - --ethereum.url - - $(ETH_WS_URL) - - --ethereum.keyFile - - /mnt/keep-client/keyfile/account-5-keyfile - - --bitcoin.electrum.url - - $(ELECTRUM_TCP_URL) - - --storage.dir - - /mnt/keep-client/data - - --network.port - - "3919" - - --clientInfo.port - - "9601" - - --tbtc.keyGenerationConcurrency - - "2" - initContainers: - - name: initcontainer-beacon - image: gcr.io/keep-test-f3e0/keep-random-beacon-hardhat:latest - imagePullPolicy: Always - env: - - name: CHAIN_API_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: http-url - - name: CONTRACT_OWNER_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-account-privatekeys - key: account-5 - - name: ACCOUNTS_PRIVATE_KEYS - value: $(CONTRACT_OWNER_ETH_PRIVATE_KEY),$(KEEP_CLIENT_ETH_PRIVATE_KEY) - - name: KEEP_CLIENT_ETH_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-account-info - key: account-5-address - args: - - initialize - - --network - - sepolia - - --owner - - $(KEEP_CLIENT_ETH_ADDRESS) - - --provider - - $(KEEP_CLIENT_ETH_ADDRESS) - - --operator - - $(KEEP_CLIENT_ETH_ADDRESS) - - --amount - - "800000" - - --authorization - - "800000" - - name: initcontainer-ecdsa - image: gcr.io/keep-test-f3e0/keep-ecdsa-hardhat:latest - imagePullPolicy: Always - env: - - name: CHAIN_API_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: http-url - - name: CONTRACT_OWNER_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-account-privatekeys - key: account-5 - - name: ACCOUNTS_PRIVATE_KEYS - value: $(CONTRACT_OWNER_ETH_PRIVATE_KEY),$(KEEP_CLIENT_ETH_PRIVATE_KEY) - - name: KEEP_CLIENT_ETH_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-account-info - key: account-5-address - args: - - initialize - - --network - - sepolia - - --owner - - $(KEEP_CLIENT_ETH_ADDRESS) - - --provider - - $(KEEP_CLIENT_ETH_ADDRESS) - - --operator - - $(KEEP_CLIENT_ETH_ADDRESS) - - --amount - - "800000" - - --authorization - - "800000" ---- -apiVersion: v1 -kind: Service -metadata: - name: keep-client-5 - namespace: default - labels: - app: keep - type: client - id: "5" - network: sepolia -spec: - type: LoadBalancer - ports: - - name: network - port: 3919 - targetPort: network - - name: client-info - port: 9601 - targetPort: client-info - selector: - app: keep - type: client - id: "5" - network: sepolia - loadBalancerIP: null ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: keep-client-6 - namespace: default - labels: - app: keep - type: client - id: "6" - network: sepolia -spec: - replicas: 1 - selector: - matchLabels: - app: keep - type: client - id: "6" - network: sepolia - serviceName: keep-client-6 - volumeClaimTemplates: - - metadata: - name: keep-client-data - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 4096Mi - template: - metadata: - labels: - app: keep - type: client - id: "6" - network: sepolia - spec: - volumes: - - name: keep-client-data - persistentVolumeClaim: - claimName: keep-client-data - - name: eth-account-keyfile - configMap: - name: eth-account-info - items: - - key: account-6-keyfile - path: account-6-keyfile - containers: - - name: keep-client - image: gcr.io/keep-test-f3e0/keep-client:latest - imagePullPolicy: Always - resources: - requests: - cpu: 1500m - memory: 512M - ports: - - name: network - containerPort: 3919 - - name: client-info - containerPort: 9601 - env: - - name: KEEP_ETHEREUM_PASSWORD - valueFrom: - secretKeyRef: - name: eth-account-passphrases - key: account-6 - - name: ETH_WS_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: ws-url - envFrom: - - configMapRef: - name: keep-client-config - volumeMounts: - - name: keep-client-data - mountPath: /mnt/keep-client/data - - name: eth-account-keyfile - mountPath: /mnt/keep-client/keyfile - command: - - keep-client - - start - args: - - --testnet - - --ethereum.url - - $(ETH_WS_URL) - - --ethereum.keyFile - - /mnt/keep-client/keyfile/account-6-keyfile - - --bitcoin.electrum.url - - $(ELECTRUM_TCP_URL) - - --storage.dir - - /mnt/keep-client/data - - --network.port - - "3919" - - --clientInfo.port - - "9601" - - --tbtc.keyGenerationConcurrency - - "2" - initContainers: - - name: initcontainer-beacon - image: gcr.io/keep-test-f3e0/keep-random-beacon-hardhat:latest - imagePullPolicy: Always - env: - - name: CHAIN_API_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: http-url - - name: CONTRACT_OWNER_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-account-privatekeys - key: account-6 - - name: ACCOUNTS_PRIVATE_KEYS - value: $(CONTRACT_OWNER_ETH_PRIVATE_KEY),$(KEEP_CLIENT_ETH_PRIVATE_KEY) - - name: KEEP_CLIENT_ETH_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-account-info - key: account-6-address - args: - - initialize - - --network - - sepolia - - --owner - - $(KEEP_CLIENT_ETH_ADDRESS) - - --provider - - $(KEEP_CLIENT_ETH_ADDRESS) - - --operator - - $(KEEP_CLIENT_ETH_ADDRESS) - - --amount - - "800000" - - --authorization - - "800000" - - name: initcontainer-ecdsa - image: gcr.io/keep-test-f3e0/keep-ecdsa-hardhat:latest - imagePullPolicy: Always - env: - - name: CHAIN_API_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: http-url - - name: CONTRACT_OWNER_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-account-privatekeys - key: account-6 - - name: ACCOUNTS_PRIVATE_KEYS - value: $(CONTRACT_OWNER_ETH_PRIVATE_KEY),$(KEEP_CLIENT_ETH_PRIVATE_KEY) - - name: KEEP_CLIENT_ETH_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-account-info - key: account-6-address - args: - - initialize - - --network - - sepolia - - --owner - - $(KEEP_CLIENT_ETH_ADDRESS) - - --provider - - $(KEEP_CLIENT_ETH_ADDRESS) - - --operator - - $(KEEP_CLIENT_ETH_ADDRESS) - - --amount - - "800000" - - --authorization - - "800000" ---- -apiVersion: v1 -kind: Service -metadata: - name: keep-client-6 - namespace: default - labels: - app: keep - type: client - id: "6" - network: sepolia -spec: - type: LoadBalancer - ports: - - name: network - port: 3919 - targetPort: network - - name: client-info - port: 9601 - targetPort: client-info - selector: - app: keep - type: client - id: "6" - network: sepolia - loadBalancerIP: null ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: keep-client-7 - namespace: default - labels: - app: keep - type: client - id: "7" - network: sepolia -spec: - replicas: 1 - selector: - matchLabels: - app: keep - type: client - id: "7" - network: sepolia - serviceName: keep-client-7 - volumeClaimTemplates: - - metadata: - name: keep-client-data - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 4096Mi - template: - metadata: - labels: - app: keep - type: client - id: "7" - network: sepolia - spec: - volumes: - - name: keep-client-data - persistentVolumeClaim: - claimName: keep-client-data - - name: eth-account-keyfile - configMap: - name: eth-account-info - items: - - key: account-7-keyfile - path: account-7-keyfile - containers: - - name: keep-client - image: gcr.io/keep-test-f3e0/keep-client:latest - imagePullPolicy: Always - resources: - requests: - cpu: 1500m - memory: 512M - ports: - - name: network - containerPort: 3919 - - name: client-info - containerPort: 9601 - env: - - name: KEEP_ETHEREUM_PASSWORD - valueFrom: - secretKeyRef: - name: eth-account-passphrases - key: account-7 - - name: ETH_WS_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: ws-url - envFrom: - - configMapRef: - name: keep-client-config - volumeMounts: - - name: keep-client-data - mountPath: /mnt/keep-client/data - - name: eth-account-keyfile - mountPath: /mnt/keep-client/keyfile - command: - - keep-client - - start - args: - - --testnet - - --ethereum.url - - $(ETH_WS_URL) - - --ethereum.keyFile - - /mnt/keep-client/keyfile/account-7-keyfile - - --bitcoin.electrum.url - - $(ELECTRUM_TCP_URL) - - --storage.dir - - /mnt/keep-client/data - - --network.port - - "3919" - - --clientInfo.port - - "9601" - - --tbtc.keyGenerationConcurrency - - "2" - initContainers: - - name: initcontainer-beacon - image: gcr.io/keep-test-f3e0/keep-random-beacon-hardhat:latest - imagePullPolicy: Always - env: - - name: CHAIN_API_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: http-url - - name: CONTRACT_OWNER_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-account-privatekeys - key: account-7 - - name: ACCOUNTS_PRIVATE_KEYS - value: $(CONTRACT_OWNER_ETH_PRIVATE_KEY),$(KEEP_CLIENT_ETH_PRIVATE_KEY) - - name: KEEP_CLIENT_ETH_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-account-info - key: account-7-address - args: - - initialize - - --network - - sepolia - - --owner - - $(KEEP_CLIENT_ETH_ADDRESS) - - --provider - - $(KEEP_CLIENT_ETH_ADDRESS) - - --operator - - $(KEEP_CLIENT_ETH_ADDRESS) - - --amount - - "800000" - - --authorization - - "800000" - - name: initcontainer-ecdsa - image: gcr.io/keep-test-f3e0/keep-ecdsa-hardhat:latest - imagePullPolicy: Always - env: - - name: CHAIN_API_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: http-url - - name: CONTRACT_OWNER_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-account-privatekeys - key: account-7 - - name: ACCOUNTS_PRIVATE_KEYS - value: $(CONTRACT_OWNER_ETH_PRIVATE_KEY),$(KEEP_CLIENT_ETH_PRIVATE_KEY) - - name: KEEP_CLIENT_ETH_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-account-info - key: account-7-address - args: - - initialize - - --network - - sepolia - - --owner - - $(KEEP_CLIENT_ETH_ADDRESS) - - --provider - - $(KEEP_CLIENT_ETH_ADDRESS) - - --operator - - $(KEEP_CLIENT_ETH_ADDRESS) - - --amount - - "800000" - - --authorization - - "800000" ---- -apiVersion: v1 -kind: Service -metadata: - name: keep-client-7 - namespace: default - labels: - app: keep - type: client - id: "7" - network: sepolia -spec: - type: LoadBalancer - ports: - - name: network - port: 3919 - targetPort: network - - name: client-info - port: 9601 - targetPort: client-info - selector: - app: keep - type: client - id: "7" - network: sepolia - loadBalancerIP: null ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: keep-client-8 - namespace: default - labels: - app: keep - type: client - id: "8" - network: sepolia -spec: - replicas: 1 - selector: - matchLabels: - app: keep - type: client - id: "8" - network: sepolia - serviceName: keep-client-8 - volumeClaimTemplates: - - metadata: - name: keep-client-data - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 4096Mi - template: - metadata: - labels: - app: keep - type: client - id: "8" - network: sepolia - spec: - volumes: - - name: keep-client-data - persistentVolumeClaim: - claimName: keep-client-data - - name: eth-account-keyfile - configMap: - name: eth-account-info - items: - - key: account-8-keyfile - path: account-8-keyfile - containers: - - name: keep-client - image: gcr.io/keep-test-f3e0/keep-client:latest - imagePullPolicy: Always - resources: - requests: - cpu: 1500m - memory: 512M - ports: - - name: network - containerPort: 3919 - - name: client-info - containerPort: 9601 - env: - - name: KEEP_ETHEREUM_PASSWORD - valueFrom: - secretKeyRef: - name: eth-account-passphrases - key: account-8 - - name: ETH_WS_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: ws-url - envFrom: - - configMapRef: - name: keep-client-config - volumeMounts: - - name: keep-client-data - mountPath: /mnt/keep-client/data - - name: eth-account-keyfile - mountPath: /mnt/keep-client/keyfile - command: - - keep-client - - start - args: - - --testnet - - --ethereum.url - - $(ETH_WS_URL) - - --ethereum.keyFile - - /mnt/keep-client/keyfile/account-8-keyfile - - --bitcoin.electrum.url - - $(ELECTRUM_TCP_URL) - - --storage.dir - - /mnt/keep-client/data - - --network.port - - "3919" - - --clientInfo.port - - "9601" - - --tbtc.keyGenerationConcurrency - - "2" - initContainers: - - name: initcontainer-beacon - image: gcr.io/keep-test-f3e0/keep-random-beacon-hardhat:latest - imagePullPolicy: Always - env: - - name: CHAIN_API_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: http-url - - name: CONTRACT_OWNER_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-account-privatekeys - key: account-8 - - name: ACCOUNTS_PRIVATE_KEYS - value: $(CONTRACT_OWNER_ETH_PRIVATE_KEY),$(KEEP_CLIENT_ETH_PRIVATE_KEY) - - name: KEEP_CLIENT_ETH_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-account-info - key: account-8-address - args: - - initialize - - --network - - sepolia - - --owner - - $(KEEP_CLIENT_ETH_ADDRESS) - - --provider - - $(KEEP_CLIENT_ETH_ADDRESS) - - --operator - - $(KEEP_CLIENT_ETH_ADDRESS) - - --amount - - "800000" - - --authorization - - "800000" - - name: initcontainer-ecdsa - image: gcr.io/keep-test-f3e0/keep-ecdsa-hardhat:latest - imagePullPolicy: Always - env: - - name: CHAIN_API_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: http-url - - name: CONTRACT_OWNER_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-account-privatekeys - key: account-8 - - name: ACCOUNTS_PRIVATE_KEYS - value: $(CONTRACT_OWNER_ETH_PRIVATE_KEY),$(KEEP_CLIENT_ETH_PRIVATE_KEY) - - name: KEEP_CLIENT_ETH_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-account-info - key: account-8-address - args: - - initialize - - --network - - sepolia - - --owner - - $(KEEP_CLIENT_ETH_ADDRESS) - - --provider - - $(KEEP_CLIENT_ETH_ADDRESS) - - --operator - - $(KEEP_CLIENT_ETH_ADDRESS) - - --amount - - "800000" - - --authorization - - "800000" ---- -apiVersion: v1 -kind: Service -metadata: - name: keep-client-8 - namespace: default - labels: - app: keep - type: client - id: "8" - network: sepolia -spec: - type: LoadBalancer - ports: - - name: network - port: 3919 - targetPort: network - - name: client-info - port: 9601 - targetPort: client-info - selector: - app: keep - type: client - id: "8" - network: sepolia - loadBalancerIP: null ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: keep-client-9 - namespace: default - labels: - app: keep - type: client - id: "9" - network: sepolia -spec: - replicas: 1 - selector: - matchLabels: - app: keep - type: client - id: "9" - network: sepolia - serviceName: keep-client-9 - volumeClaimTemplates: - - metadata: - name: keep-client-data - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 4096Mi - template: - metadata: - labels: - app: keep - type: client - id: "9" - network: sepolia - spec: - volumes: - - name: keep-client-data - persistentVolumeClaim: - claimName: keep-client-data - - name: eth-account-keyfile - configMap: - name: eth-account-info - items: - - key: account-9-keyfile - path: account-9-keyfile - containers: - - name: keep-client - image: gcr.io/keep-test-f3e0/keep-client:latest - imagePullPolicy: Always - resources: - requests: - cpu: 1500m - memory: 512M - ports: - - name: network - containerPort: 3919 - - name: client-info - containerPort: 9601 - env: - - name: KEEP_ETHEREUM_PASSWORD - valueFrom: - secretKeyRef: - name: eth-account-passphrases - key: account-9 - - name: ETH_WS_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: ws-url - envFrom: - - configMapRef: - name: keep-client-config - volumeMounts: - - name: keep-client-data - mountPath: /mnt/keep-client/data - - name: eth-account-keyfile - mountPath: /mnt/keep-client/keyfile - command: - - keep-client - - start - args: - - --testnet - - --ethereum.url - - $(ETH_WS_URL) - - --ethereum.keyFile - - /mnt/keep-client/keyfile/account-9-keyfile - - --bitcoin.electrum.url - - $(ELECTRUM_TCP_URL) - - --storage.dir - - /mnt/keep-client/data - - --network.port - - "3919" - - --clientInfo.port - - "9601" - - --tbtc.keyGenerationConcurrency - - "2" - initContainers: - - name: initcontainer-beacon - image: gcr.io/keep-test-f3e0/keep-random-beacon-hardhat:latest - imagePullPolicy: Always - env: - - name: CHAIN_API_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: http-url - - name: CONTRACT_OWNER_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-account-privatekeys - key: account-9 - - name: ACCOUNTS_PRIVATE_KEYS - value: $(CONTRACT_OWNER_ETH_PRIVATE_KEY),$(KEEP_CLIENT_ETH_PRIVATE_KEY) - - name: KEEP_CLIENT_ETH_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-account-info - key: account-9-address - args: - - initialize - - --network - - sepolia - - --owner - - $(KEEP_CLIENT_ETH_ADDRESS) - - --provider - - $(KEEP_CLIENT_ETH_ADDRESS) - - --operator - - $(KEEP_CLIENT_ETH_ADDRESS) - - --amount - - "800000" - - --authorization - - "800000" - - name: initcontainer-ecdsa - image: gcr.io/keep-test-f3e0/keep-ecdsa-hardhat:latest - imagePullPolicy: Always - env: - - name: CHAIN_API_URL - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: http-url - - name: CONTRACT_OWNER_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-network-sepolia - key: contract-owner-eth-account-private-key - - name: KEEP_CLIENT_ETH_PRIVATE_KEY - valueFrom: - secretKeyRef: - name: eth-account-privatekeys - key: account-9 - - name: ACCOUNTS_PRIVATE_KEYS - value: $(CONTRACT_OWNER_ETH_PRIVATE_KEY),$(KEEP_CLIENT_ETH_PRIVATE_KEY) - - name: KEEP_CLIENT_ETH_ADDRESS - valueFrom: - configMapKeyRef: - name: eth-account-info - key: account-9-address - args: - - initialize - - --network - - sepolia - - --owner - - $(KEEP_CLIENT_ETH_ADDRESS) - - --provider - - $(KEEP_CLIENT_ETH_ADDRESS) - - --operator - - $(KEEP_CLIENT_ETH_ADDRESS) - - --amount - - "800000" - - --authorization - - "800000" ---- -apiVersion: v1 -kind: Service -metadata: - name: keep-client-9 - namespace: default - labels: - app: keep - type: client - id: "9" - network: sepolia -spec: - type: LoadBalancer - ports: - - name: network - port: 3919 - targetPort: network - - name: client-info - port: 9601 - targetPort: client-info - selector: - app: keep - type: client - id: "9" - network: sepolia - loadBalancerIP: null diff --git a/infrastructure/kube/keep-test/keep-maintainer/kustomization.yaml b/infrastructure/kube/keep-test/keep-maintainer/kustomization.yaml deleted file mode 100644 index 59ad3afb84..0000000000 --- a/infrastructure/kube/keep-test/keep-maintainer/kustomization.yaml +++ /dev/null @@ -1,55 +0,0 @@ -resources: - - ../../templates/keep-maintainer - -namespace: default - -commonLabels: - app: keep-maintainer - # The current setup runs only the spv module as a workaround - # for reasons mentioned in `patches` property below. - type: all - network: sepolia - -images: - # Special maintainer version working with the modified version of LightRelay - # contract (SepoliaLightRelay). Source code lives in the `keep-maintainer-testnet` - # branch of the `keep-network/keep-core` repository. - - name: keep-maintainer - newName: gcr.io/keep-test-f3e0/keep-maintainer - newTag: latest - -configMapGenerator: - - name: keep-maintainer-config - behavior: merge - literals: - - network=testnet - - electrum-api-url=ws://electrumx.bitcoin-testnet:8080 - - redemption-request-amount-limit=0 # Use the default value - files: - - .secret/keep-maintainer-keyfile - -secretGenerator: - - name: keep-maintainer-eth-account-password - files: - - .secret/keep-maintainer-password - -patches: - # Testnet's maintainer shouldn't run `--bitcoinDifficulty` module, as the testnet - # uses modified version of LightRelay contract (SepoliaLightRelay) that doesn't - # require the bitcoin difficulty to be submitted. This patch defines manually - # which modules should be started. - - target: - kind: StatefulSet - name: keep-maintainer - patch: |- - - op: add - path: /spec/template/spec/containers/0/args/- - value: --spv - - op: replace - path: /spec/template/spec/containers/0/env/0/valueFrom/secretKeyRef/name - value: eth-network-sepolia - -generatorOptions: - disableNameSuffixHash: true - annotations: - note: generated diff --git a/infrastructure/kube/keep-test/monitoring/README.adoc b/infrastructure/kube/keep-test/monitoring/README.adoc deleted file mode 100644 index 98df5cb4b7..0000000000 --- a/infrastructure/kube/keep-test/monitoring/README.adoc +++ /dev/null @@ -1,399 +0,0 @@ -:icons: font -:toc: left - -ifdef::env-github[] -:tip-caption: :bulb: -:note-caption: :information_source: -:important-caption: :heavy_exclamation_mark: -:caution-caption: :fire: -:warning-caption: :warning: -endif::[] - -# Monitoring - -## Components - -The monitoring stack has the following components: - -1. <> -2. <> -3. <> - -[ditaa] ----- - +--------+ +--------+ +--------+ +--------+ - | Node | | Node | | Node | | Node | - +--------+ +--------+ +--------+ +--------+ - ^ ^ ^ ^ - | | | | - +--------------------------------------------- - | - | -+--------------+ +--------------+ +--------------+ -| | | | | | -| Prometheus |<-------| Trickster |<-------| Grafana | -| | | | | | -+--------------+ +--------------+ +--------------+ ----- - -## Namespace - -Kubernetes monitoring resources are configured in `monitoring` namespace. - -To create the namespace execute: - -```bash -kubectl create namespace monitoring -``` - -TIP: To easily switch between namespaces use -link:https://github.com/ahmetb/kubectx[`kubens` command]: -`kubens monitoring`. - -## Storage Class - -To define a Storage Class used by the Persistent Volume Claims execute: - -```bash -kubectl apply -f storage-class.yaml -``` - -[#prometheus] -## Prometheus - -Prometheus is used to collect metrics from the endpoints. - -### Cluster Role - -To let the Prometheus monitor Kubernetes cluster resources a Cluster Role has to -be created: - -```bash -kubectl create -f prometheus-cluster-role.yaml -``` - -NOTE: This step is necessary only if the Prometheus instance should scrape the -endpoints discovered in the Kubernetes cluster. It may not be necessary for -the production, where Keep Network Nodes will be discovered with -<> tool. - -TIP: In case of permissions issues please refer to the <> -section. - -[#cluster-role-binding] -#### Cluster Role Binding - -Additional Cluster Role Binding may be required for your user to create -a Cluster Role. It can be done by the Owner in the GCP IAM or by executing a -command: - -```bash -ACCOUNT=$(gcloud info --format='value(config.account)') -kubectl create clusterrolebinding owner-cluster-admin-binding \ - --clusterrole cluster-admin \ - --user $ACCOUNT -``` - -### Config Map - -Prometheus configuration files are held in a Config Map that is generated with <> tool. -The files included in the Config Map are: - -- link:prometheus/config/config.yaml[`config.yaml`] is a link:https://prometheus.io/docs/prometheus/latest/configuration/configuration/[Prometheus configuration file], -- link:prometheus/config/external-clients-targets.yaml[`external-clients-targets.yaml`] -is a list of endpoints to monitor (see: <> section), -- `rules.yaml` is a link:https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/#configuring-rules[Prometheus rules configuration] file. - -By externalizing Prometheus configuration to a Config Map, there is no need to build Prometheus image whenever it needs configuration amendments. Updating the Config Map -and restarting the Prometheus pod is enough to reconfigure Prometheus. - -NOTE: To apply the configuration to the cluster please see <> -section. - -### Persistent Volume Claim - -Prometheus stores data in a Persistent Volume Claim configured in a -link:prometheus/prometheus-pvc.yaml[prometheus-pvc.yaml] file. - -NOTE: To apply the configuration to the cluster please see <> -section. - -### Deployment - -Prometheus instance is configured as a Deployment in a -link:prometheus/prometheus-deployment.yaml[prometheus-deployment.yaml] file. - -The configuration uses Config Map resources and Persistent Volume claim described -in the previous sections. - -NOTE: To apply the configuration to the cluster please see <> -section. - -### Service - -Prometheus is exposed as a Service configured in -link:prometheus/prometheus-service.yaml[prometheus-service.yaml] file. - -NOTE: To apply the configuration to the cluster please see <> -section. - -The service will be available under http://prometheus.monitoring.svc.cluster.local. - -The FQDN was resolved automatically from the service configuration by `kube-dns`: - -```yaml -metadata: - name: prometheus - namespace: monitoring -... -spec: - ports: - - port: 8080 -``` - -NOTE: To access the cluster you may need a VPN connection to the `keep-test` network. - -### Health Check - -To verify health of the service open the following website: -http://prometheus.monitoring.svc.cluster.local:9090/prometheus/-/healthy - -Read more about health checks in the link:https://prometheus.io/docs/prometheus/latest/management_api/[Prometheus documentation]. - -### Keep Nodes Discovery - -There are three scrape jobs configured for Prometheus: - -[#keep-discovered-nodes] -#### keep-discovered-nodes - -The nodes to monitor are discovered with -link:https://github.com/keep-network/prometheus-sd[Prometheus Custom Service Discovery]. - -[#keep-external-nodes] -#### keep-external-nodes - -The nodes to monitor are configured in a fixed: `external-clients-targets.yaml`. - -#### keep-internal-nodes - -The nodes to monitor are resolved from Kubernetes' services labeled `app=keep`. - -[#trickster] -## Trickster - -link:https://github.com/trickstercache/trickster[Trickster] is used as a caching-proxy between Grafana and Prometheus. - -Queries to metrics should be made to the Trickster instance instead of the Prometheus. Trickster will obtain data from Prometheus and cache the results for future usage. - -### Config Map - -Trickster configuration file is held in a Config Map that is generated with <> tool. -The files included in the Config Map are: - -- link:trickster/config/trickster.yaml[`trickster.yaml`] is a configuration file, based on the link:https://github.com/trickstercache/trickster/blob/main/examples/conf/example.full.yaml[example], - -NOTE: To apply the configuration to the cluster please see <> -section. - -### Deployment - -Trickster instance is configured as a Deployment in a -link:trickster/trickster-deployment.yaml[trickster-deployment.yaml] file. - -The configuration uses Config Map resources described -in the previous sections. - -NOTE: To apply the configuration to the cluster please see <> -section. - -### Service - -Trickster is exposed as a Service configured in -link:trickster/trickster-service.yaml[trickster-service.yaml] file. - -NOTE: To apply the configuration to the cluster please see <> -section. - -The service will be available under http://trickster.monitoring.svc.cluster.local. - -NOTE: To access the cluster you may need a VPN connection to the `keep-test` network. - -### Health Check - -To verify health of the service open the following website: -http://trickster.monitoring.svc.cluster.local:8480/trickster/ping - -To verify Trickster's connection with Prometheus open the following website: -http://trickster.monitoring.svc.cluster.local:8481/trickster/health - -Read more about health checks in the link:https://github.com/trickstercache/trickster/blob/main/docs/health.md[Trickster documentation]. - -[#grafana] -## Grafana - -### Config Map - -Grafana configuration files are held in Config Maps that are generated with <> tool. - -NOTE: To apply the configuration to the cluster please see <> -section. - -#### Config - -The files included in the `grafana-config` Config Map are: - -- link:grafana/datasources.yaml[`datasources.yaml`] defines a reference to the -Prometheus instance, - -- link:grafana/dashboards.yaml[`dashboards.yaml`] defines path to Grafana -Dashboards configuration. - -#### Dashboards - -The files included in the `grafana-dashboards` Config Map are Grafana -link:grafana/dashboards[`dashboards`] for data presentation. - -### Persistent Volume Claim - -Grafana stores data in a Persistent Volume Claim configured in a -link:grafana/grafana-pvc.yaml[grafana-pvc.yaml] file. - -NOTE: To apply the configuration to the cluster please see <> -section. - -#### Deployment - -Grafana instance is configured as a Deployment in a -link:grafana/grafana-deployment.yaml[grafana-deployment.yaml] file. - -The configuration uses Config Map resources and Persistent Volume claim described -in the previous sections. - -NOTE: To apply the configuration to the cluster please see <> -section. - -### Service - -Grafana is exposed as a Service configured in -link:grafana/grafana-service.yaml[grafana-service.yaml] file. - -NOTE: To apply the configuration to the cluster please see <> -section. - -The service will be available under http://grafana.monitoring.svc.cluster.local:3000/. - -[#grafana-google] -### Google OAuth2 - -Grafana is integrated with Google OAuth2 authentication. - -You can login to the Grafana with a Google account under any of the following domains: - -- `threshold.network`, -- `keep.network`, -- `thesis.co`. - -Read more about configuration in the link:https://grafana.com/docs/grafana/latest/setup-grafana/configure-security/configure-authentication/google/[Grafana documentation]. - -## Kubernetes - -[#kustomization] -### Kustomization - -Kubernetes resources configuration uses link:https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization[Kustomization] to set common fields and -generate Config Maps. - -[#kustomization-prometheus] -#### Prometheus - -Configuration is stored in link:./prometheus/kustomization.yaml[prometheus/kustomization.yaml] -file. - -To preview generated config run: `kubectl kustomize prometheus/` - -To see a configuration diff run: `kubectl diff -k prometheus/` - -To apply the configuration run: `kubectl apply -k prometheus/` - -[#kustomization-trickster] -#### Trickster - -Configuration is stored in link:./trickster/kustomization.yaml[trickster/kustomization.yaml] -file. - -To preview generated config run: `kubectl kustomize trickster/` - -To see a configuration diff run: `kubectl diff -k trickster/` - -To apply the configuration run: `kubectl apply -k trickster/` - -[#kustomization-grafana] -#### Grafana - -Configuration is stored in link:./grafana/kustomization.yaml[grafana/kustomization.yaml] file. - -To preview generated config run `kubectl kustomize grafana/` - -To see a configuration diff run: `kubectl diff -k grafana/` - -To apply the configuration run `kubectl apply -k grafana/` - -## Ingress - -Ingress is used to expose the services to the internet. As an Ingress controller -we use Google Kubernetes Engine (GKE) built-in and managed Ingress controller -called link:https://cloud.google.com/kubernetes-engine/docs/concepts/ingress[GKE Ingress]. - -Following resources are exposed publicly: - -https://monitoring.test.threshold.network/grafana - -https://monitoring.test.threshold.network/prometheus (via Trickster) - -### Configuration - -To configure the Ingress following steps have to be executed: - -1. Create Static IP for the Monitoring Ingress: -+ -```bash -gcloud compute addresses create keep-test-monitoring-ingress --global -``` - -2. Create a Cloud DNS entry to point to the IP created in the previous step (`gcloud compute addresses list`). -Follow the -link:https://cloud.google.com/dns/docs/set-up-dns-records-domain-name#create_a_record_to_point_the_domain_to_an_external_ip_address[Google Cloud documentation]. - -3. Deploy the Ingress configuration: -+ -```bash -kubectl apply -f monitoring-ingress.yaml -``` - -## Public Dashboard - -By default Grafana requires login to view the dashboards. We enabled this possibility -for Google accounts in selected domains (see: <> section). -To share the monitoring dashboard broadly we configured a -link:https://grafana.com/docs/grafana/latest/dashboards/dashboard-public/[Public Dashboard]. - -The dashboard is exposed publicly with an additional Google Cloud Load Balancer -and a redirection under: - -https://public.monitoring.test.threshold.network - -## Resources - -This configuration was inspired by this link:https://devopscube.com/setup-prometheus-monitoring-on-kubernetes/[tutorial]. - -Google Cloud Documentation: - -- link:https://cloud.google.com/kubernetes-engine/docs/concepts/ingress[GKE Ingress for HTTP(S) Load Balancing] -- link:https://cloud.google.com/dns/docs/set-up-dns-records-domain-name[Set up DNS records for a domain name with Cloud DNS] -- link:https://cloud.google.com/kubernetes-engine/docs/how-to/managed-certs#gcloud[Using Google-managed SSL certificates] - -// TODO: -// - [ ] Revisit kubernetes scrape configuration in Prometheus' `config.yaml` - -// remove not needed entries -// - [ ] Add Grafana dashboard for Kubernetes resources monitoring diff --git a/infrastructure/kube/keep-test/monitoring/grafana/config/dashboards.yaml b/infrastructure/kube/keep-test/monitoring/grafana/config/dashboards.yaml deleted file mode 100644 index 54bf65f56f..0000000000 --- a/infrastructure/kube/keep-test/monitoring/grafana/config/dashboards.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: 1 -providers: - - name: dashboards-provider - type: file - disableDeletion: true - updateIntervalSeconds: 10 - allowUiUpdates: true - options: - path: "/var/lib/grafana/dashboards" - foldersFromFilesStructure: true diff --git a/infrastructure/kube/keep-test/monitoring/grafana/config/datasources.yaml b/infrastructure/kube/keep-test/monitoring/grafana/config/datasources.yaml deleted file mode 100644 index bb65f9e0fd..0000000000 --- a/infrastructure/kube/keep-test/monitoring/grafana/config/datasources.yaml +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: 1 -datasources: - - name: Trickster - type: prometheus - access: proxy - editable: true - orgId: 1 - url: http://trickster:8480/prometheus - version: 1 - isDefault: true - - - name: Prometheus - type: prometheus - access: proxy - editable: true - orgId: 1 - url: http://prometheus:9090/prometheus - version: 1 diff --git a/infrastructure/kube/keep-test/monitoring/grafana/config/grafana.ini b/infrastructure/kube/keep-test/monitoring/grafana/config/grafana.ini deleted file mode 100644 index 60a3e1f036..0000000000 --- a/infrastructure/kube/keep-test/monitoring/grafana/config/grafana.ini +++ /dev/null @@ -1,19 +0,0 @@ -[auth.google] -enabled = true -scopes = https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email -auth_url = https://accounts.google.com/o/oauth2/auth -token_url = https://accounts.google.com/o/oauth2/token -allow_sign_up = true - -[auth.github] -enabled = true -allow_sign_up = true -scopes = user:email,read:org -auth_url = https://github.com/login/oauth/authorize -token_url = https://github.com/login/oauth/access_token -api_url = https://api.github.com/user -allowed_organizations = keep-network threshold-network -role_attribute_path = contains(groups[*], '@keep-network/developers') && 'Editor' || 'Viewer' - -[feature_toggles] -publicDashboards = true diff --git a/infrastructure/kube/keep-test/monitoring/grafana/dashboards/infrastructure/kubernetes-deployments.json b/infrastructure/kube/keep-test/monitoring/grafana/dashboards/infrastructure/kubernetes-deployments.json deleted file mode 100644 index 9549c0bcc0..0000000000 --- a/infrastructure/kube/keep-test/monitoring/grafana/dashboards/infrastructure/kubernetes-deployments.json +++ /dev/null @@ -1,1387 +0,0 @@ -{ - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "target": { - "limit": 100, - "matchAny": false, - "tags": [], - "type": "dashboard" - }, - "type": "dashboard" - } - ] - }, - "description": "Monitors Kubernetes deployments in cluster using Prometheus. Shows overall cluster CPU / Memory of deployments, replicas in each deployment. Uses Kube state metrics and cAdvisor metrics (741)", - "editable": true, - "fiscalYearStartMonth": 0, - "gnetId": 8588, - "graphTooltip": 0, - "id": 2, - "links": [], - "liveNow": false, - "panels": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "max": 100, - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(50, 172, 45, 0.97)", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 65 - }, - { - "color": "rgba(245, 54, 54, 0.9)", - "value": 90 - } - ] - }, - "unit": "percent" - }, - "overrides": [] - }, - "gridPos": { - "h": 5, - "w": 8, - "x": 0, - "y": 0 - }, - "id": 1, - "links": [], - "maxDataPoints": 100, - "options": { - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "showThresholdLabels": false, - "showThresholdMarkers": true - }, - "pluginVersion": "9.1.8", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum (container_memory_working_set_bytes{pod_name=~\"^$Deployment$Statefulset$Daemonset.*$\", kubernetes_io_hostname=~\"^$Node$\", pod_name!=\"\"}) / sum (kube_node_status_allocatable_memory_bytes{node=~\"^$Node.*$\"}) * 100", - "format": "time_series", - "interval": "10s", - "intervalFactor": 1, - "refId": "A", - "step": 900 - } - ], - "title": "Deployment memory usage", - "type": "gauge" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 2, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "max": 100, - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(50, 172, 45, 0.97)", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 65 - }, - { - "color": "rgba(245, 54, 54, 0.9)", - "value": 90 - } - ] - }, - "unit": "percent" - }, - "overrides": [] - }, - "gridPos": { - "h": 5, - "w": 8, - "x": 8, - "y": 0 - }, - "id": 2, - "links": [], - "maxDataPoints": 100, - "options": { - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "showThresholdLabels": false, - "showThresholdMarkers": true - }, - "pluginVersion": "9.1.8", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "expr": "sum (rate (container_cpu_usage_seconds_total{pod_name=~\"^$Deployment$Statefulset$Daemonset.*$\", kubernetes_io_hostname=~\"^$Node$\"}[2m])) / sum (machine_cpu_cores{kubernetes_io_hostname=~\"^$Node$\"}) * 100", - "format": "time_series", - "interval": "10s", - "intervalFactor": 1, - "refId": "A", - "step": 900 - } - ], - "title": "Deployment CPU usage", - "type": "gauge" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "max": 100, - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(50, 172, 45, 0.97)", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 1 - }, - { - "color": "rgba(245, 54, 54, 0.9)", - "value": 30 - } - ] - }, - "unit": "percent" - }, - "overrides": [] - }, - "gridPos": { - "h": 5, - "w": 8, - "x": 16, - "y": 0 - }, - "id": 3, - "links": [], - "maxDataPoints": 100, - "options": { - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "showThresholdLabels": false, - "showThresholdMarkers": true - }, - "pluginVersion": "9.1.8", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "(((sum(kube_deployment_status_replicas{deployment=~\".*$Deployment$Statefulset$Daemonset\"}) or vector(0)) + (sum(kube_statefulset_replicas{statefulset=~\".*$Deployment$Statefulset$Daemonset\"}) or vector(0)) + (sum(kube_daemonset_status_desired_number_scheduled{daemonset=~\".*$Deployment$Statefulset$Daemonset\"}) or vector(0))) - ((sum(kube_deployment_status_replicas_available{deployment=~\".*$Deployment$Statefulset$Daemonset\"}) or vector(0)) + (sum(kube_statefulset_status_replicas{statefulset=~\".*$Deployment$Statefulset$Daemonset\"}) or vector(0)) + (sum(kube_daemonset_status_number_ready{daemonset=~\".*$Deployment$Statefulset$Daemonset\"}) or vector(0)))) / ((sum(kube_deployment_status_replicas{deployment=~\".*$Deployment$Statefulset$Daemonset\"}) or vector(0)) + (sum(kube_statefulset_replicas{statefulset=~\".*$Deployment$Statefulset$Daemonset\"}) or vector(0)) + (sum(kube_daemonset_status_desired_number_scheduled{daemonset=~\".*$Deployment$Statefulset$Daemonset\"}) or vector(0))) * 100", - "format": "time_series", - "intervalFactor": 2, - "refId": "A", - "step": 1800 - } - ], - "title": "Unavailable Replicas", - "type": "gauge" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "bytes" - }, - "overrides": [] - }, - "gridPos": { - "h": 3, - "w": 4, - "x": 0, - "y": 5 - }, - "id": 4, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "none", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.1.8", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum (container_memory_working_set_bytes{pod_name=~\"^$Deployment$Statefulset$Daemonset.*$\", kubernetes_io_hostname=~\"^$Node$\", pod_name!=\"\"})", - "format": "time_series", - "intervalFactor": 2, - "refId": "A", - "step": 1800 - } - ], - "title": "Used", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "bytes" - }, - "overrides": [] - }, - "gridPos": { - "h": 3, - "w": 4, - "x": 4, - "y": 5 - }, - "id": 5, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "none", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.1.8", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum (kube_node_status_allocatable_memory_bytes{node=~\"^$Node.*$\"})", - "format": "time_series", - "intervalFactor": 2, - "refId": "A", - "step": 1800 - } - ], - "title": "Total", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 3, - "w": 4, - "x": 8, - "y": 5 - }, - "id": 6, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "none", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.1.8", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum (rate (container_cpu_usage_seconds_total{pod_name=~\"^$Deployment$Statefulset$Daemonset.*$\", kubernetes_io_hostname=~\"^$Node$\"}[1m]))", - "format": "time_series", - "intervalFactor": 2, - "refId": "A", - "step": 1800 - } - ], - "title": "Used", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 3, - "w": 4, - "x": 12, - "y": 5 - }, - "id": 7, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "none", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "mean" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.1.8", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum (machine_cpu_cores{kubernetes_io_hostname=~\"^$Node$\"})", - "intervalFactor": 2, - "refId": "A", - "step": 1800 - } - ], - "title": "Total", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 3, - "w": 4, - "x": 16, - "y": 5 - }, - "id": 8, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "none", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.1.8", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "(sum(kube_deployment_status_replicas_available{deployment=~\".*$Deployment$Statefulset$Daemonset\"}) or vector(0)) + (sum(kube_statefulset_status_replicas{statefulset=~\".*$Deployment$Statefulset$Daemonset\"}) or vector(0)) + (sum(kube_daemonset_status_number_ready{daemonset=~\".*$Deployment$Statefulset$Daemonset\"}) or vector(0))", - "format": "time_series", - "intervalFactor": 2, - "refId": "A", - "step": 1800 - } - ], - "title": "Available (cluster)", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 3, - "w": 4, - "x": 20, - "y": 5 - }, - "id": 9, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "none", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.1.8", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "(sum(kube_deployment_status_replicas{deployment=~\".*$Deployment$Statefulset$Daemonset\"}) or vector(0)) + (sum(kube_statefulset_replicas{statefulset=~\".*$Deployment$Statefulset$Daemonset\"}) or vector(0)) + (sum(kube_daemonset_status_desired_number_scheduled{daemonset=~\".*$Deployment$Statefulset$Daemonset\"}) or vector(0))", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ $Daemonset }}", - "refId": "A", - "step": 1800 - } - ], - "title": "Total (cluster)", - "type": "stat" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "decimals": 3, - "editable": true, - "error": false, - "fill": 0, - "fillGradient": 0, - "grid": {}, - "gridPos": { - "h": 11, - "w": 24, - "x": 0, - "y": 8 - }, - "height": "", - "hiddenSeries": false, - "id": 10, - "legend": { - "alignAsTable": true, - "avg": false, - "current": true, - "hideEmpty": false, - "hideZero": false, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "sort": "current", - "sortDesc": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.1.8", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [ - { - "alias": "/avlbl.*/", - "yaxis": 2 - } - ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum (rate (container_cpu_usage_seconds_total{image!=\"\",name=~\"^k8s_.*\",io_kubernetes_container_name!=\"POD\",pod_name=~\"^$Deployment$Statefulset$Daemonset.*$\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (pod_name,kubernetes_io_hostname)", - "format": "time_series", - "hide": false, - "interval": "10s", - "intervalFactor": 1, - "legendFormat": "real: {{ kubernetes_io_hostname }} | {{ pod_name }} ", - "metric": "container_cpu", - "refId": "A", - "step": 60 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum (kube_pod_container_resource_requests_cpu_cores{pod=~\"^$Deployment$Statefulset$Daemonset.*$\",node=~\"^$Node$\"}) by (pod,node)", - "format": "time_series", - "hide": false, - "intervalFactor": 2, - "legendFormat": "rqst: {{ node }} | {{ pod }}", - "refId": "B", - "step": 120 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum ((kube_node_status_allocatable_cpu_cores{node=~\"^$Node$\"})) by (node)", - "format": "time_series", - "hide": true, - "intervalFactor": 2, - "legendFormat": "avlbl: {{ node }}", - "refId": "C", - "step": 30 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "CPU usage", - "tooltip": { - "msResolution": true, - "shared": true, - "sort": 2, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": "cores", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "decimals": 2, - "editable": true, - "error": false, - "fill": 0, - "fillGradient": 0, - "grid": {}, - "gridPos": { - "h": 13, - "w": 24, - "x": 0, - "y": 19 - }, - "hiddenSeries": false, - "id": 11, - "legend": { - "alignAsTable": true, - "avg": false, - "current": true, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "sort": "current", - "sortDesc": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.1.8", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [ - { - "alias": "/^avlbl.*$/", - "yaxis": 2 - } - ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum (container_memory_working_set_bytes{id!=\"/\",pod_name=~\"^$Deployment$Statefulset$Daemonset.*$\",kubernetes_io_hostname=~\"^$Node$\"}) by (pod_name,kubernetes_io_hostname)", - "format": "time_series", - "hide": false, - "interval": "10s", - "intervalFactor": 1, - "legendFormat": "real: {{kubernetes_io_hostname }} | {{ pod_name }}", - "metric": "container_memory_usage:sort_desc", - "refId": "A", - "step": 60 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum ((kube_pod_container_resource_requests_memory_bytes{pod=~\"^$Deployment$Statefulset$Daemonset.*$\",node=~\"^$Node$\"})) by (pod,node)", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "rqst: {{ node }} | {{ pod }}", - "refId": "B", - "step": 120 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum ((kube_node_status_allocatable_memory_bytes{node=~\"^$Node$\"})) by (node)", - "format": "time_series", - "hide": true, - "intervalFactor": 2, - "legendFormat": "avlbl: {{ node }}", - "refId": "C", - "step": 30 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Memory usage", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 2, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "bytes", - "logBase": 1, - "show": true - }, - { - "format": "bytes", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 9, - "w": 24, - "x": 0, - "y": 32 - }, - "hiddenSeries": false, - "id": 12, - "legend": { - "alignAsTable": true, - "avg": false, - "current": true, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "sort": "current", - "sortDesc": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.1.8", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "expr": "100 * (kubelet_volume_stats_used_bytes{kubernetes_io_hostname=~\"^$Node$\", persistentvolumeclaim=~\".*$Deployment$Statefulset$Daemonset.*$\"} / kubelet_volume_stats_capacity_bytes{kubernetes_io_hostname=~\"^$Node$\", persistentvolumeclaim=~\".*$Deployment$Statefulset$Daemonset.*$\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ persistentvolumeclaim }} | {{ kubernetes_io_hostname }}", - "refId": "A", - "step": 120 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Disk Usage", - "tooltip": { - "shared": true, - "sort": 2, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "percent", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": false - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "decimals": 2, - "editable": true, - "error": false, - "fill": 1, - "fillGradient": 0, - "grid": {}, - "gridPos": { - "h": 13, - "w": 24, - "x": 0, - "y": 41 - }, - "hiddenSeries": false, - "id": 13, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "sort": "current", - "sortDesc": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.1.8", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum (rate (container_network_receive_bytes_total{id!=\"/\",pod_name=~\"^$Deployment$Statefulset$Daemonset.*$\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (pod_name, kubernetes_io_hostname)", - "format": "time_series", - "interval": "10s", - "intervalFactor": 1, - "legendFormat": "-> {{ kubernetes_io_hostname }} | {{ pod_name }}", - "metric": "network", - "refId": "A", - "step": 60 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "- sum( rate (container_network_transmit_bytes_total{id!=\"/\",pod_name=~\"^$Deployment$Statefulset$Daemonset.*$\",kubernetes_io_hostname=~\"^$Node$\"}[1m])) by (pod_name, kubernetes_io_hostname)", - "format": "time_series", - "interval": "10s", - "intervalFactor": 1, - "legendFormat": "<- {{ kubernetes_io_hostname }} | {{ pod_name }}", - "metric": "network", - "refId": "B", - "step": 60 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "All processes network I/O", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 2, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "Bps", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": false - } - ], - "yaxis": { - "align": false - } - } - ], - "refresh": "30s", - "schemaVersion": 37, - "style": "dark", - "tags": [ - "kubernetes", - "deployment", - "infrastructure" - ], - "templating": { - "list": [ - { - "allValue": "()", - "current": { - "selected": false, - "text": "All", - "value": "$__all" - }, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "definition": "", - "hide": 0, - "includeAll": true, - "multi": false, - "name": "Deployment", - "options": [], - "query": { - "query": "label_values(deployment)", - "refId": "prometheus-Deployment-Variable-Query" - }, - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 0, - "tagValuesQuery": "", - "tagsQuery": "", - "type": "query", - "useTags": false - }, - { - "allValue": "()", - "current": { - "selected": false, - "text": "All", - "value": "$__all" - }, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "definition": "", - "hide": 0, - "includeAll": true, - "multi": false, - "name": "Statefulset", - "options": [], - "query": { - "query": "label_values(statefulset)", - "refId": "prometheus-Statefulset-Variable-Query" - }, - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 0, - "tagValuesQuery": "", - "tagsQuery": "", - "type": "query", - "useTags": false - }, - { - "allValue": "()", - "current": { - "selected": false, - "text": "All", - "value": "$__all" - }, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "definition": "", - "hide": 0, - "includeAll": true, - "multi": false, - "name": "Daemonset", - "options": [], - "query": { - "query": "label_values(daemonset)", - "refId": "prometheus-Daemonset-Variable-Query" - }, - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 0, - "tagValuesQuery": "", - "tagsQuery": "", - "type": "query", - "useTags": false - }, - { - "allValue": ".*", - "current": { - "selected": false, - "text": "All", - "value": "$__all" - }, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "definition": "", - "hide": 0, - "includeAll": true, - "multi": false, - "name": "Node", - "options": [], - "query": { - "query": "label_values(kubernetes_io_hostname)", - "refId": "prometheus-Node-Variable-Query" - }, - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 0, - "tagValuesQuery": "", - "tagsQuery": "", - "type": "query", - "useTags": false - } - ] - }, - "time": { - "from": "now-3h", - "to": "now" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] - }, - "timezone": "browser", - "title": "Kubernetes Deployments", - "uid": "oWe9aYxmk", - "version": 2, - "weekStart": "" -} diff --git a/infrastructure/kube/keep-test/monitoring/grafana/dashboards/keep/keep-network-nodes-public.json b/infrastructure/kube/keep-test/monitoring/grafana/dashboards/keep/keep-network-nodes-public.json deleted file mode 100644 index 251faf1588..0000000000 --- a/infrastructure/kube/keep-test/monitoring/grafana/dashboards/keep/keep-network-nodes-public.json +++ /dev/null @@ -1,1032 +0,0 @@ -{ - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "grafana", - "uid": "-- Grafana --" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "target": { - "limit": 100, - "matchAny": false, - "tags": [], - "type": "dashboard" - }, - "type": "dashboard" - } - ] - }, - "description": "", - "editable": true, - "fiscalYearStartMonth": 0, - "graphTooltip": 0, - "id": 5, - "links": [], - "liveNow": false, - "panels": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "min": 0, - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "orange", - "value": 30 - }, - { - "color": "green", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 11, - "x": 0, - "y": 0 - }, - "id": 8, - "interval": "1m", - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.2.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "expr": "sum by(job) (sum by(chain_address) (up{job=\"keep-discovered-nodes\"}))", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Nodes Up", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "super-light-red", - "value": null - }, - { - "color": "super-light-yellow", - "value": 30 - }, - { - "color": "super-light-green", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 16, - "w": 13, - "x": 11, - "y": 0 - }, - "id": 3, - "interval": "1m", - "options": { - "legend": { - "calcs": [ - "last" - ], - "displayMode": "table", - "placement": "right", - "showLegend": true, - "sortBy": "Last", - "sortDesc": true - }, - "tooltip": { - "mode": "multi", - "sort": "desc" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "exemplar": false, - "expr": "min by(chain_address) (connected_wellknown_peers_count{job=\"keep-discovered-nodes\"})", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "C" - } - ], - "title": "Connected Bootstraps", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "log": 2, - "type": "log" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "area" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "orange", - "value": 100 - }, - { - "color": "light-yellow", - "value": 300 - }, - { - "color": "green", - "value": 900 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 28, - "w": 11, - "x": 0, - "y": 8 - }, - "id": 4, - "interval": "1m", - "options": { - "legend": { - "calcs": [ - "last" - ], - "displayMode": "table", - "placement": "bottom", - "showLegend": true, - "sortBy": "Last", - "sortDesc": true - }, - "tooltip": { - "mode": "multi", - "sort": "asc" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "exemplar": false, - "expr": "min by(chain_address) (tbtc_pre_params_count{job=\"keep-discovered-nodes\"})", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "C" - } - ], - "title": "TBTC PreParams Count", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "super-light-yellow", - "value": 50 - }, - { - "color": "super-light-green", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "__systemRef": "hideSeriesFrom", - "matcher": { - "id": "byNames", - "options": { - "mode": "exclude", - "names": [ - "0xDc7C1b54eB3944454dD19Bd8Ed0299F92A758B0C" - ], - "prefix": "All except:", - "readOnly": true - } - }, - "properties": [ - { - "id": "custom.hideFrom", - "value": { - "legend": false, - "tooltip": false, - "viz": true - } - } - ] - } - ] - }, - "gridPos": { - "h": 20, - "w": 13, - "x": 11, - "y": 16 - }, - "id": 2, - "interval": "1m", - "options": { - "legend": { - "calcs": [ - "last" - ], - "displayMode": "table", - "placement": "right", - "showLegend": true, - "sortBy": "Last", - "sortDesc": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "expr": "min by(chain_address) (connected_peers_count{job=\"keep-discovered-nodes\"})", - "hide": false, - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "Discovered Keep Nodes" - } - ], - "title": "Connected Peers", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "align": "auto", - "displayMode": "auto", - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 25, - "w": 11, - "x": 0, - "y": 36 - }, - "id": 10, - "options": { - "footer": { - "fields": "", - "reducer": [ - "sum" - ], - "show": false - }, - "frameIndex": 1, - "showHeader": true, - "sortBy": [ - { - "desc": false, - "displayName": "chain_address" - } - ] - }, - "pluginVersion": "9.2.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "exemplar": false, - "expr": "up{job=\"keep-discovered-nodes\"}", - "format": "table", - "hide": false, - "instant": true, - "interval": "", - "legendFormat": "__auto", - "range": false, - "refId": "Nodes" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "exemplar": false, - "expr": "client_info{job=\"keep-discovered-nodes\"}", - "format": "table", - "hide": false, - "instant": true, - "legendFormat": "", - "range": false, - "refId": "Client Info" - } - ], - "title": "Client Versions", - "transformations": [ - { - "id": "seriesToColumns", - "options": { - "byField": "chain_address" - } - }, - { - "id": "organize", - "options": { - "excludeByName": { - "Time": true, - "Time 1": false, - "Time 2": true, - "Value": true, - "Value #A": true, - "Value #B": true, - "Value #Client Info": true, - "Value #Nodes": true, - "__name__": true, - "__name__ 1": true, - "__name__ 2": true, - "app": true, - "controller_revision_hash": true, - "id": true, - "instance": false, - "instance 1": false, - "instance 2": true, - "job": true, - "job 1": true, - "job 2": true, - "kubernetes_namespace": true, - "kubernetes_pod_name": true, - "kubernetes_pod_name_monitoring": true, - "network": true, - "network_id": true, - "network_id 1": true, - "network_id 2": true, - "statefulset_kubernetes_io_pod_name": true, - "type": true - }, - "indexByName": { - "Time 1": 3, - "Time 2": 8, - "Value #Client Info": 13, - "Value #Nodes": 7, - "__name__ 1": 4, - "__name__ 2": 9, - "chain_address": 0, - "instance 1": 1, - "instance 2": 10, - "job 1": 5, - "job 2": 11, - "network_id 1": 6, - "network_id 2": 12, - "version": 2 - }, - "renameByName": { - "chain_address": "Chain Address", - "instance 1": "Instance", - "version": "Client Version" - } - } - } - ], - "type": "table" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "description": "Provides information whether the node is connected to the Bitcoin network", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [ - { - "options": { - "0": { - "index": 1, - "text": "False" - }, - "1": { - "index": 0, - "text": "True" - }, - "N/A": { - "index": 3, - "text": "False" - }, - "Null": { - "index": 2, - "text": "False" - } - }, - "type": "value" - } - ], - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "super-light-yellow", - "value": 50 - }, - { - "color": "super-light-green", - "value": 80 - } - ] - }, - "unit": "bool" - }, - "overrides": [ - { - "__systemRef": "hideSeriesFrom", - "matcher": { - "id": "byNames", - "options": { - "mode": "exclude", - "names": [ - "0xcAB2a402bAc470686d14956FB310D51BbEF9fA31" - ], - "prefix": "All except:", - "readOnly": true - } - }, - "properties": [ - { - "id": "custom.hideFrom", - "value": { - "legend": false, - "tooltip": false, - "viz": true - } - } - ] - } - ] - }, - "gridPos": { - "h": 10, - "w": 13, - "x": 11, - "y": 36 - }, - "id": 11, - "interval": "1m", - "options": { - "legend": { - "calcs": [ - "last" - ], - "displayMode": "table", - "placement": "right", - "showLegend": true, - "sortBy": "Last", - "sortDesc": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "expr": "min by(chain_address) (btc_connectivity{job=\"keep-discovered-nodes\"})", - "format": "heatmap", - "hide": false, - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "Discovered Keep Nodes" - } - ], - "title": "BTC Connectivity", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "description": "Provides information whether the node is connected to the Ethereum network", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [ - { - "options": { - "0": { - "index": 1, - "text": "False" - }, - "1": { - "index": 0, - "text": "True" - }, - "N/A": { - "index": 3, - "text": "False" - }, - "Null": { - "index": 2, - "text": "False" - } - }, - "type": "value" - } - ], - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "super-light-yellow", - "value": 50 - }, - { - "color": "super-light-green", - "value": 80 - } - ] - }, - "unit": "bool" - }, - "overrides": [ - { - "__systemRef": "hideSeriesFrom", - "matcher": { - "id": "byNames", - "options": { - "mode": "exclude", - "names": [ - "0x794f8F4F12996632781c7526054c448797acF41b" - ], - "prefix": "All except:", - "readOnly": true - } - }, - "properties": [ - { - "id": "custom.hideFrom", - "value": { - "legend": false, - "tooltip": false, - "viz": true - } - } - ] - } - ] - }, - "gridPos": { - "h": 10, - "w": 13, - "x": 11, - "y": 46 - }, - "id": 12, - "interval": "1m", - "options": { - "legend": { - "calcs": [ - "last" - ], - "displayMode": "table", - "placement": "right", - "showLegend": true, - "sortBy": "Last", - "sortDesc": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "expr": "min by(chain_address) (eth_connectivity{job=\"keep-discovered-nodes\"})", - "format": "heatmap", - "hide": false, - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "Discovered Keep Nodes" - } - ], - "title": "ETH Connectivity", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "fillOpacity": 70, - "lineWidth": 0, - "spanNulls": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 25, - "w": 13, - "x": 11, - "y": 56 - }, - "id": 6, - "options": { - "alignValue": "left", - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "mergeValues": true, - "rowHeight": 0.9, - "showValue": "auto", - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "9.1.2", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "expr": "min by(chain_address) (up{job=\"keep-discovered-nodes\"})", - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "A" - } - ], - "title": "Uptime (experimental)", - "type": "state-timeline" - } - ], - "refresh": false, - "schemaVersion": 37, - "style": "dark", - "tags": [ - "tbtc", - "keep", - "public" - ], - "templating": { - "list": [] - }, - "time": { - "from": "now-7d", - "to": "now" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ] - }, - "timezone": "", - "title": "Keep Nodes (Public)", - "uid": "hhDyYDI4z", - "version": 24, - "weekStart": "" -} diff --git a/infrastructure/kube/keep-test/monitoring/grafana/dashboards/keep/keep-network-nodes.json b/infrastructure/kube/keep-test/monitoring/grafana/dashboards/keep/keep-network-nodes.json deleted file mode 100644 index a03d2e8de7..0000000000 --- a/infrastructure/kube/keep-test/monitoring/grafana/dashboards/keep/keep-network-nodes.json +++ /dev/null @@ -1,1272 +0,0 @@ -{ - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "grafana", - "uid": "-- Grafana --" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "target": { - "limit": 100, - "matchAny": false, - "tags": [], - "type": "dashboard" - }, - "type": "dashboard" - } - ] - }, - "description": "", - "editable": true, - "fiscalYearStartMonth": 0, - "graphTooltip": 0, - "id": 1, - "links": [], - "liveNow": false, - "panels": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "min": 0, - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "orange", - "value": 30 - }, - { - "color": "green", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 11, - "x": 0, - "y": 0 - }, - "id": 8, - "interval": "1m", - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.2.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "exemplar": false, - "expr": "sum by(job) (sum by(chain_address) (up{job=\"keep-discovered-nodes\"}))", - "format": "time_series", - "instant": false, - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Nodes Up", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "super-light-red", - "value": null - }, - { - "color": "super-light-yellow", - "value": 30 - }, - { - "color": "super-light-green", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 16, - "w": 13, - "x": 11, - "y": 0 - }, - "id": 3, - "interval": "1m", - "options": { - "legend": { - "calcs": [ - "last" - ], - "displayMode": "table", - "placement": "right", - "showLegend": true, - "sortBy": "Last", - "sortDesc": true - }, - "tooltip": { - "mode": "multi", - "sort": "desc" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "exemplar": false, - "expr": "min by(chain_address) (connected_wellknown_peers_count{job=\"keep-discovered-nodes\"})", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "C" - } - ], - "title": "Connected Bootstraps", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "log": 2, - "type": "log" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "area" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "orange", - "value": 100 - }, - { - "color": "light-yellow", - "value": 300 - }, - { - "color": "green", - "value": 900 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 28, - "w": 11, - "x": 0, - "y": 8 - }, - "id": 4, - "interval": "1m", - "options": { - "legend": { - "calcs": [ - "last" - ], - "displayMode": "table", - "placement": "bottom", - "showLegend": true, - "sortBy": "Last", - "sortDesc": true - }, - "tooltip": { - "mode": "multi", - "sort": "asc" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "exemplar": false, - "expr": "min by(chain_address) (tbtc_pre_params_count{job=\"keep-discovered-nodes\"})", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "C" - } - ], - "title": "TBTC PreParams Count", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "super-light-yellow", - "value": 50 - }, - { - "color": "super-light-green", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 20, - "w": 13, - "x": 11, - "y": 16 - }, - "id": 2, - "interval": "1m", - "options": { - "legend": { - "calcs": [ - "last" - ], - "displayMode": "table", - "placement": "right", - "showLegend": true, - "sortBy": "Last", - "sortDesc": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "expr": "min by(chain_address) (connected_peers_count{job=\"keep-discovered-nodes\"})", - "hide": false, - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "Discovered Keep Nodes" - } - ], - "title": "Connected Peers", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "align": "auto", - "displayMode": "auto", - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 25, - "w": 11, - "x": 0, - "y": 36 - }, - "id": 10, - "options": { - "footer": { - "fields": "", - "reducer": [ - "sum" - ], - "show": false - }, - "frameIndex": 1, - "showHeader": true, - "sortBy": [ - { - "desc": false, - "displayName": "chain_address" - } - ] - }, - "pluginVersion": "9.2.5", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "exemplar": false, - "expr": "up{job=\"keep-discovered-nodes\"}", - "format": "table", - "hide": false, - "instant": true, - "interval": "", - "legendFormat": "__auto", - "range": false, - "refId": "Nodes" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "exemplar": false, - "expr": "client_info{job=\"keep-discovered-nodes\"}", - "format": "table", - "hide": false, - "instant": true, - "legendFormat": "", - "range": false, - "refId": "Client Info" - } - ], - "title": "Client Versions", - "transformations": [ - { - "id": "seriesToColumns", - "options": { - "byField": "chain_address" - } - }, - { - "id": "organize", - "options": { - "excludeByName": { - "Time": true, - "Time 1": false, - "Time 2": true, - "Value": true, - "Value #A": true, - "Value #B": true, - "Value #Client Info": true, - "Value #Nodes": true, - "__name__": true, - "__name__ 1": true, - "__name__ 2": true, - "app": true, - "controller_revision_hash": true, - "id": true, - "instance": false, - "instance 1": false, - "instance 2": true, - "job": true, - "job 1": true, - "job 2": true, - "kubernetes_namespace": true, - "kubernetes_pod_name": true, - "kubernetes_pod_name_monitoring": true, - "network": true, - "network_id": true, - "network_id 1": true, - "network_id 2": true, - "statefulset_kubernetes_io_pod_name": true, - "type": true - }, - "indexByName": { - "Time 1": 3, - "Time 2": 8, - "Value #Client Info": 13, - "Value #Nodes": 7, - "__name__ 1": 4, - "__name__ 2": 9, - "chain_address": 0, - "instance 1": 1, - "instance 2": 10, - "job 1": 5, - "job 2": 11, - "network_id 1": 6, - "network_id 2": 12, - "version": 2 - }, - "renameByName": { - "chain_address": "Chain Address", - "instance 1": "Instance", - "version": "Client Version" - } - } - } - ], - "type": "table" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "description": "Provides information whether the node is connected to the Bitcoin network", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [ - { - "options": { - "0": { - "index": 1, - "text": "False" - }, - "1": { - "index": 0, - "text": "True" - }, - "N/A": { - "index": 2, - "text": "False" - }, - "Null": { - "index": 3, - "text": "False" - } - }, - "type": "value" - } - ], - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "super-light-yellow", - "value": 50 - }, - { - "color": "super-light-green", - "value": 80 - } - ] - }, - "unit": "bool" - }, - "overrides": [] - }, - "gridPos": { - "h": 10, - "w": 13, - "x": 11, - "y": 36 - }, - "id": 13, - "interval": "1m", - "options": { - "legend": { - "calcs": [ - "last" - ], - "displayMode": "table", - "placement": "right", - "showLegend": true, - "sortBy": "Last", - "sortDesc": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "expr": "min by(chain_address) (btc_connectivity{job=\"keep-discovered-nodes\"})", - "hide": false, - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "Discovered Keep Nodes" - } - ], - "title": "BTC Connectivity", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "description": "Provides information whether the node is connected to the Ethereum network", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [ - { - "options": { - "0": { - "index": 1, - "text": "False" - }, - "1": { - "index": 0, - "text": "True" - }, - "N/A": { - "index": 3, - "text": "False" - }, - "Null": { - "index": 2, - "text": "False" - } - }, - "type": "value" - } - ], - "thresholds": { - "mode": "percentage", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "super-light-yellow", - "value": 50 - }, - { - "color": "super-light-green", - "value": 80 - } - ] - }, - "unit": "bool" - }, - "overrides": [ - { - "__systemRef": "hideSeriesFrom", - "matcher": { - "id": "byNames", - "options": { - "mode": "exclude", - "names": [ - "0x8e78De834407E863A79a9820688CdA0AedFfAB6a" - ], - "prefix": "All except:", - "readOnly": true - } - }, - "properties": [ - { - "id": "custom.hideFrom", - "value": { - "legend": false, - "tooltip": false, - "viz": true - } - } - ] - } - ] - }, - "gridPos": { - "h": 10, - "w": 13, - "x": 11, - "y": 46 - }, - "id": 14, - "interval": "1m", - "options": { - "legend": { - "calcs": [ - "last" - ], - "displayMode": "table", - "placement": "right", - "showLegend": true, - "sortBy": "Last", - "sortDesc": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "expr": "min by(chain_address) (eth_connectivity{job=\"keep-discovered-nodes\"})", - "hide": false, - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "Discovered Keep Nodes" - } - ], - "title": "ETH Connectivity", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "fillOpacity": 70, - "lineWidth": 0, - "spanNulls": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 25, - "w": 13, - "x": 11, - "y": 56 - }, - "id": 6, - "options": { - "alignValue": "left", - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "mergeValues": true, - "rowHeight": 0.9, - "showValue": "auto", - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "9.1.2", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "expr": "min by(chain_address) (up{job=\"keep-discovered-nodes\"})", - "interval": "", - "legendFormat": "{{chain_address}}", - "range": true, - "refId": "A" - } - ], - "title": "Uptime (experimental)", - "type": "state-timeline" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "description": "A number of running instances for each operator address.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "fillOpacity": 60, - "lineWidth": 0, - "spanNulls": false - }, - "mappings": [], - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "super-light-orange" - }, - { - "color": "super-light-green", - "value": 1 - }, - { - "color": "super-light-red", - "value": 2 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 20, - "w": 11, - "x": 0, - "y": 61 - }, - "id": 12, - "options": { - "alignValue": "center", - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "mergeValues": true, - "rowHeight": 0.9, - "showValue": "auto", - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "9.1.2", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "builder", - "expr": "count by(chain_address) (up{job=\"keep-discovered-nodes\"})", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Node Instances", - "type": "state-timeline" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "description": "Inbound network join requests across all monitored nodes, with the failure-reason breakdown. A high failure share is expected: unrecognized peers probing the network are rejected by the on-chain firewall check. Investigate when the mix shifts (e.g. firewall rpc error or timeout growth) or when bursts coincide with peer loss.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 20, - "w": 11, - "x": 0, - "y": 81 - }, - "id": 15, - "interval": "1m", - "options": { - "legend": { - "calcs": [ - "last" - ], - "displayMode": "table", - "placement": "right", - "showLegend": true, - "sortBy": "Last", - "sortDesc": true - }, - "tooltip": { - "mode": "multi", - "sort": "desc" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "code", - "exemplar": false, - "expr": "sum(increase(performance_network_join_requests_total{job=\"keep-discovered-nodes\"}[10m]))", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "total", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "code", - "exemplar": false, - "expr": "sum(increase(performance_network_join_requests_success_total{job=\"keep-discovered-nodes\"}[10m]))", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "success", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "code", - "exemplar": false, - "expr": "sum(increase(performance_network_join_requests_failed_total{job=\"keep-discovered-nodes\"}[10m]))", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "failed", - "range": true, - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "code", - "exemplar": false, - "expr": "sum(increase(performance_network_join_requests_failed_timeout_total{job=\"keep-discovered-nodes\"}[10m]))", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "failed: timeout", - "range": true, - "refId": "D" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "code", - "exemplar": false, - "expr": "sum(increase(performance_network_join_requests_failed_eof_reset_total{job=\"keep-discovered-nodes\"}[10m]))", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "failed: eof/reset", - "range": true, - "refId": "E" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "code", - "exemplar": false, - "expr": "sum(increase(performance_network_join_requests_failed_protocol_crypto_total{job=\"keep-discovered-nodes\"}[10m]))", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "failed: protocol/crypto", - "range": true, - "refId": "F" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "code", - "exemplar": false, - "expr": "sum(increase(performance_network_join_requests_failed_firewall_unrecognized_total{job=\"keep-discovered-nodes\"}[10m]))", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "failed: firewall unrecognized", - "range": true, - "refId": "G" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P09205B1DD12FB1C6" - }, - "editorMode": "code", - "exemplar": false, - "expr": "sum(increase(performance_network_join_requests_failed_firewall_rpc_error_total{job=\"keep-discovered-nodes\"}[10m]))", - "format": "time_series", - "hide": false, - "instant": false, - "interval": "", - "legendFormat": "failed: firewall rpc error", - "range": true, - "refId": "H" - } - ], - "title": "Network Join Requests (per 10m)", - "type": "timeseries" - } - ], - "refresh": false, - "schemaVersion": 37, - "style": "dark", - "tags": [ - "tbtc", - "keep" - ], - "templating": { - "list": [] - }, - "time": { - "from": "now-7d", - "to": "now" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ] - }, - "timezone": "", - "title": "Keep Nodes", - "uid": "tMgEvbnVk", - "version": 33, - "weekStart": "" -} diff --git a/infrastructure/kube/keep-test/monitoring/grafana/dashboards/prometheus.json b/infrastructure/kube/keep-test/monitoring/grafana/dashboards/prometheus.json deleted file mode 100644 index 0223f42228..0000000000 --- a/infrastructure/kube/keep-test/monitoring/grafana/dashboards/prometheus.json +++ /dev/null @@ -1,3707 +0,0 @@ -{ - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "grafana", - "uid": "-- Grafana --" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "target": { - "limit": 100, - "matchAny": false, - "tags": [], - "type": "dashboard" - }, - "type": "dashboard" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "enable": true, - "expr": "sum(changes(prometheus_config_last_reload_success_timestamp_seconds{instance=~\"$instance\"}[10m])) by (instance)", - "hide": false, - "iconColor": "rgb(0, 96, 19)", - "limit": 100, - "name": "reloads", - "showIn": 0, - "step": "5m", - "type": "alert" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "enable": true, - "expr": "count(sum(up{instance=\"$instance\"}) by (instance) < 1)", - "hide": false, - "iconColor": "rgba(255, 96, 96, 1)", - "limit": 100, - "name": "down", - "showIn": 0, - "step": "5m", - "type": "alert" - } - ] - }, - "description": "Get started faster with Grafana Cloud then easily build these dashboards. https://grafana.com/products/cloud/\nOverview of metrics from Prometheus 2.0. \nUseful for using prometheus to monitor your prometheus.\nRevisions welcome!", - "editable": true, - "fiscalYearStartMonth": 0, - "gnetId": 3662, - "graphTooltip": 0, - "id": 5, - "links": [], - "liveNow": false, - "panels": [ - { - "collapsed": false, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 34, - "panels": [], - "targets": [ - { - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "refId": "A" - } - ], - "title": "at a glance", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "description": "Percentage of uptime during the most recent $interval period. Change the period with the 'interval' dropdown above.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 3, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(245, 54, 54, 0.9)", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 90 - }, - { - "color": "rgba(50, 172, 45, 0.97)", - "value": 99 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 0, - "y": 1 - }, - "id": 2, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.1.2", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "avg(avg_over_time(up{instance=~\"$instance\",job=~\"$job\"}[$interval]) * 100)", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A", - "step": 40 - } - ], - "title": "Uptime [$interval]", - "type": "stat" - }, - { - "columns": [], - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "description": "Servers which are DOWN RIGHT NOW! \nFIX THEM!!", - "fontSize": "100%", - "gridPos": { - "h": 7, - "w": 6, - "x": 6, - "y": 1 - }, - "hideTimeOverride": true, - "id": 25, - "links": [], - "scroll": true, - "showHeader": true, - "sort": { - "col": 0, - "desc": true - }, - "styles": [ - { - "alias": "Time", - "align": "auto", - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "pattern": "Time", - "type": "hidden" - }, - { - "alias": "", - "align": "auto", - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 2, - "pattern": "/__name__|job|Value/", - "thresholds": [], - "type": "hidden", - "unit": "short" - }, - { - "alias": " ", - "align": "auto", - "colorMode": "cell", - "colors": [ - "rgba(255, 0, 0, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(255, 0, 0, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 2, - "link": false, - "pattern": "instance", - "thresholds": [ - "", - "", - "" - ], - "type": "string", - "unit": "short" - } - ], - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "up{instance=~\"$instance\",job=~\"$job\"} < 1", - "format": "table", - "intervalFactor": 2, - "refId": "A", - "step": 2 - } - ], - "timeFrom": "1s", - "title": "Currently Down", - "transform": "table", - "type": "table-old" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "description": "Total number of time series in prometheus", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(50, 172, 45, 0.97)", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 1000000 - }, - { - "color": "rgba(245, 54, 54, 0.9)", - "value": 2000000 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 12, - "y": 1 - }, - "id": 12, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.1.2", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(prometheus_tsdb_head_series{job=~\"$job\",instance=~\"$instance\"})", - "format": "time_series", - "intervalFactor": 2, - "refId": "B", - "step": 40 - } - ], - "title": "Total Series", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "fieldConfig": { - "defaults": { - "color": { - "fixedColor": "rgb(31, 120, 193)", - "mode": "fixed" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 18, - "y": 1 - }, - "id": 14, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "none", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.1.2", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(prometheus_tsdb_head_chunks{job=~\"$job\",instance=~\"$instance\"})", - "format": "time_series", - "intervalFactor": 2, - "refId": "B", - "step": 40 - } - ], - "title": "Memory Chunks", - "type": "stat" - }, - { - "collapsed": false, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 8 - }, - "id": 35, - "panels": [], - "targets": [ - { - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "refId": "A" - } - ], - "title": "quick numbers", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "description": "The total number of rule group evaluations missed due to slow rule group evaluation.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(50, 172, 45, 0.97)", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 1 - }, - { - "color": "rgba(245, 54, 54, 0.9)", - "value": 10 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 0, - "y": 9 - }, - "id": 16, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.1.2", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(sum_over_time(prometheus_evaluator_iterations_missed_total{job=~\"$job\",instance=~\"$instance\"}[$interval]))", - "format": "time_series", - "intervalFactor": 2, - "refId": "A", - "step": 40 - } - ], - "title": "Missed Iterations [$interval]", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "description": "The total number of rule group evaluations skipped due to throttled metric storage.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(50, 172, 45, 0.97)", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 1 - }, - { - "color": "rgba(245, 54, 54, 0.9)", - "value": 10 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 4, - "y": 9 - }, - "id": 18, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.1.2", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(sum_over_time(prometheus_evaluator_iterations_skipped_total{job=~\"$job\",instance=~\"$instance\"}[$interval]))", - "format": "time_series", - "intervalFactor": 2, - "refId": "A", - "step": 40 - } - ], - "title": "Skipped Iterations [$interval]", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "description": "Total number of scrapes that hit the sample limit and were rejected.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(50, 172, 45, 0.97)", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 1 - }, - { - "color": "rgba(245, 54, 54, 0.9)", - "value": 10 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 8, - "y": 9 - }, - "id": 19, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.1.2", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(sum_over_time(prometheus_target_scrapes_exceeded_sample_limit_total{job=~\"$job\",instance=~\"$instance\"}[$interval]))", - "format": "time_series", - "intervalFactor": 2, - "refId": "A", - "step": 40 - } - ], - "title": "Tardy Scrapes [$interval]", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "description": "Number of times the database failed to reload block data from disk.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(50, 172, 45, 0.97)", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 1 - }, - { - "color": "rgba(245, 54, 54, 0.9)", - "value": 10 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 4, - "x": 12, - "y": 9 - }, - "id": 13, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.1.2", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(sum_over_time(prometheus_tsdb_reloads_failures_total{job=~\"$job\",instance=~\"$instance\"}[$interval]))", - "format": "time_series", - "intervalFactor": 2, - "refId": "A", - "step": 40 - } - ], - "title": "Reload Failures [$interval]", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "description": "Sum of all skipped scrapes", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(50, 172, 45, 0.97)", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 1 - }, - { - "color": "rgba(245, 54, 54, 0.9)", - "value": 10 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 8, - "x": 16, - "y": 9 - }, - "id": 20, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.1.2", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(sum_over_time(prometheus_target_scrapes_exceeded_sample_limit_total{job=~\"$job\",instance=~\"$instance\"}[$interval])) + \nsum(sum_over_time(prometheus_target_scrapes_sample_duplicate_timestamp_total{job=~\"$job\",instance=~\"$instance\"}[$interval])) + \nsum(sum_over_time(prometheus_target_scrapes_sample_out_of_bounds_total{job=~\"$job\",instance=~\"$instance\"}[$interval])) + \nsum(sum_over_time(prometheus_target_scrapes_sample_out_of_order_total{job=~\"$job\",instance=~\"$instance\"}[$interval])) ", - "format": "time_series", - "intervalFactor": 2, - "refId": "A", - "step": 40 - } - ], - "title": "Skipped Scrapes [$interval]", - "type": "stat" - }, - { - "collapsed": false, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 16 - }, - "id": 36, - "panels": [], - "targets": [ - { - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "refId": "A" - } - ], - "title": "errors", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "description": "All non-zero failures and errors", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 17 - }, - "hiddenSeries": false, - "id": 33, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.1.2", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(increase(net_conntrack_dialer_conn_failed_total{instance=~\"$instance\"}[5m])) > 0", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Failed Connections", - "refId": "A", - "step": 2 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(increase(prometheus_evaluator_iterations_missed_total{instance=~\"$instance\"}[5m])) > 0", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Missed Iterations", - "refId": "B", - "step": 2 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(increase(prometheus_evaluator_iterations_skipped_total{instance=~\"$instance\"}[5m])) > 0", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Skipped Iterations", - "refId": "C", - "step": 2 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(increase(prometheus_rule_evaluation_failures_total{instance=~\"$instance\"}[5m])) > 0", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Evaluation", - "refId": "D", - "step": 2 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(increase(prometheus_sd_azure_refresh_failures_total{instance=~\"$instance\"}[5m])) > 0", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Azure Refresh", - "refId": "E", - "step": 2 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(increase(prometheus_sd_consul_rpc_failures_total{instance=~\"$instance\"}[5m])) > 0", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Consul RPC", - "refId": "F", - "step": 2 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(increase(prometheus_sd_dns_lookup_failures_total{instance=~\"$instance\"}[5m])) > 0", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "DNS Lookup", - "refId": "G", - "step": 2 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(increase(prometheus_sd_ec2_refresh_failures_total{instance=~\"$instance\"}[5m])) > 0", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "EC2 Refresh", - "refId": "H", - "step": 2 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(increase(prometheus_sd_gce_refresh_failures_total{instance=~\"$instance\"}[5m])) > 0", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "GCE Refresh", - "refId": "I", - "step": 2 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(increase(prometheus_sd_marathon_refresh_failures_total{instance=~\"$instance\"}[5m])) > 0", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Marathon Refresh", - "refId": "J", - "step": 2 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(increase(prometheus_sd_openstack_refresh_failures_total{instance=~\"$instance\"}[5m])) > 0", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Openstack Refresh", - "refId": "K", - "step": 2 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(increase(prometheus_sd_triton_refresh_failures_total{instance=~\"$instance\"}[5m])) > 0", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Triton Refresh", - "refId": "L", - "step": 2 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(increase(prometheus_target_scrapes_exceeded_sample_limit_total{instance=~\"$instance\"}[5m])) > 0", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Sample Limit", - "refId": "M", - "step": 2 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(increase(prometheus_target_scrapes_sample_duplicate_timestamp_total{instance=~\"$instance\"}[5m])) > 0", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Duplicate Timestamp", - "refId": "N", - "step": 2 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(increase(prometheus_target_scrapes_sample_out_of_bounds_total{instance=~\"$instance\"}[5m])) > 0", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Timestamp Out of Bounds", - "refId": "O", - "step": 2 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(increase(prometheus_target_scrapes_sample_out_of_order_total{instance=~\"$instance\"}[5m])) > 0", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Sample Out of Order", - "refId": "P", - "step": 2 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(increase(prometheus_treecache_zookeeper_failures_total{instance=~\"$instance\"}[5m])) > 0", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Zookeeper", - "refId": "Q", - "step": 2 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(increase(prometheus_tsdb_compactions_failed_total{instance=~\"$instance\"}[5m])) > 0", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "TSDB Compactions", - "refId": "R", - "step": 2 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(increase(prometheus_tsdb_head_series_not_found{instance=~\"$instance\"}[5m])) > 0", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Series Not Found", - "refId": "S", - "step": 2 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(increase(prometheus_tsdb_reloads_failures_total{instance=~\"$instance\"}[5m])) > 0", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Reload", - "refId": "T", - "step": 2 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Failures and Errors", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Errors", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 24 - }, - "id": 37, - "panels": [], - "targets": [ - { - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "refId": "A" - } - ], - "title": "up", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 12, - "x": 0, - "y": 25 - }, - "hiddenSeries": false, - "id": 1, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.1.2", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": true, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "up{instance=~\"$instance\",job=~\"$job\"}", - "format": "time_series", - "interval": "", - "intervalFactor": 1, - "legendFormat": "{{instance}}", - "refId": "A", - "step": 2 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Upness (stacked)", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "decimals": 0, - "format": "none", - "label": "Up", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": false - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 25 - }, - "hiddenSeries": false, - "id": 5, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.1.2", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "prometheus_tsdb_head_chunks{job=~\"$job\",instance=~\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{instance}}", - "refId": "A", - "step": 4 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Storage Memory Chunks", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Chunks", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 32 - }, - "id": 38, - "panels": [], - "targets": [ - { - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "refId": "A" - } - ], - "title": "series", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 12, - "x": 0, - "y": 33 - }, - "hiddenSeries": false, - "id": 3, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.1.2", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "prometheus_tsdb_head_series{job=~\"$job\",instance=~\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{instance}}", - "refId": "A", - "step": 4 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Series Count", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Series", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 33 - }, - "hiddenSeries": false, - "id": 32, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.1.2", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [ - { - "alias": "removed", - "transform": "negative-Y" - } - ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum( increase(prometheus_tsdb_head_series_created_total{instance=~\"$instance\"}[5m]) )", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "created", - "refId": "A", - "step": 4 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum( increase(prometheus_tsdb_head_series_removed_total{instance=~\"$instance\"}[5m]) )", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "removed", - "refId": "B", - "step": 4 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Series Created / Removed", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Series Count", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 40 - }, - "id": 39, - "panels": [], - "targets": [ - { - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "refId": "A" - } - ], - "title": "appended samples", - "type": "row" - }, - { - "aliasColors": { - "10.58.3.10:80": "#BA43A9" - }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "description": "Rate of total number of appended samples", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 41 - }, - "hiddenSeries": false, - "id": 4, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.1.2", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "rate(prometheus_tsdb_head_samples_appended_total{job=~\"$job\",instance=~\"$instance\"}[1m])", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{instance}}", - "refId": "A", - "step": 2 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Appended Samples per Second", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Samples / Second", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 48 - }, - "id": 40, - "panels": [], - "targets": [ - { - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "refId": "A" - } - ], - "title": "sync", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "description": "Total number of syncs that were executed on a scrape pool.", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 12, - "x": 0, - "y": 49 - }, - "hiddenSeries": false, - "id": 6, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.1.2", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(prometheus_target_scrape_pool_sync_total{job=~\"$job\",instance=~\"$instance\"}) by (scrape_job)", - "format": "time_series", - "hide": false, - "intervalFactor": 2, - "legendFormat": "{{scrape_job}}", - "refId": "B", - "step": 4 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Scrape Sync Total", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Syncs", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "description": "Actual interval to sync the scrape pool.", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 49 - }, - "hiddenSeries": false, - "id": 21, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.1.2", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(rate(prometheus_target_sync_length_seconds_sum{job=~\"$job\",instance=~\"$instance\"}[2m])) by (scrape_job) * 1000", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{scrape_job}}", - "refId": "A", - "step": 4 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Target Sync", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Milliseconds", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 56 - }, - "id": 41, - "panels": [], - "targets": [ - { - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "refId": "A" - } - ], - "title": "scrapes", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 12, - "x": 0, - "y": 57 - }, - "hiddenSeries": false, - "id": 29, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.1.2", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "scrape_duration_seconds{instance=~\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{instance}}", - "refId": "A", - "step": 4 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Scrape Duration", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Seconds", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "description": "Total number of rejected scrapes", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 57 - }, - "hiddenSeries": false, - "id": 30, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.1.2", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(prometheus_target_scrapes_exceeded_sample_limit_total{job=~\"$job\",instance=~\"$instance\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "exceeded sample limit", - "refId": "A", - "step": 4 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(prometheus_target_scrapes_sample_duplicate_timestamp_total{job=~\"$job\",instance=~\"$instance\"})", - "format": "time_series", - "hide": false, - "intervalFactor": 2, - "legendFormat": "duplicate timestamp", - "refId": "B", - "step": 4 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(prometheus_target_scrapes_sample_out_of_bounds_total{job=~\"$job\",instance=~\"$instance\"})", - "format": "time_series", - "hide": false, - "intervalFactor": 2, - "legendFormat": "out of bounds", - "refId": "C", - "step": 4 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(prometheus_target_scrapes_sample_out_of_order_total{job=~\"$job\",instance=~\"$instance\"}) ", - "format": "time_series", - "hide": false, - "intervalFactor": 2, - "legendFormat": "out of order", - "refId": "D", - "step": 4 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Rejected Scrapes", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "decimals": 0, - "format": "short", - "label": "Scrapes", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 64 - }, - "id": 42, - "panels": [], - "targets": [ - { - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "refId": "A" - } - ], - "title": "durations", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "description": "The duration of rule group evaluations", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 12, - "x": 0, - "y": 65 - }, - "hiddenSeries": false, - "id": 10, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.1.2", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "1000 * rate(prometheus_evaluator_duration_seconds_sum{job=~\"$job\", instance=~\"$instance\"}[5m]) / rate(prometheus_evaluator_duration_seconds_count{job=~\"$job\", instance=~\"$instance\"}[5m])", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{instance}}", - "refId": "E", - "step": 4 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Average Rule Evaluation Duration", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Milliseconds", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 65 - }, - "hiddenSeries": false, - "id": 11, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.1.2", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(rate(http_request_duration_microseconds_count{job=~\"$job\",instance=~\"$instance\"}[1m])) by (handler) > 0", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{handler}}", - "refId": "A", - "step": 4 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "HTTP Request Duration", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Microseconds", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 12, - "x": 0, - "y": 72 - }, - "hiddenSeries": false, - "id": 15, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.1.2", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(prometheus_engine_query_duration_seconds_sum{job=~\"$job\",instance=~\"$instance\"}) by (slice)", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{slice}}", - "refId": "A", - "step": 4 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Prometheus Engine Query Duration Seconds", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Seconds", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "description": "Rule-group evaluations \n - total\n - missed due to slow rule group evaluation\n - skipped due to throttled metric storage", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 72 - }, - "hiddenSeries": false, - "id": 31, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.1.2", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(rate(prometheus_evaluator_iterations_total{job=~\"$job\", instance=~\"$instance\"}[5m]))", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Total", - "refId": "B", - "step": 4 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(rate(prometheus_evaluator_iterations_missed_total{job=~\"$job\", instance=~\"$instance\"}[5m]))", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Missed", - "refId": "A", - "step": 4 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(rate(prometheus_evaluator_iterations_skipped_total{job=~\"$job\", instance=~\"$instance\"}[5m]))", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Skipped", - "refId": "C", - "step": 4 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Rule Evaluator Iterations", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "iterations", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 79 - }, - "id": 43, - "panels": [], - "targets": [ - { - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "refId": "A" - } - ], - "title": "notifications", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 80 - }, - "hiddenSeries": false, - "id": 22, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.1.2", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "rate(prometheus_notifications_sent_total[5m])", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{instance}}", - "refId": "A", - "step": 2 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Notifications Sent", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Notifications", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 87 - }, - "id": 44, - "panels": [], - "targets": [ - { - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "refId": "A" - } - ], - "title": "config", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 12, - "x": 0, - "y": 88 - }, - "hiddenSeries": false, - "id": 23, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.1.2", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "(time() - prometheus_config_last_reload_success_timestamp_seconds{job=~\"$job\",instance=~\"$instance\"}) / 60", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{instance}}", - "refId": "A", - "step": 4 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Minutes Since Successful Config Reload", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Minutes", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 88 - }, - "hiddenSeries": false, - "id": 24, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.1.2", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "prometheus_config_last_reload_successful{job=~\"$job\",instance=~\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{instance}}", - "refId": "A", - "step": 4 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Successful Config Reload", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "decimals": 0, - "format": "short", - "label": "Success", - "logBase": 1, - "max": "1", - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 95 - }, - "id": 45, - "panels": [], - "targets": [ - { - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "refId": "A" - } - ], - "title": "garbage collection", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "description": "GC invocation durations", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 96 - }, - "hiddenSeries": false, - "id": 28, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.1.2", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(rate(go_gc_duration_seconds_sum{instance=~\"$instance\",job=~\"$job\"}[2m])) by (instance)", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{instance}}", - "refId": "A", - "step": 2 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "GC Rate / 2m", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": true, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 103 - }, - "id": 46, - "panels": [ - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "description": "This is probably wrong! Please help.", - "fill": 1, - "gridPos": { - "h": 7, - "w": 12, - "x": 0, - "y": 104 - }, - "id": 26, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [ - { - "alias": "allocated", - "stack": false - } - ], - "spaceLength": 10, - "stack": true, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(go_memstats_alloc_bytes_total{job=~\"$job\", instance=~\"$instance\"})", - "format": "time_series", - "hide": true, - "intervalFactor": 2, - "legendFormat": "alloc_bytes_total", - "refId": "A", - "step": 10 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(go_memstats_alloc_bytes{job=~\"$job\", instance=~\"$instance\"})", - "format": "time_series", - "hide": false, - "intervalFactor": 2, - "legendFormat": "allocated", - "refId": "B", - "step": 10 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(go_memstats_buck_hash_sys_bytes{job=~\"$job\", instance=~\"$instance\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "profiling bucket hash table", - "refId": "C", - "step": 10 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(go_memstats_gc_sys_bytes{job=~\"$job\", instance=~\"$instance\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "GC metadata", - "refId": "D", - "step": 10 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(go_memstats_heap_alloc_bytes{job=~\"$job\", instance=~\"$instance\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "heap in-use", - "refId": "E", - "step": 10 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(go_memstats_heap_idle_bytes{job=~\"$job\", instance=~\"$instance\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "heap idle", - "refId": "F", - "step": 10 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(go_memstats_heap_inuse_bytes{job=~\"$job\", instance=~\"$instance\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "heap in use", - "refId": "G", - "step": 10 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(go_memstats_heap_released_bytes{job=~\"$job\", instance=~\"$instance\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "heap released", - "refId": "H", - "step": 10 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(go_memstats_heap_sys_bytes{job=~\"$job\", instance=~\"$instance\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "heap system", - "refId": "I", - "step": 10 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(go_memstats_mcache_inuse_bytes{job=~\"$job\", instance=~\"$instance\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "mcache in use", - "refId": "J", - "step": 10 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(go_memstats_mcache_sys_bytes{job=~\"$job\", instance=~\"$instance\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "mcache sys", - "refId": "K", - "step": 10 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(go_memstats_mspan_inuse_bytes{job=~\"$job\", instance=~\"$instance\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "mspan in use", - "refId": "L", - "step": 10 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(go_memstats_mspan_sys_bytes{job=~\"$job\", instance=~\"$instance\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "mspan sys", - "refId": "M", - "step": 10 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(go_memstats_next_gc_bytes{job=~\"$job\", instance=~\"$instance\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "heap next gc", - "refId": "N", - "step": 10 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(go_memstats_other_sys_bytes{job=~\"$job\", instance=~\"$instance\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "other sys", - "refId": "O", - "step": 10 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(go_memstats_stack_inuse_bytes{job=~\"$job\", instance=~\"$instance\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "stack in use", - "refId": "P", - "step": 10 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(go_memstats_stack_sys_bytes{job=~\"$job\", instance=~\"$instance\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "stack sys", - "refId": "Q", - "step": 10 - }, - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(go_memstats_sys_bytes{job=~\"$job\", instance=~\"$instance\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "sys", - "refId": "R", - "step": 10 - } - ], - "thresholds": [], - "title": "Go Memory Usage (FIXME)", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "bytes", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "fill": 1, - "gridPos": { - "h": 7, - "w": 6, - "x": 12, - "y": 104 - }, - "id": 9, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "prometheus_target_interval_length_seconds{instance=~\"$instance\", job=~\"$job\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{quantile}} {{interval}}", - "refId": "A", - "step": 20 - } - ], - "thresholds": [], - "title": "Scrape Duration", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Seconds", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "fill": 1, - "gridPos": { - "h": 7, - "w": 6, - "x": 18, - "y": 104 - }, - "id": 7, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "expr": "sum(rate(prometheus_target_interval_length_seconds_count{job=~\"$job\",instance=~\"$instance\"}[5m])) by (interval)", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{interval}}", - "refId": "A", - "step": 20 - } - ], - "thresholds": [], - "title": "Target Scrapes / 5m", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Scrapes", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ] - } - ], - "targets": [ - { - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "refId": "A" - } - ], - "title": "Broken, ignore", - "type": "row" - } - ], - "refresh": "30s", - "schemaVersion": 37, - "style": "dark", - "tags": [], - "templating": { - "list": [ - { - "current": { - "selected": false, - "text": "All", - "value": "$__all" - }, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "definition": "", - "hide": 0, - "includeAll": true, - "multi": true, - "name": "job", - "options": [], - "query": { - "query": "query_result(prometheus_tsdb_head_samples_appended_total)", - "refId": "prometheus-job-Variable-Query" - }, - "refresh": 2, - "regex": "/.*job=\"([^\"]+)/", - "skipUrlSync": false, - "sort": 1, - "tagValuesQuery": "", - "tagsQuery": "", - "type": "query", - "useTags": false - }, - { - "current": { - "selected": false, - "text": "All", - "value": "$__all" - }, - "datasource": { - "type": "prometheus", - "uid": "P1809F7CD0C75ACF3" - }, - "definition": "", - "hide": 0, - "includeAll": true, - "multi": true, - "name": "instance", - "options": [], - "query": { - "query": "query_result(up{job=~\"$job\"})", - "refId": "prometheus-instance-Variable-Query" - }, - "refresh": 2, - "regex": "/.*instance=\"([^\"]+).*/", - "skipUrlSync": false, - "sort": 0, - "tagValuesQuery": "", - "tagsQuery": "", - "type": "query", - "useTags": false - }, - { - "current": { - "selected": true, - "text": "1h", - "value": "1h" - }, - "hide": 0, - "includeAll": false, - "multi": false, - "name": "interval", - "options": [ - { - "selected": true, - "text": "1h", - "value": "1h" - }, - { - "selected": false, - "text": "3h", - "value": "3h" - }, - { - "selected": false, - "text": "6h", - "value": "6h" - }, - { - "selected": false, - "text": "12h", - "value": "12h" - }, - { - "selected": false, - "text": "1d", - "value": "1d" - }, - { - "selected": false, - "text": "2d", - "value": "2d" - }, - { - "selected": false, - "text": "7d", - "value": "7d" - }, - { - "selected": false, - "text": "30d", - "value": "30d" - }, - { - "selected": false, - "text": "90d", - "value": "90d" - }, - { - "selected": false, - "text": "180d", - "value": "180d" - } - ], - "query": "1h, 3h, 6h, 12h, 1d, 2d, 7d, 30d, 90d, 180d", - "skipUrlSync": false, - "type": "custom" - } - ] - }, - "time": { - "from": "now-30m", - "to": "now" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] - }, - "timezone": "", - "title": "Prometheus Overview", - "uid": "jNCsuX44k", - "version": 2, - "weekStart": "" -} diff --git a/infrastructure/kube/keep-test/monitoring/grafana/grafana-deployment.yaml b/infrastructure/kube/keep-test/monitoring/grafana/grafana-deployment.yaml deleted file mode 100644 index bae85548f2..0000000000 --- a/infrastructure/kube/keep-test/monitoring/grafana/grafana-deployment.yaml +++ /dev/null @@ -1,114 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: grafana -spec: - replicas: 1 - selector: - matchLabels: - app: grafana - template: - spec: - securityContext: - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - runAsNonRoot: true - containers: - - name: grafana - image: grafana/grafana:9.2.5 - env: - - name: GF_SERVER_DOMAIN - value: monitoring.test.keep.network - - name: GF_SERVER_ROOT_URL - value: "%(protocol)s://%(domain)s:80/grafana/" - - name: GF_SERVER_SERVE_FROM_SUB_PATH - value: "true" - - name: GF_FEATURE_TOGGLES_PUBLICDASHBOARDS - value: "true" - - name: GF_AUTH_GOOGLE_CLIENT_ID - valueFrom: - secretKeyRef: - name: grafana-auth-google - key: client_id - - name: GF_AUTH_GOOGLE_CLIENT_SECRET - valueFrom: - secretKeyRef: - name: grafana-auth-google - key: client_secret - - name: GF_AUTH_GITHUB_CLIENT_ID - valueFrom: - secretKeyRef: - name: grafana-auth-github - key: client_id - - name: GF_AUTH_GITHUB_CLIENT_SECRET - valueFrom: - secretKeyRef: - name: grafana-auth-github - key: client_secret - ports: - - name: grafana - containerPort: 3000 - readinessProbe: - httpGet: - path: /api/health - port: grafana - initialDelaySeconds: 10 - periodSeconds: 30 - timeoutSeconds: 2 - livenessProbe: - initialDelaySeconds: 30 - tcpSocket: - port: grafana - resources: - limits: - cpu: 1000m - memory: 1Gi - requests: - cpu: 250m - memory: 512Mi - volumeMounts: - - name: grafana-grafana-ini - mountPath: /etc/grafana/grafana.ini - subPath: grafana.ini - - name: grafana-config-datasources - mountPath: /etc/grafana/provisioning/datasources - - name: grafana-config-dashboards - mountPath: /etc/grafana/provisioning/dashboards - - name: grafana-storage - mountPath: /var/lib/grafana - - name: grafana-dashboards-infrastructure - mountPath: /var/lib/grafana/dashboards/infrastructure - - name: grafana-dashboards-keep - mountPath: /var/lib/grafana/dashboards/keep - securityContext: - readOnlyRootFilesystem: true - volumes: - - name: grafana-storage - persistentVolumeClaim: - claimName: grafana-pvc - - name: grafana-dashboards-keep - configMap: - name: grafana-dashboards-keep - - name: grafana-dashboards-infrastructure - configMap: - name: grafana-dashboards-infrastructure - - name: grafana-config-datasources - configMap: - name: grafana-config - items: - - key: datasources.yaml - path: datasources.yaml - - name: grafana-config-dashboards - configMap: - name: grafana-config - items: - - key: dashboards.yaml - path: dashboards.yaml - - name: grafana-grafana-ini - configMap: - name: grafana-config - items: - - key: grafana.ini - path: grafana.ini diff --git a/infrastructure/kube/keep-test/monitoring/grafana/grafana-pvc.yaml b/infrastructure/kube/keep-test/monitoring/grafana/grafana-pvc.yaml deleted file mode 100644 index 46b9de4205..0000000000 --- a/infrastructure/kube/keep-test/monitoring/grafana/grafana-pvc.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: grafana-pvc - namespace: monitoring - labels: - app: grafana -spec: - storageClassName: monitoring-storage - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 5Gi diff --git a/infrastructure/kube/keep-test/monitoring/grafana/grafana-service.yaml b/infrastructure/kube/keep-test/monitoring/grafana/grafana-service.yaml deleted file mode 100644 index 2db62dbeda..0000000000 --- a/infrastructure/kube/keep-test/monitoring/grafana/grafana-service.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: grafana -spec: - selector: - app: grafana - type: NodePort - ports: - - port: 3000 - targetPort: grafana diff --git a/infrastructure/kube/keep-test/monitoring/grafana/kustomization.yaml b/infrastructure/kube/keep-test/monitoring/grafana/kustomization.yaml deleted file mode 100644 index d8478e7325..0000000000 --- a/infrastructure/kube/keep-test/monitoring/grafana/kustomization.yaml +++ /dev/null @@ -1,29 +0,0 @@ -resources: - - grafana-deployment.yaml - - grafana-pvc.yaml - - grafana-service.yaml - -namespace: monitoring - -commonLabels: - app: grafana - type: monitoring - -configMapGenerator: - - name: grafana-config - files: - - config/grafana.ini - - config/dashboards.yaml - - config/datasources.yaml - - name: grafana-dashboards-keep - files: - - dashboards/keep/keep-network-nodes-public.json - - dashboards/keep/keep-network-nodes.json - - name: grafana-dashboards-infrastructure - files: - - dashboards/infrastructure/kubernetes-deployments.json - -generatorOptions: - disableNameSuffixHash: true - annotations: - note: generated diff --git a/infrastructure/kube/keep-test/monitoring/monitoring-ingress.yaml b/infrastructure/kube/keep-test/monitoring/monitoring-ingress.yaml deleted file mode 100644 index 357448d0cc..0000000000 --- a/infrastructure/kube/keep-test/monitoring/monitoring-ingress.yaml +++ /dev/null @@ -1,37 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: monitoring - namespace: monitoring - annotations: - kubernetes.io/ingress.class: "gce" - # The static IP has to be created with the following command: - # `gcloud compute addresses create keep-test-monitoring-ingress --global` - kubernetes.io/ingress.global-static-ip-name: "keep-test-monitoring-ingress" - networking.gke.io/managed-certificates: monitoring-cert -spec: - defaultBackend: - service: - name: grafana - port: - number: 3000 - rules: - - http: - paths: - - path: "/grafana" - pathType: Prefix - backend: - service: - name: grafana - port: - number: 3000 ---- -apiVersion: networking.gke.io/v1 -kind: ManagedCertificate -metadata: - name: monitoring-cert - namespace: monitoring -spec: - domains: - - monitoring.test.threshold.network - - monitoring.test.keep.network diff --git a/infrastructure/kube/keep-test/monitoring/prometheus/config/config.yaml b/infrastructure/kube/keep-test/monitoring/prometheus/config/config.yaml deleted file mode 100644 index 96086d5d64..0000000000 --- a/infrastructure/kube/keep-test/monitoring/prometheus/config/config.yaml +++ /dev/null @@ -1,153 +0,0 @@ -global: - scrape_interval: 1m - scrape_timeout: 10s - evaluation_interval: 1m -# TODO: Configure Alert Manager -# alerting: -# alertmanagers: -# - follow_redirects: true -# enable_http2: true -# scheme: http -# timeout: 10s -# api_version: v2 -# static_configs: -# - targets: -# - alertmanager.monitoring.svc:9093 -rule_files: - - /etc/prometheus/rules.yaml -scrape_configs: - - job_name: keep-discovered-nodes - honor_timestamps: true - metrics_path: /metrics - scheme: http - follow_redirects: true - enable_http2: true - relabel_configs: - - source_labels: [__meta_chain_address] - separator: ; - regex: (.*) - target_label: chain_address - replacement: $1 - action: replace - - source_labels: [__meta_network_id] - separator: ; - regex: (.*) - target_label: network_id - replacement: $1 - action: replace - file_sd_configs: - - files: - - /etc/prometheus/sd/keep-sd.json - refresh_interval: 5m - - job_name: keep-external-nodes - honor_timestamps: true - metrics_path: /metrics - scheme: http - follow_redirects: true - enable_http2: true - file_sd_configs: - - files: - - /etc/prometheus/external-clients-targets.yaml - refresh_interval: 5m - - job_name: keep-internal-nodes - honor_timestamps: true - metrics_path: /metrics - scheme: http - follow_redirects: true - enable_http2: true - relabel_configs: - - source_labels: [__meta_kubernetes_service_port_name] - separator: ; - regex: metrics - replacement: $1 - action: keep - kubernetes_sd_configs: - - role: service - kubeconfig_file: "" - follow_redirects: true - enable_http2: true - namespaces: - own_namespace: false - names: - - default - selectors: - - role: service - label: app=keep - - job_name: grafana - honor_timestamps: true - metrics_path: /metrics - scheme: http - follow_redirects: true - enable_http2: true - relabel_configs: - - source_labels: [__meta_kubernetes_pod_label_app] - separator: ; - regex: grafana.* - replacement: $1 - action: keep - - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] - separator: ; - regex: (.+) - target_label: __metrics_path__ - replacement: $1 - action: replace - - separator: ; - regex: __meta_kubernetes_pod_label_(.+) - replacement: $1 - action: labelmap - - source_labels: [__meta_kubernetes_namespace] - separator: ; - regex: (.*) - target_label: kubernetes_namespace - replacement: $1 - action: replace - - source_labels: [__meta_kubernetes_pod_name] - separator: ; - regex: (.*) - target_label: kubernetes_pod_name - replacement: $1 - action: replace - kubernetes_sd_configs: - - role: pod - kubeconfig_file: "" - follow_redirects: true - enable_http2: true - - job_name: prometheus - honor_timestamps: true - metrics_path: /metrics - scheme: http - follow_redirects: true - enable_http2: true - relabel_configs: - - source_labels: [__meta_kubernetes_pod_label_app] - separator: ; - regex: prometheus.* - replacement: $1 - action: keep - - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] - separator: ; - regex: (.+) - target_label: __metrics_path__ - replacement: $1 - action: replace - - separator: ; - regex: __meta_kubernetes_pod_label_(.+) - replacement: $1 - action: labelmap - - source_labels: [__meta_kubernetes_namespace] - separator: ; - regex: (.*) - target_label: kubernetes_namespace - replacement: $1 - action: replace - - source_labels: [__meta_kubernetes_pod_name] - separator: ; - regex: (.*) - target_label: kubernetes_pod_name - replacement: $1 - action: replace - kubernetes_sd_configs: - - role: pod - kubeconfig_file: "" - follow_redirects: true - enable_http2: true diff --git a/infrastructure/kube/keep-test/monitoring/prometheus/config/external-clients-targets.yaml b/infrastructure/kube/keep-test/monitoring/prometheus/config/external-clients-targets.yaml deleted file mode 100644 index 83f68bff7d..0000000000 --- a/infrastructure/kube/keep-test/monitoring/prometheus/config/external-clients-targets.yaml +++ /dev/null @@ -1,4 +0,0 @@ -- targets: - - bst-a01.test.keep.boar.network:9601 - - keep-validator-0.eks-ap-northeast-2-secure.staging.staked.cloud:9601 - - bootstrap-alpha.test.threshold.p2p.org:9601 diff --git a/infrastructure/kube/keep-test/monitoring/prometheus/config/rules.yaml b/infrastructure/kube/keep-test/monitoring/prometheus/config/rules.yaml deleted file mode 100644 index eaec118f2b..0000000000 --- a/infrastructure/kube/keep-test/monitoring/prometheus/config/rules.yaml +++ /dev/null @@ -1,53 +0,0 @@ -groups: - # TODO: Define some common rules to record: https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/ - - name: keep-network-join-requests - rules: - # Fires only when an abnormal burst of inbound join-request failures - # coincides with peer loss or coordination degradation on the same - # node. A high failure ratio alone is expected behavior (unrecognized - # peers probing the network are rejected by the on-chain firewall - # check) and intentionally does not fire this alert. - - alert: KeepNodeJoinFailureBurstWithConnectivityDegradation - expr: | - ( - sum by (chain_address) ( - rate(performance_network_join_requests_failed_total{job="keep-discovered-nodes"}[30m]) - ) - > - 4 * sum by (chain_address) ( - rate(performance_network_join_requests_failed_total{job="keep-discovered-nodes"}[6h] offset 30m) - ) + 0.05 - ) - and on (chain_address) - ( - min by (chain_address) ( - connected_wellknown_peers_count{job="keep-discovered-nodes"} - ) == 0 - or - min by (chain_address) ( - delta(connected_peers_count{job="keep-discovered-nodes"}[30m]) - ) < -5 - or - sum by (chain_address) ( - increase(performance_coordination_failed_total{job="keep-discovered-nodes"}[1h]) - ) > 0 - or - sum by (chain_address) ( - increase(performance_coordination_leader_timeout_total{job="keep-discovered-nodes"}[1h]) - ) > 2 - ) - for: 15m - labels: - severity: warning - annotations: - summary: >- - Join-request failure burst with connectivity degradation on - {{ $labels.chain_address }} - description: >- - Inbound network join-request failures on node - {{ $labels.chain_address }} spiked to more than 4x their 6h - baseline while the node also shows well-known peer isolation, - peer loss, or coordination degradation. Check the per-reason - breakdown (performance_network_join_requests_failed_*_total) - to tell genuine non-recognition (firewall_unrecognized) apart - from firewall RPC errors, timeouts, and connection resets. diff --git a/infrastructure/kube/keep-test/monitoring/prometheus/kustomization.yaml b/infrastructure/kube/keep-test/monitoring/prometheus/kustomization.yaml deleted file mode 100644 index d3b4eecc57..0000000000 --- a/infrastructure/kube/keep-test/monitoring/prometheus/kustomization.yaml +++ /dev/null @@ -1,22 +0,0 @@ -resources: - - prometheus-deployment.yaml - - prometheus-pvc.yaml - - prometheus-service.yaml - -namespace: monitoring - -commonLabels: - app: prometheus - type: monitoring - -configMapGenerator: - - name: prometheus-config - files: - - config/config.yaml - - config/external-clients-targets.yaml - - config/rules.yaml - -generatorOptions: - disableNameSuffixHash: true - annotations: - note: generated diff --git a/infrastructure/kube/keep-test/monitoring/prometheus/prometheus-cluster-role.yaml b/infrastructure/kube/keep-test/monitoring/prometheus/prometheus-cluster-role.yaml deleted file mode 100644 index 5c67a8ca9f..0000000000 --- a/infrastructure/kube/keep-test/monitoring/prometheus/prometheus-cluster-role.yaml +++ /dev/null @@ -1,34 +0,0 @@ ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: prometheus -rules: - - apiGroups: [""] - resources: - - nodes - - nodes/proxy - - services - - endpoints - - pods - verbs: ["get", "list", "watch"] - - apiGroups: - - extensions - resources: - - ingresses - verbs: ["get", "list", "watch"] - - nonResourceURLs: ["/metrics"] - verbs: ["get"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: prometheus -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: prometheus -subjects: - - kind: ServiceAccount - name: default - namespace: monitoring diff --git a/infrastructure/kube/keep-test/monitoring/prometheus/prometheus-deployment.yaml b/infrastructure/kube/keep-test/monitoring/prometheus/prometheus-deployment.yaml deleted file mode 100644 index 1aa0116e0d..0000000000 --- a/infrastructure/kube/keep-test/monitoring/prometheus/prometheus-deployment.yaml +++ /dev/null @@ -1,92 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: prometheus -spec: - replicas: 1 - strategy: - type: Recreate - selector: - matchLabels: - app: prometheus - type: monitoring - template: - spec: - securityContext: - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - runAsNonRoot: true - containers: - - name: prometheus - image: prom/prometheus:v2.43.1 - args: - - --config.file=/etc/prometheus/config.yaml - - --storage.tsdb.path=/etc/prometheus/data - - --storage.tsdb.retention.time=1y - - --web.external-url=/prometheus/ - ports: - - name: prometheus - containerPort: 9090 - readinessProbe: - httpGet: - path: "/prometheus/-/ready" - port: prometheus - initialDelaySeconds: 10 - periodSeconds: 30 - timeoutSeconds: 2 - livenessProbe: - httpGet: - path: "/prometheus/-/healthy" - port: prometheus - initialDelaySeconds: 10 - periodSeconds: 30 - timeoutSeconds: 2 - resources: - limits: - cpu: 1000m - memory: 1Gi - requests: - cpu: 500m - memory: 512Mi - volumeMounts: - - name: prometheus-config-volume - mountPath: /etc/prometheus/ - - name: prometheus-storage-volume - mountPath: /etc/prometheus/data/ - - name: prometheus-sd-volume - mountPath: /etc/prometheus/sd/ - securityContext: - readOnlyRootFilesystem: true - - name: keep-sd - image: keepnetwork/keep-prometheus-sd - args: - - --output.file=/etc/prometheus/sd/keep-sd.json - - --source.address=bootstrap-0.test.keep.network:9601 - - --source.address=bootstrap-1.test.keep.network:9601 - - --refresh.interval=5m - - --scan.timeout=3s - - --log.json - - --scan.allowPrivateAddresses - resources: - limits: - cpu: 1000m - memory: 1Gi - requests: - cpu: 250m - memory: 256Mi - volumeMounts: - - name: prometheus-sd-volume - mountPath: /etc/prometheus/sd/ - securityContext: - readOnlyRootFilesystem: true - volumes: - - name: prometheus-config-volume - configMap: - name: prometheus-config - - name: prometheus-storage-volume - persistentVolumeClaim: - claimName: prometheus-pvc - - name: prometheus-sd-volume - emptyDir: {} diff --git a/infrastructure/kube/keep-test/monitoring/prometheus/prometheus-pvc.yaml b/infrastructure/kube/keep-test/monitoring/prometheus/prometheus-pvc.yaml deleted file mode 100644 index 6ca54ca443..0000000000 --- a/infrastructure/kube/keep-test/monitoring/prometheus/prometheus-pvc.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: prometheus-pvc -spec: - storageClassName: monitoring-storage - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 100Gi diff --git a/infrastructure/kube/keep-test/monitoring/prometheus/prometheus-service.yaml b/infrastructure/kube/keep-test/monitoring/prometheus/prometheus-service.yaml deleted file mode 100644 index ce86a2fc1e..0000000000 --- a/infrastructure/kube/keep-test/monitoring/prometheus/prometheus-service.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: prometheus -spec: - selector: - app: prometheus - type: NodePort - ports: - - port: 9090 - targetPort: prometheus diff --git a/infrastructure/kube/keep-test/monitoring/storage-class.yaml b/infrastructure/kube/keep-test/monitoring/storage-class.yaml deleted file mode 100644 index bf375bd8c0..0000000000 --- a/infrastructure/kube/keep-test/monitoring/storage-class.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: storage.k8s.io/v1 -kind: StorageClass -metadata: - name: monitoring-storage -provisioner: kubernetes.io/gce-pd -parameters: - type: pd-ssd - replication-type: none -reclaimPolicy: Retain -allowVolumeExpansion: true -mountOptions: - - debug -volumeBindingMode: Immediate diff --git a/infrastructure/kube/keep-test/monitoring/trickster/config/trickster.yaml b/infrastructure/kube/keep-test/monitoring/trickster/config/trickster.yaml deleted file mode 100644 index 0c4b5797c5..0000000000 --- a/infrastructure/kube/keep-test/monitoring/trickster/config/trickster.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# Trickster Configuration File. -# -# A full configuration file example can be found here: -# https://github.com/trickstercache/trickster/blob/main/examples/conf/example.full.yaml - -frontend: - listen_port: 8480 - -backends: - default: - provider: prometheus - origin_url: http://prometheus:9090 - is_default: true - healthcheck: - path: /prometheus/-/ready - upstream_path: /prometheus/-/ready - interval_ms: 5000 - expected_body: "Prometheus Server is Ready.\n" - -metrics: - listen_port: 8481 - listen_address: "" - -logging: - log_level: info diff --git a/infrastructure/kube/keep-test/monitoring/trickster/kustomization.yaml b/infrastructure/kube/keep-test/monitoring/trickster/kustomization.yaml deleted file mode 100644 index 0ca82fb0a6..0000000000 --- a/infrastructure/kube/keep-test/monitoring/trickster/kustomization.yaml +++ /dev/null @@ -1,19 +0,0 @@ -resources: - - trickster-deployment.yaml - - trickster-service.yaml - -namespace: monitoring - -commonLabels: - app: trickster - type: monitoring - -configMapGenerator: - - name: trickster-config - files: - - config/trickster.yaml - -generatorOptions: - disableNameSuffixHash: true - annotations: - note: generated diff --git a/infrastructure/kube/keep-test/monitoring/trickster/trickster-deployment.yaml b/infrastructure/kube/keep-test/monitoring/trickster/trickster-deployment.yaml deleted file mode 100644 index f63c615dad..0000000000 --- a/infrastructure/kube/keep-test/monitoring/trickster/trickster-deployment.yaml +++ /dev/null @@ -1,58 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: trickster -spec: - replicas: 1 - selector: - matchLabels: - app: trickster - type: monitoring - template: - spec: - securityContext: - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - runAsNonRoot: true - containers: - - name: trickster - image: trickstercache/trickster:2 - ports: - - name: trickster - containerPort: 8480 - - name: metrics - containerPort: 8481 - readinessProbe: - httpGet: - path: "/trickster/health/default" - port: metrics - livenessProbe: - httpGet: - path: "/trickster/ping" - port: trickster - resources: - limits: - cpu: 1000m - memory: 1Gi - requests: - cpu: 500m - memory: 512Mi - volumeMounts: - - name: trickster-config - mountPath: /etc/trickster - env: - - name: NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - securityContext: - readOnlyRootFilesystem: true - volumes: - - name: trickster-config - configMap: - name: trickster-config - items: - - key: trickster.yaml - path: trickster.yaml diff --git a/infrastructure/kube/keep-test/monitoring/trickster/trickster-service.yaml b/infrastructure/kube/keep-test/monitoring/trickster/trickster-service.yaml deleted file mode 100644 index 420994a406..0000000000 --- a/infrastructure/kube/keep-test/monitoring/trickster/trickster-service.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: trickster -spec: - selector: - app: trickster - type: NodePort - ports: - - name: trickster - port: 8480 - targetPort: trickster - - name: metrics - port: 8481 - targetPort: metrics diff --git a/infrastructure/kube/keep-test/tbtc-v2-monitoring/.env.secret b/infrastructure/kube/keep-test/tbtc-v2-monitoring/.env.secret deleted file mode 100644 index a7d6ed3bf9..0000000000 --- a/infrastructure/kube/keep-test/tbtc-v2-monitoring/.env.secret +++ /dev/null @@ -1,4 +0,0 @@ -ethereum-url= -electrum-url= -sentry-dsn= -discord-webhook-url= \ No newline at end of file diff --git a/infrastructure/kube/keep-test/tbtc-v2-monitoring/README.md b/infrastructure/kube/keep-test/tbtc-v2-monitoring/README.md deleted file mode 100644 index baa876dd6a..0000000000 --- a/infrastructure/kube/keep-test/tbtc-v2-monitoring/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# TBTCv2 system events monitoring - -Configuration to run TBTCv2 system events monitoring. It is a test -overlay of the [base `tbtc-v2-monitoring` configuration](../../templates/tbtc-v2-monitoring) - -To apply the configuration execute: - -```sh -kubectl apply -k ./ -``` diff --git a/infrastructure/kube/keep-test/tbtc-v2-monitoring/kustomization.yaml b/infrastructure/kube/keep-test/tbtc-v2-monitoring/kustomization.yaml deleted file mode 100644 index 67b1bd0cf9..0000000000 --- a/infrastructure/kube/keep-test/tbtc-v2-monitoring/kustomization.yaml +++ /dev/null @@ -1,25 +0,0 @@ -bases: - - ../../templates/tbtc-v2-monitoring - -images: - - name: tbtc-v2-monitoring - newName: gcr.io/keep-test-f3e0/tbtc-v2-monitoring - newTag: latest - -configMapGenerator: - - name: tbtc-v2-monitoring-config - literals: - - environment=testnet - - large-deposit-threshold-sat=1000000000 # 10 BTC - - large-redemption-threshold-sat=1000000000 # 10 BTC - -secretGenerator: - - name: tbtc-v2-monitoring-config - envs: - - .env.secret - -generatorOptions: - disableNameSuffixHash: true - annotations: - note: generated - diff --git a/infrastructure/kube/lcl/dashboard.yaml b/infrastructure/kube/lcl/dashboard.yaml deleted file mode 100644 index c9d9e45243..0000000000 --- a/infrastructure/kube/lcl/dashboard.yaml +++ /dev/null @@ -1,44 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: dashboard - labels: - app: dashboard -spec: - ports: - - port: 3000 - targetPort: 3000 - name: tcp-3000 - - port: 3001 - targetPort: 3001 - name: tcp-3001 - selector: - app: dashboard - type: LoadBalancer - ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: dashboard -spec: - replicas: 1 - template: - metadata: - labels: - app: dashboard - spec: - imagePullSecrets: - - name: google-container-registry-auth - containers: - - name: dashboard - image: gcr.io/keep-dev-fe24/eth-dashboard-node:latest - ports: - - containerPort: 3000 - - containerPort: 3001 - env: - - name: WS_SECRET - value: BANZAI!!!! - - name: BOOTNODE_URL - value: http://dashboard:3001 diff --git a/infrastructure/kube/lcl/k8s-pod.yaml b/infrastructure/kube/lcl/k8s-pod.yaml deleted file mode 100644 index 7b1933feb0..0000000000 --- a/infrastructure/kube/lcl/k8s-pod.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: keep-dev-environment -spec: - containers: - - name: keep-client - image: gcr.io/keep.network/keep-client diff --git a/infrastructure/kube/lcl/keystore-configmap-job.yaml b/infrastructure/kube/lcl/keystore-configmap-job.yaml deleted file mode 100644 index 2ce41b29e4..0000000000 --- a/infrastructure/kube/lcl/keystore-configmap-job.yaml +++ /dev/null @@ -1,30 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: keystore-configmap-job -spec: - template: - metadata: - name: batch-configmap-job - spec: - containers: - - name: batch-configmap-job - image: gcr.io/google_containers/busybox - volumeMounts: - - name: keystore-configmap-volume - mountPath: /keystore - command: ["cat", "$(KEEP_ETHEREUM_KEYFILE)"] - env: - - name: KEEP_ETHEREUM_ACCOUNT - value: "8b99e241b3a65030661cf8788de8e5ca45c48f2b" - - name: KEEP_ETHEREUM_KEYFILE - value: "/keystore/8b99e241b3a65030661cf8788de8e5ca45c48f2b" - volumes: - - name: keystore-configmap-volume - configMap: - name: 8b99e241b3a65030661cf8788de8e5ca45c48f2b - items: - - key: 8b99e241b3a65030661cf8788de8e5ca45c48f2b - path: 8b99e241b3a65030661cf8788de8e5ca45c48f2b - restartPolicy: Never - backoffLimit: 4 diff --git a/infrastructure/kube/lcl/miner-nodes.yaml b/infrastructure/kube/lcl/miner-nodes.yaml deleted file mode 100644 index 26081ab984..0000000000 --- a/infrastructure/kube/lcl/miner-nodes.yaml +++ /dev/null @@ -1,89 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: miner-node - labels: - app: geth - type: miner -spec: - ports: - - port: 8545 - targetPort: 8545 - name: tcp-8545 - - port: 8546 - targetPort: 8546 - name: tcp-8546 - - port: 30303 - targetPort: 30303 - name: tcp-30303 - - port: 30303 - targetPort: 30303 - name: udp-30303 - protocol: UDP - selector: - app: geth - type: miner ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: miner-node -spec: - replicas: 1 # must be 1 to utilize local persistent volume (see docs) - template: - metadata: - labels: - app: geth - type: miner - spec: - imagePullSecrets: - - name: google-container-registry-auth - containers: - - name: miner - image: gcr.io/keep-dev-fe24/eth-geth-node:latest - volumeMounts: - - mountPath: "/hostvolume" - name: hostvolume - ports: - - containerPort: 8545 - - containerPort: 8546 - - containerPort: 30303 - env: - - name: INSTANCE_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: HOST_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - - name: NETWORKID - value: "1101" - - name: WS_SERVER - value: ws://dashboard:3000 - - name: WS_SECRET - value: BANZAI!!!! - - name: BOOTNODE_URL - value: http://dashboard:3001 - - name: BOOTNODE_NETWORK - value: network_1 - - name: BOOTNODE_PUBLIC_IP - value: dashboard - - name: ENABLE_MINER - value: "1" - - name: MINER_THREADS - value: "1" - - name: HOSTVOLUME - value: "/hostvolume" - - name: ETH_IPC_PATH - value: "/root/.geth/geth.ipc" - volumes: - - name: hostvolume - hostPath: - path: /tmp/k8-volumes/miner - type: DirectoryOrCreate diff --git a/infrastructure/kube/lcl/tx-nodes.yaml b/infrastructure/kube/lcl/tx-nodes.yaml deleted file mode 100644 index a00211310a..0000000000 --- a/infrastructure/kube/lcl/tx-nodes.yaml +++ /dev/null @@ -1,85 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: tx-node - labels: - app: geth - type: tx -spec: - ports: - - port: 8545 - targetPort: 8545 - name: tcp-8545 - - port: 8546 - targetPort: 8546 - name: tcp-8546 - - port: 30303 - targetPort: 30303 - name: tcp-30303 - # - port: 30303 - # targetPort: 30303 - # name: udp-30303 - # protocol: UDP - selector: - app: geth - type: tx - type: LoadBalancer ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: tx-node -spec: - replicas: 1 # must be 1 to utilize local persistent volume (see docs) - template: - metadata: - labels: - app: geth - type: tx - spec: - imagePullSecrets: - - name: google-container-registry-auth - containers: - - name: tx - image: gcr.io/keep-dev-fe24/eth-geth-node:latest - volumeMounts: - - mountPath: "/hostvolume" - name: hostvolume - ports: - - containerPort: 8545 - - containerPort: 8546 - - containerPort: 30303 - env: - - name: INSTANCE_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: HOST_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - - name: NETWORKID - value: "1101" - - name: WS_SERVER - value: ws://dashboard:3000 - - name: WS_SECRET - value: BANZAI!!!! - - name: BOOTNODE_URL - value: http://dashboard:3001 - - name: BOOTNODE_NETWORK - value: network_1 - - name: BOOTNODE_PUBLIC_IP - value: dashboard - - name: HOSTVOLUME - value: "/hostvolume" - - name: ETH_IPC_PATH - value: "/root/.geth/geth.ipc" - volumes: - - name: hostvolume - hostPath: - path: /tmp/k8-volumes/tx - type: DirectoryOrCreate diff --git a/infrastructure/kube/templates/bitcoin/bitcoind/.env.sample b/infrastructure/kube/templates/bitcoin/bitcoind/.env.sample deleted file mode 100644 index fd955ccfd0..0000000000 --- a/infrastructure/kube/templates/bitcoin/bitcoind/.env.sample +++ /dev/null @@ -1,2 +0,0 @@ -rpc-user= -rpc-password= diff --git a/infrastructure/kube/templates/bitcoin/bitcoind/bitcoind-service.yaml b/infrastructure/kube/templates/bitcoin/bitcoind/bitcoind-service.yaml deleted file mode 100644 index c2513a87bf..0000000000 --- a/infrastructure/kube/templates/bitcoin/bitcoind/bitcoind-service.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: bitcoind -spec: - type: ClusterIP - ports: - - name: rpc - port: 8332 - targetPort: rpc - - name: network - port: 8333 - targetPort: network diff --git a/infrastructure/kube/templates/bitcoin/bitcoind/bitcoind-statefulset.yaml b/infrastructure/kube/templates/bitcoin/bitcoind/bitcoind-statefulset.yaml deleted file mode 100644 index 3b1968f487..0000000000 --- a/infrastructure/kube/templates/bitcoin/bitcoind/bitcoind-statefulset.yaml +++ /dev/null @@ -1,92 +0,0 @@ ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: bitcoind -spec: - replicas: 1 - serviceName: bitcoind - template: - spec: - securityContext: - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - # https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#configure-volume-permission-and-ownership-change-policy-for-pods - fsGroupChangePolicy: "OnRootMismatch" - containers: - - name: bitcoind - image: keepnetwork/bitcoind:24.1 - imagePullPolicy: Always - command: - - bitcoind - - -chain=$(CHAIN) - - -datadir=/mnt/bitcoind/data - - -rpcport=8332 - - -port=8333 - - -rpcbind=0.0.0.0 - - -rpcallowip=0.0.0.0/0 - - -rpcuser=$(RPC_USER) - - -rpcpassword=$(RPC_PASSWORD) - - -disablewallet=1 - - -txindex=1 - env: - - name: RPC_USER - valueFrom: - secretKeyRef: - name: bitcoind - key: rpc-user - - name: RPC_PASSWORD - valueFrom: - secretKeyRef: - name: bitcoind - key: rpc-password - - name: CHAIN - valueFrom: - configMapKeyRef: - name: bitcoind - key: chain - ports: - - name: rpc - containerPort: 8332 - protocol: TCP - - name: network - containerPort: 8333 - protocol: TCP - livenessProbe: - tcpSocket: - port: rpc - initialDelaySeconds: 20 - periodSeconds: 10 - # TODO: Define readiness probe based on: https://bitcoin.stackexchange.com/a/103370 - # readinessProbe: - # exec: - # command: - # - bitcoin-cli - # - getblockcount - # initialDelaySeconds: 20 - # periodSeconds: 15 - resources: - requests: - cpu: 100m - memory: 2Gi - volumeMounts: - - mountPath: /mnt/bitcoind/data - name: bitcoind-data - volumes: - - name: bitcoind-data - persistentVolumeClaim: - claimName: bitcoind-data - volumeClaimTemplates: - - metadata: - name: bitcoind-data - spec: - storageClassName: bitcoind - accessModes: - - ReadWriteOnce - resources: - requests: - # Estimated required storage based on the network: - # - for mainnet: 650 Gi (default) - # - for testnet: 40 Gi - storage: 650Gi diff --git a/infrastructure/kube/templates/bitcoin/bitcoind/bitcoind-storageclass.yaml b/infrastructure/kube/templates/bitcoin/bitcoind/bitcoind-storageclass.yaml deleted file mode 100644 index 3f66a4ba3c..0000000000 --- a/infrastructure/kube/templates/bitcoin/bitcoind/bitcoind-storageclass.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: storage.k8s.io/v1 -kind: StorageClass -metadata: - name: bitcoind -# Requires Google Compute Engine persistent disk CSI Driver to be enabled on the -# cluster, see: https://cloud.google.com/kubernetes-engine/docs/how-to/persistent-volumes/gce-pd-csi-driver -provisioner: pd.csi.storage.gke.io -parameters: - type: pd-ssd - replication-type: none -reclaimPolicy: Retain -allowVolumeExpansion: true -volumeBindingMode: WaitForFirstConsumer diff --git a/infrastructure/kube/templates/bitcoin/bitcoind/bitcoind-volumesnapshotclass.yaml b/infrastructure/kube/templates/bitcoin/bitcoind/bitcoind-volumesnapshotclass.yaml deleted file mode 100644 index 8529d3fa4c..0000000000 --- a/infrastructure/kube/templates/bitcoin/bitcoind/bitcoind-volumesnapshotclass.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: snapshot.storage.k8s.io/v1 -kind: VolumeSnapshotClass -metadata: - name: bitcoind -driver: pd.csi.storage.gke.io -deletionPolicy: Retain diff --git a/infrastructure/kube/templates/bitcoin/bitcoind/kustomization.yaml b/infrastructure/kube/templates/bitcoin/bitcoind/kustomization.yaml deleted file mode 100644 index ea88cfd445..0000000000 --- a/infrastructure/kube/templates/bitcoin/bitcoind/kustomization.yaml +++ /dev/null @@ -1,24 +0,0 @@ -resources: - - bitcoind-service.yaml - - bitcoind-statefulset.yaml - - bitcoind-storageclass.yaml - - bitcoind-volumesnapshotclass.yaml - -commonLabels: - chain: bitcoin - app: bitcoind - -configMapGenerator: - - name: bitcoind - literals: - - chain=main - -secretGenerator: - - name: bitcoind - envs: - - .env.sample - -generatorOptions: - disableNameSuffixHash: true - annotations: - note: generated diff --git a/infrastructure/kube/templates/bitcoin/electrumx/electrumx-service.yaml b/infrastructure/kube/templates/bitcoin/electrumx/electrumx-service.yaml deleted file mode 100644 index 5b618b17c4..0000000000 --- a/infrastructure/kube/templates/bitcoin/electrumx/electrumx-service.yaml +++ /dev/null @@ -1,24 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: electrumx -spec: - type: LoadBalancer - # Replace the value. - loadBalancerIP: XX.XX.XX.XX - # Expose the service on ports that are proxied by Cloudflare. - # See: https://developers.cloudflare.com/fundamentals/get-started/reference/network-ports/ - ports: - - name: tcp - port: 80 - targetPort: tcp - - name: ssl - port: 443 - targetPort: ssl - - name: ws - port: 8080 - targetPort: ws - - name: wss - port: 8443 - targetPort: wss diff --git a/infrastructure/kube/templates/bitcoin/electrumx/electrumx-statefulset.yaml b/infrastructure/kube/templates/bitcoin/electrumx/electrumx-statefulset.yaml deleted file mode 100644 index 4835c42aec..0000000000 --- a/infrastructure/kube/templates/bitcoin/electrumx/electrumx-statefulset.yaml +++ /dev/null @@ -1,104 +0,0 @@ ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: electrumx -spec: - replicas: 1 - serviceName: electrumx - podManagementPolicy: Parallel - template: - spec: - securityContext: - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - # https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#configure-volume-permission-and-ownership-change-policy-for-pods - fsGroupChangePolicy: "OnRootMismatch" - containers: - - name: electrumx - image: lukechilds/electrumx:v1.16.0 # TODO: switch to our image - imagePullPolicy: Always - # Full list of env vars: https://electrumx.readthedocs.io/en/latest/environment.html - env: - - name: COIN - value: BitcoinSegwit - - name: NET - value: mainnet - - name: DAEMON_USER - valueFrom: - secretKeyRef: - name: bitcoind - key: rpc-user - - name: DAEMON_TOKEN - valueFrom: - secretKeyRef: - name: bitcoind - key: rpc-password - - name: DAEMON_HOST - valueFrom: - configMapKeyRef: - name: electrumx - key: daemon-host - - name: DAEMON_URL - value: http://$(DAEMON_USER):$(DAEMON_TOKEN)@$(DAEMON_HOST) - - name: DB_DIRECTORY - value: /mnt/electrum/data - - name: SSL_CERTFILE - value: /mnt/electrum/cert/tls.crt - - name: SSL_KEYFILE - value: /mnt/electrum/cert/tls.key - - name: SERVICES - value: tcp://:50001,ssl://:50002,ws://:50003,wss://:50004,rpc://0.0.0.0:8000 - - name: COST_SOFT_LIMIT - value: "0" - - name: COST_HARD_LIMIT - value: "0" - - name: LOG_LEVEL - value: debug - ports: - - name: tcp - containerPort: 50001 - - name: ssl - containerPort: 50002 - - name: ws - containerPort: 50003 - - name: wss - containerPort: 50004 - - name: rpc - containerPort: 8000 - livenessProbe: - tcpSocket: - port: rpc - initialDelaySeconds: 20 - periodSeconds: 30 - readinessProbe: - tcpSocket: - port: tcp - initialDelaySeconds: 20 - periodSeconds: 30 - resources: - requests: - cpu: 500m - memory: 8Gi - volumeMounts: - - name: electrumx-data - mountPath: /mnt/electrum/data - - name: tbtc-network-cloudflare-origin-cert - mountPath: /mnt/electrum/cert - volumes: - - name: electrumx-data - persistentVolumeClaim: - claimName: electrumx - - name: tbtc-network-cloudflare-origin-cert - secret: - secretName: tbtc-network-cloudflare-origin-cert - volumeClaimTemplates: - - metadata: - name: electrumx-data - spec: - storageClassName: electrumx-v2 - accessModes: [ReadWriteOnce] - resources: - requests: - storage: 450Gi diff --git a/infrastructure/kube/templates/bitcoin/electrumx/electrumx-storageclass.yaml b/infrastructure/kube/templates/bitcoin/electrumx/electrumx-storageclass.yaml deleted file mode 100644 index b83cd30c20..0000000000 --- a/infrastructure/kube/templates/bitcoin/electrumx/electrumx-storageclass.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: storage.k8s.io/v1 -kind: StorageClass -metadata: - name: electrumx-v2 -# Requires Google Compute Engine persistent disk CSI Driver to be enabled on the -# cluster, see: https://cloud.google.com/kubernetes-engine/docs/how-to/persistent-volumes/gce-pd-csi-driver -provisioner: pd.csi.storage.gke.io -parameters: - type: pd-ssd - replication-type: none -reclaimPolicy: Retain -allowVolumeExpansion: true -volumeBindingMode: WaitForFirstConsumer diff --git a/infrastructure/kube/templates/bitcoin/electrumx/electrumx-volumesnapshotclass.yaml b/infrastructure/kube/templates/bitcoin/electrumx/electrumx-volumesnapshotclass.yaml deleted file mode 100644 index 45069c78c1..0000000000 --- a/infrastructure/kube/templates/bitcoin/electrumx/electrumx-volumesnapshotclass.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: snapshot.storage.k8s.io/v1 -# Read more: https://cloud.google.com/kubernetes-engine/docs/how-to/persistent-volumes/volume-snapshots#v1 -kind: VolumeSnapshotClass -metadata: - name: electrumx -driver: pd.csi.storage.gke.io -deletionPolicy: Retain diff --git a/infrastructure/kube/templates/bitcoin/electrumx/kustomization.yaml b/infrastructure/kube/templates/bitcoin/electrumx/kustomization.yaml deleted file mode 100644 index d001cae390..0000000000 --- a/infrastructure/kube/templates/bitcoin/electrumx/kustomization.yaml +++ /dev/null @@ -1,19 +0,0 @@ -resources: - - electrumx-service.yaml - - electrumx-statefulset.yaml - - electrumx-storageclass.yaml - - electrumx-volumesnapshotclass.yaml - -commonLabels: - chain: bitcoin - app: electrumx - -configMapGenerator: - - name: electrumx - literals: - - daemon-host=bitcoind:8332 - -generatorOptions: - disableNameSuffixHash: true - annotations: - note: generated diff --git a/infrastructure/kube/templates/keep-client/initcontainer/provision-keep-client/Dockerfile b/infrastructure/kube/templates/keep-client/initcontainer/provision-keep-client/Dockerfile deleted file mode 100644 index 5fb390f023..0000000000 --- a/infrastructure/kube/templates/keep-client/initcontainer/provision-keep-client/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM node:11 AS runtime - -WORKDIR /tmp - -COPY ./package.json /tmp/package.json -COPY ./package-lock.json /tmp/package-lock.json - -RUN npm install - -COPY ./TokenStaking.json /tmp/TokenStaking.json -COPY ./KeepToken.json /tmp/KeepToken.json -COPY ./KeepRandomBeaconService.json /tmp/KeepRandomBeaconService.json -COPY ./KeepRandomBeaconOperator.json /tmp/KeepRandomBeaconOperator.json - -COPY ./keep-client-config-template.toml /tmp/keep-client-config-template.toml - -COPY ./provision-keep-client.js /tmp/provision-keep-client.js - -ENTRYPOINT ["node", "./provision-keep-client.js"] diff --git a/infrastructure/kube/templates/keep-client/initcontainer/provision-keep-client/keep-client-config-template.toml b/infrastructure/kube/templates/keep-client/initcontainer/provision-keep-client/keep-client-config-template.toml deleted file mode 100644 index f328b9c606..0000000000 --- a/infrastructure/kube/templates/keep-client/initcontainer/provision-keep-client/keep-client-config-template.toml +++ /dev/null @@ -1,30 +0,0 @@ -# Values from Kube ConfigMap and set via InitContainer run, do not update manually. - -[ethereum] - URL = "" - URLRPC = "" - - [ethereum.account] - Address = "" - KeyFile = "" - - [ethereum.ContractAddresses] - # Hex-encoded address of KeepRandomBeaconOperator contract - KeepRandomBeaconOperator = "" - - # Hex-encoded address of TokenStaking contract - TokenStaking = "" - - # Hex-encoded address of KeepRandomBeaconService contract. Only needed - KeepRandomBeaconService = "" - -[LibP2P] - Peers = [] - Port = "" - AnnouncedAddresses = [] - -[Storage] - DataDir = "" - -[ClientInfo] - Port = "" diff --git a/infrastructure/kube/templates/keep-client/initcontainer/provision-keep-client/package-lock.json b/infrastructure/kube/templates/keep-client/initcontainer/provision-keep-client/package-lock.json deleted file mode 100644 index af075441bb..0000000000 --- a/infrastructure/kube/templates/keep-client/initcontainer/provision-keep-client/package-lock.json +++ /dev/null @@ -1,3935 +0,0 @@ -{ - "requires": true, - "lockfileVersion": 1, - "dependencies": { - "@babel/helper-module-imports": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz", - "integrity": "sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==", - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" - }, - "@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==" - }, - "@babel/plugin-transform-runtime": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.11.0.tgz", - "integrity": "sha512-LFEsP+t3wkYBlis8w6/kmnd6Kb1dxTd+wGJ8MlxTGzQo//ehtqlVL4S9DNUa53+dtPSQobN2CXx4d81FqC58cw==", - "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "resolve": "^1.8.1", - "semver": "^5.5.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "@babel/runtime": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.0.tgz", - "integrity": "sha512-qArkXsjJq7H+T86WrIFV0Fnu/tNOkZ4cgXmjkzAu3b/58D5mFIO8JH/y77t7C9q0OdDRdh9s7Ue5GasYssxtXw==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/types": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz", - "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==", - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "@ethersproject/abi": { - "version": "5.0.0-beta.153", - "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.0.0-beta.153.tgz", - "integrity": "sha512-aXweZ1Z7vMNzJdLpR1CZUAIgnwjrZeUSvN9syCwlBaEBUFJmFY+HHnfuTI5vIhVs/mRkfJVrbEyl51JZQqyjAg==", - "requires": { - "@ethersproject/address": ">=5.0.0-beta.128", - "@ethersproject/bignumber": ">=5.0.0-beta.130", - "@ethersproject/bytes": ">=5.0.0-beta.129", - "@ethersproject/constants": ">=5.0.0-beta.128", - "@ethersproject/hash": ">=5.0.0-beta.128", - "@ethersproject/keccak256": ">=5.0.0-beta.127", - "@ethersproject/logger": ">=5.0.0-beta.129", - "@ethersproject/properties": ">=5.0.0-beta.131", - "@ethersproject/strings": ">=5.0.0-beta.130" - } - }, - "@ethersproject/address": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.0.2.tgz", - "integrity": "sha512-+rz26RKj7ujGfQynys4V9VJRbR+wpC6eL8F22q3raWMH3152Ha31GwJPWzxE/bEA+43M/zTNVwY0R53gn53L2Q==", - "requires": { - "@ethersproject/bignumber": "^5.0.0", - "@ethersproject/bytes": "^5.0.0", - "@ethersproject/keccak256": "^5.0.0", - "@ethersproject/logger": "^5.0.0", - "@ethersproject/rlp": "^5.0.0", - "bn.js": "^4.4.0" - } - }, - "@ethersproject/bignumber": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.0.5.tgz", - "integrity": "sha512-24ln7PV0g8ZzjcVZiLW9Wod0i+XCmK6zKkAaxw5enraTIT1p7gVOcSXFSzNQ9WYAwtiFQPvvA+TIO2oEITZNJA==", - "requires": { - "@ethersproject/bytes": "^5.0.0", - "@ethersproject/logger": "^5.0.0", - "bn.js": "^4.4.0" - } - }, - "@ethersproject/bytes": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.0.3.tgz", - "integrity": "sha512-AyPMAlY+Amaw4Zfp8OAivm1xYPI8mqiUYmEnSUk1CnS2NrQGHEMmFJFiOJdS3gDDpgSOFhWIjZwxKq2VZpqNTA==", - "requires": { - "@ethersproject/logger": "^5.0.0" - } - }, - "@ethersproject/constants": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.0.2.tgz", - "integrity": "sha512-nNoVlNP6bgpog7pQ2EyD1xjlaXcy1Cl4kK5v1KoskHj58EtB6TK8M8AFGi3GgHTdMldfT4eN3OsoQ/CdOTVNFA==", - "requires": { - "@ethersproject/bignumber": "^5.0.0" - } - }, - "@ethersproject/hash": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.0.2.tgz", - "integrity": "sha512-dWGvNwmVRX2bxoQQ3ciMw46Vzl1nqfL+5R8+2ZxsRXD3Cjgw1dL2mdjJF7xMMWPvPdrlhKXWSK0gb8VLwHZ8Cw==", - "requires": { - "@ethersproject/bytes": "^5.0.0", - "@ethersproject/keccak256": "^5.0.0", - "@ethersproject/logger": "^5.0.0", - "@ethersproject/strings": "^5.0.0" - } - }, - "@ethersproject/keccak256": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.0.2.tgz", - "integrity": "sha512-MbroXutc0gPNYIrUjS4Aw0lDuXabdzI7+l7elRWr1G6G+W0v00e/3gbikWkCReGtt2Jnt4lQSgnflhDwQGcIhA==", - "requires": { - "@ethersproject/bytes": "^5.0.0", - "js-sha3": "0.5.7" - }, - "dependencies": { - "js-sha3": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", - "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=" - } - } - }, - "@ethersproject/logger": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.0.4.tgz", - "integrity": "sha512-alA2LiAy1LdQ/L1SA9ajUC7MvGAEQLsICEfKK4erX5qhkXE1LwLSPIzobtOWFsMHf2yrXGKBLnnpuVHprI3sAw==" - }, - "@ethersproject/properties": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.0.2.tgz", - "integrity": "sha512-FxAisPGAOACQjMJzewl9OJG6lsGCPTm5vpUMtfeoxzAlAb2lv+kHzQPUh9h4jfAILzE8AR1jgXMzRmlhwyra1Q==", - "requires": { - "@ethersproject/logger": "^5.0.0" - } - }, - "@ethersproject/rlp": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.0.2.tgz", - "integrity": "sha512-oE0M5jqQ67fi2SuMcrpoewOpEuoXaD8M9JeR9md1bXRMvDYgKXUtDHs22oevpEOdnO2DPIRabp6MVHa4aDuWmw==", - "requires": { - "@ethersproject/bytes": "^5.0.0", - "@ethersproject/logger": "^5.0.0" - } - }, - "@ethersproject/signing-key": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.0.3.tgz", - "integrity": "sha512-5QPZaBRGCLzfVMbFb3LcVjNR0UbTXnwDHASnQYfbzwUOnFYHKxHsrcbl/5ONGoppgi8yXgOocKqlPCFycJJVWQ==", - "requires": { - "@ethersproject/bytes": "^5.0.0", - "@ethersproject/logger": "^5.0.0", - "@ethersproject/properties": "^5.0.0", - "elliptic": "6.5.3" - } - }, - "@ethersproject/strings": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.0.2.tgz", - "integrity": "sha512-oNa+xvSqsFU96ndzog0IBTtsRFGOqGpzrXJ7shXLBT7juVeSEyZA/sYs0DMZB5mJ9FEjHdZKxR/rTyBY91vuXg==", - "requires": { - "@ethersproject/bytes": "^5.0.0", - "@ethersproject/constants": "^5.0.0", - "@ethersproject/logger": "^5.0.0" - } - }, - "@ethersproject/transactions": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.0.2.tgz", - "integrity": "sha512-jZp0ZbbJlq4JLZY6qoMzNtp2HQsX6USQposi3ns0MPUdn3OdZJBDtrcO15r/2VS5t/K1e1GE5MI1HmMKlcTbbQ==", - "requires": { - "@ethersproject/address": "^5.0.0", - "@ethersproject/bignumber": "^5.0.0", - "@ethersproject/bytes": "^5.0.0", - "@ethersproject/constants": "^5.0.0", - "@ethersproject/keccak256": "^5.0.0", - "@ethersproject/logger": "^5.0.0", - "@ethersproject/properties": "^5.0.0", - "@ethersproject/rlp": "^5.0.0", - "@ethersproject/signing-key": "^5.0.0" - } - }, - "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" - }, - "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "requires": { - "defer-to-connect": "^1.0.1" - } - }, - "@truffle/hdwallet-provider": { - "version": "1.0.40", - "resolved": "https://registry.npmjs.org/@truffle/hdwallet-provider/-/hdwallet-provider-1.0.40.tgz", - "integrity": "sha512-6SCzccdiFnlTREeVrGgd+ViVZCLFzrOYEIF/4qyzH2L6ilq/Taps5txKsd+/j8Jzz67ZRAB6utKxwBDv2wfW3A==", - "requires": { - "@trufflesuite/web3-provider-engine": "15.0.13-0", - "@types/web3": "^1.0.20", - "any-promise": "^1.3.0", - "bindings": "^1.5.0", - "ethereum-cryptography": "^0.1.3", - "ethereum-protocol": "^1.0.1", - "ethereumjs-tx": "^1.0.0", - "ethereumjs-util": "^6.1.0", - "ethereumjs-wallet": "^0.6.3", - "source-map-support": "^0.5.19" - } - }, - "@trufflesuite/eth-json-rpc-filters": { - "version": "4.1.2-1", - "resolved": "https://registry.npmjs.org/@trufflesuite/eth-json-rpc-filters/-/eth-json-rpc-filters-4.1.2-1.tgz", - "integrity": "sha512-/MChvC5dw2ck9NU1cZmdovCz2VKbOeIyR4tcxDvA5sT+NaL0rA2/R5U0yI7zsbo1zD+pgqav77rQHTzpUdDNJQ==", - "requires": { - "@trufflesuite/eth-json-rpc-middleware": "^4.4.2-0", - "await-semaphore": "^0.1.3", - "eth-query": "^2.1.2", - "json-rpc-engine": "^5.1.3", - "lodash.flatmap": "^4.5.0", - "safe-event-emitter": "^1.0.1" - } - }, - "@trufflesuite/eth-json-rpc-middleware": { - "version": "4.4.2-1", - "resolved": "https://registry.npmjs.org/@trufflesuite/eth-json-rpc-middleware/-/eth-json-rpc-middleware-4.4.2-1.tgz", - "integrity": "sha512-iEy9H8ja7/8aYES5HfrepGBKU9n/Y4OabBJEklVd/zIBlhCCBAWBqkIZgXt11nBXO/rYAeKwYuE3puH3ByYnLA==", - "requires": { - "@trufflesuite/eth-sig-util": "^1.4.2", - "btoa": "^1.2.1", - "clone": "^2.1.1", - "eth-json-rpc-errors": "^1.0.1", - "eth-query": "^2.1.2", - "ethereumjs-block": "^1.6.0", - "ethereumjs-tx": "^1.3.7", - "ethereumjs-util": "^5.1.2", - "ethereumjs-vm": "^2.6.0", - "fetch-ponyfill": "^4.0.0", - "json-rpc-engine": "^5.1.3", - "json-stable-stringify": "^1.0.1", - "pify": "^3.0.0", - "safe-event-emitter": "^1.0.1" - }, - "dependencies": { - "eth-json-rpc-errors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/eth-json-rpc-errors/-/eth-json-rpc-errors-1.1.1.tgz", - "integrity": "sha512-WT5shJ5KfNqHi9jOZD+ID8I1kuYWNrigtZat7GOQkvwo99f8SzAVaEcWhJUv656WiZOAg3P1RiJQANtUmDmbIg==", - "requires": { - "fast-safe-stringify": "^2.0.6" - } - }, - "ethereumjs-util": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", - "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "elliptic": "^6.5.2", - "ethereum-cryptography": "^0.1.3", - "ethjs-util": "^0.1.3", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1" - } - } - } - }, - "@trufflesuite/eth-sig-util": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@trufflesuite/eth-sig-util/-/eth-sig-util-1.4.2.tgz", - "integrity": "sha512-+GyfN6b0LNW77hbQlH3ufZ/1eCON7mMrGym6tdYf7xiNw9Vv3jBO72bmmos1EId2NgBvPMhmYYm6DSLQFTmzrA==", - "requires": { - "ethereumjs-abi": "^0.6.8", - "ethereumjs-util": "^5.1.1" - }, - "dependencies": { - "ethereumjs-util": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", - "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "elliptic": "^6.5.2", - "ethereum-cryptography": "^0.1.3", - "ethjs-util": "^0.1.3", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1" - } - } - } - }, - "@trufflesuite/web3-provider-engine": { - "version": "15.0.13-0", - "resolved": "https://registry.npmjs.org/@trufflesuite/web3-provider-engine/-/web3-provider-engine-15.0.13-0.tgz", - "integrity": "sha512-bgGE2Sg56XMu0dhJl7UMiFfEFSvxW47G0RCQ3schV2kUilLKeqvGHE9z1ElVi8W30F/pF7VDbp5DkprvFC9+HQ==", - "requires": { - "@trufflesuite/eth-json-rpc-filters": "^4.1.2-1", - "@trufflesuite/eth-json-rpc-middleware": "^4.4.2-1", - "@trufflesuite/eth-sig-util": "^1.4.2", - "async": "^2.5.0", - "backoff": "^2.5.0", - "clone": "^2.0.0", - "cross-fetch": "^2.1.0", - "eth-block-tracker": "^4.4.2", - "eth-json-rpc-errors": "^2.0.2", - "eth-json-rpc-infura": "^4.0.1", - "ethereumjs-block": "^1.2.2", - "ethereumjs-tx": "^1.2.0", - "ethereumjs-util": "^5.1.5", - "ethereumjs-vm": "^2.3.4", - "json-stable-stringify": "^1.0.1", - "promise-to-callback": "^1.0.0", - "readable-stream": "^2.2.9", - "request": "^2.85.0", - "semaphore": "^1.0.3", - "ws": "^5.1.1", - "xhr": "^2.2.0", - "xtend": "^4.0.1" - }, - "dependencies": { - "ethereumjs-util": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", - "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "elliptic": "^6.5.2", - "ethereum-cryptography": "^0.1.3", - "ethjs-util": "^0.1.3", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1" - } - } - } - }, - "@types/bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", - "requires": { - "@types/node": "*" - } - }, - "@types/node": { - "version": "14.0.27", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.27.tgz", - "integrity": "sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g==" - }, - "@types/pbkdf2": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz", - "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", - "requires": { - "@types/node": "*" - } - }, - "@types/secp256k1": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.1.tgz", - "integrity": "sha512-+ZjSA8ELlOp8SlKi0YLB2tz9d5iPNEmOBd+8Rz21wTMdaXQIa9b6TEnD6l5qKOCypE7FSyPyck12qZJxSDNoog==", - "requires": { - "@types/node": "*" - } - }, - "@types/web3": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@types/web3/-/web3-1.2.2.tgz", - "integrity": "sha512-eFiYJKggNrOl0nsD+9cMh2MLk4zVBfXfGnVeRFbpiZzBE20eet4KLA3fXcjSuHaBn0RnQzwLAGdgzgzdet4C0A==", - "requires": { - "web3": "*" - } - }, - "abstract-leveldown": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-2.6.3.tgz", - "integrity": "sha512-2++wDf/DYqkPR3o5tbfdhF96EfMApo1GpPfzOsR/ZYXdkSmELlvOOEAl9iKkRsktMPHdGjO4rtkBpf2I7TiTeA==", - "requires": { - "xtend": "~4.0.0" - } - }, - "aes-js": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.1.2.tgz", - "integrity": "sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==" - }, - "ajv": { - "version": "6.12.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", - "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "requires": { - "lodash": "^4.17.14" - } - }, - "async-eventemitter": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/async-eventemitter/-/async-eventemitter-0.2.4.tgz", - "integrity": "sha512-pd20BwL7Yt1zwDFy+8MX8F1+WCT8aQeKj0kQnTrH9WaeRETlRamVhD0JtRPmrV4GfOJ2F9CvdQkZeZhnh2TuHw==", - "requires": { - "async": "^2.4.0" - } - }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "await-semaphore": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/await-semaphore/-/await-semaphore-0.1.3.tgz", - "integrity": "sha512-d1W2aNSYcz/sxYO4pMGX9vq65qOTu0P800epMud+6cYYX0QcT7zyqcxec3VWzpgvdXo57UWmVbZpLMjX2m1I7Q==" - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" - }, - "aws4": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz", - "integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==" - }, - "backoff": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz", - "integrity": "sha1-9hbtqdPktmuMp/ynn2lXIsX44m8=", - "requires": { - "precond": "0.2" - } - }, - "base-x": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.8.tgz", - "integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "bignumber.js": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", - "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" - }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "requires": { - "file-uri-to-path": "1.0.0" - } - }, - "blakejs": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.1.0.tgz", - "integrity": "sha1-ad+S75U6qIylGjLfarHFShVfx6U=" - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" - }, - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" - }, - "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "requires": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" - }, - "dependencies": { - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" - } - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" - }, - "browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "requires": { - "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" - } - }, - "browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "browserify-rsa": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", - "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", - "requires": { - "bn.js": "^4.1.0", - "randombytes": "^2.0.1" - } - }, - "browserify-sign": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", - "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", - "requires": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.3", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "bn.js": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.2.tgz", - "integrity": "sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==" - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "bs58": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", - "requires": { - "base-x": "^3.0.2" - } - }, - "bs58check": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", - "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", - "requires": { - "bs58": "^4.0.0", - "create-hash": "^1.1.0", - "safe-buffer": "^5.1.2" - } - }, - "btoa": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", - "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==" - }, - "buffer": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", - "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" - }, - "buffer-to-arraybuffer": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", - "integrity": "sha1-YGSkD6dutDxyOrqe+PbhIW0QURo=" - }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" - }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" - }, - "cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "dependencies": { - "get-stream": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", - "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", - "requires": { - "pump": "^3.0.0" - } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" - } - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "checkpoint-store": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/checkpoint-store/-/checkpoint-store-1.1.0.tgz", - "integrity": "sha1-BOTLUWuRQziTWB5tRgGnjpVS6gY=", - "requires": { - "functional-red-black-tree": "^1.0.1" - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, - "cids": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/cids/-/cids-0.7.5.tgz", - "integrity": "sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA==", - "requires": { - "buffer": "^5.5.0", - "class-is": "^1.1.0", - "multibase": "~0.6.0", - "multicodec": "^1.0.0", - "multihashes": "~0.4.15" - }, - "dependencies": { - "multicodec": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-1.0.4.tgz", - "integrity": "sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg==", - "requires": { - "buffer": "^5.6.0", - "varint": "^5.0.0" - } - } - } - }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "class-is": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz", - "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==" - }, - "clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" - }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", - "requires": { - "mimic-response": "^1.0.0" - } - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "concat-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", - "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.0.2", - "typedarray": "^0.0.6" - }, - "dependencies": { - "readable-stream": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.5.0.tgz", - "integrity": "sha512-gSz026xs2LfxBPudDuI41V1lka8cxg64E66SGe78zJlsUofOg/yqwezdIcdfwik6B4h8LFmWPA9ef9X3FiNFLA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "content-hash": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/content-hash/-/content-hash-2.5.2.tgz", - "integrity": "sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw==", - "requires": { - "cids": "^0.7.1", - "multicodec": "^0.5.5", - "multihashes": "^0.4.15" - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "cookiejar": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", - "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "requires": { - "object-assign": "^4", - "vary": "^1" - } - }, - "create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - } - }, - "create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "requires": { - "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" - } - }, - "cross-fetch": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-2.2.6.tgz", - "integrity": "sha512-9JZz+vXCmfKUZ68zAptS7k4Nu8e2qcibe7WVZYps7sAgk5R8GYTc+T1WR0v1rlP9HxgARmOX1UTIJZFytajpNA==", - "requires": { - "node-fetch": "^2.6.7", - "whatwg-fetch": "^2.0.4" - }, - "dependencies": { - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "requires": { - "whatwg-url": "^5.0.0" - } - } - } - }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - } - }, - "d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==" - }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "requires": { - "mimic-response": "^1.0.0" - } - }, - "defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" - }, - "deferred-leveldown": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-1.2.2.tgz", - "integrity": "sha512-uukrWD2bguRtXilKt6cAWKyoXrTSMo5m7crUdLfWQmu8kIm88w3QZoUL+6nhpfKVmhHANER6Re3sKoNoZ3IKMA==", - "requires": { - "abstract-leveldown": "~2.6.0" - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "des.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", - "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "dom-walk": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", - "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "elliptic": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", - "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - } - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" - }, - "encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "requires": { - "iconv-lite": "^0.6.2" - } - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", - "requires": { - "prr": "~1.0.1" - } - }, - "es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", - "requires": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" - } - }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "requires": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "eth-block-tracker": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-4.4.3.tgz", - "integrity": "sha512-A8tG4Z4iNg4mw5tP1Vung9N9IjgMNqpiMoJ/FouSFwNCGHv2X0mmOYwtQOJzki6XN7r7Tyo01S29p7b224I4jw==", - "requires": { - "@babel/plugin-transform-runtime": "^7.5.5", - "@babel/runtime": "^7.5.5", - "eth-query": "^2.1.0", - "json-rpc-random-id": "^1.0.1", - "pify": "^3.0.0", - "safe-event-emitter": "^1.0.1" - } - }, - "eth-ens-namehash": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz", - "integrity": "sha1-IprEbsqG1S4MmR58sq74P/D2i88=", - "requires": { - "idna-uts46-hx": "^2.3.1", - "js-sha3": "^0.5.7" - }, - "dependencies": { - "js-sha3": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", - "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=" - } - } - }, - "eth-json-rpc-errors": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/eth-json-rpc-errors/-/eth-json-rpc-errors-2.0.2.tgz", - "integrity": "sha512-uBCRM2w2ewusRHGxN8JhcuOb2RN3ueAOYH/0BhqdFmQkZx5lj5+fLKTz0mIVOzd4FG5/kUksCzCD7eTEim6gaA==", - "requires": { - "fast-safe-stringify": "^2.0.6" - } - }, - "eth-json-rpc-infura": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/eth-json-rpc-infura/-/eth-json-rpc-infura-4.0.2.tgz", - "integrity": "sha512-dvgOrci9lZqpjpp0hoC3Zfedhg3aIpLFVDH0TdlKxRlkhR75hTrKTwxghDrQwE0bn3eKrC8RsN1m/JdnIWltpw==", - "requires": { - "cross-fetch": "^2.1.1", - "eth-json-rpc-errors": "^1.0.1", - "eth-json-rpc-middleware": "^4.1.4", - "json-rpc-engine": "^5.1.3" - }, - "dependencies": { - "eth-json-rpc-errors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/eth-json-rpc-errors/-/eth-json-rpc-errors-1.1.1.tgz", - "integrity": "sha512-WT5shJ5KfNqHi9jOZD+ID8I1kuYWNrigtZat7GOQkvwo99f8SzAVaEcWhJUv656WiZOAg3P1RiJQANtUmDmbIg==", - "requires": { - "fast-safe-stringify": "^2.0.6" - } - } - } - }, - "eth-json-rpc-middleware": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-4.4.1.tgz", - "integrity": "sha512-yoSuRgEYYGFdVeZg3poWOwAlRI+MoBIltmOB86MtpoZjvLbou9EB/qWMOWSmH2ryCWLW97VYY6NWsmWm3OAA7A==", - "requires": { - "btoa": "^1.2.1", - "clone": "^2.1.1", - "eth-json-rpc-errors": "^1.0.1", - "eth-query": "^2.1.2", - "eth-sig-util": "^1.4.2", - "ethereumjs-block": "^1.6.0", - "ethereumjs-tx": "^1.3.7", - "ethereumjs-util": "^5.1.2", - "ethereumjs-vm": "^2.6.0", - "fetch-ponyfill": "^4.0.0", - "json-rpc-engine": "^5.1.3", - "json-stable-stringify": "^1.0.1", - "pify": "^3.0.0", - "safe-event-emitter": "^1.0.1" - }, - "dependencies": { - "eth-json-rpc-errors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/eth-json-rpc-errors/-/eth-json-rpc-errors-1.1.1.tgz", - "integrity": "sha512-WT5shJ5KfNqHi9jOZD+ID8I1kuYWNrigtZat7GOQkvwo99f8SzAVaEcWhJUv656WiZOAg3P1RiJQANtUmDmbIg==", - "requires": { - "fast-safe-stringify": "^2.0.6" - } - }, - "ethereumjs-util": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", - "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "elliptic": "^6.5.2", - "ethereum-cryptography": "^0.1.3", - "ethjs-util": "^0.1.3", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1" - } - } - } - }, - "eth-lib": { - "version": "0.1.29", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.29.tgz", - "integrity": "sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ==", - "requires": { - "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" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "ws": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", - "requires": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0", - "ultron": "~1.1.0" - } - } - } - }, - "eth-query": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/eth-query/-/eth-query-2.1.2.tgz", - "integrity": "sha1-1nQdkAAQa1FRDHLbktY2VFam2l4=", - "requires": { - "json-rpc-random-id": "^1.0.0", - "xtend": "^4.0.1" - } - }, - "eth-rpc-errors": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eth-rpc-errors/-/eth-rpc-errors-3.0.0.tgz", - "integrity": "sha512-iPPNHPrLwUlR9xCSYm7HHQjWBasor3+KZfRvwEWxMz3ca0yqnlBeJrnyphkGIXZ4J7AMAaOLmwy4AWhnxOiLxg==", - "requires": { - "fast-safe-stringify": "^2.0.6" - } - }, - "eth-sig-util": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", - "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", - "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", - "ethereumjs-util": "^5.1.1" - }, - "dependencies": { - "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#1cfbb13862f90f0b391d8a699544d5fe4dfb8c7b", - "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", - "requires": { - "bn.js": "^4.11.8", - "ethereumjs-util": "^6.0.0" - }, - "dependencies": { - "ethereumjs-util": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", - "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", - "requires": { - "@types/bn.js": "^4.11.3", - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "elliptic": "^6.5.2", - "ethereum-cryptography": "^0.1.3", - "ethjs-util": "0.1.6", - "rlp": "^2.2.3" - } - } - } - }, - "ethereumjs-util": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", - "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "elliptic": "^6.5.2", - "ethereum-cryptography": "^0.1.3", - "ethjs-util": "^0.1.3", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1" - } - } - } - }, - "ethereum-bloom-filters": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.7.tgz", - "integrity": "sha512-cDcJJSJ9GMAcURiAWO3DxIEhTL/uWqlQnvgKpuYQzYPrt/izuGU+1ntQmHt0IRq6ADoSYHFnB+aCEFIldjhkMQ==", - "requires": { - "js-sha3": "^0.8.0" - } - }, - "ethereum-common": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/ethereum-common/-/ethereum-common-0.2.0.tgz", - "integrity": "sha512-XOnAR/3rntJgbCdGhqdaLIxDLWKLmsZOGhHdBKadEr6gEnJLH52k93Ou+TUdFaPN3hJc3isBZBal3U/XZ15abA==" - }, - "ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "requires": { - "@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" - } - }, - "ethereum-protocol": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ethereum-protocol/-/ethereum-protocol-1.0.1.tgz", - "integrity": "sha512-3KLX1mHuEsBW0dKG+c6EOJS1NBNqdCICvZW9sInmZTt5aY0oxmHVggYRE0lJu1tcnMD1K+AKHdLi6U43Awm1Vg==" - }, - "ethereumjs-abi": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", - "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", - "requires": { - "bn.js": "^4.11.8", - "ethereumjs-util": "^6.0.0" - } - }, - "ethereumjs-account": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/ethereumjs-account/-/ethereumjs-account-2.0.5.tgz", - "integrity": "sha512-bgDojnXGjhMwo6eXQC0bY6UK2liSFUSMwwylOmQvZbSl/D7NXQ3+vrGO46ZeOgjGfxXmgIeVNDIiHw7fNZM4VA==", - "requires": { - "ethereumjs-util": "^5.0.0", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1" - }, - "dependencies": { - "ethereumjs-util": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", - "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "elliptic": "^6.5.2", - "ethereum-cryptography": "^0.1.3", - "ethjs-util": "^0.1.3", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1" - } - } - } - }, - "ethereumjs-block": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz", - "integrity": "sha512-B+sSdtqm78fmKkBq78/QLKJbu/4Ts4P2KFISdgcuZUPDm9x+N7qgBPIIFUGbaakQh8bzuquiRVbdmvPKqbILRg==", - "requires": { - "async": "^2.0.1", - "ethereum-common": "0.2.0", - "ethereumjs-tx": "^1.2.2", - "ethereumjs-util": "^5.0.0", - "merkle-patricia-tree": "^2.1.2" - }, - "dependencies": { - "ethereumjs-util": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", - "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "elliptic": "^6.5.2", - "ethereum-cryptography": "^0.1.3", - "ethjs-util": "^0.1.3", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1" - } - } - } - }, - "ethereumjs-common": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-1.5.2.tgz", - "integrity": "sha512-hTfZjwGX52GS2jcVO6E2sx4YuFnf0Fhp5ylo4pEPhEffNln7vS59Hr5sLnp3/QCazFLluuBZ+FZ6J5HTp0EqCA==" - }, - "ethereumjs-tx": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz", - "integrity": "sha512-wvLMxzt1RPhAQ9Yi3/HKZTn0FZYpnsmQdbKYfUUpi4j1SEIcbkd9tndVjcPrufY3V7j2IebOpC00Zp2P/Ay2kA==", - "requires": { - "ethereum-common": "^0.0.18", - "ethereumjs-util": "^5.0.0" - }, - "dependencies": { - "ethereum-common": { - "version": "0.0.18", - "resolved": "https://registry.npmjs.org/ethereum-common/-/ethereum-common-0.0.18.tgz", - "integrity": "sha1-L9w1dvIykDNYl26znaeDIT/5Uj8=" - }, - "ethereumjs-util": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", - "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "elliptic": "^6.5.2", - "ethereum-cryptography": "^0.1.3", - "ethjs-util": "^0.1.3", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1" - } - } - } - }, - "ethereumjs-util": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", - "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", - "requires": { - "@types/bn.js": "^4.11.3", - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "elliptic": "^6.5.2", - "ethereum-cryptography": "^0.1.3", - "ethjs-util": "0.1.6", - "rlp": "^2.2.3" - } - }, - "ethereumjs-vm": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/ethereumjs-vm/-/ethereumjs-vm-2.6.0.tgz", - "integrity": "sha512-r/XIUik/ynGbxS3y+mvGnbOKnuLo40V5Mj1J25+HEO63aWYREIqvWeRO/hnROlMBE5WoniQmPmhiaN0ctiHaXw==", - "requires": { - "async": "^2.1.2", - "async-eventemitter": "^0.2.2", - "ethereumjs-account": "^2.0.3", - "ethereumjs-block": "~2.2.0", - "ethereumjs-common": "^1.1.0", - "ethereumjs-util": "^6.0.0", - "fake-merkle-patricia-tree": "^1.0.1", - "functional-red-black-tree": "^1.0.1", - "merkle-patricia-tree": "^2.3.2", - "rustbn.js": "~0.2.0", - "safe-buffer": "^5.1.1" - }, - "dependencies": { - "ethereumjs-block": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/ethereumjs-block/-/ethereumjs-block-2.2.2.tgz", - "integrity": "sha512-2p49ifhek3h2zeg/+da6XpdFR3GlqY3BIEiqxGF8j9aSRIgkb7M1Ky+yULBKJOu8PAZxfhsYA+HxUk2aCQp3vg==", - "requires": { - "async": "^2.0.1", - "ethereumjs-common": "^1.5.0", - "ethereumjs-tx": "^2.1.1", - "ethereumjs-util": "^5.0.0", - "merkle-patricia-tree": "^2.1.2" - }, - "dependencies": { - "ethereumjs-util": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", - "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "elliptic": "^6.5.2", - "ethereum-cryptography": "^0.1.3", - "ethjs-util": "^0.1.3", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1" - } - } - } - }, - "ethereumjs-tx": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz", - "integrity": "sha512-zZEK1onCeiORb0wyCXUvg94Ve5It/K6GD1K+26KfFKodiBiS6d9lfCXlUKGBBdQ+bv7Day+JK0tj1K+BeNFRAw==", - "requires": { - "ethereumjs-common": "^1.5.0", - "ethereumjs-util": "^6.0.0" - } - } - } - }, - "ethereumjs-wallet": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/ethereumjs-wallet/-/ethereumjs-wallet-0.6.5.tgz", - "integrity": "sha512-MDwjwB9VQVnpp/Dc1XzA6J1a3wgHQ4hSvA1uWNatdpOrtCbPVuQSKSyRnjLvS0a+KKMw2pvQ9Ybqpb3+eW8oNA==", - "requires": { - "aes-js": "^3.1.1", - "bs58check": "^2.1.2", - "ethereum-cryptography": "^0.1.3", - "ethereumjs-util": "^6.0.0", - "randombytes": "^2.0.6", - "safe-buffer": "^5.1.2", - "scryptsy": "^1.2.1", - "utf8": "^3.0.0", - "uuid": "^3.3.2" - } - }, - "ethjs-unit": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", - "integrity": "sha1-xmWSHkduh7ziqdWIpv4EBbLEFpk=", - "requires": { - "bn.js": "4.11.6", - "number-to-bn": "1.7.0" - }, - "dependencies": { - "bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" - } - } - }, - "ethjs-util": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", - "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", - "requires": { - "is-hex-prefixed": "1.0.0", - "strip-hex-prefix": "1.0.0" - } - }, - "eventemitter3": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", - "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" - }, - "events": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", - "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==" - }, - "evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", - "requires": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.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" - }, - "dependencies": { - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, - "body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "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.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - } - }, - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "requires": { - "safe-buffer": "5.2.1" - } - }, - "cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, - "destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" - }, - "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "requires": { - "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" - } - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" - }, - "on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "requires": { - "ee-first": "1.1.1" - } - }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - } - }, - "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "requires": { - "side-channel": "^1.0.4" - } - }, - "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "requires": { - "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" - } - }, - "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - } - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" - }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" - } - } - }, - "ext": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", - "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", - "requires": { - "type": "^2.0.0" - }, - "dependencies": { - "type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", - "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==" - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "fake-merkle-patricia-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fake-merkle-patricia-tree/-/fake-merkle-patricia-tree-1.0.1.tgz", - "integrity": "sha1-S4w6z7Ugr635hgsfFM2M40As3dM=", - "requires": { - "checkpoint-store": "^1.1.0" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "fast-safe-stringify": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", - "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" - }, - "fetch-ponyfill": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz", - "integrity": "sha1-rjzl9zLGReq4fkroeTQUcJsjmJM=", - "requires": { - "node-fetch": "~1.7.1" - } - }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" - }, - "fs-extra": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", - "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs-minipass": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", - "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", - "requires": { - "minipass": "^2.6.0" - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" - }, - "get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - } - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "requires": { - "pump": "^3.0.0" - } - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "global": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz", - "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=", - "requires": { - "min-document": "^2.19.0", - "process": "~0.5.1" - } - }, - "got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "requires": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-symbol-support-x": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", - "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==" - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" - }, - "has-to-string-tag-x": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", - "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", - "requires": { - "has-symbol-support-x": "^1.4.1" - } - }, - "hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", - "requires": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" - }, - "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - } - } - }, - "http-https": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", - "integrity": "sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs=" - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "iconv-lite": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", - "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, - "idna-uts46-hx": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz", - "integrity": "sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA==", - "requires": { - "punycode": "2.1.0" - }, - "dependencies": { - "punycode": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", - "integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=" - } - } - }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" - }, - "immediate": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", - "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==" - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" - }, - "is-fn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fn/-/is-fn-1.0.0.tgz", - "integrity": "sha1-lUPV3nvPWwiiLsiiC65uKG1RDYw=" - }, - "is-function": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", - "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==" - }, - "is-hex-prefixed": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", - "integrity": "sha1-fY035q135dEnFIkTxXPggtd39VQ=" - }, - "is-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", - "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=" - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" - }, - "is-retry-allowed": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", - "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==" - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "isurl": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", - "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", - "requires": { - "has-to-string-tag-x": "^1.2.0", - "is-object": "^1.0.1" - } - }, - "js-sha3": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, - "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" - }, - "json-rpc-engine": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-5.3.0.tgz", - "integrity": "sha512-+diJ9s8rxB+fbJhT7ZEf8r8spaLRignLd8jTgQ/h5JSGppAHGtNMZtCoabipCaleR1B3GTGxbXBOqhaJSGmPGQ==", - "requires": { - "eth-rpc-errors": "^3.0.0", - "safe-event-emitter": "^1.0.1" - } - }, - "json-rpc-random-id": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-rpc-random-id/-/json-rpc-random-id-1.0.1.tgz", - "integrity": "sha1-uknZat7RRE27jaPSA3SKy7zeyMg=" - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "requires": { - "jsonify": "~0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "keccak": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.1.tgz", - "integrity": "sha512-epq90L9jlFWCW7+pQa6JOnKn2Xgl2mtI664seYR6MHskvI9agt7AnDqmAlp9TqU4/caMYbA08Hi5DMZAl5zdkA==", - "requires": { - "node-addon-api": "^2.0.0", - "node-gyp-build": "^4.2.0" - } - }, - "keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "requires": { - "json-buffer": "3.0.0" - } - }, - "level-codec": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-7.0.1.tgz", - "integrity": "sha512-Ua/R9B9r3RasXdRmOtd+t9TCOEIIlts+TN/7XTT2unhDaL6sJn83S3rUyljbr6lVtw49N3/yA0HHjpV6Kzb2aQ==" - }, - "level-errors": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-1.0.5.tgz", - "integrity": "sha512-/cLUpQduF6bNrWuAC4pwtUKA5t669pCsCi2XbmojG2tFeOr9j6ShtdDCtFFQO1DRt+EVZhx9gPzP9G2bUaG4ig==", - "requires": { - "errno": "~0.1.1" - } - }, - "level-iterator-stream": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-1.3.1.tgz", - "integrity": "sha1-5Dt4sagUPm+pek9IXrjqUwNS8u0=", - "requires": { - "inherits": "^2.0.1", - "level-errors": "^1.0.3", - "readable-stream": "^1.0.33", - "xtend": "^4.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } - }, - "level-ws": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/level-ws/-/level-ws-0.0.0.tgz", - "integrity": "sha1-Ny5RIXeSSgBCSwtDrvK7QkltIos=", - "requires": { - "readable-stream": "~1.0.15", - "xtend": "~2.1.1" - }, - "dependencies": { - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, - "xtend": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", - "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", - "requires": { - "object-keys": "~0.4.0" - } - } - } - }, - "levelup": { - "version": "1.3.9", - "resolved": "https://registry.npmjs.org/levelup/-/levelup-1.3.9.tgz", - "integrity": "sha512-VVGHfKIlmw8w1XqpGOAGwq6sZm2WwWLmlDcULkKWQXEA5EopA8OBNJ2Ck2v6bdk8HeEZSbCSEgzXadyQFm76sQ==", - "requires": { - "deferred-leveldown": "~1.2.1", - "level-codec": "~7.0.0", - "level-errors": "~1.0.3", - "level-iterator-stream": "~1.3.0", - "prr": "~1.0.1", - "semver": "~5.4.1", - "xtend": "~4.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.flatmap": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.flatmap/-/lodash.flatmap-4.5.0.tgz", - "integrity": "sha1-74y/QI9uSCaGYzRTBcaswLd4cC4=" - }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" - }, - "ltgt": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz", - "integrity": "sha1-81ypHEk/e3PaDgdJUwTxezH4fuU=" - }, - "md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" - }, - "memdown": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/memdown/-/memdown-1.4.1.tgz", - "integrity": "sha1-tOThkhdGZP+65BNhqlAPMRnv4hU=", - "requires": { - "abstract-leveldown": "~2.7.1", - "functional-red-black-tree": "^1.0.1", - "immediate": "^3.2.3", - "inherits": "~2.0.1", - "ltgt": "~2.2.0", - "safe-buffer": "~5.1.1" - }, - "dependencies": { - "abstract-leveldown": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-2.7.2.tgz", - "integrity": "sha512-+OVvxH2rHVEhWLdbudP6p0+dNMXu8JA1CbhP19T8paTYAcX7oJ4OVjT+ZUVpv7mITxXHqDMej+GdqXBmXkw09w==", - "requires": { - "xtend": "~4.0.0" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } - } - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "merkle-patricia-tree": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/merkle-patricia-tree/-/merkle-patricia-tree-2.3.2.tgz", - "integrity": "sha512-81PW5m8oz/pz3GvsAwbauj7Y00rqm81Tzad77tHBwU7pIAtN+TJnMSOJhxBKflSVYhptMMb9RskhqHqrSm1V+g==", - "requires": { - "async": "^1.4.2", - "ethereumjs-util": "^5.0.0", - "level-ws": "0.0.0", - "levelup": "^1.2.1", - "memdown": "^1.0.0", - "readable-stream": "^2.0.0", - "rlp": "^2.0.0", - "semaphore": ">=1.0.1" - }, - "dependencies": { - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" - }, - "ethereumjs-util": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", - "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "elliptic": "^6.5.2", - "ethereum-cryptography": "^0.1.3", - "ethjs-util": "^0.1.3", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1" - } - } - } - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" - }, - "mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", - "requires": { - "mime-db": "1.44.0" - } - }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" - }, - "min-document": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", - "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", - "requires": { - "dom-walk": "^0.1.0" - } - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" - }, - "minipass": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", - "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", - "requires": { - "minipass": "^2.9.0" - } - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" - }, - "mkdirp-promise": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz", - "integrity": "sha1-6bj2jlUsaKnBcTuEiD96HdA5uKE=", - "requires": { - "mkdirp": "*" - } - }, - "mock-fs": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.12.0.tgz", - "integrity": "sha512-/P/HtrlvBxY4o/PzXY9cCNBrdylDNxg7gnrv2sMNxj+UJ2m8jSpl0/A6fuJeNAWr99ZvGWH8XCbE0vmnM5KupQ==" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "multibase": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.6.1.tgz", - "integrity": "sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==", - "requires": { - "base-x": "^3.0.8", - "buffer": "^5.5.0" - } - }, - "multicodec": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-0.5.7.tgz", - "integrity": "sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA==", - "requires": { - "varint": "^5.0.0" - } - }, - "multihashes": { - "version": "0.4.21", - "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.21.tgz", - "integrity": "sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw==", - "requires": { - "buffer": "^5.5.0", - "multibase": "^0.7.0", - "varint": "^5.0.0" - }, - "dependencies": { - "multibase": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.7.0.tgz", - "integrity": "sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==", - "requires": { - "base-x": "^3.0.8", - "buffer": "^5.5.0" - } - } - } - }, - "nan": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", - "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==" - }, - "nano-json-stream-parser": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", - "integrity": "sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18=" - }, - "next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" - }, - "node-addon-api": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", - "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==" - }, - "node-fetch": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", - "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", - "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" - } - }, - "node-gyp-build": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz", - "integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==" - }, - "normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==" - }, - "number-to-bn": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", - "integrity": "sha1-uzYjWS9+X54AMLGXe9QaDFP+HqA=", - "requires": { - "bn.js": "4.11.6", - "strip-hex-prefix": "1.0.0" - }, - "dependencies": { - "bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" - } - } - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" - }, - "object-keys": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", - "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=" - }, - "oboe": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.4.tgz", - "integrity": "sha1-IMiM2wwVNxuwQRklfU/dNLCqSfY=", - "requires": { - "http-https": "^1.0.0" - } - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" - }, - "p-timeout": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", - "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", - "requires": { - "p-finally": "^1.0.0" - } - }, - "parse-asn1": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", - "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", - "requires": { - "asn1.js": "^4.0.0", - "browserify-aes": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, - "parse-headers": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.3.tgz", - "integrity": "sha512-QhhZ+DCCit2Coi2vmAKbq5RGTRcQUOE2+REgv8vdyu7MnYx2eZztegqtTx99TZ86GTIwqiy3+4nQTWZ2tgmdCA==" - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" - }, - "pbkdf2": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", - "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - }, - "precond": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz", - "integrity": "sha1-qpWRvKokkj8eD0hJ0kD0fvwQdaw=" - }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" - }, - "process": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", - "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=" - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "promise-to-callback": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/promise-to-callback/-/promise-to-callback-1.0.0.tgz", - "integrity": "sha1-XSp0kBC/tn2WNZj805YHRqaP7vc=", - "requires": { - "is-fn": "^1.0.0", - "set-immediate-shim": "^1.0.1" - } - }, - "prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" - }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" - }, - "public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" - }, - "query-string": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", - "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", - "requires": { - "decode-uri-component": "^0.2.0", - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" - } - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "dependencies": { - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - } - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } - } - }, - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" - }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "requires": { - "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" - } - }, - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "requires": { - "path-parse": "^1.0.6" - } - }, - "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", - "requires": { - "lowercase-keys": "^1.0.0" - } - }, - "ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "rlp": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.6.tgz", - "integrity": "sha512-HAfAmL6SDYNWPUOJNrM500x4Thn4PZsEy5pijPh40U9WfNk0z15hUYzO9xVIMAdIHdFtD8CBDHd75Td1g36Mjg==", - "requires": { - "bn.js": "^4.11.1" - } - }, - "rustbn.js": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz", - "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==" - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "safe-event-emitter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-event-emitter/-/safe-event-emitter-1.0.1.tgz", - "integrity": "sha512-e1wFe99A91XYYxoQbcq2ZJUWurxEyP8vfz7A7vuUe1s95q8r5ebraVaA1BukYJcpM6V16ugWoD9vngi8Ccu5fg==", - "requires": { - "events": "^3.0.0" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "scrypt-js": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", - "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" - }, - "scryptsy": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/scryptsy/-/scryptsy-1.2.1.tgz", - "integrity": "sha1-oyJfpLJST4AnAHYeKFW987LZIWM=", - "requires": { - "pbkdf2": "^3.0.3" - } - }, - "secp256k1": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz", - "integrity": "sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg==", - "requires": { - "elliptic": "^6.5.2", - "node-addon-api": "^2.0.0", - "node-gyp-build": "^4.2.0" - } - }, - "semaphore": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/semaphore/-/semaphore-1.1.0.tgz", - "integrity": "sha512-O4OZEaNtkMd/K0i6js9SL+gqy0ZCBMgUvlSqHKi4IBdjhe7wB8pwztUk1BbZ1fmrvpwFrPbHzqd2w5pTcJH6LA==" - }, - "semver": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", - "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==" - }, - "servify": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/servify/-/servify-0.1.12.tgz", - "integrity": "sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw==", - "requires": { - "body-parser": "^1.16.0", - "cors": "^2.8.1", - "express": "^4.14.0", - "request": "^2.79.0", - "xhr": "^2.3.3" - } - }, - "set-immediate-shim": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", - "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=" - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" - }, - "simple-get": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz", - "integrity": "sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw==", - "requires": { - "decompress-response": "^3.3.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "requires": { - "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" - } - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" - }, - "strict-uri-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } - } - }, - "strip-hex-prefix": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", - "integrity": "sha1-DF8VX+8RUTczd96du1iNoFUA428=", - "requires": { - "is-hex-prefixed": "1.0.0" - } - }, - "swarm-js": { - "version": "0.1.40", - "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.40.tgz", - "integrity": "sha512-yqiOCEoA4/IShXkY3WKwP5PvZhmoOOD8clsKA7EEcRILMkTEYHCQ21HDCAcVpmIxZq4LyZvWeRJ6quIyHk1caA==", - "requires": { - "bluebird": "^3.5.0", - "buffer": "^5.0.5", - "eth-lib": "^0.1.26", - "fs-extra": "^4.0.2", - "got": "^7.1.0", - "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" - }, - "dependencies": { - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" - }, - "got": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", - "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", - "requires": { - "decompress-response": "^3.2.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-plain-obj": "^1.1.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "isurl": "^1.0.0-alpha5", - "lowercase-keys": "^1.0.0", - "p-cancelable": "^0.3.0", - "p-timeout": "^1.1.1", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "url-parse-lax": "^1.0.0", - "url-to-options": "^1.0.1" - } - }, - "p-cancelable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", - "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==" - }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" - }, - "url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", - "requires": { - "prepend-http": "^1.0.1" - } - } - } - }, - "tar": { - "version": "4.4.19", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", - "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", - "requires": { - "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" - }, - "dependencies": { - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - } - } - } - }, - "timed-out": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" - }, - "to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==" - }, - "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" - }, - "toml": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", - "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==" - }, - "tomlify-j0.4": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tomlify-j0.4/-/tomlify-j0.4-3.0.0.tgz", - "integrity": "sha512-2Ulkc8T7mXJ2l0W476YC/A209PR38Nw8PuaCNtk9uI3t1zzFdGQeWYGQvmj2PZkVvRC/Yoi4xQKMRnWc/N29tQ==" - }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - }, - "type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "ultron": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" - }, - "underscore": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", - "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "requires": { - "punycode": "^2.1.0" - } - }, - "url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "requires": { - "prepend-http": "^2.0.0" - } - }, - "url-set-query": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", - "integrity": "sha1-AW6M/Xwg7gXK/neV6JK9BwL6ozk=" - }, - "url-to-options": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", - "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=" - }, - "utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", - "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==" - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - }, - "varint": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.0.tgz", - "integrity": "sha1-2Ca4n3SQcy+rwMDtaT7Uddyynr8=" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "web3": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3/-/web3-1.2.9.tgz", - "integrity": "sha512-Mo5aBRm0JrcNpN/g4VOrDzudymfOnHRC3s2VarhYxRA8aWgF5rnhQ0ziySaugpic1gksbXPe105pUWyRqw8HUA==", - "requires": { - "web3-bzz": "1.2.9", - "web3-core": "1.2.9", - "web3-eth": "1.2.9", - "web3-eth-personal": "1.2.9", - "web3-net": "1.2.9", - "web3-shh": "1.2.9", - "web3-utils": "1.2.9" - } - }, - "web3-bzz": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.2.9.tgz", - "integrity": "sha512-ogVQr9jHodu9HobARtvUSmWG22cv2EUQzlPeejGWZ7j5h20HX40EDuWyomGY5VclIj5DdLY76Tmq88RTf/6nxA==", - "requires": { - "@types/node": "^10.12.18", - "got": "9.6.0", - "swarm-js": "^0.1.40", - "underscore": "1.9.1" - }, - "dependencies": { - "@types/node": { - "version": "10.17.28", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.28.tgz", - "integrity": "sha512-dzjES1Egb4c1a89C7lKwQh8pwjYmlOAG9dW1pBgxEk57tMrLnssOfEthz8kdkNaBd7lIqQx7APm5+mZ619IiCQ==" - } - } - }, - "web3-core": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.2.9.tgz", - "integrity": "sha512-fSYv21IP658Ty2wAuU9iqmW7V+75DOYMVZsDH/c14jcF/1VXnedOcxzxSj3vArsCvXZNe6XC5/wAuGZyQwR9RA==", - "requires": { - "@types/bn.js": "^4.11.4", - "@types/node": "^12.6.1", - "bignumber.js": "^9.0.0", - "web3-core-helpers": "1.2.9", - "web3-core-method": "1.2.9", - "web3-core-requestmanager": "1.2.9", - "web3-utils": "1.2.9" - }, - "dependencies": { - "@types/node": { - "version": "12.12.53", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.53.tgz", - "integrity": "sha512-51MYTDTyCziHb70wtGNFRwB4l+5JNvdqzFSkbDvpbftEgVUBEE+T5f7pROhWMp/fxp07oNIEQZd5bbfAH22ohQ==" - } - } - }, - "web3-core-helpers": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.9.tgz", - "integrity": "sha512-t0WAG3orLCE3lqi77ZoSRNFok3VQWZXTniZigDQjyOJYMAX7BU3F3js8HKbjVnAxlX3tiKoDxI0KBk9F3AxYuw==", - "requires": { - "underscore": "1.9.1", - "web3-eth-iban": "1.2.9", - "web3-utils": "1.2.9" - } - }, - "web3-core-method": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.2.9.tgz", - "integrity": "sha512-bjsIoqP3gs7A/gP8+QeLUCyOKJ8bopteCSNbCX36Pxk6TYfYWNuC6hP+2GzUuqdP3xaZNe+XEElQFUNpR3oyAg==", - "requires": { - "@ethersproject/transactions": "^5.0.0-beta.135", - "underscore": "1.9.1", - "web3-core-helpers": "1.2.9", - "web3-core-promievent": "1.2.9", - "web3-core-subscriptions": "1.2.9", - "web3-utils": "1.2.9" - } - }, - "web3-core-promievent": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.2.9.tgz", - "integrity": "sha512-0eAUA2zjgXTleSrnc1wdoKQPPIHU6KHf4fAscu4W9kKrR+mqP1KsjYrxY9wUyjNnXxfQ+5M29ipvbiaK8OqdOw==", - "requires": { - "eventemitter3": "3.1.2" - } - }, - "web3-core-requestmanager": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.2.9.tgz", - "integrity": "sha512-1PwKV2m46ALUnIN5VPPgjOj8yMLJhhqZYvYJE34hTN5SErOkwhzx5zScvo5MN7v7KyQGFnpVCZKKGCiEnDmtFA==", - "requires": { - "underscore": "1.9.1", - "web3-core-helpers": "1.2.9", - "web3-providers-http": "1.2.9", - "web3-providers-ipc": "1.2.9", - "web3-providers-ws": "1.2.9" - } - }, - "web3-core-subscriptions": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.2.9.tgz", - "integrity": "sha512-Y48TvXPSPxEM33OmXjGVDMzTd0j8X0t2+sDw66haeBS8eYnrEzasWuBZZXDq0zNUsqyxItgBGDn+cszkgEnFqg==", - "requires": { - "eventemitter3": "3.1.2", - "underscore": "1.9.1", - "web3-core-helpers": "1.2.9" - } - }, - "web3-eth": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.2.9.tgz", - "integrity": "sha512-sIKO4iE9FEBa/CYUd6GdPd7GXt/wISqxUd8PlIld6+hvMJj02lgO7Z7p5T9mZIJcIZJGvZX81ogx8oJ9yif+Ag==", - "requires": { - "underscore": "1.9.1", - "web3-core": "1.2.9", - "web3-core-helpers": "1.2.9", - "web3-core-method": "1.2.9", - "web3-core-subscriptions": "1.2.9", - "web3-eth-abi": "1.2.9", - "web3-eth-accounts": "1.2.9", - "web3-eth-contract": "1.2.9", - "web3-eth-ens": "1.2.9", - "web3-eth-iban": "1.2.9", - "web3-eth-personal": "1.2.9", - "web3-net": "1.2.9", - "web3-utils": "1.2.9" - } - }, - "web3-eth-abi": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.2.9.tgz", - "integrity": "sha512-3YwUYbh/DMfDbhMWEebAdjSd5bj3ZQieOjLzWFHU23CaLEqT34sUix1lba+hgUH/EN6A7bKAuKOhR3p0OvTn7Q==", - "requires": { - "@ethersproject/abi": "5.0.0-beta.153", - "underscore": "1.9.1", - "web3-utils": "1.2.9" - } - }, - "web3-eth-accounts": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.2.9.tgz", - "integrity": "sha512-jkbDCZoA1qv53mFcRHCinoCsgg8WH+M0YUO1awxmqWXRmCRws1wW0TsuSQ14UThih5Dxolgl+e+aGWxG58LMwg==", - "requires": { - "crypto-browserify": "3.12.0", - "eth-lib": "^0.2.8", - "ethereumjs-common": "^1.3.2", - "ethereumjs-tx": "^2.1.1", - "scrypt-js": "^3.0.1", - "underscore": "1.9.1", - "uuid": "3.3.2", - "web3-core": "1.2.9", - "web3-core-helpers": "1.2.9", - "web3-core-method": "1.2.9", - "web3-utils": "1.2.9" - }, - "dependencies": { - "eth-lib": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", - "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", - "requires": { - "bn.js": "^4.11.6", - "elliptic": "^6.4.0", - "xhr-request-promise": "^0.1.2" - } - }, - "ethereumjs-tx": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz", - "integrity": "sha512-zZEK1onCeiORb0wyCXUvg94Ve5It/K6GD1K+26KfFKodiBiS6d9lfCXlUKGBBdQ+bv7Day+JK0tj1K+BeNFRAw==", - "requires": { - "ethereumjs-common": "^1.5.0", - "ethereumjs-util": "^6.0.0" - } - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" - } - } - }, - "web3-eth-contract": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.2.9.tgz", - "integrity": "sha512-PYMvJf7EG/HyssUZa+pXrc8IB06K/YFfWYyW4R7ed3sab+9wWUys1TlWxBCBuiBXOokSAyM6H6P6/cKEx8FT8Q==", - "requires": { - "@types/bn.js": "^4.11.4", - "underscore": "1.9.1", - "web3-core": "1.2.9", - "web3-core-helpers": "1.2.9", - "web3-core-method": "1.2.9", - "web3-core-promievent": "1.2.9", - "web3-core-subscriptions": "1.2.9", - "web3-eth-abi": "1.2.9", - "web3-utils": "1.2.9" - } - }, - "web3-eth-ens": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.2.9.tgz", - "integrity": "sha512-kG4+ZRgZ8I1WYyOBGI8QVRHfUSbbJjvJAGA1AF/NOW7JXQ+x7gBGeJw6taDWJhSshMoEKWcsgvsiuoG4870YxQ==", - "requires": { - "content-hash": "^2.5.2", - "eth-ens-namehash": "2.0.8", - "underscore": "1.9.1", - "web3-core": "1.2.9", - "web3-core-helpers": "1.2.9", - "web3-core-promievent": "1.2.9", - "web3-eth-abi": "1.2.9", - "web3-eth-contract": "1.2.9", - "web3-utils": "1.2.9" - } - }, - "web3-eth-iban": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.2.9.tgz", - "integrity": "sha512-RtdVvJE0pyg9dHLy0GzDiqgnLnssSzfz/JYguhC1wsj9+Gnq1M6Diy3NixACWUAp6ty/zafyOaZnNQ+JuH9TjQ==", - "requires": { - "bn.js": "4.11.8", - "web3-utils": "1.2.9" - }, - "dependencies": { - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" - } - } - }, - "web3-eth-personal": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.2.9.tgz", - "integrity": "sha512-cFiNrktxZ1C/rIdJFzQTvFn3/0zcsR3a+Jf8Y3KxeQDHszQtosjLWptP7bsUmDwEh4hzh0Cy3KpOxlYBWB8bJQ==", - "requires": { - "@types/node": "^12.6.1", - "web3-core": "1.2.9", - "web3-core-helpers": "1.2.9", - "web3-core-method": "1.2.9", - "web3-net": "1.2.9", - "web3-utils": "1.2.9" - }, - "dependencies": { - "@types/node": { - "version": "12.12.53", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.53.tgz", - "integrity": "sha512-51MYTDTyCziHb70wtGNFRwB4l+5JNvdqzFSkbDvpbftEgVUBEE+T5f7pROhWMp/fxp07oNIEQZd5bbfAH22ohQ==" - } - } - }, - "web3-net": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.2.9.tgz", - "integrity": "sha512-d2mTn8jPlg+SI2hTj2b32Qan6DmtU9ap/IUlJTeQbZQSkTLf0u9suW8Vjwyr4poJYXTurdSshE7OZsPNn30/ZA==", - "requires": { - "web3-core": "1.2.9", - "web3-core-method": "1.2.9", - "web3-utils": "1.2.9" - } - }, - "web3-providers-http": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.2.9.tgz", - "integrity": "sha512-F956tCIj60Ttr0UvEHWFIhx+be3He8msoPzyA44/kfzzYoMAsCFRn5cf0zQG6al0znE75g6HlWVSN6s3yAh51A==", - "requires": { - "web3-core-helpers": "1.2.9", - "xhr2-cookies": "1.1.0" - } - }, - "web3-providers-ipc": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.2.9.tgz", - "integrity": "sha512-NQ8QnBleoHA2qTJlqoWu7EJAD/FR5uimf7Ielzk4Z2z+m+6UAuJdJMSuQNj+Umhz9L/Ys6vpS1vHx9NizFl+aQ==", - "requires": { - "oboe": "2.1.4", - "underscore": "1.9.1", - "web3-core-helpers": "1.2.9" - } - }, - "web3-providers-ws": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.2.9.tgz", - "integrity": "sha512-6+UpvINeI//dglZoAKStUXqxDOXJy6Iitv2z3dbgInG4zb8tkYl/VBDL80UjUg3ZvzWG0g7EKY2nRPEpON2TFA==", - "requires": { - "eventemitter3": "^4.0.0", - "underscore": "1.9.1", - "web3-core-helpers": "1.2.9", - "websocket": "^1.0.31" - }, - "dependencies": { - "eventemitter3": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", - "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==" - } - } - }, - "web3-shh": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.2.9.tgz", - "integrity": "sha512-PWa8b/EaxaMinFaxy6cV0i0EOi2M7a/ST+9k9nhyhCjVa2vzXuNoBNo2IUOmeZ0WP2UQB8ByJ2+p4htlJaDOjA==", - "requires": { - "web3-core": "1.2.9", - "web3-core-method": "1.2.9", - "web3-core-subscriptions": "1.2.9", - "web3-net": "1.2.9" - } - }, - "web3-utils": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.9.tgz", - "integrity": "sha512-9hcpuis3n/LxFzEVjwnVgvJzTirS2S9/MiNAa7l4WOEoywY+BSNwnRX4MuHnjkh9NY25B6QOjuNG6FNnSjTw1w==", - "requires": { - "bn.js": "4.11.8", - "eth-lib": "0.2.7", - "ethereum-bloom-filters": "^1.0.6", - "ethjs-unit": "0.1.6", - "number-to-bn": "1.7.0", - "randombytes": "^2.1.0", - "underscore": "1.9.1", - "utf8": "3.0.0" - }, - "dependencies": { - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" - }, - "eth-lib": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", - "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", - "requires": { - "bn.js": "^4.11.6", - "elliptic": "^6.4.0", - "xhr-request-promise": "^0.1.2" - } - } - } - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" - }, - "websocket": { - "version": "1.0.31", - "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.31.tgz", - "integrity": "sha512-VAouplvGKPiKFDTeCCO65vYHsyay8DqoBSlzIO3fayrfOgU94lQN5a1uWVnFrMLceTJw/+fQXR5PGbUVRaHshQ==", - "requires": { - "debug": "^2.2.0", - "es5-ext": "^0.10.50", - "nan": "^2.14.0", - "typedarray-to-buffer": "^3.1.5", - "yaeti": "^0.0.6" - } - }, - "whatwg-fetch": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", - "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "ws": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", - "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", - "requires": { - "async-limiter": "~1.0.0" - } - }, - "xhr": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.5.0.tgz", - "integrity": "sha512-4nlO/14t3BNUZRXIXfXe+3N6w3s1KoxcJUUURctd64BLRe67E4gRwp4PjywtDY72fXpZ1y6Ch0VZQRY/gMPzzQ==", - "requires": { - "global": "~4.3.0", - "is-function": "^1.0.1", - "parse-headers": "^2.0.0", - "xtend": "^4.0.0" - } - }, - "xhr-request": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/xhr-request/-/xhr-request-1.1.0.tgz", - "integrity": "sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==", - "requires": { - "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" - } - }, - "xhr-request-promise": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz", - "integrity": "sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg==", - "requires": { - "xhr-request": "^1.1.0" - } - }, - "xhr2-cookies": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz", - "integrity": "sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg=", - "requires": { - "cookiejar": "^2.1.1" - } - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, - "yaeti": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", - "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - } - } -} diff --git a/infrastructure/kube/templates/keep-client/initcontainer/provision-keep-client/package.json b/infrastructure/kube/templates/keep-client/initcontainer/provision-keep-client/package.json deleted file mode 100644 index 1f01db8deb..0000000000 --- a/infrastructure/kube/templates/keep-client/initcontainer/provision-keep-client/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "dependencies": { - "concat-stream": "^2.0.0", - "toml": "^3.0.0", - "tomlify-j0.4": "^3.0.0", - "@truffle/hdwallet-provider": "^1.0.38", - "web3": "1.2.9" - } -} diff --git a/infrastructure/kube/templates/keep-client/initcontainer/provision-keep-client/provision-keep-client.js b/infrastructure/kube/templates/keep-client/initcontainer/provision-keep-client/provision-keep-client.js deleted file mode 100755 index 88bb5a83e1..0000000000 --- a/infrastructure/kube/templates/keep-client/initcontainer/provision-keep-client/provision-keep-client.js +++ /dev/null @@ -1,229 +0,0 @@ -const fs = require('fs'); -const toml = require('toml'); -const tomlify = require('tomlify-j0.4'); -const concat = require('concat-stream'); -const Web3 = require('web3'); -const HDWalletProvider = require("@truffle/hdwallet-provider"); - -// ETH host info -const ethRPCUrl = process.env.ETH_RPC_URL -const ethWSUrl = process.env.ETH_WS_URL -const ethNetworkId = process.env.ETH_NETWORK_ID; - -// Contract owner info -const contractOwnerAddress = process.env.CONTRACT_OWNER_ETH_ACCOUNT_ADDRESS; -const authorizer = contractOwnerAddress -const purse = contractOwnerAddress; - -const contractOwnerProvider = new HDWalletProvider(process.env.CONTRACT_OWNER_ETH_ACCOUNT_PRIVATE_KEY, ethRPCUrl); - -const operatorKeyFile = process.env.KEEP_CLIENT_ETH_KEYFILE_PATH; - -// LibP2P network info -const libp2pPeers = [process.env.KEEP_CLIENT_PEERS] -const libp2pPort = Number(process.env.KEEP_CLIENT_PORT) -const libp2pAnnouncedAddresses = [process.env.KEEP_CLIENT_ANNOUNCED_ADDRESSES] - -/* -We override transactionConfirmationBlocks and transactionBlockTimeout because they're -25 and 50 blocks respectively at default. The result of this on small private testnets -is long wait times for scripts to execute. -*/ -const web3_options = { - defaultBlock: 'latest', - defaultGas: 4712388, - transactionBlockTimeout: 25, - transactionConfirmationBlocks: 3, - transactionPollingTimeout: 480 -}; - -const web3 = new Web3(contractOwnerProvider, null, web3_options); - -/* -Each file is sourced directly from the InitContainer. Files are generated by -Truffle during contract and copied to the InitContainer image via Circle. -*/ - -// TokenStaking -const tokenStakingContractJsonFile = '/tmp/TokenStaking.json'; -const tokenStakingContractParsed = JSON.parse(fs.readFileSync(tokenStakingContractJsonFile)); -const tokenStakingContractAbi = tokenStakingContractParsed.abi; -const tokenStakingContractAddress = tokenStakingContractParsed.networks[ethNetworkId].address; -const tokenStakingContract = new web3.eth.Contract(tokenStakingContractAbi, tokenStakingContractAddress); - -// KeepToken -const keepTokenContractJsonFile = '/tmp/KeepToken.json'; -const keepTokenContractParsed = JSON.parse(fs.readFileSync(keepTokenContractJsonFile)); -const keepTokenContractAbi = keepTokenContractParsed.abi; -const keepTokenContractAddress = keepTokenContractParsed.networks[ethNetworkId].address; -const keepTokenContract = new web3.eth.Contract(keepTokenContractAbi, keepTokenContractAddress); - -// keepRandomBeaconService, only contract address for config file create -const keepRandomBeaconServiceJsonFile = '/tmp/KeepRandomBeaconService.json'; -const keepRandomBeaconServiceParsed = JSON.parse(fs.readFileSync(keepRandomBeaconServiceJsonFile)); -const keepRandomBeaconServiceContractAddress = keepRandomBeaconServiceParsed.networks[ethNetworkId].address; - -// KeepRandomBeaconOperator, only contract address for config file create -const keepRandomBeaconOperatorJsonFile = '/tmp/KeepRandomBeaconOperator.json'; -const keepRandomBeaconOperatorParsed = JSON.parse(fs.readFileSync(keepRandomBeaconOperatorJsonFile)); -const keepRandomBeaconOperatorContractAddress = keepRandomBeaconOperatorParsed.networks[ethNetworkId].address; - -async function provisionKeepClient() { - - try { - console.log(`\n<<<<<<<<<<<< Read operator address from key file >>>>>>>>>>>>`) - const operatorAddress = readAddressFromKeyFile(operatorKeyFile) - - console.log(`\n<<<<<<<<<<<< Funding Operator Account ${operatorAddress} >>>>>>>>>>>>`); - await fundOperator(operatorAddress, '10'); - - console.log(`\n<<<<<<<<<<<< Staking Operator Account ${operatorAddress} >>>>>>>>>>>>`); - await stakeOperator(operatorAddress, contractOwnerAddress, authorizer); - - console.log(`\n<<<<<<<<<<<< Authorizing Operator Contract ${keepRandomBeaconOperatorContractAddress} >>>>>>>>>>>>`); - await authorizeOperatorContract(operatorAddress, authorizer); - - console.log('\n<<<<<<<<<<<< Creating keep-client Config File >>>>>>>>>>>>'); - await createKeepClientConfig(operatorAddress); - process.exit() - } - catch(error) { - console.error(error.message); - throw error; - } -}; - -async function isStaked(operatorAddress) { - - console.log('Checking if operator address is staked:'); - let stakedAmount = await tokenStakingContract.methods.balanceOf(operatorAddress).call(); - return stakedAmount != 0; -} - -async function isFunded(operatorAddress) { - - console.log('Checking if operator address has ether:') - let fundedAmount = await web3.utils.fromWei( - await web3.eth.getBalance(operatorAddress), 'ether') - return fundedAmount >= 1; -} - -async function stakeOperator(operatorAddress, contractOwnerAddress, authorizer) { - - let beneficiary = contractOwnerAddress; - let staked = await isStaked(operatorAddress); - - /* - We need to stake only in cases where an operator account is not already staked. If the account - is staked, or the client type is relay-requester we need to exit staking, albeit for different - reasons. In the case where the account is already staked, additional staking will fail. - Clients of type relay-requester don't need to be staked to submit a request, they're acting more - as a consumer of the network, rather than an operator. - */ - if (process.env.KEEP_CLIENT_TYPE === 'relay-requester') { - console.log('Subtype relay-requester set. No staking needed, exiting!'); - return; - } else if (staked === true) { - console.log('Operator account already staked, exiting!'); - return; - } else { - console.log(`Staking 4000000 KEEP tokens on operator account ${operatorAddress}`); - } - - let delegation = '0x' + Buffer.concat([ - Buffer.from(beneficiary.substr(2), 'hex'), - Buffer.from(operatorAddress.substr(2), 'hex'), - Buffer.from(authorizer.substr(2), 'hex') - ]).toString('hex'); - - await keepTokenContract.methods.approveAndCall( - tokenStakingContract.options.address, - formatAmount(4000000, 18), - delegation).send({from: contractOwnerAddress}) - - console.log(`Staked!`); -}; - -async function authorizeOperatorContract(operatorAddress, authorizer) { - - if (process.env.KEEP_CLIENT_TYPE === 'relay-requester') { - console.log('Subtype relay-requester set. No authorization needed, exiting!'); - return; - } else { - console.log(`Authorizing Operator Contract ${keepRandomBeaconOperatorContractAddress} for operator account ${operatorAddress}`); - } - await tokenStakingContract.methods.authorizeOperatorContract( - operatorAddress, - keepRandomBeaconOperatorContractAddress).send({from: authorizer}); - - console.log(`Authorized!`); -}; - -function readAddressFromKeyFile(keyFilePath) { - const keyFile = JSON.parse(fs.readFileSync(keyFilePath, 'utf8')) - - return web3.utils.toHex(keyFile.address) -} - -async function fundOperator(operatorAddress, etherToTransfer) { - - let funded = await isFunded(operatorAddress); - let transferAmount = web3.utils.toWei(etherToTransfer, 'ether'); - - if (funded === true) { - console.log('Operator address is already funded, exiting!'); - return; - } else { - console.log(`Funding account ${operatorAddress} with ${etherToTransfer} ether from purse ${purse}`); - await web3.eth.sendTransaction({from:purse, to:operatorAddress, value:transferAmount}); - console.log(`Account ${operatorAddress} funded!`); - } -}; - -async function createKeepClientConfig() { - - let parsedConfigFile = toml.parse(fs.readFileSync('/tmp/keep-client-config-template.toml', 'utf8')); - - parsedConfigFile.ethereum.URL = ethWSUrl; - parsedConfigFile.ethereum.URLRPC = ethRPCUrl; - - parsedConfigFile.ethereum.account.KeyFile = operatorKeyFile; - - parsedConfigFile.ethereum.ContractAddresses.KeepRandomBeaconOperator = keepRandomBeaconOperatorContractAddress; - parsedConfigFile.ethereum.ContractAddresses.KeepRandomBeaconService = keepRandomBeaconServiceContractAddress; - parsedConfigFile.ethereum.ContractAddresses.TokenStaking = tokenStakingContractAddress; - - parsedConfigFile.LibP2P.Peers = libp2pPeers - parsedConfigFile.LibP2P.Port = libp2pPort - parsedConfigFile.LibP2P.AnnouncedAddresses = libp2pAnnouncedAddresses - - parsedConfigFile.Storage.DataDir = process.env.KEEP_CLIENT_DATA_DIR; - - parsedConfigFile.Metrics.Port = Number(process.env.METRICS_PORT) - - /* - tomlify.toToml() writes our Seed/Port values as a float. The added precision renders our config - file unreadable by the keep-client as it interprets 3919.0 as a string when it expects an int. - Here we format the default rendering to write the config file with Seed/Port values as needed. - */ - let formattedConfigFile = tomlify.toToml(parsedConfigFile, { - space: 2, - replace: (key, value) => { return (key == 'Port') ? value.toFixed(0) : false } - }); - fs.writeFileSync('/mnt/keep-client/config/keep-client-config.toml', formattedConfigFile) - console.log('keep-client config written to /mnt/keep-client/config/keep-client-config.toml'); -}; - -/* -\heimdall aliens numbers. Really though, the approveAndCall function expects numbers -in a particular format, this function facilitates that. -*/ -function formatAmount(amount, decimals) { - return '0x' + web3.utils.toBN(amount).mul(web3.utils.toBN(10).pow(web3.utils.toBN(decimals))).toString('hex'); -}; - -provisionKeepClient().catch(error => { - console.error(error); - process.exit(1); -}); - diff --git a/infrastructure/kube/templates/keep-maintainer/kustomization.yaml b/infrastructure/kube/templates/keep-maintainer/kustomization.yaml index 6967680059..41f7107232 100644 --- a/infrastructure/kube/templates/keep-maintainer/kustomization.yaml +++ b/infrastructure/kube/templates/keep-maintainer/kustomization.yaml @@ -1,5 +1,6 @@ resources: - maintainer-statefulset.yaml + - maintainer-service.yaml commonLabels: app: keep-maintainer diff --git a/infrastructure/kube/templates/keep-maintainer/maintainer-service.yaml b/infrastructure/kube/templates/keep-maintainer/maintainer-service.yaml new file mode 100644 index 0000000000..c7af510f36 --- /dev/null +++ b/infrastructure/kube/templates/keep-maintainer/maintainer-service.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: keep-maintainer-metrics +spec: + type: ClusterIP + selector: + app: keep-maintainer + ports: + - name: metrics + port: 9601 + targetPort: metrics diff --git a/infrastructure/kube/templates/keep-maintainer/maintainer-statefulset.yaml b/infrastructure/kube/templates/keep-maintainer/maintainer-statefulset.yaml index 8587a6a9ea..8a5d0febd1 100644 --- a/infrastructure/kube/templates/keep-maintainer/maintainer-statefulset.yaml +++ b/infrastructure/kube/templates/keep-maintainer/maintainer-statefulset.yaml @@ -11,6 +11,9 @@ spec: - name: keep-maintainer image: keep-maintainer:latest imagePullPolicy: Always + ports: + - name: metrics + containerPort: 9601 resources: requests: cpu: 1500m diff --git a/infrastructure/kube/templates/tbtc-v2-monitoring/README.md b/infrastructure/kube/templates/tbtc-v2-monitoring/README.md deleted file mode 100644 index 9be00f78cc..0000000000 --- a/infrastructure/kube/templates/tbtc-v2-monitoring/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# TBTCv2 system events monitoring - -Base configuration to run [TBTCv2 system events monitoring](https://github.com/keep-network/tbtc-v2/tree/main/monitoring). -It is referenced by environment-specific overlays: -- [`keep-prd` production overlay](../../keep-prd/tbtc-v2-monitoring) -- [`keep-test` test overlay](../../keep-test/tbtc-v2-monitoring) diff --git a/infrastructure/monitoring/maintainer/README.md b/infrastructure/monitoring/maintainer/README.md new file mode 100644 index 0000000000..3a652586ea --- /dev/null +++ b/infrastructure/monitoring/maintainer/README.md @@ -0,0 +1,81 @@ +# Maintainer monitoring + +These rules cover the standalone SPV maintainer's availability, Ethereum and +Bitcoin RPC health, proof processing, and relay difficulty constraints. They +require the maintainer telemetry added by the #4187 / #4190 / #4290 stack. They +complement the tBTC event monitor's redemption request and timeout notifications. + +## Rollout + +1. Build and publish a client image containing the telemetry stack. Set the + maintainer overlay's image tag to that release. The production overlay still + pins `v2.1.0`; this configuration change does not publish or select a new image. +2. Render the applicable overlay, review it, and apply it through the usual + deployment process. The upgraded client defaults to client-info port 9601; + the template exposes `/metrics` through the internal `keep-maintainer-metrics` + ClusterIP service. No new CLI flag is passed, preserving compatibility with + older images until the image rollout. Metrics require the upgraded image. + Production rendering requires the existing local `.secret` files. The template + alone can be rendered without credentials: + `kubectl kustomize infrastructure/kube/templates/keep-maintainer`. +3. Mount `rules.yml` into the cluster's existing Prometheus and merge the + `rule_files` and `scrape_configs` sections from `prometheus.example.yml` into its + configuration. Adjust the service namespace and environment label. The example + target is for the existing single-replica deployment; for multiple replicas, + discover individual pod endpoints so one failed replica cannot hide behind + the Service. Restrict port 9601 to the monitoring network. +4. Verify the target is UP and all health/timestamp series in + `KeepMaintainerTelemetryMissing` are present. This catches a scrape endpoint + running an older image. Use a separate job for a Bitcoin-difficulty-only + maintainer: these rules expect SPV processing to be enabled. +5. Configure Prometheus's `alerting.alertmanagers` with the actual Alertmanager + endpoint. Route `component="keep-maintainer"` to the existing on-call receiver + and preserve `environment` and `instance` in notifications. The example leaves + this endpoint unset because it is installation-specific. Validate routing with + a temporary test receiver before enabling paging. If using Sentry, use an + existing Sentry integration that translates Alertmanager notifications; a + Sentry DSN is not an Alertmanager webhook endpoint. +6. Confirm a notification and its resolution arrive through the intended route + in staging, then remove the test alert. Verify RPC outage, process outage, and + recovery using controlled staging interruptions. Keep #3664 open until this + delivery check and the remaining redemption-event rollout are complete. + +## Semantics and tuning + +- RPC health is the last completed probe's result. Separate freshness rules catch + hung probes even if the last result was healthy. The rules allow three probe + intervals plus one minute for metric sampling and five minutes before firing. +- SPV activity records task starts and completions. The stalled rule allows the + configured maximum idle/restart backoff plus 30 minutes for work, then requires + another ten minutes without progress. Tune the processing allowance against + observed proof durations; an idle maintainer need not submit proofs regularly. +- Task failure state persists until a later successful complete cycle, including + failures before the first scrape. A successful cycle may find no pending + transactions; it does not imply a redemption was proven. Timestamps have + one-second resolution: a failure and recovery in the same second remain + conservative until the next successful cycle. +- Relay-range and header-limit counters count attempts, including retries of the + same Bitcoin transaction. They are distinct skip reasons, not task failures or + counts of unique stuck redemptions. Their alerts require an observed counter + increase and can miss a single skip before the first scrape; inspect absolute + counter values during rollout. A recurring skip triggers on subsequent attempts. +- These rules do not prove end-to-end alert delivery or diagnose a particular + redemption. Correlate maintainer logs, redemption request deadlines, relay + updates, and accepted `RedemptionsCompleted` events before intervening. + +## Validation and rollback + +From this directory, with Prometheus `promtool` installed: + +```sh +promtool check config prometheus.example.yml +promtool test rules rules.test.yml +``` + +Tests cover healthy operation, unavailable/missing telemetry, RPC failures and +hung probes, configured long backoffs, first-scrape task failures and recovery, +and both difficulty skip reasons. Remove the scrape job and rule file to roll +back monitoring. On the upgraded client, use `--clientInfo.port=0` to disable the +endpoint, and remove the metrics Service and container port declaration, along +with the `- maintainer-service.yaml` entry in +`infrastructure/kube/templates/keep-maintainer/kustomization.yaml`. diff --git a/infrastructure/monitoring/maintainer/prometheus.example.yml b/infrastructure/monitoring/maintainer/prometheus.example.yml new file mode 100644 index 0000000000..375c29e458 --- /dev/null +++ b/infrastructure/monitoring/maintainer/prometheus.example.yml @@ -0,0 +1,17 @@ +# Merge these sections into the Prometheus configuration serving this cluster. +global: + scrape_interval: 30s + evaluation_interval: 30s + +rule_files: + - rules.yml + +scrape_configs: + - job_name: keep-maintainer + scrape_interval: 30s + static_configs: + - targets: [keep-maintainer-metrics.default.svc.cluster.local:9601] + labels: + environment: mainnet + +# Configure alerting.alertmanagers and an Alertmanager receiver before rollout. diff --git a/infrastructure/monitoring/maintainer/rules.test.yml b/infrastructure/monitoring/maintainer/rules.test.yml new file mode 100644 index 0000000000..7c2f54b426 --- /dev/null +++ b/infrastructure/monitoring/maintainer/rules.test.yml @@ -0,0 +1,1301 @@ +# Run with: promtool test rules rules.test.yml +rule_files: [rules.yml] +evaluation_interval: 1m +tests: + - name: "healthy service" + interval: 1m + input_series: + - series: "up{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_spv_maintainer_active{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_eth_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_btc_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_health_check_interval_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "60+0x120" + - series: "performance_rpc_eth_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_rpc_btc_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_activity_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_success_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_failure_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_maintainer_max_backoff_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1800+0x120" + - series: "performance_spv_proof_skipped_outside_relay_range_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_proof_skipped_exceeded_max_headers_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + alert_rule_test: + - eval_time: 120m + alertname: KeepMaintainerDown + exp_alerts: [] + - eval_time: 120m + alertname: KeepMaintainerTelemetryMissing + exp_alerts: [] + - eval_time: 120m + alertname: KeepMaintainerSPVInactive + exp_alerts: [] + - eval_time: 120m + alertname: KeepMaintainerEthereumRPCUnhealthy + exp_alerts: [] + - eval_time: 120m + alertname: KeepMaintainerBitcoinRPCUnhealthy + exp_alerts: [] + - eval_time: 120m + alertname: KeepMaintainerEthereumProbeStalled + exp_alerts: [] + - eval_time: 120m + alertname: KeepMaintainerBitcoinProbeStalled + exp_alerts: [] + - eval_time: 120m + alertname: KeepMaintainerSPVStalled + exp_alerts: [] + - eval_time: 120m + alertname: KeepMaintainerProofTaskFailed + exp_alerts: [] + - eval_time: 120m + alertname: KeepMaintainerProofOutsideRelayRange + exp_alerts: [] + - eval_time: 120m + alertname: KeepMaintainerProofExceedsHeaderLimit + exp_alerts: [] + - name: "scrape failure waits two minutes" + interval: 1m + input_series: + - series: "up{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_maintainer_active{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_eth_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_btc_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_health_check_interval_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "60+0x120" + - series: "performance_rpc_eth_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_rpc_btc_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_activity_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_success_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_failure_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_maintainer_max_backoff_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1800+0x120" + - series: "performance_spv_proof_skipped_outside_relay_range_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_proof_skipped_exceeded_max_headers_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + alert_rule_test: + - eval_time: 1m + alertname: KeepMaintainerDown + exp_alerts: [] + - eval_time: 1m + alertname: KeepMaintainerTelemetryMissing + exp_alerts: [] + - eval_time: 1m + alertname: KeepMaintainerSPVInactive + exp_alerts: [] + - eval_time: 1m + alertname: KeepMaintainerEthereumRPCUnhealthy + exp_alerts: [] + - eval_time: 1m + alertname: KeepMaintainerBitcoinRPCUnhealthy + exp_alerts: [] + - eval_time: 1m + alertname: KeepMaintainerEthereumProbeStalled + exp_alerts: [] + - eval_time: 1m + alertname: KeepMaintainerBitcoinProbeStalled + exp_alerts: [] + - eval_time: 1m + alertname: KeepMaintainerSPVStalled + exp_alerts: [] + - eval_time: 1m + alertname: KeepMaintainerProofTaskFailed + exp_alerts: [] + - eval_time: 1m + alertname: KeepMaintainerProofOutsideRelayRange + exp_alerts: [] + - eval_time: 1m + alertname: KeepMaintainerProofExceedsHeaderLimit + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerDown + exp_alerts: + - exp_labels: + job: keep-maintainer + instance: maintainer:9601 + component: keep-maintainer + severity: critical + exp_annotations: + summary: "Maintainer maintainer:9601 cannot be scraped" + - eval_time: 2m + alertname: KeepMaintainerTelemetryMissing + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerSPVInactive + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerEthereumRPCUnhealthy + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerBitcoinRPCUnhealthy + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerEthereumProbeStalled + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerBitcoinProbeStalled + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerSPVStalled + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerProofTaskFailed + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerProofOutsideRelayRange + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerProofExceedsHeaderLimit + exp_alerts: [] + - name: "an old endpoint is missing required telemetry" + interval: 1m + input_series: + - series: "up{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_spv_maintainer_active{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_eth_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_btc_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_health_check_interval_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "60+0x120" + - series: "performance_rpc_eth_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_rpc_btc_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_activity_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_success_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_max_backoff_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1800+0x120" + - series: "performance_spv_proof_skipped_outside_relay_range_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_proof_skipped_exceeded_max_headers_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + alert_rule_test: + - eval_time: 5m + alertname: KeepMaintainerDown + exp_alerts: [] + - eval_time: 4m + alertname: KeepMaintainerTelemetryMissing + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerTelemetryMissing + exp_alerts: + - exp_labels: + job: keep-maintainer + instance: maintainer:9601 + component: keep-maintainer + severity: critical + exp_annotations: + summary: "Maintainer maintainer:9601 is missing required telemetry" + - eval_time: 5m + alertname: KeepMaintainerSPVInactive + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerEthereumRPCUnhealthy + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerBitcoinRPCUnhealthy + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerEthereumProbeStalled + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerBitcoinProbeStalled + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerSPVStalled + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerProofTaskFailed + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerProofOutsideRelayRange + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerProofExceedsHeaderLimit + exp_alerts: [] + - name: "SPV disabled" + interval: 1m + input_series: + - series: "up{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_spv_maintainer_active{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_rpc_eth_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_btc_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_health_check_interval_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "60+0x120" + - series: "performance_rpc_eth_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_rpc_btc_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_activity_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_success_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_failure_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_maintainer_max_backoff_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1800+0x120" + - series: "performance_spv_proof_skipped_outside_relay_range_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_proof_skipped_exceeded_max_headers_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + alert_rule_test: + - eval_time: 5m + alertname: KeepMaintainerDown + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerTelemetryMissing + exp_alerts: [] + - eval_time: 4m + alertname: KeepMaintainerSPVInactive + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerSPVInactive + exp_alerts: + - exp_labels: + job: keep-maintainer + instance: maintainer:9601 + component: keep-maintainer + severity: critical + exp_annotations: + summary: "SPV processing is inactive on maintainer:9601" + - eval_time: 5m + alertname: KeepMaintainerEthereumRPCUnhealthy + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerBitcoinRPCUnhealthy + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerEthereumProbeStalled + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerBitcoinProbeStalled + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerSPVStalled + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerProofTaskFailed + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerProofOutsideRelayRange + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerProofExceedsHeaderLimit + exp_alerts: [] + - name: "Ethereum RPC fails" + interval: 1m + input_series: + - series: "up{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_spv_maintainer_active{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_eth_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_rpc_btc_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_health_check_interval_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "60+0x120" + - series: "performance_rpc_eth_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_rpc_btc_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_activity_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_success_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_failure_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_maintainer_max_backoff_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1800+0x120" + - series: "performance_spv_proof_skipped_outside_relay_range_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_proof_skipped_exceeded_max_headers_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + alert_rule_test: + - eval_time: 5m + alertname: KeepMaintainerDown + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerTelemetryMissing + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerSPVInactive + exp_alerts: [] + - eval_time: 4m + alertname: KeepMaintainerEthereumRPCUnhealthy + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerEthereumRPCUnhealthy + exp_alerts: + - exp_labels: + job: keep-maintainer + instance: maintainer:9601 + component: keep-maintainer + severity: critical + exp_annotations: + summary: "Ethereum RPC is unhealthy on maintainer:9601" + - eval_time: 5m + alertname: KeepMaintainerBitcoinRPCUnhealthy + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerEthereumProbeStalled + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerBitcoinProbeStalled + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerSPVStalled + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerProofTaskFailed + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerProofOutsideRelayRange + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerProofExceedsHeaderLimit + exp_alerts: [] + - name: "Bitcoin RPC fails" + interval: 1m + input_series: + - series: "up{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_spv_maintainer_active{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_eth_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_btc_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_rpc_health_check_interval_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "60+0x120" + - series: "performance_rpc_eth_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_rpc_btc_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_activity_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_success_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_failure_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_maintainer_max_backoff_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1800+0x120" + - series: "performance_spv_proof_skipped_outside_relay_range_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_proof_skipped_exceeded_max_headers_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + alert_rule_test: + - eval_time: 5m + alertname: KeepMaintainerDown + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerTelemetryMissing + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerSPVInactive + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerEthereumRPCUnhealthy + exp_alerts: [] + - eval_time: 4m + alertname: KeepMaintainerBitcoinRPCUnhealthy + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerBitcoinRPCUnhealthy + exp_alerts: + - exp_labels: + job: keep-maintainer + instance: maintainer:9601 + component: keep-maintainer + severity: critical + exp_annotations: + summary: "Bitcoin RPC is unhealthy on maintainer:9601" + - eval_time: 5m + alertname: KeepMaintainerEthereumProbeStalled + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerBitcoinProbeStalled + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerSPVStalled + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerProofTaskFailed + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerProofOutsideRelayRange + exp_alerts: [] + - eval_time: 5m + alertname: KeepMaintainerProofExceedsHeaderLimit + exp_alerts: [] + - name: "Ethereum probe hangs after a healthy result" + interval: 1m + input_series: + - series: "up{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_spv_maintainer_active{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_eth_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_btc_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_health_check_interval_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "60+0x120" + - series: "performance_rpc_eth_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_btc_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_activity_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_success_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_failure_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_maintainer_max_backoff_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1800+0x120" + - series: "performance_spv_proof_skipped_outside_relay_range_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_proof_skipped_exceeded_max_headers_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + alert_rule_test: + - eval_time: 10m + alertname: KeepMaintainerDown + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerTelemetryMissing + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerSPVInactive + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerEthereumRPCUnhealthy + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerBitcoinRPCUnhealthy + exp_alerts: [] + - eval_time: 9m + alertname: KeepMaintainerEthereumProbeStalled + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerEthereumProbeStalled + exp_alerts: + - exp_labels: + job: keep-maintainer + instance: maintainer:9601 + component: keep-maintainer + severity: critical + exp_annotations: + summary: "Ethereum RPC probes stopped completing on maintainer:9601" + - eval_time: 10m + alertname: KeepMaintainerBitcoinProbeStalled + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerSPVStalled + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerProofTaskFailed + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerProofOutsideRelayRange + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerProofExceedsHeaderLimit + exp_alerts: [] + - name: "Bitcoin probe hangs after a healthy result" + interval: 1m + input_series: + - series: "up{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_spv_maintainer_active{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_eth_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_btc_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_health_check_interval_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "60+0x120" + - series: "performance_rpc_eth_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_rpc_btc_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_spv_maintainer_last_activity_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_success_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_failure_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_maintainer_max_backoff_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1800+0x120" + - series: "performance_spv_proof_skipped_outside_relay_range_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_proof_skipped_exceeded_max_headers_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + alert_rule_test: + - eval_time: 10m + alertname: KeepMaintainerDown + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerTelemetryMissing + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerSPVInactive + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerEthereumRPCUnhealthy + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerBitcoinRPCUnhealthy + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerEthereumProbeStalled + exp_alerts: [] + - eval_time: 9m + alertname: KeepMaintainerBitcoinProbeStalled + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerBitcoinProbeStalled + exp_alerts: + - exp_labels: + job: keep-maintainer + instance: maintainer:9601 + component: keep-maintainer + severity: critical + exp_annotations: + summary: "Bitcoin RPC probes stopped completing on maintainer:9601" + - eval_time: 10m + alertname: KeepMaintainerSPVStalled + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerProofTaskFailed + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerProofOutsideRelayRange + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerProofExceedsHeaderLimit + exp_alerts: [] + - name: "SPV task hangs beyond its processing allowance" + interval: 1m + input_series: + - series: "up{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_spv_maintainer_active{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_eth_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_btc_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_health_check_interval_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "60+0x120" + - series: "performance_rpc_eth_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_rpc_btc_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_activity_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_spv_maintainer_last_success_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_spv_maintainer_last_failure_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_maintainer_max_backoff_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "600+0x120" + - series: "performance_spv_proof_skipped_outside_relay_range_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_proof_skipped_exceeded_max_headers_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + alert_rule_test: + - eval_time: 40m + alertname: KeepMaintainerDown + exp_alerts: [] + - eval_time: 40m + alertname: KeepMaintainerTelemetryMissing + exp_alerts: [] + - eval_time: 40m + alertname: KeepMaintainerSPVInactive + exp_alerts: [] + - eval_time: 40m + alertname: KeepMaintainerEthereumRPCUnhealthy + exp_alerts: [] + - eval_time: 40m + alertname: KeepMaintainerBitcoinRPCUnhealthy + exp_alerts: [] + - eval_time: 40m + alertname: KeepMaintainerEthereumProbeStalled + exp_alerts: [] + - eval_time: 40m + alertname: KeepMaintainerBitcoinProbeStalled + exp_alerts: [] + - eval_time: 40m + alertname: KeepMaintainerSPVStalled + exp_alerts: [] + - eval_time: 40m + alertname: KeepMaintainerProofTaskFailed + exp_alerts: [] + - eval_time: 40m + alertname: KeepMaintainerProofOutsideRelayRange + exp_alerts: [] + - eval_time: 40m + alertname: KeepMaintainerProofExceedsHeaderLimit + exp_alerts: [] + - eval_time: 52m + alertname: KeepMaintainerDown + exp_alerts: [] + - eval_time: 52m + alertname: KeepMaintainerTelemetryMissing + exp_alerts: [] + - eval_time: 52m + alertname: KeepMaintainerSPVInactive + exp_alerts: [] + - eval_time: 52m + alertname: KeepMaintainerEthereumRPCUnhealthy + exp_alerts: [] + - eval_time: 52m + alertname: KeepMaintainerBitcoinRPCUnhealthy + exp_alerts: [] + - eval_time: 52m + alertname: KeepMaintainerEthereumProbeStalled + exp_alerts: [] + - eval_time: 52m + alertname: KeepMaintainerBitcoinProbeStalled + exp_alerts: [] + - eval_time: 52m + alertname: KeepMaintainerSPVStalled + exp_alerts: + - exp_labels: + job: keep-maintainer + instance: maintainer:9601 + component: keep-maintainer + severity: critical + exp_annotations: + summary: "SPV processing stopped making progress on maintainer:9601" + - eval_time: 52m + alertname: KeepMaintainerProofTaskFailed + exp_alerts: [] + - eval_time: 52m + alertname: KeepMaintainerProofOutsideRelayRange + exp_alerts: [] + - eval_time: 52m + alertname: KeepMaintainerProofExceedsHeaderLimit + exp_alerts: [] + - name: "configured long backoff is healthy" + interval: 1m + input_series: + - series: "up{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_spv_maintainer_active{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_eth_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_btc_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_health_check_interval_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "60+0x120" + - series: "performance_rpc_eth_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_rpc_btc_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_activity_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_spv_maintainer_last_success_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_spv_maintainer_last_failure_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_maintainer_max_backoff_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "7200+0x120" + - series: "performance_spv_proof_skipped_outside_relay_range_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_proof_skipped_exceeded_max_headers_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + alert_rule_test: + - eval_time: 120m + alertname: KeepMaintainerDown + exp_alerts: [] + - eval_time: 120m + alertname: KeepMaintainerTelemetryMissing + exp_alerts: [] + - eval_time: 120m + alertname: KeepMaintainerSPVInactive + exp_alerts: [] + - eval_time: 120m + alertname: KeepMaintainerEthereumRPCUnhealthy + exp_alerts: [] + - eval_time: 120m + alertname: KeepMaintainerBitcoinRPCUnhealthy + exp_alerts: [] + - eval_time: 120m + alertname: KeepMaintainerEthereumProbeStalled + exp_alerts: [] + - eval_time: 120m + alertname: KeepMaintainerBitcoinProbeStalled + exp_alerts: [] + - eval_time: 120m + alertname: KeepMaintainerSPVStalled + exp_alerts: [] + - eval_time: 120m + alertname: KeepMaintainerProofTaskFailed + exp_alerts: [] + - eval_time: 120m + alertname: KeepMaintainerProofOutsideRelayRange + exp_alerts: [] + - eval_time: 120m + alertname: KeepMaintainerProofExceedsHeaderLimit + exp_alerts: [] + - name: "failure before first scrape clears after successful cycle" + interval: 1m + input_series: + - series: "up{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_spv_maintainer_active{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_eth_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_btc_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_health_check_interval_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "60+0x120" + - series: "performance_rpc_eth_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_rpc_btc_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_activity_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_success_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x4 300+60x115" + - series: "performance_spv_maintainer_last_failure_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "10+0x120" + - series: "performance_spv_maintainer_max_backoff_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1800+0x120" + - series: "performance_spv_proof_skipped_outside_relay_range_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_proof_skipped_exceeded_max_headers_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + alert_rule_test: + - eval_time: 1m + alertname: KeepMaintainerProofTaskFailed + exp_alerts: [] + - eval_time: 3m + alertname: KeepMaintainerDown + exp_alerts: [] + - eval_time: 3m + alertname: KeepMaintainerTelemetryMissing + exp_alerts: [] + - eval_time: 3m + alertname: KeepMaintainerSPVInactive + exp_alerts: [] + - eval_time: 3m + alertname: KeepMaintainerEthereumRPCUnhealthy + exp_alerts: [] + - eval_time: 3m + alertname: KeepMaintainerBitcoinRPCUnhealthy + exp_alerts: [] + - eval_time: 3m + alertname: KeepMaintainerEthereumProbeStalled + exp_alerts: [] + - eval_time: 3m + alertname: KeepMaintainerBitcoinProbeStalled + exp_alerts: [] + - eval_time: 3m + alertname: KeepMaintainerSPVStalled + exp_alerts: [] + - eval_time: 3m + alertname: KeepMaintainerProofTaskFailed + exp_alerts: + - exp_labels: + job: keep-maintainer + instance: maintainer:9601 + component: keep-maintainer + severity: warning + exp_annotations: + summary: "SPV processing has not recovered from a task failure on maintainer:9601" + - eval_time: 3m + alertname: KeepMaintainerProofOutsideRelayRange + exp_alerts: [] + - eval_time: 3m + alertname: KeepMaintainerProofExceedsHeaderLimit + exp_alerts: [] + - eval_time: 6m + alertname: KeepMaintainerDown + exp_alerts: [] + - eval_time: 6m + alertname: KeepMaintainerTelemetryMissing + exp_alerts: [] + - eval_time: 6m + alertname: KeepMaintainerSPVInactive + exp_alerts: [] + - eval_time: 6m + alertname: KeepMaintainerEthereumRPCUnhealthy + exp_alerts: [] + - eval_time: 6m + alertname: KeepMaintainerBitcoinRPCUnhealthy + exp_alerts: [] + - eval_time: 6m + alertname: KeepMaintainerEthereumProbeStalled + exp_alerts: [] + - eval_time: 6m + alertname: KeepMaintainerBitcoinProbeStalled + exp_alerts: [] + - eval_time: 6m + alertname: KeepMaintainerSPVStalled + exp_alerts: [] + - eval_time: 6m + alertname: KeepMaintainerProofTaskFailed + exp_alerts: [] + - eval_time: 6m + alertname: KeepMaintainerProofOutsideRelayRange + exp_alerts: [] + - eval_time: 6m + alertname: KeepMaintainerProofExceedsHeaderLimit + exp_alerts: [] + - name: "relay range skip is distinct from failure" + interval: 1m + input_series: + - series: "up{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_spv_maintainer_active{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_eth_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_btc_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_health_check_interval_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "60+0x120" + - series: "performance_rpc_eth_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_rpc_btc_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_activity_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_success_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_failure_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_maintainer_max_backoff_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1800+0x120" + - series: "performance_spv_proof_skipped_outside_relay_range_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+1x120" + - series: "performance_spv_proof_skipped_exceeded_max_headers_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + alert_rule_test: + - eval_time: 2m + alertname: KeepMaintainerDown + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerTelemetryMissing + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerSPVInactive + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerEthereumRPCUnhealthy + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerBitcoinRPCUnhealthy + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerEthereumProbeStalled + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerBitcoinProbeStalled + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerSPVStalled + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerProofTaskFailed + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerProofOutsideRelayRange + exp_alerts: + - exp_labels: + job: keep-maintainer + instance: maintainer:9601 + component: keep-maintainer + severity: warning + exp_annotations: + summary: "SPV proofs exceed the relay difficulty range on maintainer:9601" + - eval_time: 2m + alertname: KeepMaintainerProofExceedsHeaderLimit + exp_alerts: [] + - name: "header limit skip is distinct from failure" + interval: 1m + input_series: + - series: "up{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_spv_maintainer_active{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_eth_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_btc_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_health_check_interval_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "60+0x120" + - series: "performance_rpc_eth_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_rpc_btc_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_activity_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_success_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_failure_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_maintainer_max_backoff_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1800+0x120" + - series: "performance_spv_proof_skipped_outside_relay_range_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_proof_skipped_exceeded_max_headers_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+1x120" + alert_rule_test: + - eval_time: 2m + alertname: KeepMaintainerDown + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerTelemetryMissing + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerSPVInactive + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerEthereumRPCUnhealthy + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerBitcoinRPCUnhealthy + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerEthereumProbeStalled + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerBitcoinProbeStalled + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerSPVStalled + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerProofTaskFailed + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerProofOutsideRelayRange + exp_alerts: [] + - eval_time: 2m + alertname: KeepMaintainerProofExceedsHeaderLimit + exp_alerts: + - exp_labels: + job: keep-maintainer + instance: maintainer:9601 + component: keep-maintainer + severity: critical + exp_annotations: + summary: "SPV proofs exceed the supported header count on maintainer:9601" + - name: "proof skip counters already nonzero but flat do not fire" + interval: 1m + input_series: + - series: "up{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x150" + - series: "performance_spv_maintainer_active{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x150" + - series: "performance_rpc_eth_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x150" + - series: "performance_rpc_btc_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x150" + - series: "performance_rpc_health_check_interval_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "60+0x150" + - series: "performance_rpc_eth_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x150" + - series: "performance_rpc_btc_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x150" + - series: "performance_spv_maintainer_last_activity_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x150" + - series: "performance_spv_maintainer_last_success_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x150" + - series: "performance_spv_maintainer_last_failure_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x150" + - series: "performance_spv_maintainer_max_backoff_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1800+0x150" + - series: "performance_spv_proof_skipped_outside_relay_range_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "5+0x90 5+1x60" + - series: "performance_spv_proof_skipped_exceeded_max_headers_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "5+0x90 5+1x60" + alert_rule_test: + - eval_time: 90m + alertname: KeepMaintainerDown + exp_alerts: [] + - eval_time: 90m + alertname: KeepMaintainerTelemetryMissing + exp_alerts: [] + - eval_time: 90m + alertname: KeepMaintainerSPVInactive + exp_alerts: [] + - eval_time: 90m + alertname: KeepMaintainerEthereumRPCUnhealthy + exp_alerts: [] + - eval_time: 90m + alertname: KeepMaintainerBitcoinRPCUnhealthy + exp_alerts: [] + - eval_time: 90m + alertname: KeepMaintainerEthereumProbeStalled + exp_alerts: [] + - eval_time: 90m + alertname: KeepMaintainerBitcoinProbeStalled + exp_alerts: [] + - eval_time: 90m + alertname: KeepMaintainerSPVStalled + exp_alerts: [] + - eval_time: 90m + alertname: KeepMaintainerProofTaskFailed + exp_alerts: [] + - eval_time: 90m + alertname: KeepMaintainerProofOutsideRelayRange + exp_alerts: [] + - eval_time: 90m + alertname: KeepMaintainerProofExceedsHeaderLimit + exp_alerts: [] + - eval_time: 130m + alertname: KeepMaintainerDown + exp_alerts: [] + - eval_time: 130m + alertname: KeepMaintainerTelemetryMissing + exp_alerts: [] + - eval_time: 130m + alertname: KeepMaintainerSPVInactive + exp_alerts: [] + - eval_time: 130m + alertname: KeepMaintainerEthereumRPCUnhealthy + exp_alerts: [] + - eval_time: 130m + alertname: KeepMaintainerBitcoinRPCUnhealthy + exp_alerts: [] + - eval_time: 130m + alertname: KeepMaintainerEthereumProbeStalled + exp_alerts: [] + - eval_time: 130m + alertname: KeepMaintainerBitcoinProbeStalled + exp_alerts: [] + - eval_time: 130m + alertname: KeepMaintainerSPVStalled + exp_alerts: [] + - eval_time: 130m + alertname: KeepMaintainerProofTaskFailed + exp_alerts: [] + - eval_time: 130m + alertname: KeepMaintainerProofOutsideRelayRange + exp_alerts: + - exp_labels: + job: keep-maintainer + instance: maintainer:9601 + component: keep-maintainer + severity: warning + exp_annotations: + summary: "SPV proofs exceed the relay difficulty range on maintainer:9601" + - eval_time: 130m + alertname: KeepMaintainerProofExceedsHeaderLimit + exp_alerts: + - exp_labels: + job: keep-maintainer + instance: maintainer:9601 + component: keep-maintainer + severity: critical + exp_annotations: + summary: "SPV proofs exceed the supported header count on maintainer:9601" + - name: "same-second failure and recovery stays conservative" + interval: 1m + input_series: + - series: "up{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_spv_maintainer_active{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_eth_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_btc_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_health_check_interval_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "60+0x120" + - series: "performance_rpc_eth_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_rpc_btc_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_activity_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_success_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x4 300+0x115" + - series: "performance_spv_maintainer_last_failure_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x4 300+0x115" + - series: "performance_spv_maintainer_max_backoff_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1800+0x120" + - series: "performance_spv_proof_skipped_outside_relay_range_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_proof_skipped_exceeded_max_headers_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + alert_rule_test: + - eval_time: 10m + alertname: KeepMaintainerDown + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerTelemetryMissing + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerSPVInactive + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerEthereumRPCUnhealthy + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerBitcoinRPCUnhealthy + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerEthereumProbeStalled + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerBitcoinProbeStalled + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerSPVStalled + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerProofTaskFailed + exp_alerts: + - exp_labels: + job: keep-maintainer + instance: maintainer:9601 + component: keep-maintainer + severity: warning + exp_annotations: + summary: "SPV processing has not recovered from a task failure on maintainer:9601" + - eval_time: 10m + alertname: KeepMaintainerProofOutsideRelayRange + exp_alerts: [] + - eval_time: 10m + alertname: KeepMaintainerProofExceedsHeaderLimit + exp_alerts: [] + - name: "probe stall threshold scales with a non-default check interval" + interval: 1m + input_series: + - series: "up{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_spv_maintainer_active{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_eth_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_btc_healthy{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1+0x120" + - series: "performance_rpc_health_check_interval_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "300+0x120" + - series: "performance_rpc_eth_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_rpc_btc_last_check_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_activity_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_success_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+60x120" + - series: "performance_spv_maintainer_last_failure_timestamp_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_maintainer_max_backoff_seconds{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "1800+0x120" + - series: "performance_spv_proof_skipped_outside_relay_range_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + - series: "performance_spv_proof_skipped_exceeded_max_headers_total{job=\"keep-maintainer\", instance=\"maintainer:9601\"}" + values: "0+0x120" + alert_rule_test: + - eval_time: 20m + alertname: KeepMaintainerDown + exp_alerts: [] + - eval_time: 20m + alertname: KeepMaintainerTelemetryMissing + exp_alerts: [] + - eval_time: 20m + alertname: KeepMaintainerSPVInactive + exp_alerts: [] + - eval_time: 20m + alertname: KeepMaintainerEthereumRPCUnhealthy + exp_alerts: [] + - eval_time: 20m + alertname: KeepMaintainerBitcoinRPCUnhealthy + exp_alerts: [] + - eval_time: 20m + alertname: KeepMaintainerEthereumProbeStalled + exp_alerts: [] + - eval_time: 20m + alertname: KeepMaintainerBitcoinProbeStalled + exp_alerts: [] + - eval_time: 20m + alertname: KeepMaintainerSPVStalled + exp_alerts: [] + - eval_time: 20m + alertname: KeepMaintainerProofTaskFailed + exp_alerts: [] + - eval_time: 20m + alertname: KeepMaintainerProofOutsideRelayRange + exp_alerts: [] + - eval_time: 20m + alertname: KeepMaintainerProofExceedsHeaderLimit + exp_alerts: [] + - eval_time: 22m + alertname: KeepMaintainerDown + exp_alerts: [] + - eval_time: 22m + alertname: KeepMaintainerTelemetryMissing + exp_alerts: [] + - eval_time: 22m + alertname: KeepMaintainerSPVInactive + exp_alerts: [] + - eval_time: 22m + alertname: KeepMaintainerEthereumRPCUnhealthy + exp_alerts: [] + - eval_time: 22m + alertname: KeepMaintainerBitcoinRPCUnhealthy + exp_alerts: [] + - eval_time: 22m + alertname: KeepMaintainerEthereumProbeStalled + exp_alerts: + - exp_labels: + job: keep-maintainer + instance: maintainer:9601 + component: keep-maintainer + severity: critical + exp_annotations: + summary: "Ethereum RPC probes stopped completing on maintainer:9601" + - eval_time: 22m + alertname: KeepMaintainerBitcoinProbeStalled + exp_alerts: [] + - eval_time: 22m + alertname: KeepMaintainerSPVStalled + exp_alerts: [] + - eval_time: 22m + alertname: KeepMaintainerProofTaskFailed + exp_alerts: [] + - eval_time: 22m + alertname: KeepMaintainerProofOutsideRelayRange + exp_alerts: [] + - eval_time: 22m + alertname: KeepMaintainerProofExceedsHeaderLimit + exp_alerts: [] diff --git a/infrastructure/monitoring/maintainer/rules.yml b/infrastructure/monitoring/maintainer/rules.yml new file mode 100644 index 0000000000..8217da8912 --- /dev/null +++ b/infrastructure/monitoring/maintainer/rules.yml @@ -0,0 +1,110 @@ +groups: + - name: keep-maintainer + rules: + - alert: KeepMaintainerDown + expr: up{job="keep-maintainer"} == 0 + for: 2m + labels: + severity: critical + component: keep-maintainer + annotations: + summary: "Maintainer {{ $labels.instance }} cannot be scraped" + - alert: KeepMaintainerTelemetryMissing + expr: | + up{job="keep-maintainer"} == 1 unless on(job, instance) + (performance_spv_maintainer_active + and performance_rpc_eth_healthy + and performance_rpc_btc_healthy + and performance_rpc_eth_last_check_timestamp_seconds + and performance_rpc_btc_last_check_timestamp_seconds + and performance_rpc_health_check_interval_seconds + and performance_spv_maintainer_last_activity_timestamp_seconds + and performance_spv_maintainer_last_success_timestamp_seconds + and performance_spv_maintainer_last_failure_timestamp_seconds + and performance_spv_maintainer_max_backoff_seconds) + for: 5m + labels: + severity: critical + component: keep-maintainer + annotations: + summary: "Maintainer {{ $labels.instance }} is missing required telemetry" + - alert: KeepMaintainerSPVInactive + expr: performance_spv_maintainer_active{job="keep-maintainer"} == 0 + for: 5m + labels: + severity: critical + component: keep-maintainer + annotations: + summary: "SPV processing is inactive on {{ $labels.instance }}" + - alert: KeepMaintainerEthereumRPCUnhealthy + expr: performance_rpc_eth_healthy{job="keep-maintainer"} == 0 + for: 5m + labels: + severity: critical + component: keep-maintainer + annotations: + summary: "Ethereum RPC is unhealthy on {{ $labels.instance }}" + - alert: KeepMaintainerBitcoinRPCUnhealthy + expr: performance_rpc_btc_healthy{job="keep-maintainer"} == 0 + for: 5m + labels: + severity: critical + component: keep-maintainer + annotations: + summary: "Bitcoin RPC is unhealthy on {{ $labels.instance }}" + - alert: KeepMaintainerEthereumProbeStalled + expr: | + time() - performance_rpc_eth_last_check_timestamp_seconds{job="keep-maintainer"} + > 3 * performance_rpc_health_check_interval_seconds + 60 + for: 5m + labels: + severity: critical + component: keep-maintainer + annotations: + summary: "Ethereum RPC probes stopped completing on {{ $labels.instance }}" + - alert: KeepMaintainerBitcoinProbeStalled + expr: | + time() - performance_rpc_btc_last_check_timestamp_seconds{job="keep-maintainer"} + > 3 * performance_rpc_health_check_interval_seconds + 60 + for: 5m + labels: + severity: critical + component: keep-maintainer + annotations: + summary: "Bitcoin RPC probes stopped completing on {{ $labels.instance }}" + - alert: KeepMaintainerSPVStalled + expr: | + (time() - performance_spv_maintainer_last_activity_timestamp_seconds{job="keep-maintainer"} + > performance_spv_maintainer_max_backoff_seconds + 1800) + and (performance_spv_maintainer_active == 1) + for: 10m + labels: + severity: critical + component: keep-maintainer + annotations: + summary: "SPV processing stopped making progress on {{ $labels.instance }}" + - alert: KeepMaintainerProofTaskFailed + expr: | + (performance_spv_maintainer_last_failure_timestamp_seconds{job="keep-maintainer"} > 0) + and (performance_spv_maintainer_last_failure_timestamp_seconds + >= performance_spv_maintainer_last_success_timestamp_seconds) + for: 2m + labels: + severity: warning + component: keep-maintainer + annotations: + summary: "SPV processing has not recovered from a task failure on {{ $labels.instance }}" + - alert: KeepMaintainerProofOutsideRelayRange + expr: increase(performance_spv_proof_skipped_outside_relay_range_total{job="keep-maintainer"}[1h]) > 0 + labels: + severity: warning + component: keep-maintainer + annotations: + summary: "SPV proofs exceed the relay difficulty range on {{ $labels.instance }}" + - alert: KeepMaintainerProofExceedsHeaderLimit + expr: increase(performance_spv_proof_skipped_exceeded_max_headers_total{job="keep-maintainer"}[1h]) > 0 + labels: + severity: critical + component: keep-maintainer + annotations: + summary: "SPV proofs exceed the supported header count on {{ $labels.instance }}" diff --git a/infrastructure/scripts/create-google-container-registry-secret.sh b/infrastructure/scripts/create-google-container-registry-secret.sh deleted file mode 100755 index 13d06cea10..0000000000 --- a/infrastructure/scripts/create-google-container-registry-secret.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash - -HELP="Usage: ./$(basename $0) -c \nExample: ./$(basename $0) -c docker-for-desktop" - -while getopts ":c:" opt; do - case $opt in - c ) LOCAL_KUBE_CONTEXT=$OPTARG;; - - \?) - echo -e $HELP - exit 1 - esac -done - -if [ $# -eq 0 ] -then - echo -e $HELP - exit 1 -fi - -function use_local_context() { - - kubectl config use-context $LOCAL_KUBE_CONTEXT -} - -function create_google_container_registry_secret() { - - DOCKER_PASSWORD="$(gcloud auth print-access-token)" - DOCKER_EMAIL="$(gcloud info | grep Account | awk '{print $2}' | tr -d "[]")" - - kubectl create secret docker-registry google-container-registry-auth \ - --docker-server=https://gcr.io \ - --docker-username=oauth2accesstoken \ - --docker-password=$DOCKER_PASSWORD \ - --docker-email=$DOCKER_EMAIL -} - -echo "Setting kube context to local:" -use_local_context -echo "----------------" - -echo "Creating secret for accessing Google private container registry:" -create_google_container_registry_secret \ No newline at end of file diff --git a/infrastructure/scripts/download-gke-creds.sh b/infrastructure/scripts/download-gke-creds.sh deleted file mode 100755 index 11468a0bb7..0000000000 --- a/infrastructure/scripts/download-gke-creds.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -HELP="Usage: ./$(basename $0) -e -r " - -while getopts ":e:r:" opt; do - case $opt in - e ) ENVIRONMENT=$OPTARG;; - r ) REGION=$OPTARG;; - - \?) - echo -e $HELP - exit 1 - esac -done - -if [ $# -eq 0 ] -then - echo -e $HELP - exit 1 -fi - -function download_gke_creds() { - - PROJECT_ID=`gcloud projects list | grep -i $ENVIRONMENT | awk '{print $1}'` - CLUSTER_NAME=`gcloud container clusters list --project $PROJECT_ID | grep -i $ENVIRONMENT | awk '{print $1}'` - - gcloud container clusters get-credentials $CLUSTER_NAME --region $REGION --project $PROJECT_ID --internal-ip -} - -download_gke_creds \ No newline at end of file diff --git a/infrastructure/scripts/download-gke-secrets.sh b/infrastructure/scripts/download-gke-secrets.sh deleted file mode 100755 index 023c79af31..0000000000 --- a/infrastructure/scripts/download-gke-secrets.sh +++ /dev/null @@ -1,20 +0,0 @@ -# Bare script to download each secret from a cluster. -# This assumes you're using the intended Kube context. -# This assumes you're on the correct VPN for that context. - -# Downloaded secrets will have key values base64 encoded. -# The last applied actuals should be in metadata. - -# If you want decoded values in one swoop, third party -# tooling is required. e.g. https://github.com/ashleyschuett/kubernetes-secret-decode - -CURRENT_CONTEXT=$(kubectl config current-context) - -printf "current kube context: [${CURRENT_CONTEXT}]\n\n" -printf "SECRETS TO BE DOWNLOADED:\n" - -kubectl get secret --no-headers - -kubectl get secret --no-headers | awk '{print $1}' | \ - xargs -I{} sh -c 'kubectl get secret -o yaml "$1" > "$1.yaml"' - {} - \ No newline at end of file diff --git a/infrastructure/terraform/keep-dev/backend.tf b/infrastructure/terraform/keep-dev/backend.tf deleted file mode 100644 index 2b7003eb29..0000000000 --- a/infrastructure/terraform/keep-dev/backend.tf +++ /dev/null @@ -1,6 +0,0 @@ -terraform { - backend "gcs" { - bucket = "keep-dev-tf-backend-bucket" - prefix = "terraform/state" - } -} diff --git a/infrastructure/terraform/keep-dev/config-files/jupyterhub-values.yaml.tmpl b/infrastructure/terraform/keep-dev/config-files/jupyterhub-values.yaml.tmpl deleted file mode 100644 index 734cb34d7e..0000000000 --- a/infrastructure/terraform/keep-dev/config-files/jupyterhub-values.yaml.tmpl +++ /dev/null @@ -1,8 +0,0 @@ -auth: - type: google - google: - clientId: "42518614489-elr1i0khrg215fo6ic7iqp20e5i7kdat.apps.googleusercontent.com" - clientSecret: ${clientSecret} - callbackUrl: "http://jupyterhub.research.keep.network/hub/oauth_callback" - hostedDomain: "thesis.co" - loginService: "Google" diff --git a/infrastructure/terraform/keep-dev/dns.tf b/infrastructure/terraform/keep-dev/dns.tf deleted file mode 100644 index 6dae4314fd..0000000000 --- a/infrastructure/terraform/keep-dev/dns.tf +++ /dev/null @@ -1,15 +0,0 @@ -resource "google_dns_managed_zone" "dev_keep_network" { - project = "${module.project.project_id}" - description = "keep-dev subdomain for hosts who will be accessed from the outside world." - name = "dev-keep-network" - dns_name = "dev.keep.network." - labels = "${local.labels}" -} - -resource "google_dns_managed_zone" "dev_tbtc_network" { - project = "${module.project.project_id}" - description = "tbtc-dev subdomain for hosts who will be accessed from the outside world." - name = "dev-tbtc-network" - dns_name = "dev.tbtc.network." - labels = "${local.labels}" -} diff --git a/infrastructure/terraform/keep-dev/iam.tf b/infrastructure/terraform/keep-dev/iam.tf deleted file mode 100644 index cdeca639aa..0000000000 --- a/infrastructure/terraform/keep-dev/iam.tf +++ /dev/null @@ -1,13 +0,0 @@ -module "iam_members_editor" { - source = "git@github.com:thesis/infrastructure.git//terraform/modules/gcp_iam_member" - project = "${module.project.project_id}" - role = "${var.editor_iam_role}" - members = "${var.editor_iam_members}" -} - -module "iam_members_storage_objectviewer" { - source = "git@github.com:thesis/infrastructure.git//terraform/modules/gcp_iam_member" - project = "${module.project.project_id}" - role = "${var.storage_objectviewer_iam_role}" - members = "${var.storage_objectviewer_iam_members}" -} diff --git a/infrastructure/terraform/keep-dev/jupyterhub.tf b/infrastructure/terraform/keep-dev/jupyterhub.tf deleted file mode 100644 index 34941d93ce..0000000000 --- a/infrastructure/terraform/keep-dev/jupyterhub.tf +++ /dev/null @@ -1,38 +0,0 @@ -data "template_file" "jupyterhub_values" { - template = "${file("${path.module}/config-files/jupyterhub-values.yaml.tmpl")}" - - vars = { - clientSecret = "${data.kubernetes_secret.jupyter_oauth_key.data.jupyter-oauth-key}" - } -} - -data "helm_repository" "jupyterhub" { - name = "jupyterhub" - url = "https://jupyterhub.github.io/helm-chart/" -} - -data "kubernetes_secret" "jupyter_oauth_key" { - metadata { - name = "jupyter-oauth-key" - } -} - -resource "helm_release" "jupyterhub" { - name = "helm-jupyterhub" - namespace = "default" - repository = "${data.helm_repository.jupyterhub.metadata.0.name}" - chart = "jupyterhub" - version = "0.8.2" - - values = ["${data.template_file.jupyterhub_values.rendered}"] - - set { - name = "proxy.secretToken" - value = "${random_string.proxy_secrettoken.result}" - } -} - -resource "random_string" "proxy_secrettoken" { - length = 32 - special = true -} diff --git a/infrastructure/terraform/keep-dev/main.tf b/infrastructure/terraform/keep-dev/main.tf deleted file mode 100644 index f436f8eb57..0000000000 --- a/infrastructure/terraform/keep-dev/main.tf +++ /dev/null @@ -1,249 +0,0 @@ -/* Set your locals. - * Terraform doesn't allow for string interpolation in variable maps. - * We cheat it by defining a local. A local instance variable mapping - * allows for string interpolation in maps. Locals are also good for - * names who are a construct of multiple values, to keep module blocks - * clean. -*/ -locals { - public_subnet_name = "${var.environment}-${module.vpc.vpc_subnet_prefix}-pub-${var.region_data["region"]}" - private_subnet_name = "${var.environment}-${module.vpc.vpc_subnet_prefix}-pri-${var.region_data["region"]}" - gke_subnet_name = "${var.environment}-${module.vpc.vpc_subnet_prefix}-gke-${var.region_data["region"]}" - service_account_prefix = "serviceAccount" - - labels { - contact = "${var.contacts}" - environment = "${var.environment}" - vertical = "${var.vertical}" - } -} - -module "project" { - source = "git@github.com:thesis/infrastructure.git//terraform/modules/gcp_project" - name = "${var.project_name}" - org_id = "${var.gcp_thesis_org_id}" - billing_account = "${var.gcp_thesis_billing_account}" - project_owner_members = "${var.project_owner_members}" - labels = "${local.labels}" -} - -# Remote state storage bucket -module "backend_bucket" { - source = "git@github.com:thesis/infrastructure.git//terraform/modules/gcp_bucket" - name = "${var.backend_bucket_name}" - project = "${module.project.project_id}" - location = "${var.region_data["region"]}" - labels = "${local.labels}" -} - -# Create vpc and primary subnets -module "vpc" { - source = "git@github.com:thesis/infrastructure.git//terraform/modules/gcp_vpc" - vpc_network_name = "${var.vpc_network_name}" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - routing_mode = "${var.routing_mode}" - - public_subnet_name = "${local.public_subnet_name}" - public_subnet_ip_cidr_range = "${var.public_subnet_ip_cidr_range}" - - private_subnet_name = "${local.private_subnet_name}" - private_subnet_ip_cidr_range = "${var.private_subnet_ip_cidr_range}" -} - -module "nat_gateway_external_ips" { - source = "git@github.com:thesis/infrastructure.git//terraform/modules/gcp_ip" - name = "${var.nat_gateway_ip_name}" - count = "${var.nat_gateway_ip_allocation_count}" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - address_type = "${var.nat_gateway_ip_address_type}" - labels = "${local.labels}" -} - -module "nat_gateway_zone_a" { - source = "GoogleCloudPlatform/nat-gateway/google" - version = "1.2.2" - name = "${module.vpc.vpc_network_name}-" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - zone = "${var.region_data["zone_a"]}" - network = "${module.vpc.vpc_network_name}" - subnetwork = "${module.vpc.vpc_public_subnet_self_link}" - ip_address_name = "${module.nat_gateway_external_ips.ip_address_name[0]}" # Here's an example of taking a value from a list. - ssh_fw_rule = false - instance_labels = "${local.labels}" -} - -module "nat_gateway_zone_b" { - source = "GoogleCloudPlatform/nat-gateway/google" - version = "1.2.2" - name = "${module.vpc.vpc_network_name}-" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - zone = "${var.region_data["zone_b"]}" - network = "${module.vpc.vpc_network_name}" - subnetwork = "${module.vpc.vpc_public_subnet_self_link}" - ip_address_name = "${module.nat_gateway_external_ips.ip_address_name[1]}" - ssh_fw_rule = false - instance_labels = "${local.labels}" -} - -module "nat_gateway_zone_c" { - source = "GoogleCloudPlatform/nat-gateway/google" - version = "1.2.2" - name = "${module.vpc.vpc_network_name}-" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - zone = "${var.region_data["zone_c"]}" - network = "${module.vpc.vpc_network_name}" - subnetwork = "${module.vpc.vpc_public_subnet_self_link}" - ip_address_name = "${module.nat_gateway_external_ips.ip_address_name[2]}" - ssh_fw_rule = false - instance_labels = "${local.labels}" -} - -# create gke cluster -module "gke_cluster" { - source = "git@github.com:thesis/infrastructure.git//terraform/modules/gcp_gke" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - vpc_network_name = "${module.vpc.vpc_network_name}" - - gke_subnet { - name = "${local.gke_subnet_name}" - primary_ip_cidr_range = "${var.gke_subnet["primary_ip_cidr_range"]}" - services_secondary_range_name = "${var.gke_subnet["services_secondary_range_name"]}" - services_secondary_ip_cidr_range = "${var.gke_subnet["services_secondary_ip_cidr_range"]}" - cluster_secondary_range_name = "${var.gke_subnet["cluster_secondary_range_name"]}" - cluster_secondary_ip_cidr_range = "${var.gke_subnet["cluster_secondary_ip_cidr_range"]}" - } - - gke_cluster { - name = "${var.gke_cluster["name"]}" - private_cluster = "${var.gke_cluster["private_cluster"]}" - master_ipv4_cidr_block = "${var.gke_cluster["master_ipv4_cidr_block"]}" - daily_maintenance_window_start_time = "${var.gke_cluster["daily_maintenance_window_start_time"]}" - network_policy_enabled = "${var.gke_cluster["network_policy_enabled"]}" - network_policy_provider = "${var.gke_cluster["network_policy_provider"]}" - logging_service = "${var.gke_cluster["logging_service"]}" - } - - gke_node_pool { - name = "${var.gke_node_pool["name"]}" - node_count = "${var.gke_node_pool["node_count"]}" - machine_type = "${var.gke_node_pool["machine_type"]}" - disk_type = "${var.gke_node_pool["disk_type"]}" - disk_size_gb = "${var.gke_node_pool["disk_size_gb"]}" - oauth_scopes = "${var.gke_node_pool["oauth_scopes"]}" - auto_repair = "${var.gke_node_pool["auto_repair"]}" - auto_upgrade = "${var.gke_node_pool["auto_upgrade"]}" - tags = "${module.nat_gateway_zone_a.routing_tag_regional}" - } - - labels = "${local.labels}" -} - -/* Using this module will create a data read and an update for the - * prometheus-to-sd resource on each Terraform planand apply run. These - * updates will do nothing and are an artifact of the depends_on in the - * modules data resource. Terraform team is aware and have a proposed fix - * in the works. -*/ -module "gke_cluster_metrics" { - source = "git@github.com:thesis/infrastructure.git//terraform/modules/gke_metrics" - namespace = "${var.gke_metrics_namespace}" - - kube_state_metrics { - version = "${var.kube_state_metrics["version"]}" - } - - prometheus_to_sd { - version = "${var.prometheus_to_sd["version"]}" - } -} - -module "openvpn" { - source = "git@github.com:thesis/infrastructure.git//terraform/modules/helm_openvpn" - - openvpn { - name = "${var.openvpn["name"]}" - version = "${var.openvpn["version"]}" - } - - openvpn_parameters { - route_all_traffic_through_vpn = "${var.openvpn_parameters["route_all_traffic_through_vpn"]}" - gke_master_ipv4_cidr_address = "${var.openvpn_parameters["gke_master_ipv4_cidr_address"]}" - } -} - -module "pull_deployment_infrastructure" { - source = "git@github.com:thesis/infrastructure.git//terraform/modules/gcp_pull_deploy" - project = "${module.project.project_id}" - create_ci_publish_to_gcr_service_account = "${var.create_ci_publish_to_gcr_service_account}" - - keel { - name = "${var.keel["name"]}" - namespace = "${var.keel["namespace"]}" - version = "${var.keel["version"]}" - } - - keel_parameters { - helm_provider_enabled = "${var.keel_parameters["helm_provider_enabled"]}" - rbac_install_enabled = "${var.keel_parameters["rbac_install_enabled"]}" - gcr_enabled = "${var.keel_parameters["gcr_enabled"]}" - } -} - -module "push_deployment_infrastructure" { - source = "git@github.com:thesis/infrastructure.git//terraform/modules/gcp_push_deploy" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - vpc_network_name = "${module.vpc.vpc_network_name}" - vpc_public_subnet_name = "${module.vpc.vpc_public_subnet_name}" - vpc_gke_subnet_name = "${module.gke_cluster.vpc_gke_subnet_name}" - - jumphost { - name = "${var.jumphost["name"]}" - zone = "${var.region_data["zone_a"]}" - tags = "${var.jumphost["tags"]}" - } - - utility_box { - name = "${var.utility_box["name"]}" - machine_type = "${var.utility_box["machine_type"]}" - tools = "${var.utility_box["tools"]}" - zone = "${var.region_data["zone_a"]}" - tags = "${module.nat_gateway_zone_a.routing_tag_regional},${var.utility_box["tags"]}" - } - - labels = "${local.labels}" -} - -resource "google_storage_bucket" "keep_dev_contract_data" { - name = "keep-dev-contract-data" - project = "${module.project.project_id}" - location = "US-CENTRAL1" - storage_class = "REGIONAL" - labels = "${local.labels}" - - versioning { - enabled = true - } -} - -resource "random_id" "ci_get_bucket_object_service_account_random_account_id" { - byte_length = 2 -} - -resource "google_service_account" "ci_get_bucket_object_service_account" { - project = "${module.project.project_id}" - account_id = "ci-get-bucket-object-${random_id.ci_get_bucket_object_service_account_random_account_id.hex}" - display_name = "ci-get-bucket-object" -} - -resource "google_project_iam_member" "ci_get_bucket_object_service_account" { - project = "${module.project.project_id}" - role = "roles/storage.objectViewer" - member = "${local.service_account_prefix}:${google_service_account.ci_get_bucket_object_service_account.email}" -} diff --git a/infrastructure/terraform/keep-dev/outputs.tf b/infrastructure/terraform/keep-dev/outputs.tf deleted file mode 100644 index 27c86fc22a..0000000000 --- a/infrastructure/terraform/keep-dev/outputs.tf +++ /dev/null @@ -1,79 +0,0 @@ -output "contacts" { - value = "${var.contacts}" -} - -output "vertical" { - value = "${var.vertical}" -} - -output "environment" { - value = "${var.environment}" -} - -output "region_data" { - value = "${var.region_data}" -} - -output "project_name" { - value = "${module.project.project_name}" -} - -output "project_id" { - value = "${module.project.project_id}" -} - -output "project_owner_members" { - value = "${var.project_owner_members}" -} - -output "backend_bucket_name" { - value = "${module.backend_bucket.bucket_name}" -} - -output "vpc_network_name" { - value = "${module.vpc.vpc_network_name}" -} - -output "vpc_network_gateway_ip" { - value = "${module.vpc.vpc_network_gateway_ip}" -} - -output "vpc_public_subnet_name" { - value = "${module.vpc.vpc_public_subnet_name}" -} - -output "vpc_private_subnet_name" { - value = "${module.vpc.vpc_private_subnet_name}" -} - -output "nat_gateway_external_ips" { - value = "${module.nat_gateway_external_ips.ip_address_set}" -} - -output "nat_gateway_zone_a_instance" { - value = "${module.nat_gateway_zone_a.instance}" -} - -output "nat_gateway_zone_b_instance" { - value = "${module.nat_gateway_zone_b.instance}" -} - -output "nat_gateway_zone_c_instance" { - value = "${module.nat_gateway_zone_c.instance}" -} - -output "nat_gateway_region_route_tag" { - value = "${module.nat_gateway_zone_a.routing_tag_regional}" -} - -output "nat_gateway_zone_a_route_tag" { - value = "${module.nat_gateway_zone_a.routing_tag_zonal}" -} - -output "nat_gateway_zone_b_route_tag" { - value = "${module.nat_gateway_zone_b.routing_tag_zonal}" -} - -output "nat_gateway_zone_c_route_tag" { - value = "${module.nat_gateway_zone_c.routing_tag_zonal}" -} diff --git a/infrastructure/terraform/keep-dev/provider.tf b/infrastructure/terraform/keep-dev/provider.tf deleted file mode 100644 index 10d7ba75a5..0000000000 --- a/infrastructure/terraform/keep-dev/provider.tf +++ /dev/null @@ -1,53 +0,0 @@ -data "google_client_config" "default" {} - -# Configure the Google Cloud provider -provider "google" { - version = "<= 1.19.0" - region = "${var.region_data["region"]}" -} - -provider "google-beta" { - version = "<= 1.19.0" - region = "${var.region_data["region"]}" -} - -provider "kubernetes" { - version = "<= 1.5.0" - load_config_file = false - host = "https://${var.gke_cluster["master_private_endpoint"]}" - token = "${data.google_client_config.default.access_token}" - cluster_ca_certificate = "${base64decode(module.gke_cluster.cluster_ca_certificate)}" -} - -module "helm_provider_helper" { - source = "git@github.com:thesis/infrastructure.git//terraform/modules/helm_tiller_helper" - tiller_namespace_name = "${var.tiller_namespace_name}" -} - -provider "helm" { - version = "<= 0.10.2" - - kubernetes { - host = "https://${var.gke_cluster["master_private_endpoint"]}" - token = "${data.google_client_config.default.access_token}" - cluster_ca_certificate = "${base64decode(module.gke_cluster.cluster_ca_certificate)}" - } - - tiller_image = "gcr.io/kubernetes-helm/tiller:v2.14.2" - service_account = "${module.helm_provider_helper.tiller_service_account}" - override = ["spec.template.spec.automountserviceaccounttoken=true"] - namespace = "${module.helm_provider_helper.tiller_namespace}" - install_tiller = true -} - -provider "null" { - version = "<= 2.0.0" -} - -provider "random" { - version = "<= 2.0.0" -} - -provider "template" { - version = "<= 1.0.0" -} diff --git a/infrastructure/terraform/keep-dev/variables.tf b/infrastructure/terraform/keep-dev/variables.tf deleted file mode 100644 index 2136a9be3e..0000000000 --- a/infrastructure/terraform/keep-dev/variables.tf +++ /dev/null @@ -1,243 +0,0 @@ -# env vars -variable "gcp_thesis_org_id" { - description = "The ID for the organization the project will be created under. Local ENV VAR" -} - -variable "gcp_thesis_billing_account" { - description = "The billing account to associate with your project. Must be associated with org already. Local ENV VAR" -} - -# generic vars -variable "region_data" { - description = "Region and zone info." - - default { - region = "us-central1" - zone_a = "us-central1-a" - zone_b = "us-central1-b" - zone_c = "us-central1-c" - zone_f = "us-central1-f" - } -} - -variable "contacts" { - description = "The person(s) who contribute to this tf stack." - default = "sthompson22" -} - -variable "vertical" { - description = "Name of the vertical that the generated resources belong to. e.g. cfc, keep" - default = "keep" -} - -variable "environment" { - description = "Environment you're creating resources in. Usually project name" - default = "keep-dev" -} - -# project vars -variable "project_name" { - description = "Name for the project." - default = "keep-dev" -} - -variable "project_owner_members" { - description = "List of service and user accounts to add with owner permissions to project." - - default = [ - "user:sloan.thompson@thesis.co", - "user:antonio.salazarcardozo@thesis.co", - ] -} - -# module IAM members: editor -variable "editor_iam_role" { - default = "roles/editor" -} - -variable "editor_iam_members" { - default = ["user:jakub.nowakowski@thesis.co", "user:nicholas.evans@thesis.co", "user:nik.grinkevich@thesis.co", "user:piotr.dyraga@thesis.co", "user:rafal.czajkowski@thesis.co", "user:dymitr.paremski@thesis.co"] -} - -# module IAM members: storage.objectViewer -variable "storage_objectviewer_iam_role" { - default = "roles/storage.objectViewer" -} - -variable "storage_objectviewer_iam_members" { - default = ["user:liam.zebedee@thesis.co"] -} - -# bucket vars -## backend bucket -variable "backend_bucket_name" { - description = "Bucket for storing keep-dev Terraform remote state." - default = "keep-dev-tf-backend-bucket" -} - -# network vars -## vpc vars -### vpc-network -variable "vpc_network_name" { - description = "The name for your vpc-network" - default = "keep-dev-vpc-network" -} - -variable "routing_mode" { - description = "The dynamic router mode for the vpc-network." - default = "regional" -} - -### vpc-subnet -#### public subnet -variable "public_subnet_ip_cidr_range" { - description = "IP address range assigned to the public subnet." - default = "10.0.0.0/16" -} - -#### private subnet -variable "private_subnet_ip_cidr_range" { - description = "IP address range assigned to the private subnet." - default = "10.1.0.0/16" -} - -## nat gateway vars -### external IP address vars -variable "nat_gateway_ip_allocation_count" { - description = "Generate 3 external IPs, one for each NAT instance." - default = "3" -} - -variable "nat_gateway_ip_name" { - description = "The name for your nat gateway IPs." - default = "keep-dev-nat-gateway-external-ip" -} - -variable "nat_gateway_ip_address_type" { - description = "external or internal, for NATs we use external." - default = "external" -} - -# helm provider -variable "tiller_namespace_name" { - default = "tiller" -} - -# gke -variable "gke_cluster" { - description = "The Google managed part of the cluster configuration." - - default { - name = "keep-dev" - private_cluster = true - master_ipv4_cidr_block = "172.16.0.0/28" - master_private_endpoint = "172.16.0.2" - daily_maintenance_window_start_time = "00:00" - network_policy_enabled = false - network_policy_provider = "PROVIDER_UNSPECIFIED" - logging_service = "logging.googleapis.com" - } -} - -variable "gke_node_pool" { - description = "A node pool for the gke cluster." - - default { - name = "default-node-pool" - node_count = "1" - machine_type = "n1-standard-4" - disk_type = "pd-ssd" - disk_size_gb = 100 - auto_repair = "true" - auto_upgrade = "true" - oauth_scopes = "https://www.googleapis.com/auth/compute,https://www.googleapis.com/auth/devstorage.read_only,https://www.googleapis.com/auth/logging.write,https://www.googleapis.com/auth/monitoring" - } -} - -variable "gke_subnet" { - description = "Subnet for deploying GKE cluster resources." - - default { - primary_ip_cidr_range = "10.2.0.0/16" - - services_secondary_range_name = "keep-dev-gke-services-secondary-range" - services_secondary_ip_cidr_range = "10.102.100.0/24" - - cluster_secondary_range_name = "keep-dev-gke-cluster-secondary-range" - cluster_secondary_ip_cidr_range = "10.102.0.0/20" - } -} - -# gke_metrics -variable "gke_metrics_namespace" { - default = "metrics" -} - -variable "kube_state_metrics" { - default { - version = "0.13.0" - } -} - -variable "prometheus_to_sd" { - default { - version = "0.1.1" - } -} - -# openvpn -variable "openvpn" { - default { - name = "helm-openvpn" - version = "3.13.3" - } -} - -variable "openvpn_parameters" { - default { - route_all_traffic_through_vpn = "false" - gke_master_ipv4_cidr_address = "172.16.0.0" - } -} - -# deployment infrastructure -## pull -variable "create_ci_publish_to_gcr_service_account" { - description = "Create ServiceAccount for CI to publish images to keep-dev GCR." - default = true -} - -variable "keel" { - default { - name = "helm-keel" - namespace = "tiller" - version = "0.8.16" - } -} - -variable "keel_parameters" { - default { - helm_provider_enabled = true - rbac_install_enabled = true - gcr_enabled = true - } -} - -## push - -# gcp_deploy -variable "jumphost" { - default { - name = "keep-dev-jumphost" - tags = "public-subnet" - } -} - -variable "utility_box" { - default { - name = "keep-dev-utility-box" - tags = "gke-subnet" - machine_type = "g1-small" - tools = "kubectl, helm, jq, nodejs, geth" - } -} diff --git a/infrastructure/terraform/keep-prd/backend.tf b/infrastructure/terraform/keep-prd/backend.tf deleted file mode 100644 index b02c4562eb..0000000000 --- a/infrastructure/terraform/keep-prd/backend.tf +++ /dev/null @@ -1,6 +0,0 @@ -terraform { - backend "gcs" { - bucket = "keep-prd-terraform-backend-bucket" - prefix = "terraform/state" - } -} diff --git a/infrastructure/terraform/keep-prd/base.tf b/infrastructure/terraform/keep-prd/base.tf deleted file mode 100644 index 74c1b36c5e..0000000000 --- a/infrastructure/terraform/keep-prd/base.tf +++ /dev/null @@ -1,69 +0,0 @@ -data "google_client_config" "default" {} - -# Configure the Google Cloud provider -provider "google" { - version = "<= 1.19.0" - region = "${var.region_data["region"]}" -} - -provider "google-beta" { - version = "<= 1.19.0" - region = "${var.region_data["region"]}" -} - -provider "null" { - version = "<= 2.0.0" -} - -provider "random" { - version = "<= 2.0.0" -} - -provider "template" { - version = "<= 1.0.0" -} - -/* Set your locals. - * Terraform doesn't allow for string interpolation in variable maps. - * We cheat it by defining a local. A local instance variable mapping - * allows for string interpolation in maps. Locals are also good for - * names who are a construct of multiple values, to keep module blocks - * clean. -*/ -locals { - public_subnet_name = "${var.environment}-${module.vpc.vpc_subnet_prefix}-pub-${var.region_data["region"]}" - private_subnet_name = "${var.environment}-${module.vpc.vpc_subnet_prefix}-pri-${var.region_data["region"]}" - gke_subnet_name = "${var.environment}-${module.vpc.vpc_subnet_prefix}-gke-${var.region_data["region"]}" - - labels { - contact = "${var.contacts}" - environment = "${var.environment}" - vertical = "${var.vertical}" - } -} - -module "project" { - source = "git@github.com:thesis/terraform-google-bootstrap-project.git?ref=0.1.0" - project_name = "${var.project_name}" - org_id = "${var.gcp_thesis_org_id}" - billing_account = "${var.gcp_thesis_billing_account}" - project_owner_members = "${var.project_owner_members}" - project_service_list = "${var.project_service_list}" - location = "${var.region_data["region"]}" - labels = "${local.labels}" -} - -# Create vpc and primary subnets -module "vpc" { - source = "git@github.com:thesis/terraform-google-vpc.git?ref=0.1.0" - vpc_network_name = "${var.vpc_network_name}" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - routing_mode = "${var.routing_mode}" - - public_subnet_name = "${local.public_subnet_name}" - public_subnet_ip_cidr_range = "${var.public_subnet_ip_cidr_range}" - - private_subnet_name = "${local.private_subnet_name}" - private_subnet_ip_cidr_range = "${var.private_subnet_ip_cidr_range}" -} diff --git a/infrastructure/terraform/keep-prd/config-files/files/helm-repositories.yaml b/infrastructure/terraform/keep-prd/config-files/files/helm-repositories.yaml deleted file mode 100644 index b54351e382..0000000000 --- a/infrastructure/terraform/keep-prd/config-files/files/helm-repositories.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: "" -generated: "0001-01-01T00:00:00Z" -repositories: -- caFile: "" - certFile: "" - keyFile: "" - name: stable - password: "" - url: https://kubernetes-charts.storage.googleapis.com - username: "" diff --git a/infrastructure/terraform/keep-prd/gke.tf b/infrastructure/terraform/keep-prd/gke.tf deleted file mode 100644 index 9921be65af..0000000000 --- a/infrastructure/terraform/keep-prd/gke.tf +++ /dev/null @@ -1,60 +0,0 @@ -provider "kubernetes" { - version = "= 1.11.1" - load_config_file = false - host = "https://${var.gke_cluster["master_private_endpoint"]}" - token = "${data.google_client_config.default.access_token}" - cluster_ca_certificate = "${base64decode(module.gke_cluster.cluster_ca_certificate)}" -} - -provider "helm" { - version = "= 1.1.1" - repository_config_path = "./config-files/helm-repositories.yaml" - - kubernetes { - host = "https://${var.gke_cluster["master_private_endpoint"]}" - token = "${data.google_client_config.default.access_token}" - cluster_ca_certificate = "${base64decode(module.gke_cluster.cluster_ca_certificate)}" - } -} - -# create gke cluster -module "gke_cluster" { - source = "git@github.com:thesis/terraform-google-kubernetes-engine.git?ref=0.1.0" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - vpc_network_name = "${module.vpc.vpc_network_name}" - - gke_subnet { - name = "${local.gke_subnet_name}" - primary_ip_cidr_range = "${var.gke_subnet["primary_ip_cidr_range"]}" - services_secondary_range_name = "${var.gke_subnet["services_secondary_range_name"]}" - services_secondary_ip_cidr_range = "${var.gke_subnet["services_secondary_ip_cidr_range"]}" - cluster_secondary_range_name = "${var.gke_subnet["cluster_secondary_range_name"]}" - cluster_secondary_ip_cidr_range = "${var.gke_subnet["cluster_secondary_ip_cidr_range"]}" - } - - gke_cluster { - name = "${var.gke_cluster["name"]}" - private_cluster = "${var.gke_cluster["private_cluster"]}" - master_ipv4_cidr_block = "${var.gke_cluster["master_ipv4_cidr_block"]}" - daily_maintenance_window_start_time = "${var.gke_cluster["daily_maintenance_window_start_time"]}" - network_policy_enabled = "${var.gke_cluster["network_policy_enabled"]}" - network_policy_provider = "${var.gke_cluster["network_policy_provider"]}" - logging_service = "${var.gke_cluster["logging_service"]}" - monitoring_service = "${var.gke_cluster["monitoring_service"]}" - } - - gke_node_pool { - name = "${var.gke_node_pool["name"]}" - node_count = "${var.gke_node_pool["node_count"]}" - machine_type = "${var.gke_node_pool["machine_type"]}" - disk_type = "${var.gke_node_pool["disk_type"]}" - disk_size_gb = "${var.gke_node_pool["disk_size_gb"]}" - oauth_scopes = "${var.gke_node_pool["oauth_scopes"]}" - auto_repair = "${var.gke_node_pool["auto_repair"]}" - auto_upgrade = "${var.gke_node_pool["auto_upgrade"]}" - tags = "${module.nat_gateway_zone_a.routing_tag_regional}" - } - - labels = "${local.labels}" -} diff --git a/infrastructure/terraform/keep-prd/nats.tf b/infrastructure/terraform/keep-prd/nats.tf deleted file mode 100644 index 1e4a01965f..0000000000 --- a/infrastructure/terraform/keep-prd/nats.tf +++ /dev/null @@ -1,91 +0,0 @@ -resource "google_compute_address" "nat_gateway_zone_a" { - name = "${var.nat_gateway_ip["zone_a_name"]}" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - address_type = "${var.nat_gateway_ip["address_type"]}" - network_tier = "${var.nat_gateway_ip["network_tier"]}" - labels = "${local.labels}" -} - -resource "google_compute_address" "nat_gateway_zone_b" { - name = "${var.nat_gateway_ip["zone_b_name"]}" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - address_type = "${var.nat_gateway_ip["address_type"]}" - network_tier = "${var.nat_gateway_ip["network_tier"]}" - labels = "${local.labels}" -} - -resource "google_compute_address" "nat_gateway_zone_c" { - name = "${var.nat_gateway_ip["zone_c_name"]}" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - address_type = "${var.nat_gateway_ip["address_type"]}" - network_tier = "${var.nat_gateway_ip["network_tier"]}" - labels = "${local.labels}" -} - -resource "google_compute_address" "nat_gateway_zone_f" { - name = "${var.nat_gateway_ip["zone_f_name"]}" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - address_type = "${var.nat_gateway_ip["address_type"]}" - network_tier = "${var.nat_gateway_ip["network_tier"]}" - labels = "${local.labels}" -} - -module "nat_gateway_zone_a" { - source = "GoogleCloudPlatform/nat-gateway/google" - version = "1.2.2" - name = "${module.vpc.vpc_network_name}-" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - zone = "${var.region_data["zone_a"]}" - network = "${module.vpc.vpc_network_name}" - subnetwork = "${module.vpc.vpc_public_subnet_self_link}" - ip_address_name = "${google_compute_address.nat_gateway_zone_a.name}" - ssh_fw_rule = false - instance_labels = "${local.labels}" -} - -module "nat_gateway_zone_b" { - source = "GoogleCloudPlatform/nat-gateway/google" - version = "1.2.2" - name = "${module.vpc.vpc_network_name}-" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - zone = "${var.region_data["zone_b"]}" - network = "${module.vpc.vpc_network_name}" - subnetwork = "${module.vpc.vpc_public_subnet_self_link}" - ip_address_name = "${google_compute_address.nat_gateway_zone_b.name}" - ssh_fw_rule = false - instance_labels = "${local.labels}" -} - -module "nat_gateway_zone_c" { - source = "GoogleCloudPlatform/nat-gateway/google" - version = "1.2.2" - name = "${module.vpc.vpc_network_name}-" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - zone = "${var.region_data["zone_c"]}" - network = "${module.vpc.vpc_network_name}" - subnetwork = "${module.vpc.vpc_public_subnet_self_link}" - ip_address_name = "${google_compute_address.nat_gateway_zone_c.name}" - ssh_fw_rule = false - instance_labels = "${local.labels}" -} - -module "nat_gateway_zone_f" { - source = "GoogleCloudPlatform/nat-gateway/google" - version = "1.2.2" - name = "${module.vpc.vpc_network_name}-" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - zone = "${var.region_data["zone_f"]}" - network = "${module.vpc.vpc_network_name}" - subnetwork = "${module.vpc.vpc_public_subnet_self_link}" - ip_address_name = "${google_compute_address.nat_gateway_zone_f.name}" - ssh_fw_rule = false - instance_labels = "${local.labels}" -} diff --git a/infrastructure/terraform/keep-prd/variables.tf b/infrastructure/terraform/keep-prd/variables.tf deleted file mode 100644 index 938bea7630..0000000000 --- a/infrastructure/terraform/keep-prd/variables.tf +++ /dev/null @@ -1,161 +0,0 @@ -# env vars -variable "gcp_thesis_org_id" { - description = "The ID for the organization the project will be created under. Local ENV VAR." -} - -variable "gcp_thesis_billing_account" { - description = "The billing account to associate with your project. Must be associated with org already. Local ENV VAR." -} - -# generic vars -variable "region_data" { - description = "Region and zone info." - - default { - region = "us-central1" - zone_a = "us-central1-a" - zone_b = "us-central1-b" - zone_c = "us-central1-c" - zone_f = "us-central1-f" - } -} - -variable "contacts" { - description = "The person(s) who contribute to this tf stack." - default = "it" -} - -variable "vertical" { - description = "Name of the vertical that the generated resources belong to. e.g. cfc, keep." - default = "keep" -} - -variable "environment" { - description = "Environment you're creating resources in. Usually project name." - default = "keep-prd" -} - -# project vars -variable "project_name" { - description = "Name for the project." - default = "keep-prd" -} - -variable "project_owner_members" { - description = "List of service and user accounts to add with owner permissions to project." - - default = [ - "user:sloan.thompson@thesis.co", - "user:antonio.salazarcardozo@thesis.co", - ] -} - -variable "project_service_list" { - description = "List of google APIs/Services to enable with project creation." - - default = [ - "compute.googleapis.com", - "container.googleapis.com", - "dns.googleapis.com", - ] -} - -# network vars -## vpc vars -### vpc-network -variable "vpc_network_name" { - description = "The name for your vpc-network." - default = "keep-prd-vpc-network" -} - -variable "routing_mode" { - description = "The dynamic router mode for the vpc-network." - default = "regional" -} - -### vpc-subnet -#### public subnet -variable "public_subnet_ip_cidr_range" { - description = "IP address range assigned to the public subnet." - default = "10.0.0.0/16" -} - -#### private subnet -variable "private_subnet_ip_cidr_range" { - description = "IP address range assigned to the private subnet." - default = "10.4.0.0/16" -} - -## nat gateway vars -### external IP address vars - -variable "nat_gateway_ip" { - default { - zone_a_name = "nat-gateway-a" - zone_b_name = "nat-gateway-b" - zone_c_name = "nat-gateway-c" - zone_f_name = "nat-gateway-f" - address_type = "EXTERNAL" - network_tier = "PREMIUM" - } -} - -# gke -variable "gke_cluster" { - description = "The Google managed part of the cluster configuration." - - default { - name = "keep-prd" - private_cluster = true - master_ipv4_cidr_block = "172.16.0.0/28" - master_private_endpoint = "172.16.0.2" - daily_maintenance_window_start_time = "00:00" - network_policy_enabled = false - network_policy_provider = "PROVIDER_UNSPECIFIED" - logging_service = "logging.googleapis.com/kubernetes" - monitoring_service = "monitoring.googleapis.com/kubernetes" - } -} - -variable "gke_node_pool" { - description = "Default node pool for the keep-prd cluster." - - default { - name = "default" - node_count = "2" - machine_type = "n1-standard-4" - disk_type = "pd-ssd" - disk_size_gb = 100 - auto_repair = "true" - auto_upgrade = "true" - oauth_scopes = "https://www.googleapis.com/auth/compute,https://www.googleapis.com/auth/devstorage.read_only,https://www.googleapis.com/auth/logging.write,https://www.googleapis.com/auth/monitoring" - } -} - -variable "gke_subnet" { - description = "Subnet for deploying GKE cluster resources." - - default { - primary_ip_cidr_range = "10.8.0.0/16" - - services_secondary_range_name = "keep-prd-gke-services-secondary-range" - services_secondary_ip_cidr_range = "10.108.100.0/24" - - cluster_secondary_range_name = "keep-prd-gke-cluster-secondary-range" - cluster_secondary_ip_cidr_range = "10.108.0.0/20" - } -} - -# helm_release openvpn -variable "openvpn" { - description = "Configuration values for the keep-prd VPN server." - - default { - name = "openvpn" - namespace = "default" - helm_chart = "stable/openvpn" - helm_chart_version = "4.2.2" - route_all_traffic_through_vpn = "false" - gke_master_cidr = "172.16.0.0" - } -} diff --git a/infrastructure/terraform/keep-prd/vpn.tf b/infrastructure/terraform/keep-prd/vpn.tf deleted file mode 100644 index 4cb719ace2..0000000000 --- a/infrastructure/terraform/keep-prd/vpn.tf +++ /dev/null @@ -1,18 +0,0 @@ -resource "helm_release" "openvpn" { - name = "${var.openvpn["name"]}" - namespace = "${var.openvpn["namespace"]}" - chart = "${var.openvpn["helm_chart"]}" - version = "${var.openvpn["helm_chart_version"]}" - keyring = "" - - set { - name = "openvpn.redirectGateway" - value = "${var.openvpn["route_all_traffic_through_vpn"]}" - } - - # Netmask is not configurable because GKE requires /28 for master subnet range. - set { - name = "openvpn.serverConf" - value = "push \"route ${var.openvpn["gke_master_cidr"]} 255.255.255.240\"" - } -} diff --git a/infrastructure/terraform/keep-test/apis.tf b/infrastructure/terraform/keep-test/apis.tf deleted file mode 100644 index 19a63f0fb9..0000000000 --- a/infrastructure/terraform/keep-test/apis.tf +++ /dev/null @@ -1,9 +0,0 @@ -resource "google_project_service" "compute" { - project = "${module.project.project_id}" - service = "compute.googleapis.com" -} - -resource "google_project_service" "cloud_dns" { - project = "${module.project.project_id}" - service = "dns.googleapis.com" -} diff --git a/infrastructure/terraform/keep-test/backend.tf b/infrastructure/terraform/keep-test/backend.tf deleted file mode 100644 index 72db75a0c9..0000000000 --- a/infrastructure/terraform/keep-test/backend.tf +++ /dev/null @@ -1,6 +0,0 @@ -terraform { - backend "gcs" { - bucket = "keep-test-tf-backend-bucket" - prefix = "terraform/state" - } -} diff --git a/infrastructure/terraform/keep-test/base.tf b/infrastructure/terraform/keep-test/base.tf deleted file mode 100644 index 573aefd903..0000000000 --- a/infrastructure/terraform/keep-test/base.tf +++ /dev/null @@ -1,78 +0,0 @@ -data "google_client_config" "default" {} - -# Configure the Google Cloud provider -provider "google" { - version = "<= 1.19.0" - region = "${var.region_data["region"]}" -} - -provider "google-beta" { - version = "<= 1.19.0" - region = "${var.region_data["region"]}" -} - -provider "null" { - version = "<= 2.0.0" -} - -provider "random" { - version = "<= 2.0.0" -} - -provider "template" { - version = "<= 1.0.0" -} - -/* Set your locals. - * Terraform doesn't allow for string interpolation in variable maps. - * We cheat it by defining a local. A local instance variable mapping - * allows for string interpolation in maps. Locals are also good for - * names who are a construct of multiple values, to keep module blocks - * clean. -*/ -locals { - public_subnet_name = "${var.environment}-${module.vpc.vpc_subnet_prefix}-pub-${var.region_data["region"]}" - private_subnet_name = "${var.environment}-${module.vpc.vpc_subnet_prefix}-pri-${var.region_data["region"]}" - gke_subnet_name = "${var.environment}-${module.vpc.vpc_subnet_prefix}-gke-${var.region_data["region"]}" - - labels { - contact = "${var.contacts}" - environment = "${var.environment}" - vertical = "${var.vertical}" - } -} - -module "project" { - source = "git@github.com:thesis/infrastructure.git//terraform/modules/gcp_project" - name = "${var.project_name}" - org_id = "${var.gcp_thesis_org_id}" - billing_account = "${var.gcp_thesis_billing_account}" - project_owner_members = "${var.project_owner_members}" - labels = "${local.labels}" -} - -resource "google_storage_bucket" "backend_bucket" { - name = "${var.backend_bucket_name}" - project = "${module.project.project_id}" - location = "${var.region_data["region"]}" - labels = "${local.labels}" - - versioning { - enabled = true - } -} - -# Create vpc and primary subnets -module "vpc" { - source = "git@github.com:thesis/infrastructure.git//terraform/modules/gcp_vpc" - vpc_network_name = "${var.vpc_network_name}" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - routing_mode = "${var.routing_mode}" - - public_subnet_name = "${local.public_subnet_name}" - public_subnet_ip_cidr_range = "${var.public_subnet_ip_cidr_range}" - - private_subnet_name = "${local.private_subnet_name}" - private_subnet_ip_cidr_range = "${var.private_subnet_ip_cidr_range}" -} diff --git a/infrastructure/terraform/keep-test/deployment.tf b/infrastructure/terraform/keep-test/deployment.tf deleted file mode 100644 index 66ca541d21..0000000000 --- a/infrastructure/terraform/keep-test/deployment.tf +++ /dev/null @@ -1,73 +0,0 @@ -locals { - service_account_prefix = "serviceAccount" -} - -module "pull_deployment_infrastructure" { - source = "git@github.com:thesis/infrastructure.git//terraform/modules/gcp_pull_deploy" - project = "${module.project.project_id}" - create_ci_publish_to_gcr_service_account = "${var.create_ci_publish_to_gcr_service_account}" - - keel { - name = "${var.keel["name"]}" - namespace = "${var.keel["namespace"]}" - version = "${var.keel["version"]}" - } - - keel_parameters { - helm_provider_enabled = "${var.keel_parameters["helm_provider_enabled"]}" - rbac_install_enabled = "${var.keel_parameters["rbac_install_enabled"]}" - gcr_enabled = "${var.keel_parameters["gcr_enabled"]}" - } -} - -module "push_deployment_infrastructure" { - source = "git@github.com:thesis/infrastructure.git//terraform/modules/gcp_push_deploy" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - vpc_network_name = "${module.vpc.vpc_network_name}" - vpc_public_subnet_name = "${module.vpc.vpc_public_subnet_name}" - vpc_gke_subnet_name = "${module.gke_cluster.vpc_gke_subnet_name}" - - jumphost { - name = "${var.jumphost["name"]}" - zone = "${var.region_data["zone_a"]}" - tags = "${var.jumphost["tags"]}" - } - - utility_box { - name = "${var.utility_box["name"]}" - machine_type = "${var.utility_box["machine_type"]}" - tools = "${var.utility_box["tools"]}" - zone = "${var.region_data["zone_a"]}" - tags = "${module.nat_gateway_zone_a.routing_tag_regional},${var.utility_box["tags"]}" - } - - labels = "${local.labels}" -} - -resource "random_id" "ci_get_bucket_object_service_account_random_account_id" { - byte_length = 2 -} - -resource "google_service_account" "ci_get_bucket_object_service_account" { - project = "${module.project.project_id}" - account_id = "ci-get-bucket-object-${random_id.ci_get_bucket_object_service_account_random_account_id.hex}" - display_name = "ci-get-bucket-object" -} - -resource "google_project_iam_member" "ci_get_bucket_object_service_account" { - project = "${module.project.project_id}" - role = "roles/storage.objectViewer" - member = "${local.service_account_prefix}:${google_service_account.ci_get_bucket_object_service_account.email}" -} - -resource "google_storage_bucket" "keep_contract_data" { - name = "${var.keep_contract_data_bucket_name}" - project = "${module.project.project_id}" - location = "${var.region_data["region"]}" - labels = "${local.labels}" - - versioning { - enabled = true - } -} diff --git a/infrastructure/terraform/keep-test/dns.tf b/infrastructure/terraform/keep-test/dns.tf deleted file mode 100644 index 13f7a5f05b..0000000000 --- a/infrastructure/terraform/keep-test/dns.tf +++ /dev/null @@ -1,15 +0,0 @@ -resource "google_dns_managed_zone" "test_keep_network" { - project = "${module.project.project_id}" - description = "keep-test subdomain for hosts who will be accessed from the outside world." - name = "test-keep-network" - dns_name = "test.keep.network." - labels = "${local.labels}" -} - -resource "google_dns_managed_zone" "test_tbtc_network" { - project = "${module.project.project_id}" - description = "tbtc-test subdomain for hosts who will be accessed from the outside world." - name = "test-tbtc-network" - dns_name = "test.tbtc.network." - labels = "${local.labels}" -} diff --git a/infrastructure/terraform/keep-test/gke.tf b/infrastructure/terraform/keep-test/gke.tf deleted file mode 100644 index 15ae4e123e..0000000000 --- a/infrastructure/terraform/keep-test/gke.tf +++ /dev/null @@ -1,70 +0,0 @@ -provider "kubernetes" { - version = "= 1.5.0" - load_config_file = false - host = "https://${var.gke_cluster["master_private_endpoint"]}" - token = "${data.google_client_config.default.access_token}" - cluster_ca_certificate = "${base64decode(module.gke_cluster.cluster_ca_certificate)}" -} - -module "helm_provider_helper" { - source = "git@github.com:thesis/infrastructure.git//terraform/modules/helm_tiller_helper" - tiller_namespace_name = "${var.tiller_namespace_name}" -} - -provider "helm" { - version = "= 0.7.0" - - kubernetes { - host = "https://${var.gke_cluster["master_private_endpoint"]}" - token = "${data.google_client_config.default.access_token}" - cluster_ca_certificate = "${base64decode(module.gke_cluster.cluster_ca_certificate)}" - } - - tiller_image = "gcr.io/kubernetes-helm/tiller:v2.11.0" - service_account = "${module.helm_provider_helper.tiller_service_account}" - override = ["spec.template.spec.automountserviceaccounttoken=true"] - namespace = "${module.helm_provider_helper.tiller_namespace}" - install_tiller = true -} - -# create gke cluster -module "gke_cluster" { - source = "git@github.com:thesis/infrastructure.git//terraform/modules/gcp_gke" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - vpc_network_name = "${module.vpc.vpc_network_name}" - - gke_subnet { - name = "${local.gke_subnet_name}" - primary_ip_cidr_range = "${var.gke_subnet["primary_ip_cidr_range"]}" - services_secondary_range_name = "${var.gke_subnet["services_secondary_range_name"]}" - services_secondary_ip_cidr_range = "${var.gke_subnet["services_secondary_ip_cidr_range"]}" - cluster_secondary_range_name = "${var.gke_subnet["cluster_secondary_range_name"]}" - cluster_secondary_ip_cidr_range = "${var.gke_subnet["cluster_secondary_ip_cidr_range"]}" - } - - gke_cluster { - name = "${var.gke_cluster["name"]}" - private_cluster = "${var.gke_cluster["private_cluster"]}" - master_ipv4_cidr_block = "${var.gke_cluster["master_ipv4_cidr_block"]}" - daily_maintenance_window_start_time = "${var.gke_cluster["daily_maintenance_window_start_time"]}" - network_policy_enabled = "${var.gke_cluster["network_policy_enabled"]}" - network_policy_provider = "${var.gke_cluster["network_policy_provider"]}" - logging_service = "${var.gke_cluster["logging_service"]}" - monitoring_service = "${var.gke_cluster["monitoring_service"]}" - } - - gke_node_pool { - name = "${var.gke_node_pool["name"]}" - node_count = "${var.gke_node_pool["node_count"]}" - machine_type = "${var.gke_node_pool["machine_type"]}" - disk_type = "${var.gke_node_pool["disk_type"]}" - disk_size_gb = "${var.gke_node_pool["disk_size_gb"]}" - oauth_scopes = "${var.gke_node_pool["oauth_scopes"]}" - auto_repair = "${var.gke_node_pool["auto_repair"]}" - auto_upgrade = "${var.gke_node_pool["auto_upgrade"]}" - tags = "${module.nat_gateway_zone_a.routing_tag_regional}" - } - - labels = "${local.labels}" -} diff --git a/infrastructure/terraform/keep-test/nats.tf b/infrastructure/terraform/keep-test/nats.tf deleted file mode 100644 index e8203969b9..0000000000 --- a/infrastructure/terraform/keep-test/nats.tf +++ /dev/null @@ -1,51 +0,0 @@ -module "nat_gateway_external_ips" { - source = "git@github.com:thesis/infrastructure.git//terraform/modules/gcp_ip" - name = "${var.nat_gateway_ip_name}" - count = "${var.nat_gateway_ip_allocation_count}" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - address_type = "${var.nat_gateway_ip_address_type}" - labels = "${local.labels}" -} - -module "nat_gateway_zone_a" { - source = "GoogleCloudPlatform/nat-gateway/google" - version = "1.2.2" - name = "${module.vpc.vpc_network_name}-" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - zone = "${var.region_data["zone_a"]}" - network = "${module.vpc.vpc_network_name}" - subnetwork = "${module.vpc.vpc_public_subnet_self_link}" - ip_address_name = "${module.nat_gateway_external_ips.ip_address_name[0]}" - ssh_fw_rule = false - instance_labels = "${local.labels}" -} - -module "nat_gateway_zone_b" { - source = "GoogleCloudPlatform/nat-gateway/google" - version = "1.2.2" - name = "${module.vpc.vpc_network_name}-" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - zone = "${var.region_data["zone_b"]}" - network = "${module.vpc.vpc_network_name}" - subnetwork = "${module.vpc.vpc_public_subnet_self_link}" - ip_address_name = "${module.nat_gateway_external_ips.ip_address_name[1]}" - ssh_fw_rule = false - instance_labels = "${local.labels}" -} - -module "nat_gateway_zone_c" { - source = "GoogleCloudPlatform/nat-gateway/google" - version = "1.2.2" - name = "${module.vpc.vpc_network_name}-" - project = "${module.project.project_id}" - region = "${var.region_data["region"]}" - zone = "${var.region_data["zone_c"]}" - network = "${module.vpc.vpc_network_name}" - subnetwork = "${module.vpc.vpc_public_subnet_self_link}" - ip_address_name = "${module.nat_gateway_external_ips.ip_address_name[2]}" - ssh_fw_rule = false - instance_labels = "${local.labels}" -} diff --git a/infrastructure/terraform/keep-test/variables.tf b/infrastructure/terraform/keep-test/variables.tf deleted file mode 100644 index ca4c647a3c..0000000000 --- a/infrastructure/terraform/keep-test/variables.tf +++ /dev/null @@ -1,233 +0,0 @@ -# env vars -variable "gcp_thesis_org_id" { - description = "The ID for the organization the project will be created under. Local ENV VAR" -} - -variable "gcp_thesis_billing_account" { - description = "The billing account to associate with your project. Must be associated with org already. Local ENV VAR" -} - -# generic vars -variable "region_data" { - type = "map" - description = "Region and zone info." - - default { - region = "us-central1" - zone_a = "us-central1-a" - zone_b = "us-central1-b" - zone_c = "us-central1-c" - zone_f = "us-central1-f" - } -} - -variable "contacts" { - description = "The person(s) who contribute to this tf stack." - default = "sthompson22" -} - -variable "vertical" { - description = "Name of the vertical that the generated resources belong to. e.g. cfc, keep" - default = "keep" -} - -variable "environment" { - description = "Environment you're creating resources in. Usually project name" - default = "keep-test" -} - -# project vars -variable "project_name" { - description = "Name for the project." - default = "keep-test" -} - -variable "project_owner_members" { - description = "List of service and user accounts to add with owner permissions to project." - - default = [ - "user:sloan.thompson@thesis.co", - "user:antonio.salazarcardozo@thesis.co", - "user:markus.fix@thesis.co", - "serviceAccount:terraform-admin@thesis-terraform-admin.iam.gserviceaccount.com", - ] -} - -# bucket vars -## backend bucket -variable "backend_bucket_name" { - description = "Bucket for storing keep-test Terraform remote state." - default = "keep-test-tf-backend-bucket" -} - -# network vars -## vpc vars -### vpc-network -variable "vpc_network_name" { - description = "The name for your vpc-network" - default = "keep-test-vpc-network" -} - -variable "routing_mode" { - description = "The dynamic router mode for the vpc-network." - default = "regional" -} - -### vpc-subnet -#### public subnet -variable "public_subnet_ip_cidr_range" { - description = "IP address range assigned to the public subnet." - default = "10.0.0.0/16" -} - -#### private subnet -variable "private_subnet_ip_cidr_range" { - description = "IP address range assigned to the private subnet." - default = "10.1.0.0/16" -} - -## nat gateway vars -### external IP address vars -variable "nat_gateway_ip_allocation_count" { - description = "Generate 3 external IPs, one for each NAT instance." - default = "3" -} - -variable "nat_gateway_ip_name" { - description = "The name for your nat gateway IPs." - default = "keep-test-nat-gateway-external-ip" -} - -variable "nat_gateway_ip_address_type" { - description = "external or internal, for NATs we use external." - default = "external" -} - -# helm provider -variable "tiller_namespace_name" { - default = "tiller" -} - -# gke -variable "gke_cluster" { - description = "The Google managed part of the cluster configuration." - - default { - name = "keep-test" - private_cluster = true - master_ipv4_cidr_block = "172.16.0.0/28" - master_private_endpoint = "172.16.0.2" - daily_maintenance_window_start_time = "00:00" - network_policy_enabled = false - network_policy_provider = "PROVIDER_UNSPECIFIED" - logging_service = "logging.googleapis.com/kubernetes" - monitoring_service = "monitoring.googleapis.com/kubernetes" - } -} - -variable "gke_node_pool" { - description = "A node pool for the gke cluster." - - default { - name = "default" - node_count = "1" - machine_type = "n1-standard-4" - disk_type = "pd-ssd" - disk_size_gb = 100 - auto_repair = "true" - auto_upgrade = "true" - oauth_scopes = "https://www.googleapis.com/auth/compute,https://www.googleapis.com/auth/devstorage.read_only,https://www.googleapis.com/auth/logging.write,https://www.googleapis.com/auth/monitoring" - } -} - -variable "gke_subnet" { - description = "Subnet for deploying GKE cluster resources." - - default { - primary_ip_cidr_range = "10.2.0.0/16" - - services_secondary_range_name = "keep-test-gke-services-secondary-range" - services_secondary_ip_cidr_range = "10.102.100.0/24" - - cluster_secondary_range_name = "keep-test-gke-cluster-secondary-range" - cluster_secondary_ip_cidr_range = "10.102.0.0/20" - } -} - -# gke_metrics -variable "gke_metrics_namespace" { - default = "metrics" -} - -variable "kube_state_metrics" { - default { - version = "0.13.0" - } -} - -variable "prometheus_to_sd" { - default { - version = "0.1.1" - } -} - -# openvpn -variable "openvpn" { - default { - name = "helm-openvpn" - version = "3.13.0" - } -} - -variable "openvpn_parameters" { - default { - route_all_traffic_through_vpn = "false" - gke_master_ipv4_cidr_address = "172.16.0.0" - } -} - -# deployment infrastructure -## pull -variable "create_ci_publish_to_gcr_service_account" { - description = "Create ServiceAccount for CI to publish images to keep-test GCR." - default = true -} - -variable "keel" { - default { - name = "helm-keel" - namespace = "tiller" - version = "0.7.7" - } -} - -variable "keel_parameters" { - default { - helm_provider_enabled = true - rbac_install_enabled = true - gcr_enabled = true - } -} - -## push -variable "jumphost" { - default { - name = "keep-test-jumphost" - tags = "public-subnet" - } -} - -variable "utility_box" { - default { - name = "keep-test-utility-box" - tags = "gke-subnet" - machine_type = "g1-small" - tools = "kubectl, helm, jq, npm, geth" - } -} - -## global -variable "keep_contract_data_bucket_name" { - description = "The name for the bucket that we publish compiled contract data to after CI driven migration." - default = "keep-test-contract-data" -} diff --git a/infrastructure/terraform/keep-test/vpn.tf b/infrastructure/terraform/keep-test/vpn.tf deleted file mode 100644 index e8186bd1a3..0000000000 --- a/infrastructure/terraform/keep-test/vpn.tf +++ /dev/null @@ -1,13 +0,0 @@ -module "openvpn" { - source = "git@github.com:thesis/infrastructure.git//terraform/modules/helm_openvpn" - - openvpn { - name = "${var.openvpn["name"]}" - version = "${var.openvpn["version"]}" - } - - openvpn_parameters { - route_all_traffic_through_vpn = "${var.openvpn_parameters["route_all_traffic_through_vpn"]}" - gke_master_ipv4_cidr_address = "${var.openvpn_parameters["gke_master_ipv4_cidr_address"]}" - } -} diff --git a/internal/testdata/bitcoin/manifest.go b/internal/testdata/bitcoin/manifest.go new file mode 100644 index 0000000000..327c1fca6e --- /dev/null +++ b/internal/testdata/bitcoin/manifest.go @@ -0,0 +1,43 @@ +package bitcoin + +import "github.com/keep-network/keep-core/pkg/bitcoin" + +// RequiredBlocks, RequiredTransactions, RequiredTxMerkleProofs, and +// RequiredTransactionsForPublicKeyHash each declare the networks the +// correspondingly-named fixture map in this package MUST carry a non-empty +// entry for. +// +// The Electrum integration suite connects to Testnet, Mainnet, and Testnet4, +// but data-dependent cases skip networks for which no fixture exists. These +// slices declare the fixture coverage that must not regress: Testnet vectors +// are required even though other configured networks are allowed to be +// unsupported. +// +// The assertions live in pkg/bitcoin/electrum/testdata_manifest_test.go, not +// beside this file. The Go tool excludes any directory named "testdata" from +// package patterns, so a test here would never be matched by `go test ./...` +// and would only run when named explicitly. Hosting it in the consuming +// package means deleting a required fixture entry breaks the default build +// immediately instead of silently reducing integration coverage. +// +// Add a network only after adding fixtures for it. Remove a network before +// deliberately removing its fixture entry. +var ( + // RequiredBlocks lists the networks Blocks must have an entry for. + RequiredBlocks = []bitcoin.Network{bitcoin.Testnet} + + // RequiredTransactions lists the networks Transactions must have a + // non-empty entry for. TestGetTransaction_Integration and + // TestGetTransactionConfirmations_Integration skip when a network's entry + // is missing, so a missing entry makes both pass vacuously as skips + // rather than fail. + RequiredTransactions = []bitcoin.Network{bitcoin.Testnet} + + // RequiredTxMerkleProofs lists the networks TxMerkleProofs must have an + // entry for. + RequiredTxMerkleProofs = []bitcoin.Network{bitcoin.Testnet} + + // RequiredTransactionsForPublicKeyHash lists the networks + // TransactionsForPublicKeyHash must have an entry for. + RequiredTransactionsForPublicKeyHash = []bitcoin.Network{bitcoin.Testnet} +) diff --git a/main.go b/main.go index 96216f6909..7fbb07265a 100644 --- a/main.go +++ b/main.go @@ -7,10 +7,10 @@ import ( "github.com/ipfs/go-log" - "github.com/keep-network/keep-common/pkg/logging" "github.com/keep-network/keep-core/build" "github.com/keep-network/keep-core/cmd" "github.com/keep-network/keep-core/config" + "github.com/keep-network/keep-core/pkg/logging" ) //go:generate make gen_proto diff --git a/pkg/altbn128/altbn128_test.go b/pkg/altbn128/altbn128_test.go index 304eff948e..27563fcf96 100644 --- a/pkg/altbn128/altbn128_test.go +++ b/pkg/altbn128/altbn128_test.go @@ -81,3 +81,52 @@ func assertEqual(t *testing.T, n int, n2 int, msg string) { t.Errorf("%v: [%v] != [%v]", msg, n, n2) } } + +// --- Benchmarks --- + +func BenchmarkCompressG1(b *testing.B) { + _, p, err := bn256.RandomG1(rand.Reader) + if err != nil { + b.Fatal(err) + } + b.ResetTimer() + for range b.N { + G1Point{p}.Compress() + } +} + +func BenchmarkDecompressG1(b *testing.B) { + _, p, err := bn256.RandomG1(rand.Reader) + if err != nil { + b.Fatal(err) + } + buf := G1Point{p}.Compress() + b.ResetTimer() + for range b.N { + _, _ = DecompressToG1(buf) + } +} + +func BenchmarkCompressDecompressRoundTripG1(b *testing.B) { + _, p, err := bn256.RandomG1(rand.Reader) + if err != nil { + b.Fatal(err) + } + b.ResetTimer() + for range b.N { + buf := G1Point{p}.Compress() + _, _ = DecompressToG1(buf) + } +} + +func BenchmarkCompressDecompressRoundTripG2(b *testing.B) { + _, p, err := bn256.RandomG2(rand.Reader) + if err != nil { + b.Fatal(err) + } + b.ResetTimer() + for range b.N { + buf := G2Point{p}.Compress() + _, _ = DecompressToG2(buf) + } +} diff --git a/pkg/beacon/beacon.go b/pkg/beacon/beacon.go index 753380d697..47bda689c4 100644 --- a/pkg/beacon/beacon.go +++ b/pkg/beacon/beacon.go @@ -11,11 +11,11 @@ import ( "github.com/ipfs/go-log" - "github.com/keep-network/keep-common/pkg/persistence" beaconchain "github.com/keep-network/keep-core/pkg/beacon/chain" "github.com/keep-network/keep-core/pkg/beacon/event" "github.com/keep-network/keep-core/pkg/beacon/registry" "github.com/keep-network/keep-core/pkg/net" + "github.com/keep-network/keep-core/pkg/persistence" ) var logger = log.Logger("keep-beacon") diff --git a/pkg/beacon/dkg/dkg.go b/pkg/beacon/dkg/dkg.go index 5d032a5463..f50ebbdec2 100644 --- a/pkg/beacon/dkg/dkg.go +++ b/pkg/beacon/dkg/dkg.go @@ -197,6 +197,9 @@ func waitForDkgResultEvent( blockCounter chain.BlockCounter, ) (*event.DKGResultSubmission, error) { config := beaconChain.GetConfig() + if config.GroupSize <= 0 { + return nil, fmt.Errorf("invalid group size: [%v]", config.GroupSize) + } timeoutBlock := startPublicationBlockHeight + dkgResult.PrePublicationBlocks() + diff --git a/pkg/beacon/dkg/dkg_test.go b/pkg/beacon/dkg/dkg_test.go index af2037dac0..867c824cc5 100644 --- a/pkg/beacon/dkg/dkg_test.go +++ b/pkg/beacon/dkg/dkg_test.go @@ -160,6 +160,28 @@ func TestDecideMemberFate_Timeout(t *testing.T) { } } +func TestWaitForDkgResultEvent_InvalidGroupSize(t *testing.T) { + setup() + + localChain := local_v1.Connect(0, 3) + + _, err := waitForDkgResultEvent( + dkgResultChannel, + startPublicationBlockHeight, + localChain, + blockCounter, + ) + + expectedError := fmt.Errorf("invalid group size: [%v]", 0) + if !reflect.DeepEqual(expectedError, err) { + t.Errorf( + "unexpected error\nexpected: %v\nactual: %v\n", + expectedError, + err, + ) + } +} + func TestResolveGroupOperators(t *testing.T) { beaconConfig := &beaconchain.Config{ GroupSize: 5, diff --git a/pkg/beacon/dkg/integer_conversion_test.go b/pkg/beacon/dkg/integer_conversion_test.go new file mode 100644 index 0000000000..733a8bd27a --- /dev/null +++ b/pkg/beacon/dkg/integer_conversion_test.go @@ -0,0 +1,39 @@ +package dkg + +import ( + "math" + "math/big" + "testing" + + bn256 "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare" + "google.golang.org/protobuf/proto" + + "github.com/keep-network/keep-core/pkg/beacon/registry/gen/pb" +) + +func TestThresholdSignerMemberIndexBounds(t *testing.T) { + publicKey := new(bn256.G2).ScalarBaseMult(big.NewInt(10)).Marshal() + for _, index := range []uint32{0, 1, 255, 256, math.MaxUint32} { + for _, inMap := range []bool{false, true} { + message := &pb.ThresholdSigner{MemberIndex: index, GroupPublicKey: publicKey, GroupPrivateKeyShare: "1"} + if inMap { + message.MemberIndex = 1 + message.GroupPublicKeyShares = map[uint32][]byte{index: publicKey} + } + data, err := proto.Marshal(message) + if err != nil { + t.Fatal(err) + } + decoded := new(ThresholdSigner) + err = decoded.Unmarshal(data) + rejected := index > 255 || (!inMap && index == 0) + if rejected { + if err == nil { + t.Fatalf("accepted invalid index %d (map: %v)", index, inMap) + } + } else if err != nil { + t.Fatalf("rejected valid index %d (map: %v): %v", index, inMap, err) + } + } + } +} diff --git a/pkg/beacon/dkg/marshalling.go b/pkg/beacon/dkg/marshaling.go similarity index 85% rename from pkg/beacon/dkg/marshalling.go rename to pkg/beacon/dkg/marshaling.go index 8f2b9feed3..7dc8a705ec 100644 --- a/pkg/beacon/dkg/marshalling.go +++ b/pkg/beacon/dkg/marshaling.go @@ -1,3 +1,4 @@ +// marshaling.go: protobuf (un)marshaling for the public types in this package. package dkg import ( @@ -54,8 +55,13 @@ func (ts *ThresholdSigner) Unmarshal(bytes []byte) error { return err } + memberIndex, err := group.MemberIndexFromUint32NonZero(pbThresholdSigner.MemberIndex) + if err != nil { + return err + } + groupPublicKey := new(bn256.G2) - _, err := groupPublicKey.Unmarshal(pbThresholdSigner.GroupPublicKey) + _, err = groupPublicKey.Unmarshal(pbThresholdSigner.GroupPublicKey) if err != nil { return err } @@ -73,7 +79,7 @@ func (ts *ThresholdSigner) Unmarshal(bytes []byte) error { return err } - ts.memberIndex = group.MemberIndex(pbThresholdSigner.MemberIndex) + ts.memberIndex = memberIndex ts.groupPublicKey = groupPublicKey ts.groupPrivateKeyShare = privateKeyShare ts.groupPublicKeyShares = groupPublicKeyShares @@ -88,13 +94,17 @@ func unmarshalGroupPublicKeyShares( var unmarshalled = make(map[group.MemberIndex]*bn256.G2, len(shares)) for memberID, shareBytes := range shares { + memberIndex, err := group.MemberIndexFromUint32(memberID) + if err != nil { + return nil, err + } share := new(bn256.G2) - _, err := share.Unmarshal(shareBytes) + _, err = share.Unmarshal(shareBytes) if err != nil { return nil, fmt.Errorf("could not unmarshal share [%v]", err) } - unmarshalled[group.MemberIndex(memberID)] = share + unmarshalled[memberIndex] = share } return unmarshalled, nil diff --git a/pkg/beacon/dkg/marshalling_test.go b/pkg/beacon/dkg/marshaling_test.go similarity index 100% rename from pkg/beacon/dkg/marshalling_test.go rename to pkg/beacon/dkg/marshaling_test.go diff --git a/pkg/beacon/dkg/result/marshalling.go b/pkg/beacon/dkg/result/marshaling.go similarity index 73% rename from pkg/beacon/dkg/result/marshalling.go rename to pkg/beacon/dkg/result/marshaling.go index 147e4b5dc2..ead8f3307a 100644 --- a/pkg/beacon/dkg/result/marshalling.go +++ b/pkg/beacon/dkg/result/marshaling.go @@ -1,8 +1,7 @@ +// marshaling.go: protobuf (un)marshaling for the public types in this package. package result import ( - "fmt" - "google.golang.org/protobuf/proto" "github.com/keep-network/keep-core/pkg/beacon/chain" @@ -10,18 +9,6 @@ import ( "github.com/keep-network/keep-core/pkg/protocol/group" ) -// MemberIndex is represented as uint8 in gjkr. Protobuf does not have uint8 -// type so we are using uint32. When unmarshalling message, we need to make -// sure we do not overflow. -const maxMemberIndex = 255 - -func validateMemberIndex(protoIndex uint32) error { - if protoIndex > maxMemberIndex { - return fmt.Errorf("invalid member index value: [%v]", protoIndex) - } - return nil -} - // Type returns a string describing a DKGResultHashSignatureMessage type for // marshalling purposes. func (d *DKGResultHashSignatureMessage) Type() string { @@ -48,10 +35,11 @@ func (d *DKGResultHashSignatureMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderIndex); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderIndex) + if err != nil { return err } - d.senderIndex = group.MemberIndex(pbMsg.SenderIndex) + d.senderIndex = senderID resultHash, err := chain.DKGResultHashFromBytes(pbMsg.ResultHash) if err != nil { diff --git a/pkg/beacon/dkg/result/marshalling_test.go b/pkg/beacon/dkg/result/marshaling_test.go similarity index 88% rename from pkg/beacon/dkg/result/marshalling_test.go rename to pkg/beacon/dkg/result/marshaling_test.go index fa829ea00e..950cb1a59f 100644 --- a/pkg/beacon/dkg/result/marshalling_test.go +++ b/pkg/beacon/dkg/result/marshaling_test.go @@ -57,10 +57,12 @@ func TestFuzzDKGResultHashSignatureMessageRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &DKGResultHashSignatureMessage{}) + if err := pbutils.RoundTrip(message, &DKGResultHashSignatureMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzDKGResultHashSignatureMessageUnmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&DKGResultHashSignatureMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&DKGResultHashSignatureMessage{}) } diff --git a/pkg/beacon/entry/marshaling.go b/pkg/beacon/entry/marshaling.go index 5cdab428a6..d79860bcf0 100644 --- a/pkg/beacon/entry/marshaling.go +++ b/pkg/beacon/entry/marshaling.go @@ -1,26 +1,12 @@ package entry import ( - "fmt" - "google.golang.org/protobuf/proto" "github.com/keep-network/keep-core/pkg/beacon/entry/gen/pb" "github.com/keep-network/keep-core/pkg/protocol/group" ) -// MemberIndex is represented as uint8 in gjkr. Protobuf does not have uint8 -// type so we are using uint32. When unmarshalling message, we need to make -// sure we do not overflow. -const maxMemberIndex = 255 - -func validateMemberIndex(protoIndex uint32) error { - if protoIndex > maxMemberIndex { - return fmt.Errorf("invalid member index value: [%v]", protoIndex) - } - return nil -} - // Type returns a string describing a SignatureShareMessage's type. func (*SignatureShareMessage) Type() string { return "relay/signature/share" @@ -47,10 +33,11 @@ func (ssm *SignatureShareMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbSignatureShare.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbSignatureShare.SenderID) + if err != nil { return err } - ssm.senderID = group.MemberIndex(pbSignatureShare.SenderID) + ssm.senderID = senderID ssm.shareBytes = pbSignatureShare.Share ssm.sessionID = pbSignatureShare.SessionID diff --git a/pkg/beacon/entry/marshaling_test.go b/pkg/beacon/entry/marshaling_test.go index 457169ec66..d7e34ad257 100644 --- a/pkg/beacon/entry/marshaling_test.go +++ b/pkg/beacon/entry/marshaling_test.go @@ -51,10 +51,12 @@ func TestFuzzSignatureShareMessageRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &SignatureShareMessage{}) + if err := pbutils.RoundTrip(message, &SignatureShareMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzSignatureShareMessageUnmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&SignatureShareMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&SignatureShareMessage{}) } diff --git a/pkg/beacon/entry/message_test.go b/pkg/beacon/entry/message_test.go index 0e905e0a2b..59c58d5b7c 100644 --- a/pkg/beacon/entry/message_test.go +++ b/pkg/beacon/entry/message_test.go @@ -5,35 +5,9 @@ import ( "google.golang.org/protobuf/proto" - "github.com/keep-network/keep-core/internal/testutils" "github.com/keep-network/keep-core/pkg/beacon/entry/gen/pb" - "github.com/keep-network/keep-core/pkg/protocol/group" ) -func TestNewSignatureShareMessage(t *testing.T) { - senderID := group.MemberIndex(7) - shareBytes := []byte{0x01, 0x02, 0x03} - sessionID := "session-1" - - message := NewSignatureShareMessage(senderID, shareBytes, sessionID) - - if message.SenderID() != senderID { - t.Errorf( - "unexpected sender ID\nexpected: [%v]\nactual: [%v]", - senderID, - message.SenderID(), - ) - } - testutils.AssertBytesEqual(t, shareBytes, message.shareBytes) - if message.sessionID != sessionID { - t.Errorf( - "unexpected session ID\nexpected: [%v]\nactual: [%v]", - sessionID, - message.sessionID, - ) - } -} - // The Type string is the wire identifier used to route this message on the // broadcast channel. Changing it silently would break network compatibility // with other clients, so it must stay stable. diff --git a/pkg/beacon/entry/submission.go b/pkg/beacon/entry/submission.go index ea7b4bf3b2..a81855c588 100644 --- a/pkg/beacon/entry/submission.go +++ b/pkg/beacon/entry/submission.go @@ -2,9 +2,10 @@ package entry import ( "fmt" - "github.com/ipfs/go-log/v2" "math/big" + "github.com/ipfs/go-log/v2" + beaconchain "github.com/keep-network/keep-core/pkg/beacon/chain" "github.com/keep-network/keep-core/pkg/chain" "github.com/keep-network/keep-core/pkg/protocol/group" @@ -129,6 +130,10 @@ func (res *relayEntrySubmitter) waitForSubmissionEligibility( groupSize int, blockStep uint64, ) (<-chan uint64, error) { + if groupSize <= 0 { + return nil, fmt.Errorf("invalid group size: [%v]", groupSize) + } + // First submitter index is calculated as entry % groupSize and gives // an index from range [0, groupSize-1]. firstSubmitterMemberIndex := new(big.Int).Mod( diff --git a/pkg/beacon/entry/submission_test.go b/pkg/beacon/entry/submission_test.go index b7416cc7ea..44e2294fdc 100644 --- a/pkg/beacon/entry/submission_test.go +++ b/pkg/beacon/entry/submission_test.go @@ -1,6 +1,10 @@ package entry -import "testing" +import ( + "fmt" + "reflect" + "testing" +) func TestCalculateSubmissionQueueIndex(t *testing.T) { groupSize := uint64(64) @@ -45,3 +49,23 @@ func TestCalculateSubmissionQueueIndex(t *testing.T) { }) } } + +func TestWaitForSubmissionEligibility_InvalidGroupSize(t *testing.T) { + res := &relayEntrySubmitter{} + + _, err := res.waitForSubmissionEligibility( + []byte{1, 2, 3}, + 0, + 0, + 1, + ) + + expectedError := fmt.Errorf("invalid group size: [%v]", 0) + if !reflect.DeepEqual(expectedError, err) { + t.Errorf( + "unexpected error\nexpected: %v\nactual: %v\n", + expectedError, + err, + ) + } +} diff --git a/pkg/beacon/event/deduplicator.go b/pkg/beacon/event/deduplicator.go index f22fbcdcbf..981bd4c006 100644 --- a/pkg/beacon/event/deduplicator.go +++ b/pkg/beacon/event/deduplicator.go @@ -3,7 +3,7 @@ package event import ( "encoding/hex" "fmt" - "github.com/keep-network/keep-common/pkg/cache" + "github.com/keep-network/keep-core/pkg/cache" "math/big" "sync" "time" diff --git a/pkg/beacon/event/deduplicator_test.go b/pkg/beacon/event/deduplicator_test.go index ad36ce9e5c..44393f0df7 100644 --- a/pkg/beacon/event/deduplicator_test.go +++ b/pkg/beacon/event/deduplicator_test.go @@ -2,7 +2,7 @@ package event import ( "encoding/hex" - "github.com/keep-network/keep-common/pkg/cache" + "github.com/keep-network/keep-core/pkg/cache" "math/big" "testing" "time" diff --git a/pkg/beacon/gjkr/integer_conversion_test.go b/pkg/beacon/gjkr/integer_conversion_test.go new file mode 100644 index 0000000000..e4586fbc5e --- /dev/null +++ b/pkg/beacon/gjkr/integer_conversion_test.go @@ -0,0 +1,36 @@ +package gjkr + +import ( + "testing" + + "google.golang.org/protobuf/proto" + + "github.com/keep-network/keep-core/pkg/beacon/gjkr/gen/pb" +) + +func TestAccusationsUnmarshalValidationErrors(t *testing.T) { + for _, keys := range []map[uint32][]byte{{256: {1}}, {1: nil}} { + cases := []struct { + message proto.Message + unmarshal func([]byte) error + }{ + { + message: &pb.SecretSharesAccusations{SenderID: 1, AccusedMembersKeys: keys, SessionID: "session"}, + unmarshal: new(SecretSharesAccusationsMessage).Unmarshal, + }, + { + message: &pb.PointsAccusations{SenderID: 1, AccusedMembersKeys: keys, SessionID: "session"}, + unmarshal: new(PointsAccusationsMessage).Unmarshal, + }, + } + for _, tc := range cases { + data, err := proto.Marshal(tc.message) + if err != nil { + t.Fatal(err) + } + if err := tc.unmarshal(data); err == nil { + t.Fatalf("%T accepted invalid accusation keys", tc.message) + } + } + } +} diff --git a/pkg/beacon/gjkr/marshaling.go b/pkg/beacon/gjkr/marshaling.go index 03c80eacb1..dcfa5f0bd0 100644 --- a/pkg/beacon/gjkr/marshaling.go +++ b/pkg/beacon/gjkr/marshaling.go @@ -11,15 +11,6 @@ import ( "github.com/keep-network/keep-core/pkg/protocol/group" ) -func validateMemberIndex(protoIndex uint32) error { - // Protobuf does not have uint8 type so we are using uint32. When - // unmarshalling message, we need to make sure we do not overflow. - if protoIndex > group.MaxMemberIndex { - return fmt.Errorf("invalid member index value: [%v]", protoIndex) - } - return nil -} - // Type returns a string describing an EphemeralPublicKeyMessage type for // marshaling purposes. func (epkm *EphemeralPublicKeyMessage) Type() string { @@ -49,10 +40,11 @@ func (epkm *EphemeralPublicKeyMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } - epkm.senderID = group.MemberIndex(pbMsg.SenderID) + epkm.senderID = senderID ephemeralPublicKeys, err := unmarshalPublicKeyMap(pbMsg.EphemeralPublicKeys) if err != nil { @@ -94,10 +86,11 @@ func (mcm *MemberCommitmentsMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } - mcm.senderID = group.MemberIndex(pbMsg.SenderID) + mcm.senderID = senderID var commitments []*bn256.G1 for _, commitmentBytes := range pbMsg.Commitments { @@ -152,14 +145,16 @@ func (psm *PeerSharesMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } - psm.senderID = group.MemberIndex(pbMsg.SenderID) + psm.senderID = senderID shares := make(map[group.MemberIndex]*peerShares) for memberID, pbShares := range pbMsg.Shares { - if err := validateMemberIndex(memberID); err != nil { + memberIndex, err := group.MemberIndexFromUint32(memberID) + if err != nil { return err } @@ -167,7 +162,7 @@ func (psm *PeerSharesMessage) Unmarshal(bytes []byte) error { return fmt.Errorf("nil shares from member [%v]", memberID) } - shares[group.MemberIndex(memberID)] = &peerShares{ + shares[memberIndex] = &peerShares{ encryptedShareS: pbShares.EncryptedShareS, encryptedShareT: pbShares.EncryptedShareT, } @@ -208,14 +203,15 @@ func (ssam *SecretSharesAccusationsMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } - ssam.senderID = group.MemberIndex(pbMsg.SenderID) + ssam.senderID = senderID accusedMembersKeys, err := unmarshalPrivateKeyMap(pbMsg.AccusedMembersKeys) if err != nil { - return nil + return err } ssam.accusedMembersKeys = accusedMembersKeys @@ -257,10 +253,11 @@ func (mpspm *MemberPublicKeySharePointsMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } - mpspm.senderID = group.MemberIndex(pbMsg.SenderID) + mpspm.senderID = senderID var keySharePoints []*bn256.G2 for _, keySharePointBytes := range pbMsg.PublicKeySharePoints { @@ -309,14 +306,15 @@ func (pam *PointsAccusationsMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } - pam.senderID = group.MemberIndex(pbMsg.SenderID) + pam.senderID = senderID accusedMembersKeys, err := unmarshalPrivateKeyMap(pbMsg.AccusedMembersKeys) if err != nil { - return nil + return err } pam.accusedMembersKeys = accusedMembersKeys @@ -354,10 +352,11 @@ func (mekm *MisbehavedEphemeralKeysMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } - mekm.senderID = group.MemberIndex(pbMsg.SenderID) + mekm.senderID = senderID privateKeys, err := unmarshalPrivateKeyMap(pbMsg.PrivateKeys) if err != nil { @@ -389,7 +388,8 @@ func unmarshalPublicKeyMap( ) (map[group.MemberIndex]*ephemeral.PublicKey, error) { var unmarshalled = make(map[group.MemberIndex]*ephemeral.PublicKey, len(publicKeys)) for memberID, publicKeyBytes := range publicKeys { - if err := validateMemberIndex(memberID); err != nil { + memberIndex, err := group.MemberIndexFromUint32(memberID) + if err != nil { return nil, err } @@ -398,7 +398,7 @@ func unmarshalPublicKeyMap( return nil, fmt.Errorf("could not unmarshal public key [%v]", err) } - unmarshalled[group.MemberIndex(memberID)] = publicKey + unmarshalled[memberIndex] = publicKey } @@ -424,7 +424,8 @@ func unmarshalPrivateKeyMap( ) (map[group.MemberIndex]*ephemeral.PrivateKey, error) { var unmarshalled = make(map[group.MemberIndex]*ephemeral.PrivateKey, len(privateKeys)) for memberID, privateKeyBytes := range privateKeys { - if err := validateMemberIndex(memberID); err != nil { + memberIndex, err := group.MemberIndexFromUint32(memberID) + if err != nil { return nil, err } @@ -434,7 +435,7 @@ func unmarshalPrivateKeyMap( ) } - unmarshalled[group.MemberIndex(memberID)] = ephemeral.UnmarshalPrivateKey(privateKeyBytes) + unmarshalled[memberIndex] = ephemeral.UnmarshalPrivateKey(privateKeyBytes) } return unmarshalled, nil diff --git a/pkg/beacon/gjkr/marshaling_test.go b/pkg/beacon/gjkr/marshaling_test.go index d7694bface..0dd7bd96aa 100644 --- a/pkg/beacon/gjkr/marshaling_test.go +++ b/pkg/beacon/gjkr/marshaling_test.go @@ -67,12 +67,14 @@ func TestFuzzEphemeralPublicKeyMessageRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &EphemeralPublicKeyMessage{}) + if err := pbutils.RoundTrip(message, &EphemeralPublicKeyMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzEphemeralPublicKeyMessageUnmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&EphemeralPublicKeyMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&EphemeralPublicKeyMessage{}) } func TestMemberCommitmentsMessageRoundtrip(t *testing.T) { @@ -119,12 +121,14 @@ func TestFuzzMemberCommitmentsMessageRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &MemberCommitmentsMessage{}) + if err := pbutils.RoundTrip(message, &MemberCommitmentsMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzMemberCommitmentsMessageUnmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&MemberCommitmentsMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&MemberCommitmentsMessage{}) } func TestPeerSharesMessageRoundtrip(t *testing.T) { @@ -191,12 +195,14 @@ func TestFuzzPeerSharesMessageRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &PeerSharesMessage{}) + if err := pbutils.RoundTrip(message, &PeerSharesMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzPeerSharesMessageUnmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&PeerSharesMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&PeerSharesMessage{}) } func TestSecretSharesAccusationsMessageRoundtrip(t *testing.T) { @@ -252,12 +258,14 @@ func TestFuzzSecretSharesAccusationsMessageRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &SecretSharesAccusationsMessage{}) + if err := pbutils.RoundTrip(message, &SecretSharesAccusationsMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzSecretSharesAccusationsMessageUnmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&SecretSharesAccusationsMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&SecretSharesAccusationsMessage{}) } func TestMemberPublicKeySharePointsMessageRoundtrip(t *testing.T) { @@ -305,12 +313,14 @@ func TestFuzzMemberPublicKeySharePointsMessageRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &MemberPublicKeySharePointsMessage{}) + if err := pbutils.RoundTrip(message, &MemberPublicKeySharePointsMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzMemberPublicKeySharePointsMessageUnmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&MemberPublicKeySharePointsMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&MemberPublicKeySharePointsMessage{}) } func TestPointsAccusationsMessageRoundtrip(t *testing.T) { @@ -366,12 +376,14 @@ func TestFuzzPointsAccusationsMessageRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &PointsAccusationsMessage{}) + if err := pbutils.RoundTrip(message, &PointsAccusationsMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzPointsAccusationsMessageUnmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&PointsAccusationsMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&PointsAccusationsMessage{}) } func TestMisbehavedEphemeralKeysMessageRoundtrip(t *testing.T) { @@ -427,10 +439,129 @@ func TestFuzzMisbehavedEphemeralKeysMessageRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &MisbehavedEphemeralKeysMessage{}) + if err := pbutils.RoundTrip(message, &MisbehavedEphemeralKeysMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzMisbehavedEphemeralKeysMessageUnmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&MisbehavedEphemeralKeysMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&MisbehavedEphemeralKeysMessage{}) +} + +// --- Benchmarks --- + +// buildEphemeralKeyMap generates n key pairs and returns the public key map as +// it would appear in a real EphemeralPublicKeyMessage (one entry per peer). +func buildEphemeralKeyMap(b *testing.B, n int) map[group.MemberIndex]*ephemeral.PublicKey { + b.Helper() + m := make(map[group.MemberIndex]*ephemeral.PublicKey, n) + for i := 0; i < n; i++ { + kp, err := ephemeral.GenerateKeyPair() + if err != nil { + b.Fatal(err) + } + m[group.MemberIndex(i+1)] = kp.PublicKey + } + return m +} + +func BenchmarkMarshalEphemeralPublicKeyMessage(b *testing.B) { + kp1, err := ephemeral.GenerateKeyPair() + if err != nil { + b.Fatal(err) + } + kp2, err := ephemeral.GenerateKeyPair() + if err != nil { + b.Fatal(err) + } + msg := &EphemeralPublicKeyMessage{ + senderID: group.MemberIndex(38), + ephemeralPublicKeys: map[group.MemberIndex]*ephemeral.PublicKey{ + group.MemberIndex(211): kp1.PublicKey, + group.MemberIndex(19): kp2.PublicKey, + }, + sessionID: "session-1", + } + b.ResetTimer() + for range b.N { + _, _ = msg.Marshal() + } +} + +func BenchmarkUnmarshalEphemeralPublicKeyMessage(b *testing.B) { + kp1, err := ephemeral.GenerateKeyPair() + if err != nil { + b.Fatal(err) + } + kp2, err := ephemeral.GenerateKeyPair() + if err != nil { + b.Fatal(err) + } + msg := &EphemeralPublicKeyMessage{ + senderID: group.MemberIndex(38), + ephemeralPublicKeys: map[group.MemberIndex]*ephemeral.PublicKey{ + group.MemberIndex(211): kp1.PublicKey, + group.MemberIndex(19): kp2.PublicKey, + }, + sessionID: "session-1", + } + data, err := msg.Marshal() + if err != nil { + b.Fatal(err) + } + b.ResetTimer() + for range b.N { + _ = new(EphemeralPublicKeyMessage).Unmarshal(data) + } +} + +// The _64Keys benchmarks below (BenchmarkMarshalEphemeralPublicKeyMessage_64Keys +// and BenchmarkUnmarshalEphemeralPublicKeyMessage_64Keys) measure marshal and +// unmarshal cost on a 64-member beacon group (63 peer keys per message) as +// the gjkr package stands today. Unmarshal currently parses every peer key +// eagerly through ephemeral.UnmarshalPublicKey (each call wraps +// btcec.ParsePubKey and dominates the work), so these numbers reflect that +// eager-parsing cost. +// +// pkg/tecdsa/dkg and pkg/tecdsa/signing received a +// deferred-ephemeral-key-parsing optimization in this release cycle that +// turns the per-message cost from O(N^2) over the group into O(1) at +// unmarshal plus O(1) per key on demand. Porting that optimization to gjkr +// is intentionally out of scope here and is tracked as a follow-up +// improvement. The _64Keys benchmarks are kept as a pre-optimization +// baseline so reviewers do not mistake the suffix or the surrounding +// comments for evidence that gjkr already has the optimization. + +// BenchmarkMarshalEphemeralPublicKeyMessage_64Keys benchmarks marshaling with +// the beacon group size (64 members = 63 peer keys per message). +func BenchmarkMarshalEphemeralPublicKeyMessage_64Keys(b *testing.B) { + msg := &EphemeralPublicKeyMessage{ + senderID: group.MemberIndex(1), + ephemeralPublicKeys: buildEphemeralKeyMap(b, 63), + sessionID: "session-1", + } + b.ResetTimer() + for range b.N { + _, _ = msg.Marshal() + } +} + +// BenchmarkUnmarshalEphemeralPublicKeyMessage_64Keys benchmarks unmarshaling +// with the beacon group size. Each btcec.ParsePubKey call dominates; with 63 +// peers this represents the real per-participant beacon DKG cost. +func BenchmarkUnmarshalEphemeralPublicKeyMessage_64Keys(b *testing.B) { + msg := &EphemeralPublicKeyMessage{ + senderID: group.MemberIndex(1), + ephemeralPublicKeys: buildEphemeralKeyMap(b, 63), + sessionID: "session-1", + } + data, err := msg.Marshal() + if err != nil { + b.Fatal(err) + } + b.ResetTimer() + for range b.N { + _ = new(EphemeralPublicKeyMessage).Unmarshal(data) + } } diff --git a/pkg/beacon/gjkr/member.go b/pkg/beacon/gjkr/member.go index 55cf54c1d9..95f8e81c2a 100644 --- a/pkg/beacon/gjkr/member.go +++ b/pkg/beacon/gjkr/member.go @@ -100,10 +100,9 @@ type CommitmentsVerifyingMember struct { // Shares calculated for the current member by peer group members which passed // the validation. // - // receivedQualifiedSharesS are defined as `s_ji` and receivedQualifiedSharesT are - // defined as `t_ji` across the protocol specification. - // TODO remove receivedQualifiedSharesT - exists only for unit tests purpose - receivedQualifiedSharesS, receivedQualifiedSharesT map[group.MemberIndex]*big.Int + // receivedQualifiedSharesS are defined as `s_ji` across the protocol + // specification. + receivedQualifiedSharesS map[group.MemberIndex]*big.Int // Commitments to secret shares polynomial coefficients received from // other group members. receivedPeerCommitments map[group.MemberIndex][]*bn256.G1 @@ -285,7 +284,6 @@ func (cm *CommittingMember) InitializeCommitmentsVerification() *CommitmentsVeri return &CommitmentsVerifyingMember{ CommittingMember: cm, receivedQualifiedSharesS: make(map[group.MemberIndex]*big.Int), - receivedQualifiedSharesT: make(map[group.MemberIndex]*big.Int), receivedPeerCommitments: make(map[group.MemberIndex][]*bn256.G1), } } diff --git a/pkg/beacon/gjkr/protocol.go b/pkg/beacon/gjkr/protocol.go index 8cedfbcd0b..148d7a369b 100644 --- a/pkg/beacon/gjkr/protocol.go +++ b/pkg/beacon/gjkr/protocol.go @@ -433,7 +433,6 @@ func (cvm *CommitmentsVerifyingMember) VerifyReceivedSharesAndCommitmentsMessage break } cvm.receivedQualifiedSharesS[commitmentsMessage.senderID] = shareS - cvm.receivedQualifiedSharesT[commitmentsMessage.senderID] = shareT break } } @@ -766,7 +765,6 @@ func (sjm *SharesJustifyingMember) discardReceivedShares( memberID group.MemberIndex, ) { delete(sjm.receivedQualifiedSharesS, memberID) - delete(sjm.receivedQualifiedSharesT, memberID) } // Inspects evidence log looking for ephemeral public key message sent in phase diff --git a/pkg/beacon/gjkr/protocol_accusations_test.go b/pkg/beacon/gjkr/protocol_accusations_test.go index 016119dad8..eec68f9267 100644 --- a/pkg/beacon/gjkr/protocol_accusations_test.go +++ b/pkg/beacon/gjkr/protocol_accusations_test.go @@ -134,7 +134,7 @@ func TestResolveSecretSharesAccusations(t *testing.T) { } for testName, test := range tests { t.Run(testName, func(t *testing.T) { - members, err := initializeSharesJustifyingMemberGroup( + members, receivedSharesT, err := initializeSharesJustifyingMemberGroup( dishonestThreshold, groupSize, ) @@ -145,7 +145,7 @@ func TestResolveSecretSharesAccusations(t *testing.T) { accuser := findSharesJustifyingMemberByID(members, test.accuserID) modifiedShareS := accuser.receivedQualifiedSharesS[test.accusedID] - modifiedShareT := accuser.receivedQualifiedSharesT[test.accusedID] + modifiedShareT := receivedSharesT[test.accuserID][test.accusedID] if test.modifyShareS != nil { modifiedShareS = test.modifyShareS(modifiedShareS) @@ -422,7 +422,7 @@ func TestResolveSecretSharesAccusationsIncorrectAccussedMemberId(t *testing.T) { for testName, test := range tests { t.Run(testName, func(t *testing.T) { - members, err := initializeSharesJustifyingMemberGroup( + members, _, err := initializeSharesJustifyingMemberGroup( dishonestThreshold, groupSize, ) @@ -540,19 +540,20 @@ func findCoefficientsJustifyingMemberByID( return nil } -// InitializeSharesJustifyingMemberGroup generates a group of members and simulates -// shares calculation and commitments sharing betwen members (Phases 3 and 4). -// It generates coefficients for each group member, calculates commitments and -// shares for each peer member individually. At the end it stores values for each -// member just like they would be received from peers. +// initializeSharesJustifyingMemberGroup initializes a group of shares +// justifying members with simulated received shares and commitments. It also +// returns the received `t_ji` shares keyed by receiver then sender member +// index; these are not stored on the member (only `s_ji` is production state) +// but some accusation tests need them to reconstruct the peer shares message. func initializeSharesJustifyingMemberGroup(dishonestThreshold, groupSize int) ( []*SharesJustifyingMember, + map[group.MemberIndex]map[group.MemberIndex]*big.Int, error, ) { commitmentsVerifyingMembers, err := initializeCommitmentsVerifiyingMembersGroup(dishonestThreshold, groupSize) if err != nil { - return nil, fmt.Errorf("group initialization failed [%s]", err) + return nil, nil, fmt.Errorf("group initialization failed [%s]", err) } var sharesJustifyingMembers []*SharesJustifyingMember @@ -567,14 +568,18 @@ func initializeSharesJustifyingMemberGroup(dishonestThreshold, groupSize int) ( groupCoefficientsB := make(map[group.MemberIndex][]*big.Int, groupSize) groupCommitments := make(map[group.MemberIndex][]*bn256.G1, groupSize) + // receivedSharesT keeps the `t_ji` shares received by each member from its + // peers, keyed by receiver then sender member index. + receivedSharesT := make(map[group.MemberIndex]map[group.MemberIndex]*big.Int) + for _, m := range sharesJustifyingMembers { memberCoefficientsA, err := generatePolynomial(dishonestThreshold) if err != nil { - return nil, fmt.Errorf("polynomial generation failed [%s]", err) + return nil, nil, fmt.Errorf("polynomial generation failed [%s]", err) } memberCoefficientsB, err := generatePolynomial(dishonestThreshold) if err != nil { - return nil, fmt.Errorf("polynomial generation failed [%s]", err) + return nil, nil, fmt.Errorf("polynomial generation failed [%s]", err) } // polynomial is of degree dishonestThreshold so it has @@ -598,13 +603,16 @@ func initializeSharesJustifyingMemberGroup(dishonestThreshold, groupSize int) ( for _, p := range sharesJustifyingMembers { if m.ID != p.ID { p.receivedQualifiedSharesS[m.ID] = m.evaluateMemberShare(p.ID, groupCoefficientsA[m.ID]) - p.receivedQualifiedSharesT[m.ID] = m.evaluateMemberShare(p.ID, groupCoefficientsB[m.ID]) + if receivedSharesT[p.ID] == nil { + receivedSharesT[p.ID] = make(map[group.MemberIndex]*big.Int) + } + receivedSharesT[p.ID][m.ID] = m.evaluateMemberShare(p.ID, groupCoefficientsB[m.ID]) p.receivedPeerCommitments[m.ID] = groupCommitments[m.ID] } } } - return sharesJustifyingMembers, nil + return sharesJustifyingMembers, receivedSharesT, nil } // initializePointsJustifyingMemberGroup generates a group of members and diff --git a/pkg/beacon/gjkr/protocol_commitments_test.go b/pkg/beacon/gjkr/protocol_commitments_test.go index 14b144be3c..dd0d837ad7 100644 --- a/pkg/beacon/gjkr/protocol_commitments_test.go +++ b/pkg/beacon/gjkr/protocol_commitments_test.go @@ -277,12 +277,6 @@ func assertValidSharesAndCommitments( len(verifyingMember.receivedQualifiedSharesS), ) } - if len(verifyingMember.receivedQualifiedSharesT) != expectedReceivedSharesLength { - t.Errorf("\nexpected: %v received shares T\nactual: %v\n", - expectedReceivedSharesLength, - len(verifyingMember.receivedQualifiedSharesT), - ) - } if len(verifyingMember.receivedPeerCommitments) != groupSize-1 { t.Errorf("\nexpected: %v received commitments\nactual: %v\n", expectedReceivedSharesLength, diff --git a/pkg/beacon/gjkr/protocol_sharing_test.go b/pkg/beacon/gjkr/protocol_sharing_test.go index 51f38096c3..39f72ddd90 100644 --- a/pkg/beacon/gjkr/protocol_sharing_test.go +++ b/pkg/beacon/gjkr/protocol_sharing_test.go @@ -188,7 +188,7 @@ func initializeQualifiedMembersGroup(dishonestThreshold, groupSize int) ( []*QualifiedMember, error, ) { - sharesJustifyingMembers, err := initializeSharesJustifyingMemberGroup( + sharesJustifyingMembers, _, err := initializeSharesJustifyingMemberGroup( dishonestThreshold, groupSize, ) diff --git a/pkg/beacon/gjkr/protocol_test.go b/pkg/beacon/gjkr/protocol_test.go index 25e23363dc..a5d4631442 100644 --- a/pkg/beacon/gjkr/protocol_test.go +++ b/pkg/beacon/gjkr/protocol_test.go @@ -69,12 +69,6 @@ func TestRoundTrip(t *testing.T) { len(member.receivedQualifiedSharesS), ) } - if len(member.receivedQualifiedSharesT) != groupSize-1 { - t.Fatalf("\nexpected: %d received shares T\nactual: %d\n", - groupSize-1, - len(member.receivedQualifiedSharesT), - ) - } member.CombineMemberShares() } diff --git a/pkg/beacon/node.go b/pkg/beacon/node.go index 6bd4054d81..5cf2b6408d 100644 --- a/pkg/beacon/node.go +++ b/pkg/beacon/node.go @@ -52,6 +52,28 @@ func (n *node) IsInGroup(groupPublicKey []byte) bool { return len(n.groupRegistry.GetGroup(groupPublicKey)) > 0 } +// setBroadcastChannelFilter installs the given membership filter on the +// broadcast channel so that only messages from operators in the group are +// accepted. It returns an error if the filter cannot be set; callers must abort +// on that error instead of proceeding on an unfiltered channel, which would +// accept messages from operators outside the group. +func setBroadcastChannelFilter( + channelLogger *zap.SugaredLogger, + channel net.BroadcastChannel, + filter net.BroadcastChannelFilter, +) error { + if err := channel.SetFilter(filter); err != nil { + channelLogger.Errorf( + "could not set filter for channel [%v]: [%v]", + channel.Name(), + err, + ) + return err + } + + return nil +} + // JoinDKGIfEligible takes a seed value and undergoes the process of the // distributed key generation if this node's operator proves to be eligible for // the group generated by that seed. This is an interactive on-chain process, @@ -133,13 +155,12 @@ func (n *node) JoinDKGIfEligible( signing, ) - err = broadcastChannel.SetFilter(membershipValidator.IsInGroup) - if err != nil { - dkgLogger.Errorf( - "could not set filter for channel [%v]: [%v]", - broadcastChannel.Name(), - err, - ) + if err = setBroadcastChannelFilter( + dkgLogger, + broadcastChannel, + membershipValidator.IsInGroup, + ); err != nil { + return } for _, index := range indexes { @@ -358,13 +379,12 @@ func (n *node) GenerateRelayEntry( n.beaconChain.Signing(), ) - err = channel.SetFilter(membershipValidator.IsInGroup) - if err != nil { - relayLogger.Errorf( - "could not set filter for channel [%v]: [%v]", - channel.Name(), - err, - ) + if err = setBroadcastChannelFilter( + relayLogger, + channel, + membershipValidator.IsInGroup, + ); err != nil { + return } blockCounter, err := n.beaconChain.BlockCounter() diff --git a/pkg/beacon/node_test.go b/pkg/beacon/node_test.go index f204ee5042..6a2af9181a 100644 --- a/pkg/beacon/node_test.go +++ b/pkg/beacon/node_test.go @@ -5,11 +5,75 @@ import ( "math/big" "testing" + "go.uber.org/zap" + + beaconchain "github.com/keep-network/keep-core/pkg/beacon/chain" + "github.com/keep-network/keep-core/pkg/chain" "github.com/keep-network/keep-core/pkg/chain/local_v1" + "github.com/keep-network/keep-core/pkg/generator" + "github.com/keep-network/keep-core/pkg/net" + "github.com/keep-network/keep-core/pkg/operator" ) var relayEntryTimeout = uint64(15) +// filterErrorChannel is a broadcast channel whose SetFilter result is +// controllable, used to exercise the membership-filter abort path. +type filterErrorChannel struct { + net.BroadcastChannel + setFilterErr error +} + +func (c *filterErrorChannel) SetFilter(net.BroadcastChannelFilter) error { + return c.setFilterErr +} + +func (c *filterErrorChannel) Name() string { + return "test-channel" +} + +// TestSetBroadcastChannelFilter verifies that the membership filter is required +// before a node proceeds on a group channel: when the filter cannot be set the +// helper surfaces the error so the caller aborts, rather than proceeding on an +// unfiltered channel that would accept messages from operators outside the +// group. +func TestSetBroadcastChannelFilter(t *testing.T) { + filter := func(*operator.PublicKey) bool { return true } + + tests := map[string]struct { + setFilterErr error + expectError bool + }{ + "filter set successfully": { + setFilterErr: nil, + expectError: false, + }, + "filter cannot be set": { + setFilterErr: fmt.Errorf("cannot set filter"), + expectError: true, + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + channel := &filterErrorChannel{setFilterErr: test.setFilterErr} + + err := setBroadcastChannelFilter( + zap.NewNop().Sugar(), + channel, + filter, + ) + + if test.expectError && err == nil { + t.Fatal("expected an error, got nil") + } + if !test.expectError && err != nil { + t.Fatalf("unexpected error: [%v]", err) + } + }) + } +} + func TestMonitorRelayEntryOnChain_EntrySubmitted(t *testing.T) { localChain := local_v1.Connect(5, 3) @@ -109,3 +173,68 @@ func TestMonitorRelayEntryOnChain_EntryNotSubmitted(t *testing.T) { ) } } + +// selectGroupChain wraps a beaconchain.Interface and overrides SelectGroup, +// which the embedded implementation does not support, so that a +// deterministic set of selected operators can be returned for +// JoinDKGIfEligible tests. +type selectGroupChain struct { + beaconchain.Interface + selectedOperators chain.Addresses +} + +func (c *selectGroupChain) SelectGroup(seed *big.Int) (chain.Addresses, error) { + return c.selectedOperators, nil +} + +// fakeNetProvider is a net.Provider that always returns the given channel +// from BroadcastChannelFor, regardless of the requested channel name. +type fakeNetProvider struct { + net.Provider + channel net.BroadcastChannel +} + +func (p *fakeNetProvider) BroadcastChannelFor( + name string, +) (net.BroadcastChannel, error) { + return p.channel, nil +} + +// TestJoinDKGIfEligible_AbortsWhenFilterCannotBeSet verifies that, for an +// otherwise-eligible operator, a SetFilter failure on the broadcast channel +// causes JoinDKGIfEligible to return before spawning any DKG protocol +// goroutine. The fake broadcast channel embeds a nil net.BroadcastChannel, so +// a goroutine that incorrectly used it to run the DKG protocol would panic; +// groupRegistry is left nil for the same reason, since RegisterGroup is only +// reached from within that goroutine. +func TestJoinDKGIfEligible_AbortsWhenFilterCannotBeSet(t *testing.T) { + localChain := local_v1.Connect(5, 3) + + _, operatorPublicKey, err := localChain.OperatorKeyPair() + if err != nil { + t.Fatalf("failed to get operator key pair: [%v]", err) + } + + operatorAddress, err := localChain.Signing().PublicKeyToAddress(operatorPublicKey) + if err != nil { + t.Fatalf("failed to get operator address: [%v]", err) + } + + beaconChain := &selectGroupChain{ + Interface: localChain, + selectedOperators: chain.Addresses{operatorAddress}, + } + + testNode := &node{ + beaconChain: beaconChain, + netProvider: &fakeNetProvider{ + channel: &filterErrorChannel{ + setFilterErr: fmt.Errorf("cannot set filter"), + }, + }, + groupRegistry: nil, + protocolLatch: generator.NewProtocolLatch(), + } + + testNode.JoinDKGIfEligible(big.NewInt(1), 0) +} diff --git a/pkg/beacon/registry/groups.go b/pkg/beacon/registry/groups.go index b601e6d54b..cc8f2b6d6a 100644 --- a/pkg/beacon/registry/groups.go +++ b/pkg/beacon/registry/groups.go @@ -11,7 +11,7 @@ import ( beaconchain "github.com/keep-network/keep-core/pkg/beacon/chain" "github.com/keep-network/keep-core/pkg/beacon/dkg" - "github.com/keep-network/keep-common/pkg/persistence" + "github.com/keep-network/keep-core/pkg/persistence" ) // Groups represents a collection of Keep groups in which the given diff --git a/pkg/beacon/registry/groups_test.go b/pkg/beacon/registry/groups_test.go index 70cb0f8e37..773ed5cdbc 100644 --- a/pkg/beacon/registry/groups_test.go +++ b/pkg/beacon/registry/groups_test.go @@ -14,9 +14,9 @@ import ( bn256 "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare" - "github.com/keep-network/keep-common/pkg/persistence" "github.com/keep-network/keep-core/pkg/beacon/dkg" "github.com/keep-network/keep-core/pkg/beacon/event" + "github.com/keep-network/keep-core/pkg/persistence" "github.com/keep-network/keep-core/pkg/protocol/group" "github.com/keep-network/keep-core/pkg/subscription" ) diff --git a/pkg/beacon/registry/marshalling.go b/pkg/beacon/registry/marshaling.go similarity index 92% rename from pkg/beacon/registry/marshalling.go rename to pkg/beacon/registry/marshaling.go index a4460582a6..b4df0f383b 100644 --- a/pkg/beacon/registry/marshalling.go +++ b/pkg/beacon/registry/marshaling.go @@ -1,3 +1,4 @@ +// marshaling.go: protobuf (un)marshaling for the public types in this package. package registry import ( diff --git a/pkg/beacon/registry/marshalling_test.go b/pkg/beacon/registry/marshaling_test.go similarity index 100% rename from pkg/beacon/registry/marshalling_test.go rename to pkg/beacon/registry/marshaling_test.go diff --git a/pkg/beacon/registry/storage.go b/pkg/beacon/registry/storage.go index 31d376f1de..77f670d96f 100644 --- a/pkg/beacon/registry/storage.go +++ b/pkg/beacon/registry/storage.go @@ -4,7 +4,7 @@ import ( "fmt" "sync" - "github.com/keep-network/keep-common/pkg/persistence" + "github.com/keep-network/keep-core/pkg/persistence" "encoding/hex" ) diff --git a/pkg/bitcoin/block.go b/pkg/bitcoin/block.go index ba54a45ffe..afebcf7d39 100644 --- a/pkg/bitcoin/block.go +++ b/pkg/bitcoin/block.go @@ -39,6 +39,7 @@ func (bh *BlockHeader) Serialize() [BlockHeaderByteLength]byte { offset := 0 // Version + // #nosec G115 -- Bitcoin version fields encode the exact signed 32-bit bit pattern. binary.LittleEndian.PutUint32(result[offset:], uint32(bh.Version)) offset += 4 @@ -71,6 +72,7 @@ func (bh *BlockHeader) Deserialize(rawBlockHeader [BlockHeaderByteLength]byte) { offset := 0 // Version + // #nosec G115 -- Decode the exact signed 32-bit Bitcoin version bit pattern. bh.Version = int32(binary.LittleEndian.Uint32(rawBlockHeader[offset:])) offset += 4 diff --git a/pkg/bitcoin/electrum/block.go b/pkg/bitcoin/electrum/block.go index cb9da33059..7dd01074c4 100644 --- a/pkg/bitcoin/electrum/block.go +++ b/pkg/bitcoin/electrum/block.go @@ -29,9 +29,10 @@ func convertBlockHeader(electrumResult *electrum.GetBlockHeaderResult) (*bitcoin Version: b.Version, PreviousBlockHeaderHash: bitcoin.Hash(b.PrevBlock), MerkleRootHash: bitcoin.Hash(b.MerkleRoot), - Time: uint32(b.Timestamp.Unix()), - Bits: b.Bits, - Nonce: b.Nonce, + // #nosec G115 -- wire.BlockHeader.Deserialize reads the timestamp from a uint32 field. + Time: uint32(b.Timestamp.Unix()), + Bits: b.Bits, + Nonce: b.Nonce, } return result, nil diff --git a/pkg/bitcoin/electrum/client.go b/pkg/bitcoin/electrum/client.go new file mode 100644 index 0000000000..633563943a --- /dev/null +++ b/pkg/bitcoin/electrum/client.go @@ -0,0 +1,44 @@ +package electrum + +import ( + "context" + + "github.com/checksum0/go-electrum/electrum" +) + +// electrumClient is the RPC and lifecycle surface used by Connection. +type electrumClient interface { + GetRawTransaction(context.Context, string) (string, error) + GetHistory(context.Context, string) ([]*electrum.GetMempoolResult, error) + GetMempool(context.Context, string) ([]*electrum.GetMempoolResult, error) + BroadcastTransaction(context.Context, string) (string, error) + SubscribeHeadersSingle(context.Context) (*electrum.SubscribeHeadersResult, error) + GetBlockHeader(context.Context, uint32, ...uint32) (*electrum.GetBlockHeaderResult, error) + GetMerkleProof(context.Context, string, uint32) (*electrum.GetMerkleProofResult, error) + GetHashFromPosition(context.Context, uint32, uint32) (string, error) + ListUnspent(context.Context, string) ([]*electrum.ListUnspentResult, error) + GetFee(context.Context, uint32) (float32, error) + ServerVersion(context.Context) (string, string, error) + ServerFeatures(context.Context) (*electrum.ServerFeaturesResult, error) + Ping(context.Context) error + Abort() + Shutdown() + IsShutdown() bool +} + +// watchClientCancellation registers an Abort callback that fires when ctx is +// done, independently of the request mutex and keepalive loop; it also +// covers clients still being verified. The returned function unregisters +// that callback and, if ctx had not yet fired it, asynchronously calls +// Abort itself so the caller never blocks on transport cleanup. It does not +// retire the client from the Connection (clear c.client/c.closeClient) - +// callers that are done with a client must do that themselves. Abort must +// be idempotent and safe during active writes. +func watchClientCancellation(ctx context.Context, client electrumClient) func() { + stop := context.AfterFunc(ctx, client.Abort) + return func() { + if stop() { + go client.Abort() + } + } +} diff --git a/pkg/bitcoin/electrum/config.go b/pkg/bitcoin/electrum/config.go index 590378736b..be062df0b8 100644 --- a/pkg/bitcoin/electrum/config.go +++ b/pkg/bitcoin/electrum/config.go @@ -28,6 +28,12 @@ const ( type Config struct { // URL to the Electrum server in format: `scheme://hostname:port`. URL string + // FallbackURLs contains the remaining embedded servers when URL was + // auto-selected, or operator-supplied alternates from the + // `bitcoin.electrum.fallbackURLs` flag or config file. An explicit URL + // stays the pool's primary; these are tried in order after it fails, + // and the client heals back to the primary when it recovers. + FallbackURLs []string // Timeout for a single attempt of Electrum connection establishment. ConnectTimeout time.Duration // Timeout for Electrum connection establishment retries. diff --git a/pkg/bitcoin/electrum/electrum.go b/pkg/bitcoin/electrum/electrum.go index 430b0d6c18..4531864259 100644 --- a/pkg/bitcoin/electrum/electrum.go +++ b/pkg/bitcoin/electrum/electrum.go @@ -4,9 +4,15 @@ import ( "context" "crypto/sha256" "encoding/hex" + "errors" "fmt" + "io" "math" + "net" + "net/url" + "slices" "sort" + "strconv" "strings" "sync" "time" @@ -14,11 +20,10 @@ import ( "github.com/checksum0/go-electrum/electrum" "github.com/ipfs/go-log" "go.uber.org/zap" - "golang.org/x/exp/slices" - "github.com/keep-network/keep-common/pkg/wrappers" "github.com/keep-network/keep-core/pkg/bitcoin" "github.com/keep-network/keep-core/pkg/internal/byteutils" + "github.com/keep-network/keep-core/pkg/wrappers" ) var ( @@ -26,16 +31,228 @@ var ( logger = log.Logger("keep-electrum") ) +// ErrFeeEstimateUnavailable is set as the last error of +// EstimateSatPerVByteFee when a queried Electrum server daemon reports that it +// does not have enough information to produce a fee estimate for a confirmation +// target (blockchain.estimatefee returning -1, per the Electrum protocol docs). +// +// Callers may use errors.Is(err, ErrFeeEstimateUnavailable) to detect that the +// daemon lacked fee estimation data, as opposed to a network failure, timeout, +// or transport error. EstimateSatPerVByteFee wraps the error of the last +// confirmation target tried, so on a mixed failure the sentinel matches only +// when the last target failed with -1. +var ErrFeeEstimateUnavailable = errors.New("daemon does not have enough information to make an estimate") + +// watchAbort arranges to call client.Abort if ctx becomes Done and the +// protected operation has not finished on its own within a short grace +// period afterward. The returned stop function must be called immediately +// after the protected operation returns; it signals completion and blocks +// until the internal watcher goroutine has fully resolved one way or the +// other, so no abort can fire after the caller has already moved on. +// +// This avoids a scheduling race inherent to context.AfterFunc(ctx, f): its +// stop() can only reliably prevent f from running if called before the +// runtime actually schedules f's goroutine to execute. Under contention, the +// watcher goroutine can start and complete client.Abort() before the caller +// even reaches its stop() call, even though the protected operation had +// already returned successfully. +func watchAbort(ctx context.Context, client electrumClient) (stop func()) { + done := make(chan struct{}) + resolved := make(chan struct{}) + + go func() { + defer close(resolved) + + select { + case <-done: + return + case <-ctx.Done(): + } + + select { + case <-done: + case <-time.After(5 * time.Millisecond): + go client.Abort() + } + }() + + return func() { + close(done) + <-resolved + } +} + // Connection is a handle for interactions with Electrum server. type Connection struct { parentCtx context.Context - client *electrum.Client + client electrumClient + closeClient func() clientMutex *sync.Mutex config Config + serverURLs []string + serverIndex int + newClient func(context.Context, string) (electrumClient, error) + // verifiedGenesisHash is the first non-empty genesis_hash adopted from + // a verified candidate. Every later candidate must report the same + // hash; a candidate may also omit the field (see verifyServer). + // Accessed only while clientMutex is held. + verifiedGenesisHash string + // lastTipHeight is the most recently observed chain tip height, used to + // sanity-check the tip reported right after a (re)connect. Accessed only + // while clientMutex is held. + lastTipHeight uint + // pendingTipSanityCheck is set whenever the live client changes (a + // (re)connect, failover, or primary re-canonicalization) and cleared + // after the first subsequent tip height read compares it against + // lastTipHeight. Accessed only while clientMutex is held. + pendingTipSanityCheck bool +} + +// sanitizeServerURL strips userinfo (username and password) from a server URL +// so that credentials are never exposed in log messages or error strings. +func sanitizeServerURL(rawURL string) string { + u, err := url.Parse(rawURL) + if err == nil && u.Opaque == "" && strings.Contains(rawURL, "://") && u.Hostname() != "" { + u.User = nil + return u.String() + } + if atIdx := strings.LastIndex(rawURL, "@"); atIdx != -1 { + if schemeIdx := strings.Index(rawURL, "://"); schemeIdx != -1 && schemeIdx < atIdx { + return rawURL[:schemeIdx+3] + rawURL[atIdx+1:] + } + return rawURL[atIdx+1:] + } + return rawURL +} + +// validateServerURL validates a single electrum server URL. Accepted schemes +// are tcp, ssl, ws, and wss. The URL must have a non-empty host, and tcp/ssl +// schemes require an explicit valid port (1-65535) consistent with the +// scheme://hostname:port format. +func validateServerURL(rawURL string) error { + if rawURL == "" { + return fmt.Errorf("empty electrum server URL") + } + + u, err := url.Parse(rawURL) + if err != nil { + return fmt.Errorf( + "invalid electrum server URL [%s]", + sanitizeServerURL(rawURL), + ) + } + + if u.Opaque != "" { + return fmt.Errorf( + "missing protocol scheme in electrum server URL [%s]; expected tcp, ssl, ws, or wss", + sanitizeServerURL(rawURL), + ) + } + + switch u.Scheme { + case "tcp", "ssl", "ws", "wss": + case "": + return fmt.Errorf( + "missing protocol scheme in electrum server URL [%s]; expected tcp, ssl, ws, or wss", + sanitizeServerURL(rawURL), + ) + default: + return fmt.Errorf( + "unsupported electrum server protocol scheme [%s] in URL [%s]; expected tcp, ssl, ws, or wss", + u.Scheme, + sanitizeServerURL(rawURL), + ) + } + + if u.Hostname() == "" { + return fmt.Errorf( + "missing host in electrum server URL [%s]", + sanitizeServerURL(rawURL), + ) + } + + if (u.Scheme == "ws" || u.Scheme == "wss") && u.User != nil { + return fmt.Errorf( + "userinfo is not supported in websocket URL [%s]", + sanitizeServerURL(rawURL), + ) + } + if strings.HasSuffix(u.Host, ":") { + return fmt.Errorf( + "invalid port in electrum server URL [%s]", + sanitizeServerURL(rawURL), + ) + } + + port := u.Port() + if u.Scheme == "tcp" || u.Scheme == "ssl" { + if port == "" { + return fmt.Errorf( + "missing port in electrum server URL [%s]; tcp and ssl require scheme://hostname:port", + sanitizeServerURL(rawURL), + ) + } + } + + if port != "" { + portNum, err := strconv.Atoi(port) + if err != nil || portNum <= 0 || portNum > 65535 { + return fmt.Errorf( + "invalid port [%s] in electrum server URL [%s]", + port, + sanitizeServerURL(rawURL), + ) + } + } + + return nil +} + +// validateConfigURLs validates every effective non-empty primary and fallback +// electrum server URL in the provided configuration. +func validateConfigURLs(config Config) error { + var serverURLs []string + if config.URL != "" { + serverURLs = append(serverURLs, config.URL) + } + for _, rawURL := range config.FallbackURLs { + if rawURL != "" && !slices.Contains(serverURLs, rawURL) { + serverURLs = append(serverURLs, rawURL) + } + } + if len(serverURLs) == 0 { + return fmt.Errorf("no electrum server URLs configured") + } + + for _, serverURL := range serverURLs { + if err := validateServerURL(serverURL); err != nil { + return err + } + } + + return nil } // Connect initializes handle with provided Config. func Connect(parentCtx context.Context, config Config) (bitcoin.Chain, error) { + if err := validateConfigURLs(config); err != nil { + return nil, err + } + + connection, err := connect(parentCtx, config, func(ctx context.Context, url string) (electrumClient, error) { + return electrum.NewClient(ctx, url, nil) + }) + if err != nil { + return nil, err + } + return connection, nil +} + +func connect( + parentCtx context.Context, + config Config, + newClient func(context.Context, string) (electrumClient, error), +) (*Connection, error) { if config.ConnectTimeout == 0 { config.ConnectTimeout = DefaultConnectTimeout } @@ -56,21 +273,34 @@ func Connect(parentCtx context.Context, config Config) (bitcoin.Chain, error) { parentCtx: parentCtx, config: config, clientMutex: &sync.Mutex{}, + newClient: newClient, } - if err := c.electrumConnect(); err != nil { - return nil, fmt.Errorf("failed to initialize electrum client: [%w]", err) + if config.URL != "" { + c.serverURLs = append(c.serverURLs, config.URL) + } + for _, url := range config.FallbackURLs { + if url != "" && !slices.Contains(c.serverURLs, url) { + c.serverURLs = append(c.serverURLs, url) + } + } + if len(c.serverURLs) == 0 { + return nil, fmt.Errorf("no electrum server URLs configured") + } + + if len(c.serverURLs) > 1 { + logger.Infof("electrum failover armed with [%d] servers", len(c.serverURLs)) + } else { + logger.Infof("single server configured; failover unavailable") } - if err := c.verifyServer(); err != nil { - return nil, fmt.Errorf("failed to verify electrum server: [%w]", err) + if err := c.electrumConnect(parentCtx, parentCtx); err != nil { + return nil, fmt.Errorf("failed to initialize electrum client: [%w]", err) } // Keep the connection alive and check the connection health. go c.keepAlive() - // TODO: Add reconnects on lost connection. - return c, nil } @@ -85,7 +315,7 @@ func (c *Connection) GetTransaction( rawTransaction, err := requestWithRetry( c.parentCtx, c, - func(ctx context.Context, client *electrum.Client) (string, error) { + func(ctx context.Context, client electrumClient) (string, error) { // We cannot use `GetTransaction` to get the the transaction details // as Esplora/Electrs doesn't support verbose transactions. // See: https://github.com/Blockstream/electrs/pull/36 @@ -151,7 +381,7 @@ func (c *Connection) GetTransactionConfirmations( rawTransaction, err := requestWithRetry( reqCtx, c, - func(ctx context.Context, client *electrum.Client) (string, error) { + func(ctx context.Context, client electrumClient) (string, error) { // We cannot use `GetTransaction` to get the transaction details // as Esplora/Electrs doesn't support verbose transactions. // See: https://github.com/Blockstream/electrs/pull/36 @@ -223,7 +453,7 @@ txOutLoop: c, func( ctx context.Context, - client *electrum.Client, + client electrumClient, ) ([]*electrum.GetMempoolResult, error) { return client.GetHistory(ctx, reversedScriptHashString) }, @@ -310,7 +540,7 @@ func (c *Connection) BroadcastTransaction( response, err := requestWithRetry( c.parentCtx, c, - func(ctx context.Context, client *electrum.Client) (string, error) { + func(ctx context.Context, client electrumClient) (string, error) { return client.BroadcastTransaction(ctx, rawTx) }, "BroadcastTransaction", @@ -330,12 +560,39 @@ func (c *Connection) GetLatestBlockHeight() (uint, error) { blockHeight, err := requestWithRetry( c.parentCtx, c, - func(ctx context.Context, client *electrum.Client) (int32, error) { + func(ctx context.Context, client electrumClient) (int32, error) { tip, err := client.SubscribeHeadersSingle(ctx) if err != nil { return 0, fmt.Errorf("failed to get the blocks tip height: [%w]", err) } + if tip.Height > 0 { + newTip := uint(tip.Height) + if c.pendingTipSanityCheck { + c.pendingTipSanityCheck = false + if c.lastTipHeight > 0 { + // #nosec G115 -- newTip and lastTipHeight are only + // ever set from a checked-positive int32 tip height + // (see below), so both are well within int64 range. + diff := int64(newTip) - int64(c.lastTipHeight) + if diff < 0 { + diff = -diff + } + if diff > 500 { + logger.Warnf( + "electrum tip height changed by [%d] blocks "+ + "after reconnecting (was [%d], now [%d]); "+ + "this is expected during a legitimate reorg", + diff, + c.lastTipHeight, + newTip, + ) + } + } + } + c.lastTipHeight = newTip + } + return tip.Height, nil }, "SubscribeHeaders", @@ -357,14 +614,19 @@ func (c *Connection) GetLatestBlockHeight() (uint, error) { func (c *Connection) GetBlockHeader( blockHeight uint, ) (*bitcoin.BlockHeader, error) { + if blockHeight > math.MaxUint32 { + return nil, fmt.Errorf("block height exceeds Electrum range: [%v]", blockHeight) + } + height := uint32(blockHeight) + getBlockHeaderResult, err := requestWithRetry( c.parentCtx, c, func( ctx context.Context, - client *electrum.Client, + client electrumClient, ) (*electrum.GetBlockHeaderResult, error) { - return client.GetBlockHeader(ctx, uint32(blockHeight), 0) + return client.GetBlockHeader(ctx, height, 0) }, "GetBlockHeader", ) @@ -387,6 +649,11 @@ func (c *Connection) GetTransactionMerkleProof( transactionHash bitcoin.Hash, blockHeight uint, ) (*bitcoin.TransactionMerkleProof, error) { + if blockHeight > math.MaxUint32 { + return nil, fmt.Errorf("block height exceeds Electrum range: [%v]", blockHeight) + } + height := uint32(blockHeight) + txID := transactionHash.Hex(bitcoin.ReversedByteOrder) getMerkleProofResult, err := requestWithRetry( @@ -394,12 +661,12 @@ func (c *Connection) GetTransactionMerkleProof( c, func( ctx context.Context, - client *electrum.Client, + client electrumClient, ) (*electrum.GetMerkleProofResult, error) { return client.GetMerkleProof( ctx, txID, - uint32(blockHeight), + height, ) }, "GetMerkleProof", @@ -534,7 +801,7 @@ func (c *Connection) getConfirmedScriptHistory( c, func( ctx context.Context, - client *electrum.Client, + client electrumClient, ) ([]*electrum.GetMempoolResult, error) { return client.GetHistory(ctx, reversedScriptHashString) }, @@ -593,14 +860,19 @@ func (c *Connection) getConfirmedScriptHistory( // GetCoinbaseTxHash gets the hash of the coinbase transaction for the given // block height. func (c *Connection) GetCoinbaseTxHash(blockHeight uint) (bitcoin.Hash, error) { + if blockHeight > math.MaxUint32 { + return bitcoin.Hash{}, fmt.Errorf("block height exceeds Electrum range: [%v]", blockHeight) + } + height := uint32(blockHeight) + txHashString, err := requestWithRetry( c.parentCtx, c, func( ctx context.Context, - client *electrum.Client, + client electrumClient, ) (string, error) { - return client.GetHashFromPosition(ctx, uint32(blockHeight), 0) + return client.GetHashFromPosition(ctx, height, 0) }, "GetHashFromPosition", ) @@ -705,7 +977,7 @@ func (c *Connection) getScriptMempool( c, func( ctx context.Context, - client *electrum.Client, + client electrumClient, ) ([]*electrum.GetMempoolResult, error) { return client.GetMempool(ctx, reversedScriptHashString) }, @@ -743,6 +1015,17 @@ func (c *Connection) getScriptMempool( return convertedItems, nil } +// utxoValue converts a server-reported UTXO amount to the signed satoshi +// value bitcoin.UnspentTransactionOutput expects. A malicious or buggy +// server could report a value that overflows int64; reject it outright +// rather than silently wrapping it negative. +func utxoValue(value uint64) (int64, error) { + if value > math.MaxInt64 { + return 0, fmt.Errorf("unexpected UTXO value from Electrum server") + } + return int64(value), nil +} + // GetUtxosForPublicKeyHash gets unspent outputs of confirmed transactions that // are controlled by the given public key hash (either a P2PKH or P2WPKH script). // The returned UTXOs are ordered by block height in the ascending order, i.e. @@ -798,18 +1081,7 @@ func (c *Connection) GetUtxosForPublicKeyHash( }, ) - utxos := make([]*bitcoin.UnspentTransactionOutput, len(items)) - for i, item := range items { - utxos[i] = &bitcoin.UnspentTransactionOutput{ - Outpoint: &bitcoin.TransactionOutpoint{ - TransactionHash: item.txHash, - OutputIndex: item.outputIndex, - }, - Value: int64(item.value), - } - } - - return utxos, nil + return convertUtxoItems(items) } // GetMempoolUtxosForPublicKeyHash gets unspent outputs of unconfirmed transactions @@ -859,14 +1131,22 @@ func (c *Connection) GetMempoolUtxosForPublicKeyHash( items := append(p2pkhItems, p2wpkhItems...) + return convertUtxoItems(items) +} + +func convertUtxoItems(items []*scriptUtxoItem) ([]*bitcoin.UnspentTransactionOutput, error) { utxos := make([]*bitcoin.UnspentTransactionOutput, len(items)) for i, item := range items { + value, err := utxoValue(item.value) + if err != nil { + return nil, err + } utxos[i] = &bitcoin.UnspentTransactionOutput{ Outpoint: &bitcoin.TransactionOutpoint{ TransactionHash: item.txHash, OutputIndex: item.outputIndex, }, - Value: int64(item.value), + Value: value, } } @@ -877,7 +1157,7 @@ type scriptUtxoItem struct { txHash bitcoin.Hash outputIndex uint32 value uint64 - blockHeight uint32 + blockHeight int32 } // getScriptUtxos returns unspent outputs of confirmed/unconfirmed transactions @@ -908,7 +1188,7 @@ func (c *Connection) getScriptUtxos( c, func( ctx context.Context, - client *electrum.Client, + client electrumClient, ) ([]*electrum.ListUnspentResult, error) { return client.ListUnspent(ctx, reversedScriptHashString) }, @@ -952,7 +1232,6 @@ func (c *Connection) getScriptUtxos( err, ) } - filteredItems = append( filteredItems, &scriptUtxoItem{ txHash: txHash, @@ -1023,22 +1302,50 @@ func isElectrumFeeOracleFailure(err error) bool { strings.Contains(s, "-32603") } +// isTransportFailure reports whether err is a transport/connection-class +// failure (a dead socket, a request timeout, or the client shutting down) as +// opposed to a JSON-RPC application-level error returned by a server that is +// alive and responding correctly (tx-not-found, tx-rejected, +// height-out-of-range, -32602/-32603, etc). Only a transport failure means +// the current server is unhealthy; an application error means it answered +// and failing away from it would not help. +func isTransportFailure(err error) bool { + if err == nil { + return false + } + if errors.Is(err, electrum.ErrServerShutdown) || + errors.Is(err, electrum.ErrTimeout) || + errors.Is(err, io.ErrClosedPipe) || + errors.Is(err, io.EOF) { + return true + } + var netErr net.Error + return errors.As(err, &netErr) +} + // getFeeBtcPerKbOnce issues a single blockchain.estimatefee call (no multi-minute // retry loop). Persistent RPC errors for one confirmation target should not // exhaust RequestRetryTimeout; EstimateSatPerVByteFee tries looser targets next. -func (c *Connection) getFeeBtcPerKbOnce(blocks uint32) (float32, error) { - if err := c.reconnectIfShutdown(); err != nil { +// budgetCtx bounds both reconnection and the request itself; callers share +// one budget across every confirmation target they try. +func (c *Connection) getFeeBtcPerKbOnce(budgetCtx context.Context, blocks uint32) (float32, error) { + c.clientMutex.Lock() + defer c.clientMutex.Unlock() + if err := c.reconnectIfShutdown(c.parentCtx, budgetCtx); err != nil { return 0, err } requestCtx, requestCancel := context.WithTimeout( - c.parentCtx, + budgetCtx, c.config.RequestTimeout, ) defer requestCancel() - c.clientMutex.Lock() + stopAbort := watchAbort(requestCtx, c.client) fee, err := c.client.GetFee(requestCtx, blocks) - c.clientMutex.Unlock() + stopAbort() if err != nil { + if isTransportFailure(err) { + c.failover(c.parentCtx) + } return 0, fmt.Errorf("request failed: [%w]", err) } return fee, nil @@ -1046,14 +1353,40 @@ func (c *Connection) getFeeBtcPerKbOnce(blocks uint32) (float32, error) { // EstimateSatPerVByteFee returns the estimated sat/vbyte fee for a // transaction to be confirmed within the given number of blocks. +// +// If the queried Electrum server daemon does not have enough information to +// produce a fee estimate for the requested target or any of the fallback +// targets (the daemon returns -1 / negative fee per Electrum protocol docs), +// and a network-appropriate low-fee fallback cannot be applied (such as on +// mainnet or unrecognized networks), EstimateSatPerVByteFee returns an error +// wrapping the error of the last confirmation target tried. That error wraps +// ErrFeeEstimateUnavailable only when the last failure was an oracle -1 +// response; when a non-oracle failure (transport, timeout) was tried last, the +// wrapped error is that failure. +// +// Callers may use errors.Is(err, ErrFeeEstimateUnavailable) to detect that the +// daemon lacked fee estimation data, distinguishing an oracle lack of data from +// a network, timeout, or transport failure - keeping in mind that a mixed +// failure reports whichever class was observed last. func (c *Connection) EstimateSatPerVByteFee(blocks uint32) (int64, error) { targets := feeEstimateWithFallbackTargets(blocks) var lastErr error sawFeeOracleFailure := false sawNonOracleFailure := false + // One retry budget covers every confirmation target tried below, so a + // slow or unresponsive server cannot multiply RequestRetryTimeout by the + // number of fallback targets. + budgetCtx, budgetCancel := context.WithTimeout(c.parentCtx, c.config.RequestRetryTimeout) + defer budgetCancel() + for _, b := range targets { - btcPerKbFee, err := c.getFeeBtcPerKbOnce(b) + if budgetCtx.Err() != nil { + lastErr = budgetCtx.Err() + sawNonOracleFailure = true + break + } + btcPerKbFee, err := c.getFeeBtcPerKbOnce(budgetCtx, b) if err != nil { lastErr = err if isElectrumFeeOracleFailure(err) { @@ -1067,9 +1400,7 @@ func (c *Connection) EstimateSatPerVByteFee(blocks uint32) (int64, error) { // According to Electrum protocol docs, if the daemon does not have // enough information to make an estimate, the integer -1 is returned. if btcPerKbFee < 0 { - lastErr = fmt.Errorf( - "daemon does not have enough information to make an estimate", - ) + lastErr = ErrFeeEstimateUnavailable sawFeeOracleFailure = true logger.Debugf("GetFee for [%d] blocks returned no estimate (fee < 0)", b) continue @@ -1150,7 +1481,7 @@ func feeFallbackResult( return defaultFallbackSatPerVByteWhenEstimateFails, nil } if lastErr != nil { - return 0, fmt.Errorf("failed to get fee: [%v]", lastErr) + return 0, fmt.Errorf("failed to get fee: [%w]", lastErr) } return 0, fmt.Errorf( "failed to get fee from Electrum after trying confirmation targets %v", @@ -1167,129 +1498,315 @@ func convertBtcKbToSatVByte(btcPerKbFee float32) int64 { return int64(math.Round(satPerVByte)) } -func (c *Connection) electrumConnect() error { - var client *electrum.Client - var err error - - logger.Debug("establishing connection to electrum server...") - client, err = connectWithRetry( - c, - func(ctx context.Context) (*electrum.Client, error) { - return electrum.NewClient(ctx, c.config.URL, nil) - }, - ) - - if err == nil { - c.client = client - } - - return err -} - -func (c *Connection) verifyServer() error { - type Server struct { - version string - protocol string - } +// electrumConnect cycles through configured servers after failed attempts, +// until the connection and enclosing retry budgets are exhausted - it is not +// guaranteed to reach every configured URL. +func (c *Connection) electrumConnect(callerCtx, budgetCtx context.Context) error { + return wrappers.DoWithDefaultRetry( + budgetCtx, + c.config.ConnectRetryTimeout, + func(ctx context.Context) error { + url := c.serverURLs[c.serverIndex] + connectCtx, connectCancel := context.WithTimeout(ctx, c.config.ConnectTimeout) + client, err := c.newClient(connectCtx, url) + connectCancel() - server, err := requestWithRetry( - c.parentCtx, - c, - func(ctx context.Context, client *electrum.Client) (*Server, error) { - serverVersion, protocolVersion, err := client.ServerVersion(ctx) + var closeClient func() + if err == nil { + // Verification is an RPC with its own timeout, independent + // of dialing but still bounded by the caller and retry + // deadlines. When ctx (this attempt's connect retry budget) + // cannot cover the full request timeout, requestCtx below + // inherits ctx's own nearer deadline instead of getting its + // own timer (context.WithTimeout reuses the tighter parent + // deadline) - so a truncated verification failure and an + // expired ctx are the same event, and the check below + // correctly treats it as budget exhaustion rather than + // candidate health. + requestCtx, requestCancel := context.WithTimeout(ctx, c.config.RequestTimeout) + // While the client is provisional, only the requestCtx + // abort watcher is installed: a blocked write cannot + // outlive verification. The long-lived parentCtx watcher is + // installed only once the client is published. + stopVerification := watchAbort(requestCtx, client) + var genesisHash string + err = requestCtx.Err() + if err == nil { + genesisHash, err = verifyServer(requestCtx, client, url, c.verifiedGenesisHash) + } + // Stop before cancelling or retaining the client. An + // expired context must not leave an aborted client + // published as healthy. + stopVerification() + if err == nil { + err = requestCtx.Err() + } + if err == nil { + err = c.parentCtx.Err() + } + requestCancel() + if err != nil { + go client.Abort() + } else { + c.verifiedGenesisHash = genesisHash + closeClient = watchClientCancellation(c.parentCtx, client) + } + } if err != nil { - return nil, err + // Preserve the candidate when its attempt was interrupted by + // the caller, by parentCtx cancellation, or by the + // enclosing connect retry budget expiring mid-attempt + // (ctx.Err() != nil at this point covers both a genuinely + // expired budget and a verification requestCtx that shared + // that same expired deadline). A genuine candidate failure + // - a dial or verification error while ctx was still live - + // is the only case that indicates server health and should + // advance to the next configured URL. + if callerCtx.Err() == nil && + c.parentCtx.Err() == nil && + ctx.Err() == nil { + c.nextServer() + } + return err } - return &Server{serverVersion, protocolVersion}, nil + c.client = client + c.closeClient = closeClient + c.pendingTipSanityCheck = true + return nil }, - "ServerVersion", ) +} + +// verifyServer queries the candidate's protocol version (logging a warning +// if unsupported) and, when the candidate reports a genesis hash, verifies +// it against the connection's chain reference. A candidate that omits the +// genesis hash is accepted with a warning (chain identity simply isn't +// verified for that candidate), and only a candidate reporting a hash that +// actively mismatches the established reference is rejected. +// expectedGenesisHash is the hash previously adopted for this connection, +// or "" if no server has reported one yet. It returns the hash this +// connection should use going forward (unchanged or newly adopted), or an +// error if the candidate reports a genesis hash that mismatches the +// established reference. +func verifyServer( + ctx context.Context, + client electrumClient, + url string, + expectedGenesisHash string, +) (string, error) { + version, protocol, err := client.ServerVersion(ctx) if err != nil { - return fmt.Errorf("failed to get server version: [%w]", err) + return "", fmt.Errorf("failed to get server version: [%w]", err) } - logger.Infof( "connected to electrum server [version: [%s], protocol: [%s]]", - server.version, - server.protocol, + version, + protocol, ) - - // Log a warning if connected to a server running an unsupported protocol version. - if !slices.Contains(supportedProtocolVersions, server.protocol) { + if !slices.Contains(supportedProtocolVersions, protocol) { logger.Warnf( "electrum server [%s] runs an unsupported protocol version: [%s]; expected one of: [%s]", - c.config.URL, - server.protocol, + sanitizeServerURL(url), + protocol, strings.Join(supportedProtocolVersions, ","), ) } - return nil + features, err := client.ServerFeatures(ctx) + if err != nil { + return "", fmt.Errorf("failed to get server features: [%w]", err) + } + + if features == nil || features.GenesisHash == "" { + logger.Warnf( + "electrum server [%s] did not report a genesis hash; its chain "+ + "identity could not be verified", + sanitizeServerURL(url), + ) + return expectedGenesisHash, nil + } + + if expectedGenesisHash == "" { + logger.Warnf( + "adopting genesis hash [%s] reported by electrum server [%s] as "+ + "this connection's chain reference", + features.GenesisHash, + sanitizeServerURL(url), + ) + return features.GenesisHash, nil + } + + if !strings.EqualFold(expectedGenesisHash, features.GenesisHash) { + return "", fmt.Errorf( + "electrum server [%s] reported genesis hash [%s], which does not "+ + "match this connection's chain reference [%s]; the server "+ + "appears to be on a different chain", + sanitizeServerURL(url), + features.GenesisHash, + expectedGenesisHash, + ) + } + + return expectedGenesisHash, nil +} + +// nextServer, retireClient, and failover are called with clientMutex held. +func (c *Connection) nextServer() { + c.serverIndex = (c.serverIndex + 1) % len(c.serverURLs) } +func (c *Connection) retireClient() { + c.client = nil + if c.closeClient != nil { + c.closeClient() + } + c.closeClient = nil +} + +func (c *Connection) failover(callerCtx context.Context) { + // Cancellation belongs to the caller, not to the server's health. + if callerCtx.Err() != nil || c.parentCtx.Err() != nil { + return + } + c.retireClient() + c.nextServer() + // A single configured URL now retires and re-dials the same server on a + // transport failure instead of wedging on a half-open socket; explicit or + // pinned URLs keep the existing retry semantics otherwise. + if len(c.serverURLs) > 1 { + logger.Warn("electrum request failed; trying the next configured server") + } else { + logger.Warn("electrum request failed; reconnecting to the configured server") + } +} + +// healAfterConsecutivePings is the number of consecutive successful keepalive +// pings on a non-primary server before Connection attempts to re-canonicalize +// the primary (index 0) as the live client. +const healAfterConsecutivePings = 2 + func (c *Connection) keepAlive() { ticker := time.NewTicker(c.config.KeepAliveInterval) + defer ticker.Stop() + + consecutiveSuccesses := 0 for { select { case <-ticker.C: - _, err := requestWithRetry( - c.parentCtx, - c, - func(ctx context.Context, client *electrum.Client) (interface{}, error) { - return nil, client.Ping(ctx) - }, - "Ping", - ) - if err != nil { + c.clientMutex.Lock() + if err := c.reconnectIfShutdown(c.parentCtx, c.parentCtx); err != nil { + c.clientMutex.Unlock() + logger.Errorf( + "failed to reconnect to the electrum server during keepalive: [%v]", + err, + ) + consecutiveSuccesses = 0 + continue + } + + pingCtx, pingCancel := context.WithTimeout(c.parentCtx, c.config.RequestTimeout) + stopAbort := watchAbort(pingCtx, c.client) + pingErr := c.client.Ping(pingCtx) + stopAbort() + pingCancel() + + if pingErr != nil { + c.failover(c.parentCtx) + c.clientMutex.Unlock() logger.Errorf( "failed to ping the electrum server; "+ "please verify health of the electrum server: [%v]", - err, + pingErr, ) - } else { - // Adjust ticker starting at the time of the latest successful ping. - ticker = time.NewTicker(c.config.KeepAliveInterval) + consecutiveSuccesses = 0 + continue + } + + // Adjust ticker starting at the time of the latest successful ping. + ticker.Reset(c.config.KeepAliveInterval) + consecutiveSuccesses++ + onFallback := c.serverIndex != 0 + c.clientMutex.Unlock() + + if onFallback && consecutiveSuccesses >= healAfterConsecutivePings { + c.healPrimary() + consecutiveSuccesses = 0 } case <-c.parentCtx.Done(): - ticker.Stop() - c.client.Shutdown() + // Each client's cancellation callback closes its transport even + // if an RPC (including Ping above) is blocked while holding the + // request mutex. return } } } -func connectWithRetry( - c *Connection, - newClientFn func(ctx context.Context) (*electrum.Client, error), -) (*electrum.Client, error) { - var result *electrum.Client - err := wrappers.DoWithDefaultRetry( - c.parentCtx, - c.config.ConnectRetryTimeout, - func(ctx context.Context) error { - connectCtx, connectCancel := context.WithTimeout( - ctx, - c.config.ConnectTimeout, - ) - defer connectCancel() +// healPrimary re-verifies the primary (index 0) server after the connection +// has been running on a fallback for healAfterConsecutivePings consecutive +// keepalive pings. It dials and verifies a fresh client without holding +// clientMutex, so concurrent requests keep flowing through the current +// (fallback) client while the primary is probed. On success, the current +// client is retired and the freshly verified primary is published in its +// place. On any failure the current client is left untouched; the caller +// tries again after another healAfterConsecutivePings successful pings. +func (c *Connection) healPrimary() { + primaryURL := c.serverURLs[0] + + connectCtx, connectCancel := context.WithTimeout(c.parentCtx, c.config.ConnectTimeout) + client, err := c.newClient(connectCtx, primaryURL) + connectCancel() + if err != nil { + logger.Debugf("primary electrum server re-verification failed to dial: [%v]", err) + return + } - client, err := newClientFn(connectCtx) - if err == nil { - result = client - } + c.clientMutex.Lock() + expectedGenesisHash := c.verifiedGenesisHash + c.clientMutex.Unlock() - return err - }, - ) + requestCtx, requestCancel := context.WithTimeout(c.parentCtx, c.config.RequestTimeout) + stopVerification := watchAbort(requestCtx, client) + genesisHash, err := verifyServer(requestCtx, client, primaryURL, expectedGenesisHash) + stopVerification() + if err == nil { + err = requestCtx.Err() + } + if err == nil { + err = c.parentCtx.Err() + } + requestCancel() + if err != nil { + go client.Abort() + logger.Debugf("primary electrum server re-verification failed: [%v]", err) + return + } - return result, err + c.clientMutex.Lock() + defer c.clientMutex.Unlock() + + if c.serverIndex == 0 || c.parentCtx.Err() != nil || + c.verifiedGenesisHash != expectedGenesisHash { + // Another path already restored the primary, the connection is + // shutting down, or the chain reference changed since this + // candidate was verified against it; discard this candidate. + go client.Abort() + return + } + + c.retireClient() + c.serverIndex = 0 + c.client = client + c.closeClient = watchClientCancellation(c.parentCtx, client) + c.verifiedGenesisHash = genesisHash + c.pendingTipSanityCheck = true + logger.Infof("re-canonicalized primary electrum server [%s]", sanitizeServerURL(primaryURL)) } -func requestWithRetry[K interface{}]( +func requestWithRetry[K any]( parentCtx context.Context, c *Connection, - requestFn func(ctx context.Context, client *electrum.Client) (K, error), + requestFn func(ctx context.Context, client electrumClient) (K, error), requestName string, ) (K, error) { startTime := time.Now() @@ -1301,18 +1818,29 @@ func requestWithRetry[K interface{}]( parentCtx, c.config.RequestRetryTimeout, func(ctx context.Context) error { - if err := c.reconnectIfShutdown(); err != nil { + c.clientMutex.Lock() + defer c.clientMutex.Unlock() + + if err := c.reconnectIfShutdown(parentCtx, ctx); err != nil { return err } requestCtx, requestCancel := context.WithTimeout(ctx, c.config.RequestTimeout) defer requestCancel() - c.clientMutex.Lock() + // An established client's write is not bound by the RPC + // context: the vendored request() writes synchronously before + // selecting on ctx.Done(). Abort the transport if the + // per-request deadline elapses so a blocked write cannot + // outlive its own request. + stopAbort := watchAbort(requestCtx, c.client) r, err := requestFn(requestCtx, c.client) - c.clientMutex.Unlock() + stopAbort() if err != nil { + if isTransportFailure(err) { + c.failover(parentCtx) + } return fmt.Errorf("request failed: [%w]", err) } @@ -1336,14 +1864,22 @@ func requestWithRetry[K interface{}]( return result, err } -func (c *Connection) reconnectIfShutdown() error { - c.clientMutex.Lock() - defer c.clientMutex.Unlock() - - isClientShutdown := c.client.IsShutdown() - if isClientShutdown { +// reconnectIfShutdown is called with clientMutex held. Reconnection is bounded +// by the enclosing request budget as well as the connection retry timeout. +func (c *Connection) reconnectIfShutdown(callerCtx, budgetCtx context.Context) error { + if err := budgetCtx.Err(); err != nil { + return err + } + if err := c.parentCtx.Err(); err != nil { + return err + } + if c.client != nil && c.client.IsShutdown() { + c.retireClient() + c.nextServer() + } + if c.client == nil { logger.Warn("connection to electrum server is down; reconnecting...") - err := c.electrumConnect() + err := c.electrumConnect(callerCtx, budgetCtx) if err != nil { return fmt.Errorf("failed to reconnect to electrum server: [%w]", err) } diff --git a/pkg/bitcoin/electrum/electrum_integration_test.go b/pkg/bitcoin/electrum/electrum_integration_test.go index 382f6d8880..18aca18ef2 100644 --- a/pkg/bitcoin/electrum/electrum_integration_test.go +++ b/pkg/bitcoin/electrum/electrum_integration_test.go @@ -5,20 +5,23 @@ package electrum_test import ( "context" "encoding/json" + "errors" "fmt" "math" "reflect" + "slices" "sort" "strings" "testing" "time" - "golang.org/x/exp/slices" - "github.com/go-test/deep" + goelectrum "github.com/checksum0/go-electrum/electrum" + "github.com/keep-network/keep-core/pkg/bitcoin" "github.com/keep-network/keep-core/pkg/bitcoin/electrum" + "github.com/keep-network/keep-core/pkg/wrappers" testData "github.com/keep-network/keep-core/internal/testdata/bitcoin" @@ -58,7 +61,7 @@ var testConfigs = map[string]testConfig{ URL: "tcp://electrum.blockstream.info:60001", Network: bitcoin.Testnet, RequestTimeout: requestTimeout * 2, - RequestRetryTimeout: requestRetryTimeout * 2, + RequestRetryTimeout: requestRetryTimeout * 6, // allow slower public electrum responses }, network: bitcoin.Testnet, }, @@ -67,7 +70,7 @@ var testConfigs = map[string]testConfig{ URL: "ssl://electrum.blockstream.info:60002", Network: bitcoin.Testnet, RequestTimeout: requestTimeout * 2, - RequestRetryTimeout: requestRetryTimeout * 2, + RequestRetryTimeout: requestRetryTimeout * 6, // allow slower public electrum responses }, network: bitcoin.Testnet, }, @@ -158,19 +161,20 @@ func init() { } } -func TestConnect_Integration(t *testing.T) { - runParallel(t, func(t *testing.T, testConfig testConfig) { - _, cancelCtx := newTestConnection(t, testConfig.clientConfig) - defer cancelCtx() - }) -} - func TestGetTransaction_Integration(t *testing.T) { runParallel(t, func(t *testing.T, testConfig testConfig) { electrum, cancelCtx := newTestConnection(t, testConfig.clientConfig) defer cancelCtx() - for txName, tx := range testData.Transactions[testConfig.network] { + transactions := testData.Transactions[testConfig.network] + if len(transactions) == 0 { + t.Skipf( + "no transaction test vectors in internal/testdata for %s", + testConfig.network, + ) + } + + for txName, tx := range transactions { t.Run(txName, func(t *testing.T) { result, err := electrum.GetTransaction(tx.TxHash) if err != nil { @@ -222,7 +226,15 @@ func TestGetTransactionConfirmations_Integration(t *testing.T) { electrum, cancelCtx := newTestConnection(t, testConfig.clientConfig) defer cancelCtx() - for txName, tx := range testData.Transactions[testConfig.network] { + transactions := testData.Transactions[testConfig.network] + if len(transactions) == 0 { + t.Skipf( + "no transaction test vectors in internal/testdata for %s", + testConfig.network, + ) + } + + for txName, tx := range transactions { t.Run(txName, func(t *testing.T) { latestBlockHeight, err := electrum.GetLatestBlockHeight() if err != nil { @@ -772,14 +784,22 @@ func toJson(val interface{}) string { return string(b) } +// shouldSkipElectrumIntegrationError reports whether err is one of the +// transient external-service failures that integration tests should skip +// rather than fail on, matched by typed sentinel rather than substring so a +// reworded upstream message cannot silently widen or narrow the match: +// - goelectrum.ErrTimeout: the vendored go-electrum client's own request +// timed out talking to a public server. +// - wrappers.ErrRetryTimeout: the retry loop wrapping the request gave up +// after RequestRetryTimeout elapsed. +// - electrum.ErrFeeEstimateUnavailable: the queried server reported it +// does not have enough information to produce a fee estimate. func shouldSkipElectrumIntegrationError(err error) bool { if err == nil { return false } - msg := err.Error() - - return strings.Contains(msg, "request timeout") || - strings.Contains(msg, "retry timeout") || - strings.Contains(msg, "enough information") + return errors.Is(err, goelectrum.ErrTimeout) || + errors.Is(err, wrappers.ErrRetryTimeout) || + errors.Is(err, electrum.ErrFeeEstimateUnavailable) } diff --git a/pkg/bitcoin/electrum/electrum_test.go b/pkg/bitcoin/electrum/electrum_test.go index b09d03ec51..dc8b48ea10 100644 --- a/pkg/bitcoin/electrum/electrum_test.go +++ b/pkg/bitcoin/electrum/electrum_test.go @@ -1,9 +1,19 @@ package electrum import ( + "context" "fmt" + "math" "reflect" + "strings" + "sync" "testing" + "time" + + "github.com/checksum0/go-electrum/electrum" + "github.com/ipfs/go-log" + "go.uber.org/zap" + "go.uber.org/zap/zaptest/observer" "github.com/keep-network/keep-core/internal/testutils" "github.com/keep-network/keep-core/pkg/bitcoin" @@ -188,3 +198,531 @@ func TestFeeFallbackResult(t *testing.T) { }) } } + +func TestUtxoValue(t *testing.T) { + t.Parallel() + for _, tc := range []struct { + name string + value uint64 + want int64 + wantErr bool + }{ + {name: "zero", value: 0, want: 0}, + {name: "typical amount", value: 123456789, want: 123456789}, + {name: "largest representable int64", value: math.MaxInt64, want: math.MaxInt64}, + {name: "overflows int64", value: math.MaxInt64 + 1, wantErr: true}, + {name: "max uint64", value: math.MaxUint64, wantErr: true}, + } { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + got, err := utxoValue(tc.value) + if tc.wantErr { + if err == nil { + t.Fatal("expected an error for an out-of-range UTXO value") + } + return + } + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if got != tc.want { + t.Fatalf("expected value [%d], got [%d]", tc.want, got) + } + }) + } +} + +func TestVerifyServerGenesisHash(t *testing.T) { + t.Parallel() + const ( + mainnetGenesis = "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26" + testnetGenesis = "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943" + ) + + for _, tc := range []struct { + name string + expectedGenesisHash string + serverGenesisHash string + wantErr bool + wantGenesisHash string + }{ + { + name: "first server adopts its genesis hash", + expectedGenesisHash: "", + serverGenesisHash: mainnetGenesis, + wantGenesisHash: mainnetGenesis, + }, + { + name: "matching genesis hash passes, case-insensitively", + expectedGenesisHash: mainnetGenesis, + serverGenesisHash: strings.ToUpper(mainnetGenesis), + wantGenesisHash: mainnetGenesis, + }, + { + name: "mismatched genesis hash is rejected", + expectedGenesisHash: mainnetGenesis, + serverGenesisHash: testnetGenesis, + wantErr: true, + }, + { + name: "server omitting the field is accepted when a reference is set", + expectedGenesisHash: mainnetGenesis, + serverGenesisHash: "", + wantErr: false, + wantGenesisHash: mainnetGenesis, + }, + { + name: "first server omitting the field is accepted with no reference adopted", + expectedGenesisHash: "", + serverGenesisHash: "", + wantErr: false, + wantGenesisHash: "", + }, + } { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + client := &failoverTestClient{ + serverFeatures: func(context.Context) (*electrum.ServerFeaturesResult, error) { + return &electrum.ServerFeaturesResult{GenesisHash: tc.serverGenesisHash}, nil + }, + } + gotHash, err := verifyServer(context.Background(), client, "server", tc.expectedGenesisHash) + if tc.wantErr { + if err == nil { + t.Fatal("expected an error") + } + return + } + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if gotHash != tc.wantGenesisHash { + t.Fatalf("expected genesis hash [%s], got [%s]", tc.wantGenesisHash, gotHash) + } + }) + } +} + +// TestTipSanityCheckWarnsButAcceptsLargeHeightChange verifies the tip sanity +// check is advisory only: a large height jump right after a reconnect (a +// legitimate reorg, or simply a different server's view) is logged, not +// rejected, and the new tip is still returned and tracked. +func TestTipSanityCheckWarnsButAcceptsLargeHeightChange(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + config := failoverTestConfig() + config.KeepAliveInterval = time.Hour + heights := []int32{100, 100_000} + call := 0 + client := &failoverTestClient{header: func(context.Context) (*electrum.SubscribeHeadersResult, error) { + h := heights[call] + if call < len(heights)-1 { + call++ + } + return &electrum.SubscribeHeadersResult{Height: h}, nil + }} + connection, err := connect(ctx, config, func(context.Context, string) (electrumClient, error) { + return client, nil + }) + if err != nil { + t.Fatal(err) + } + if height, err := connection.GetLatestBlockHeight(); err != nil || height != 100 { + t.Fatalf("first height read: %d, %v", height, err) + } + if connection.lastTipHeight != 100 { + t.Fatalf("expected tracked tip height 100, got %d", connection.lastTipHeight) + } + // A reconnect (electrumConnect, failover, or healPrimary) sets this flag; + // simulate one directly to exercise the comparison in isolation. + connection.clientMutex.Lock() + connection.pendingTipSanityCheck = true + connection.clientMutex.Unlock() + if height, err := connection.GetLatestBlockHeight(); err != nil || height != 100_000 { + t.Fatalf("a large tip jump after reconnect must be accepted with a warning, not rejected: %d, %v", height, err) + } + if connection.lastTipHeight != 100_000 { + t.Fatalf("expected tracked tip height 100000, got %d", connection.lastTipHeight) + } +} + +// TestGetScriptUtxosPreservesMempoolHeightSentinel verifies getScriptUtxos +// correctly classifies a mempool item reported with Electrum's -1 height +// sentinel under both the confirmed and unconfirmed views. +func TestGetScriptUtxosPreservesMempoolHeightSentinel(t *testing.T) { + t.Parallel() + + const mempoolTxHash = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + for _, tc := range []struct { + name string + confirmed bool + wantLen int + }{ + { + name: "confirmed view excludes the mempool item", + confirmed: true, + wantLen: 0, + }, + { + name: "unconfirmed view includes the mempool item", + confirmed: false, + wantLen: 1, + }, + } { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + client := &failoverTestClient{ + listUnspent: func(context.Context, string) ([]*electrum.ListUnspentResult, error) { + return []*electrum.ListUnspentResult{ + { + Hash: mempoolTxHash, + Position: 0, + Value: 1000, + Height: -1, + }, + }, nil + }, + } + connection, err := connect( + context.Background(), + failoverTestConfig(), + func(context.Context, string) (electrumClient, error) { + return client, nil + }, + ) + if err != nil { + t.Fatal(err) + } + + items, err := connection.getScriptUtxos([]byte{0x00}, tc.confirmed) + if err != nil { + t.Fatal(err) + } + if len(items) != tc.wantLen { + t.Fatalf("expected [%d] items, got [%d]", tc.wantLen, len(items)) + } + if tc.wantLen == 1 && items[0].blockHeight != -1 { + t.Fatalf( + "expected the mempool sentinel height -1 to be preserved, got [%d]", + items[0].blockHeight, + ) + } + }) + } +} + +func TestSanitizeServerURL(t *testing.T) { + t.Parallel() + + tests := map[string]struct { + input string + expected string + }{ + "clean URL unchanged": { + input: "tcp://electrum.example.com:50001", + expected: "tcp://electrum.example.com:50001", + }, + "userinfo stripped": { + input: "wss://alice:secret123@electrum.example.com:443/path", + expected: "wss://electrum.example.com:443/path", + }, + "preserve @ in credential-free path": { + input: "wss://node.example/path@tenant", + expected: "wss://node.example/path@tenant", + }, + "userinfo stripped and path @ preserved": { + input: "wss://alice:secret123@node.example/path@tenant", + expected: "wss://node.example/path@tenant", + }, + "unsupported scheme with userinfo": { + input: "unsupported://user:pass@host:123", + expected: "unsupported://host:123", + }, + "malformed URL with userinfo": { + input: "tcp://user:secret@invalid%xx:50001", + expected: "tcp://invalid%xx:50001", + }, + "opaque raw credentials without scheme": { + input: "user:secret@host", + expected: "host", + }, + "missing host with credentials": { + input: "tcp:///user:secret@host", + expected: "tcp://host", + }, + } + for name, tc := range tests { + tc := tc + t.Run(name, func(t *testing.T) { + t.Parallel() + actual := sanitizeServerURL(tc.input) + if actual != tc.expected { + t.Fatalf("expected [%s], got [%s]", tc.expected, actual) + } + }) + } +} + +func TestValidateServerURL(t *testing.T) { + t.Parallel() + + tests := map[string]struct { + input string + wantErr bool + errContains string + }{ + "valid tcp": { + input: "tcp://electrum.example.com:50001", + wantErr: false, + }, + "valid ssl ipv6": { + input: "ssl://[::1]:50002", + wantErr: false, + }, + "valid ws default port": { + input: "ws://127.0.0.1", + wantErr: false, + }, + "valid wss with path and @": { + input: "wss://node.example/path@tenant", + wantErr: false, + }, + "websocket with userinfo rejected": { + input: "ws://user:secretpass@127.0.0.1:8546", + wantErr: true, + errContains: "userinfo is not supported in websocket URL [ws://127.0.0.1:8546]", + }, + "ws with explicit empty port rejected": { + input: "ws://127.0.0.1:", + wantErr: true, + errContains: "invalid port", + }, + "wss with explicit empty port rejected": { + input: "wss://node.example:", + wantErr: true, + errContains: "invalid port", + }, + "missing scheme": { + input: "localhost:50001", + wantErr: true, + errContains: "missing protocol scheme", + }, + "missing host": { + input: "tcp://:50001", + wantErr: true, + errContains: "missing host", + }, + "missing port for tcp": { + input: "tcp://electrum.example.com", + wantErr: true, + errContains: "missing port in electrum server URL [tcp://electrum.example.com]", + }, + "invalid port number": { + input: "ssl://electrum.example.com:99999", + wantErr: true, + errContains: "invalid port [99999]", + }, + "unsupported scheme with redaction": { + input: "http://user:secretpass@example.com:80", + wantErr: true, + errContains: "unsupported electrum server protocol scheme [http] in URL [http://example.com:80]", + }, + "malformed URL with secret redaction": { + input: "tcp://user:mysecretpassword@invalid%xx:50001", + wantErr: true, + errContains: "invalid electrum server URL [tcp://invalid%xx:50001]", + }, + "opaque raw credentials without scheme": { + input: "user:secret@host", + wantErr: true, + errContains: "missing protocol scheme in electrum server URL [host]", + }, + "missing host with credentials": { + input: "tcp:///user:secret@host", + wantErr: true, + errContains: "missing host in electrum server URL [tcp://host]", + }, + } + for name, tc := range tests { + tc := tc + t.Run(name, func(t *testing.T) { + t.Parallel() + err := validateServerURL(tc.input) + if tc.wantErr { + if err == nil { + t.Fatalf("expected error for input [%s], got nil", tc.input) + } + if tc.errContains != "" && !strings.Contains(err.Error(), tc.errContains) { + t.Fatalf("expected error containing [%s], got [%v]", tc.errContains, err) + } + if strings.Contains(tc.input, "secret") && strings.Contains(err.Error(), "secret") { + t.Fatalf("credential leaked in validation error: %v", err) + } + } else { + if err != nil { + t.Fatalf("unexpected error for input [%s]: %v", tc.input, err) + } + } + }) + } +} + +func TestConnectURLValidation(t *testing.T) { + t.Parallel() + + t.Run("empty configuration fails before dial", func(t *testing.T) { + t.Parallel() + chain, err := Connect(context.Background(), Config{}) + if err == nil || chain != nil { + t.Fatalf("expected error and nil chain, got: [%v], [%v]", err, chain) + } + if !strings.Contains(err.Error(), "no electrum server URLs configured") { + t.Fatalf("expected 'no electrum server URLs configured', got: [%v]", err) + } + }) + + t.Run("malformed fallback fails before primary is dialed", func(t *testing.T) { + t.Parallel() + config := Config{ + URL: "tcp://primary.example.com:50001", + FallbackURLs: []string{"http://bad.fallback:80"}, + } + chain, err := Connect(context.Background(), config) + if err == nil || chain != nil { + t.Fatalf("expected error and nil chain, got: [%v], [%v]", err, chain) + } + if !strings.Contains(err.Error(), "unsupported electrum server protocol scheme [http]") { + t.Fatalf("expected unsupported scheme error for fallback, got: [%v]", err) + } + }) +} + +func TestVerifyServerURLSanitization(t *testing.T) { + t.Parallel() + + client := &failoverTestClient{ + serverFeatures: func(context.Context) (*electrum.ServerFeaturesResult, error) { + return &electrum.ServerFeaturesResult{ + GenesisHash: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", + }, nil + }, + } + + rawURL := "wss://alice:secretpassword@electrum.example.com:443" + expectedReference := "1111111111111111111111111111111111111111111111111111111111111111" + + _, err := verifyServer(context.Background(), client, rawURL, expectedReference) + if err == nil { + t.Fatal("expected error on genesis hash mismatch, got nil") + } + + if strings.Contains(err.Error(), "secretpassword") || strings.Contains(err.Error(), "alice") { + t.Fatalf("credentials leaked in verifyServer error: [%v]", err) + } + if !strings.Contains(err.Error(), "wss://electrum.example.com:443") { + t.Fatalf("expected sanitized URL in verifyServer error, got: [%v]", err) + } +} + +type unsupportedProtocolMockClient struct { + failoverTestClient +} + +func (c *unsupportedProtocolMockClient) ServerVersion(ctx context.Context) (string, string, error) { + return "test", "9.9", nil +} + +func TestURLRedactionInLogs(t *testing.T) { + core, recorded := observer.New(zap.DebugLevel) + origLogger := logger + logger = &log.ZapEventLogger{ + SugaredLogger: *zap.New(core).Sugar(), + } + t.Cleanup(func() { + logger = origLogger + }) + + rawURL := "wss://alice:secretpassword@electrum.example.com:443" + + assertNoCredentialsInLogs := func(t *testing.T, expectedLogSubstring string) { + t.Helper() + allEntries := recorded.All() + found := false + for _, entry := range allEntries { + msg := entry.Message + if strings.Contains(msg, "alice") || strings.Contains(msg, "secretpassword") { + t.Fatalf("credential leaked in log message: [%s]", msg) + } + if strings.Contains(msg, expectedLogSubstring) { + found = true + } + } + if !found { + t.Fatalf("expected log containing [%s], found entries: %v", expectedLogSubstring, allEntries) + } + } + + t.Run("verifyServer unsupported protocol warning", func(t *testing.T) { + recorded.TakeAll() + client := &unsupportedProtocolMockClient{} + _, _ = verifyServer(context.Background(), client, rawURL, "") + assertNoCredentialsInLogs(t, "electrum server [wss://electrum.example.com:443] runs an unsupported protocol version") + }) + + t.Run("verifyServer missing genesis hash warning", func(t *testing.T) { + recorded.TakeAll() + client := &failoverTestClient{ + serverFeatures: func(context.Context) (*electrum.ServerFeaturesResult, error) { + return &electrum.ServerFeaturesResult{GenesisHash: ""}, nil + }, + } + _, _ = verifyServer(context.Background(), client, rawURL, "") + assertNoCredentialsInLogs(t, "electrum server [wss://electrum.example.com:443] did not report a genesis hash") + }) + + t.Run("verifyServer genesis adoption warning", func(t *testing.T) { + recorded.TakeAll() + client := &failoverTestClient{ + serverFeatures: func(context.Context) (*electrum.ServerFeaturesResult, error) { + return &electrum.ServerFeaturesResult{ + GenesisHash: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", + }, nil + }, + } + _, _ = verifyServer(context.Background(), client, rawURL, "") + assertNoCredentialsInLogs(t, "adopting genesis hash [000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f] reported by electrum server [wss://electrum.example.com:443]") + }) + + t.Run("healPrimary re-canonicalization info", func(t *testing.T) { + recorded.TakeAll() + ctx, cancel := context.WithCancel(context.Background()) + primaryClient := &failoverTestClient{ + serverFeatures: func(context.Context) (*electrum.ServerFeaturesResult, error) { + return &electrum.ServerFeaturesResult{ + GenesisHash: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", + }, nil + }, + } + conn := &Connection{ + parentCtx: ctx, + serverURLs: []string{"wss://alice:secretpassword@primary.example:443", "wss://fallback.example:443"}, + serverIndex: 1, + verifiedGenesisHash: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", + clientMutex: &sync.Mutex{}, + config: Config{ConnectTimeout: time.Second, RequestTimeout: time.Second}, + newClient: func(context.Context, string) (electrumClient, error) { + return primaryClient, nil + }, + } + t.Cleanup(func() { + cancel() + if conn.closeClient != nil { + conn.closeClient() + conn.closeClient = nil + } + }) + conn.healPrimary() + assertNoCredentialsInLogs(t, "re-canonicalized primary electrum server [wss://primary.example:443]") + }) +} diff --git a/pkg/bitcoin/electrum/errors_test.go b/pkg/bitcoin/electrum/errors_test.go new file mode 100644 index 0000000000..8fcda3ce7c --- /dev/null +++ b/pkg/bitcoin/electrum/errors_test.go @@ -0,0 +1,75 @@ +package electrum + +import ( + "errors" + "fmt" + "testing" + + "github.com/keep-network/keep-core/pkg/bitcoin" +) + +// TestFeeFallbackResultPreservesSentinel checks that the fee-estimate sentinel +// survives the wrapping feeFallbackResult applies on its way to the caller. +// +// EstimateSatPerVByteFee reports ErrFeeEstimateUnavailable when the daemon has +// no estimate, and callers classify that with errors.Is. feeFallbackResult is +// the only path that returns it, so wrapping with %v instead of %w there +// breaks the chain silently: the message still reads correctly and only the +// classification stops working. +func TestFeeFallbackResultPreservesSentinel(t *testing.T) { + _, err := feeFallbackResult( + bitcoin.Mainnet, + false, // no fee-oracle failure, so the lastErr branch is taken + ErrFeeEstimateUnavailable, + []uint32{1, 2, 3}, + ) + if err == nil { + t.Fatal("expected an error") + } + + if !errors.Is(err, ErrFeeEstimateUnavailable) { + t.Errorf( + "fee fallback error does not match ErrFeeEstimateUnavailable: [%v]", + err, + ) + } +} + +// TestFeeFallbackResultPreservesWrappedSentinel covers the same chain when the +// sentinel reaches feeFallbackResult already wrapped by an inner call. +func TestFeeFallbackResultPreservesWrappedSentinel(t *testing.T) { + _, err := feeFallbackResult( + bitcoin.Mainnet, + false, + fmt.Errorf("get fee for 2 blocks: [%w]", ErrFeeEstimateUnavailable), + []uint32{2}, + ) + if err == nil { + t.Fatal("expected an error") + } + + if !errors.Is(err, ErrFeeEstimateUnavailable) { + t.Errorf( + "fee fallback error does not match ErrFeeEstimateUnavailable: [%v]", + err, + ) + } +} + +// TestFeeFallbackResultWithoutSentinel guards the negative case: an unrelated +// error must not be classified as a missing fee estimate. +func TestFeeFallbackResultWithoutSentinel(t *testing.T) { + _, err := feeFallbackResult( + bitcoin.Mainnet, + false, + errors.New("connection reset by peer"), + []uint32{1}, + ) + if err == nil { + t.Fatal("expected an error") + } + + if errors.Is(err, ErrFeeEstimateUnavailable) { + t.Errorf("unrelated error misclassified as ErrFeeEstimateUnavailable") + } +} diff --git a/pkg/bitcoin/electrum/failover_cancellation_test.go b/pkg/bitcoin/electrum/failover_cancellation_test.go new file mode 100644 index 0000000000..00557fc367 --- /dev/null +++ b/pkg/bitcoin/electrum/failover_cancellation_test.go @@ -0,0 +1,240 @@ +package electrum + +import ( + "context" + "io" + "sync" + "testing" + "time" + + "github.com/checksum0/go-electrum/electrum" +) + +// Like a transport write without a deadline, call ignores its context and only +// returns when the client is shut down. release also lets failing tests join +// their blocked goroutines without relying on the behavior under test. +type blockedClientWrite struct { + started chan struct{} + finished chan struct{} + unblock chan struct{} + release func() +} + +func newBlockedClientWrite(client *failoverTestClient) *blockedClientWrite { + write := &blockedClientWrite{ + started: make(chan struct{}), + finished: make(chan struct{}), + unblock: make(chan struct{}), + } + write.release = sync.OnceFunc(func() { close(write.unblock) }) + client.shutdown = write.release + return write +} + +func (w *blockedClientWrite) call(context.Context) error { + close(w.started) + defer close(w.finished) + <-w.unblock + return io.ErrClosedPipe +} + +// TestRequestTimeoutAbortsBlockedWrite is a regression test for a bug where +// an established client's blocked transport write was not aborted when only +// the per-request RequestTimeout elapsed: the vendored request() writes +// synchronously before selecting on ctx.Done(), so a write that ignores its +// context (like a real blocked syscall) could hang past its own request's +// timeout. requestWithRetry now races an abort watcher against the request +// itself, so the write is aborted - and the request fails - within roughly +// RequestTimeout, without needing the outer parent context to be cancelled. +func TestRequestTimeoutAbortsBlockedWrite(t *testing.T) { + parent, cancel := context.WithCancel(context.Background()) + defer cancel() + client := new(failoverTestClient) + write := newBlockedClientWrite(client) + client.header = func(ctx context.Context) (*electrum.SubscribeHeadersResult, error) { + return nil, write.call(ctx) + } + config := failoverTestConfig() + config.RequestTimeout = 50 * time.Millisecond + config.RequestRetryTimeout = 60 * time.Millisecond + connection, err := connect(parent, config, func(context.Context, string) (electrumClient, error) { + return client, nil + }) + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { + cancel() + write.release() + }) + start := time.Now() + if _, err := connection.GetLatestBlockHeight(); err == nil { + t.Fatal("expected the blocked write to fail once RequestTimeout elapsed") + } + if elapsed := time.Since(start); elapsed > 500*time.Millisecond { + t.Fatalf("RequestTimeout did not unblock the write promptly: %v", elapsed) + } + if parent.Err() != nil { + t.Fatal("the outer parent context must not need to be cancelled") + } + client.awaitShutdown(t) +} + +func TestConnectionCancellationUnblocksTransportWrite(t *testing.T) { + for _, operation := range []string{"request", "fee", "keepalive"} { + for _, reconnect := range []bool{false, true} { + name := operation + "/initial client" + if reconnect { + name = operation + "/replacement client" + } + t.Run(name, func(t *testing.T) { + parent, cancel := context.WithCancel(context.Background()) + defer cancel() + first := new(failoverTestClient) + client := new(failoverTestClient) + write := newBlockedClientWrite(client) + config := failoverTestConfig() + switch operation { + case "request": + client.header = func(ctx context.Context) (*electrum.SubscribeHeadersResult, error) { + return nil, write.call(ctx) + } + case "fee": + client.fee = func(ctx context.Context) (float32, error) { + return 0, write.call(ctx) + } + case "keepalive": + config.KeepAliveInterval = time.Millisecond + client.ping = write.call + } + connection, err := connect(parent, config, func(_ context.Context, url string) (electrumClient, error) { + if reconnect && url == "first" { + return first, nil + } + return client, nil + }) + if err != nil { + t.Fatal(err) + } + if reconnect { + first.Shutdown() + } + finished := write.finished + result := make(chan error, 1) + if operation != "keepalive" { + finished = make(chan struct{}) + go func() { + defer close(finished) + var err error + if operation == "fee" { + _, err = connection.getFeeBtcPerKbOnce(parent, 1) + } else { + _, err = connection.GetLatestBlockHeight() + } + result <- err + }() + } + t.Cleanup(func() { + cancel() + write.release() + awaitClientResult(t, finished) + }) + awaitClientResult(t, write.started) + cancel() + select { + case <-finished: + case <-time.After(time.Second): + t.Fatal("connection cancellation did not close the transport during a blocked write") + } + if operation != "keepalive" { + if err := <-result; err == nil { + t.Fatal("expected the interrupted RPC to fail") + } + } + client.awaitShutdown(t) + if reconnect { + first.awaitShutdown(t) + } + }) + } + } +} + +func TestConnectionCancellationUnblocksVerificationWrite(t *testing.T) { + for _, reconnect := range []bool{false, true} { + name := "initial connection" + if reconnect { + name = "reconnection" + } + t.Run(name, func(t *testing.T) { + parent, cancel := context.WithCancel(context.Background()) + defer cancel() + first := new(failoverTestClient) + client := new(failoverTestClient) + write := newBlockedClientWrite(client) + client.version = write.call + result := make(chan error, 1) + finished := make(chan struct{}) + go func() { + defer close(finished) + connection, err := connect(parent, failoverTestConfig(), func(_ context.Context, url string) (electrumClient, error) { + if reconnect && url == "first" { + return first, nil + } + return client, nil + }) + if err == nil && reconnect { + first.Shutdown() + _, err = connection.GetLatestBlockHeight() + } + result <- err + }() + t.Cleanup(func() { + cancel() + write.release() + awaitClientResult(t, finished) + }) + awaitClientResult(t, write.started) + cancel() + select { + case <-finished: + case <-time.After(time.Second): + t.Fatal("connection cancellation did not close the client being verified") + } + if err := <-result; err == nil { + t.Fatal("expected interrupted verification to fail") + } + client.awaitShutdown(t) + }) + } +} + +func TestConnectionCancellationClosesReplacementDuringRetiredCleanup(t *testing.T) { + parent, cancel := context.WithCancel(context.Background()) + defer cancel() + config := failoverTestConfig() + config.RequestRetryTimeout = 50 * time.Millisecond + first := &failoverTestClient{header: func(context.Context) (*electrum.SubscribeHeadersResult, error) { + return nil, electrum.ErrServerShutdown + }} + closing := blockClientShutdown(t, first) + second := new(failoverTestClient) + connection, err := connect(parent, config, func(_ context.Context, url string) (electrumClient, error) { + if url == "first" { + return first, nil + } + return second, nil + }) + if err != nil { + t.Fatal(err) + } + if _, err := connection.GetLatestBlockHeight(); err == nil { + t.Fatal("expected the first request to fail") + } + awaitClientResult(t, closing) + if _, err := connection.GetLatestBlockHeight(); err != nil { + t.Fatal(err) + } + cancel() + second.awaitShutdown(t) +} diff --git a/pkg/bitcoin/electrum/failover_deadline_test.go b/pkg/bitcoin/electrum/failover_deadline_test.go new file mode 100644 index 0000000000..ee11a8f5a8 --- /dev/null +++ b/pkg/bitcoin/electrum/failover_deadline_test.go @@ -0,0 +1,285 @@ +package electrum + +import ( + "context" + "errors" + "sync/atomic" + "testing" + "time" + + "github.com/checksum0/go-electrum/electrum" +) + +func TestRequestRetryBudgetExpiryFailsOver(t *testing.T) { + for _, requestTimeout := range []time.Duration{50 * time.Millisecond, time.Second} { + t.Run(requestTimeout.String(), func(t *testing.T) { + parent, cancel := context.WithCancel(context.Background()) + defer cancel() + config := failoverTestConfig() + config.RequestRetryTimeout = 50 * time.Millisecond + config.RequestTimeout = requestTimeout + var firstRequests atomic.Int32 + first := &failoverTestClient{header: func(ctx context.Context) (*electrum.SubscribeHeadersResult, error) { + firstRequests.Add(1) + <-ctx.Done() + return nil, ctx.Err() + }} + second := new(failoverTestClient) + connection, err := connect(parent, config, func(_ context.Context, url string) (electrumClient, error) { + if url == "first" { + return first, nil + } + return second, nil + }) + if err != nil { + t.Fatal(err) + } + if _, err := connection.GetLatestBlockHeight(); err == nil { + t.Fatal("expected the first request to exhaust its retry budget") + } + if parent.Err() != nil { + t.Fatal("the caller must remain active after the internal timeout") + } + if height, err := connection.GetLatestBlockHeight(); err != nil || height != 42 { + t.Fatalf("request after budget expiry did not reach the fallback: %d, %v", height, err) + } + if firstRequests.Load() != 1 || second.versions.Load() != 1 { + t.Fatal("a later request reused the unresponsive server") + } + first.awaitShutdown(t) + }) + } +} + +func TestCallerDeadlineDoesNotFailover(t *testing.T) { + parent, cancelParent := context.WithCancel(context.Background()) + defer cancelParent() + first := new(failoverTestClient) + config := failoverTestConfig() + config.RequestTimeout = time.Second + connection, err := connect(parent, config, func(context.Context, string) (electrumClient, error) { + return first, nil + }) + if err != nil { + t.Fatal(err) + } + caller, cancelCaller := context.WithTimeout(parent, 100*time.Millisecond) + defer cancelCaller() + _, err = requestWithRetry(caller, connection, func(ctx context.Context, _ electrumClient) (int, error) { + <-ctx.Done() + return 0, ctx.Err() + }, "caller deadline") + if err == nil || !errors.Is(caller.Err(), context.DeadlineExceeded) { + t.Fatalf("expected caller deadline expiry, got %v", err) + } + // The request's own abort watcher (electrum.go requestWithRetry) may + // still retire the blocked transport once requestCtx inherits the + // caller's expired deadline - that is a transport-level cleanup, not a + // failover decision. What must not happen is the connection treating + // this as a server failure: no failover, same client, same index. + if connection.client != first || connection.serverIndex != 0 { + t.Fatal("caller deadline expiry changed server health") + } +} + +// A transport close handshake can outlive any of the request contexts. Keep +// cleanup blocked until the test has checked the caller's result and, where +// applicable, a subsequent request. Always release and join cleanup afterward. +func blockClientShutdown(t *testing.T, client *failoverTestClient) <-chan struct{} { + t.Helper() + started := make(chan struct{}) + release := make(chan struct{}) + done := make(chan struct{}) + client.shutdown = func() { + close(started) + <-release + close(done) + } + t.Cleanup(func() { + close(release) + select { + case <-done: + case <-time.After(time.Second): + t.Error("retired client cleanup did not finish") + } + if client.shutdowns.Load() != 1 { + t.Error("retired client must be closed exactly once") + } + }) + return started +} + +func awaitClientResult[T any](t *testing.T, result <-chan T) T { + t.Helper() + select { + case value := <-result: + return value + case <-time.After(time.Second): + t.Fatal("operation waited for retired-client cleanup") + var zero T + return zero + } +} + +func TestVerificationCleanupHonorsDeadline(t *testing.T) { + for _, callerDeadline := range []bool{false, true} { + name := "connection retry budget" + if callerDeadline { + name = "caller deadline" + } + t.Run(name, func(t *testing.T) { + config := failoverTestConfig() + config.ConnectTimeout = time.Second + config.RequestTimeout = time.Second + config.ConnectRetryTimeout = 100 * time.Millisecond + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + if callerDeadline { + var cancelDeadline context.CancelFunc + ctx, cancelDeadline = context.WithTimeout(ctx, 100*time.Millisecond) + defer cancelDeadline() + config.ConnectRetryTimeout = time.Second + } + client := &failoverTestClient{version: func(ctx context.Context) error { + <-ctx.Done() + return ctx.Err() + }} + closing := blockClientShutdown(t, client) + result := make(chan error, 1) + go func() { + _, err := connect(ctx, config, func(context.Context, string) (electrumClient, error) { + return client, nil + }) + result <- err + }() + awaitClientResult(t, closing) + if err := awaitClientResult(t, result); err == nil { + t.Fatal("expected verification to exhaust its deadline") + } + }) + } +} + +// TestReconnectVerificationCleanupDoesNotBlockRequests verifies that a +// verification abandoned due to retry budget exhaustion (not candidate +// health, see electrumConnect) does not block a later reconnection from +// retrying and using that same preserved candidate, even while its earlier +// abandoned client is still stuck mid-shutdown. +func TestReconnectVerificationCleanupDoesNotBlockRequests(t *testing.T) { + parent, cancel := context.WithCancel(context.Background()) + defer cancel() + config := failoverTestConfig() + config.FallbackURLs = []string{"second"} + config.RequestRetryTimeout = 50 * time.Millisecond + config.ConnectTimeout = time.Second + config.RequestTimeout = time.Second + first := new(failoverTestClient) + var verifyCalls atomic.Int32 + second := &failoverTestClient{version: func(ctx context.Context) error { + if verifyCalls.Add(1) == 1 { + <-ctx.Done() + return ctx.Err() + } + return nil + }} + closing := blockClientShutdown(t, second) + connection, err := connect(parent, config, func(_ context.Context, url string) (electrumClient, error) { + if url == "first" { + return first, nil + } + return second, nil + }) + if err != nil { + t.Fatal(err) + } + first.Shutdown() + result := make(chan error, 1) + go func() { + _, err := connection.GetLatestBlockHeight() + result <- err + }() + awaitClientResult(t, closing) + if err := awaitClientResult(t, result); err == nil { + t.Fatal("expected the retry budget to be exhausted mid-verification") + } + if connection.serverIndex != 1 || connection.client != nil { + t.Fatal("budget exhaustion incorrectly discarded the preserved candidate") + } + // second's Abort/Shutdown from the abandoned attempt remains blocked + // (released only in t.Cleanup); a later reconnection with a workable + // budget must still be able to retry and use the preserved candidate, + // proving the blocked cleanup did not wedge the connection. + connection.config.RequestRetryTimeout = 2 * time.Second + if height, err := connection.GetLatestBlockHeight(); err != nil || height != 42 { + t.Fatalf("blocked verification cleanup prevented retrying the preserved candidate: %d, %v", height, err) + } + if verifyCalls.Load() != 2 { + t.Fatal("preserved candidate was not retried") + } +} + +func TestFailoverCleanupDoesNotBlockRequests(t *testing.T) { + parent, cancel := context.WithCancel(context.Background()) + defer cancel() + config := failoverTestConfig() + config.RequestRetryTimeout = 50 * time.Millisecond + first := &failoverTestClient{header: func(context.Context) (*electrum.SubscribeHeadersResult, error) { + return nil, electrum.ErrServerShutdown + }} + second := new(failoverTestClient) + closing := blockClientShutdown(t, first) + connection, err := connect(parent, config, func(_ context.Context, url string) (electrumClient, error) { + if url == "first" { + return first, nil + } + return second, nil + }) + if err != nil { + t.Fatal(err) + } + failedRequest := make(chan error, 1) + go func() { + _, err := connection.GetLatestBlockHeight() + failedRequest <- err + }() + awaitClientResult(t, closing) + nextRequest := make(chan error, 1) + go func() { + _, err := connection.GetLatestBlockHeight() + nextRequest <- err + }() + if err := awaitClientResult(t, nextRequest); err != nil { + t.Fatalf("concurrent request could not use the fallback during cleanup: %v", err) + } + if err := awaitClientResult(t, failedRequest); err == nil { + t.Fatal("expected the failed request to exhaust its retry budget") + } +} + +func TestConnectionShutdownDoesNotBlockRequests(t *testing.T) { + parent, cancel := context.WithCancel(context.Background()) + defer cancel() + client := new(failoverTestClient) + closing := blockClientShutdown(t, client) + connection, err := connect(parent, failoverTestConfig(), func(context.Context, string) (electrumClient, error) { + return client, nil + }) + if err != nil { + t.Fatal(err) + } + cancel() + awaitClientResult(t, closing) + caller, cancelCaller := context.WithTimeout(context.Background(), 50*time.Millisecond) + defer cancelCaller() + result := make(chan error, 1) + go func() { + _, err := requestWithRetry(caller, connection, func(context.Context, electrumClient) (int, error) { + t.Error("request used a closed connection") + return 0, nil + }, "shutdown") + result <- err + }() + if err := awaitClientResult(t, result); err == nil { + t.Fatal("expected connection cancellation") + } +} diff --git a/pkg/bitcoin/electrum/failover_test.go b/pkg/bitcoin/electrum/failover_test.go new file mode 100644 index 0000000000..8b95c292aa --- /dev/null +++ b/pkg/bitcoin/electrum/failover_test.go @@ -0,0 +1,964 @@ +package electrum + +import ( + "context" + "errors" + "sync" + "sync/atomic" + "testing" + "time" + + "github.com/checksum0/go-electrum/electrum" +) + +// Unused RPC methods remain embedded so a test fails if it unexpectedly invokes +// a different operation. Lifecycle state is synchronized with the keepalive loop. +type failoverTestClient struct { + electrumClient + stopped atomic.Bool + versions atomic.Int32 + shutdowns atomic.Int32 + abortOnce sync.Once + versionErr error + version func(context.Context) error + shutdown func() + header func(context.Context) (*electrum.SubscribeHeadersResult, error) + ping func(context.Context) error + fee func(context.Context) (float32, error) + serverFeatures func(context.Context) (*electrum.ServerFeaturesResult, error) + listUnspent func(context.Context, string) ([]*electrum.ListUnspentResult, error) +} + +func (c *failoverTestClient) ServerVersion(ctx context.Context) (string, string, error) { + c.versions.Add(1) + if c.version != nil { + return "test", "1.4", c.version(ctx) + } + return "test", "1.4", c.versionErr +} +func (c *failoverTestClient) Shutdown() { + c.shutdowns.Add(1) + c.stopped.Store(true) + if c.shutdown != nil { + c.shutdown() + } +} +func (c *failoverTestClient) IsShutdown() bool { return c.stopped.Load() } + +func (c *failoverTestClient) Abort() { + c.abortOnce.Do(func() { + if !c.IsShutdown() { + c.Shutdown() + } + }) +} + +func (c *failoverTestClient) awaitShutdown(t *testing.T) { + t.Helper() + timeout := time.NewTimer(time.Second) + defer timeout.Stop() + tick := time.NewTicker(time.Millisecond) + defer tick.Stop() + for c.shutdowns.Load() == 0 { + select { + case <-tick.C: + case <-timeout.C: + t.Fatal("retired client was not closed") + } + } + if c.shutdowns.Load() != 1 { + t.Fatal("retired client was closed more than once") + } +} +func (c *failoverTestClient) SubscribeHeadersSingle(ctx context.Context) (*electrum.SubscribeHeadersResult, error) { + if c.header != nil { + return c.header(ctx) + } + return &electrum.SubscribeHeadersResult{Height: 42}, nil +} +func (c *failoverTestClient) Ping(ctx context.Context) error { + if c.ping != nil { + return c.ping(ctx) + } + return nil +} +func (c *failoverTestClient) GetFee(ctx context.Context, _ uint32) (float32, error) { + if c.fee != nil { + return c.fee(ctx) + } + return 0.001, nil +} + +// defaultTestGenesisHash is returned by ServerFeatures when no serverFeatures +// override is set. verifyServer now rejects a candidate that omits the +// genesis hash, so unrelated failover tests need a non-empty default to +// keep connecting successfully; tests that specifically exercise genesis +// hash handling set serverFeatures explicitly. +const defaultTestGenesisHash = "00000000000000000000000000000000000000000000000000000000000aaa" + +func (c *failoverTestClient) ServerFeatures(ctx context.Context) (*electrum.ServerFeaturesResult, error) { + if c.serverFeatures != nil { + return c.serverFeatures(ctx) + } + return &electrum.ServerFeaturesResult{GenesisHash: defaultTestGenesisHash}, nil +} +func (c *failoverTestClient) ListUnspent(ctx context.Context, scriptHash string) ([]*electrum.ListUnspentResult, error) { + if c.listUnspent != nil { + return c.listUnspent(ctx, scriptHash) + } + return nil, nil +} + +func failoverTestConfig() Config { + return Config{ + URL: "first", FallbackURLs: []string{"second"}, + ConnectTimeout: 100 * time.Millisecond, ConnectRetryTimeout: 5 * time.Second, + RequestTimeout: 20 * time.Millisecond, RequestRetryTimeout: 5 * time.Second, + KeepAliveInterval: time.Hour, + } +} + +func TestConnectFailover(t *testing.T) { + for _, handshakeFailure := range []bool{false, true} { + t.Run(map[bool]string{false: "dial failure", true: "handshake failure"}[handshakeFailure], func(t *testing.T) { + t.Parallel() + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + first := &failoverTestClient{versionErr: errors.New("server unavailable")} + second := new(failoverTestClient) + config := failoverTestConfig() + config.FallbackURLs = []string{"first", "", "second", "second"} + connection, err := connect(ctx, config, func( + _ context.Context, + url string, + ) (electrumClient, error) { + if url == "first" { + if handshakeFailure { + return first, nil + } + return nil, errors.New("dial failed") + } + return second, nil + }) + if err != nil { + t.Fatal(err) + } + if len(connection.serverURLs) != 2 || connection.client != second { + t.Fatal("did not select the fallback server") + } + if second.versions.Load() != 1 { + t.Fatal("fallback server was not verified") + } + if handshakeFailure { + first.awaitShutdown(t) + } + }) + } +} + +func TestRequestFailover(t *testing.T) { + for _, tc := range []struct { + name string + mkErr func(ctx context.Context) error + preShutdown bool + wantFailover bool + }{ + { + name: "transport timeout", + mkErr: func(ctx context.Context) error { + <-ctx.Done() + return electrum.ErrTimeout + }, + wantFailover: true, + }, + { + name: "server shutdown", + preShutdown: true, + wantFailover: true, + }, + { + name: "benign JSON-RPC application error", + mkErr: func(context.Context) error { + return errors.New("errNo: -32600, errMsg: tx not found") + }, + wantFailover: false, + }, + } { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + first := &failoverTestClient{header: func(ctx context.Context) (*electrum.SubscribeHeadersResult, error) { + if tc.mkErr == nil { + t.Error("shutdown case must not issue a request against the retired client") + return nil, errors.New("unreachable") + } + return nil, tc.mkErr(ctx) + }} + second := new(failoverTestClient) + config := failoverTestConfig() + if !tc.wantFailover { + // A benign application error never fails over, so the + // retry loop keeps hammering the same (still healthy) + // server; keep the budget short so the test stays fast. + config.RequestRetryTimeout = 60 * time.Millisecond + } + connection, err := connect(ctx, config, func( + _ context.Context, + url string, + ) (electrumClient, error) { + if url == "first" { + return first, nil + } + return second, nil + }) + if err != nil { + t.Fatal(err) + } + if tc.preShutdown { + first.Shutdown() + } + + if !tc.wantFailover { + if _, err := connection.GetLatestBlockHeight(); err == nil { + t.Fatal("expected the benign application error to surface") + } + if connection.client != first || first.IsShutdown() || second.versions.Load() != 0 { + t.Fatal("a benign JSON-RPC application error incorrectly triggered failover") + } + return + } + + height, err := connection.GetLatestBlockHeight() + if err != nil || height != 42 { + t.Fatalf("fallback request: %d, %v", height, err) + } + first.awaitShutdown(t) + if second.versions.Load() != 1 { + t.Fatal("connection lifecycle was not preserved") + } + }) + } +} + +func TestExplicitElectrumURLRemainsPinned(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + client := &failoverTestClient{header: func(context.Context) (*electrum.SubscribeHeadersResult, error) { + return nil, errors.New("temporary RPC error") + }} + config := failoverTestConfig() + config.FallbackURLs = nil + config.RequestRetryTimeout = 30 * time.Millisecond + var connections atomic.Int32 + connection, err := connect(ctx, config, func( + _ context.Context, + url string, + ) (electrumClient, error) { + if url != config.URL { + t.Errorf("unexpected URL %q", url) + } + connections.Add(1) + return client, nil + }) + if err != nil { + t.Fatal(err) + } + if _, err := connection.GetLatestBlockHeight(); err == nil { + t.Fatal("expected request failure") + } + if connection.client != client || client.IsShutdown() || connections.Load() != 1 { + t.Fatal("RPC failure changed the explicit connection") + } +} + +func TestCallerCancellationDoesNotFailover(t *testing.T) { + parent, cancelParent := context.WithCancel(context.Background()) + defer cancelParent() + caller, cancelCaller := context.WithCancel(parent) + defer cancelCaller() + first := new(failoverTestClient) + var connections atomic.Int32 + connection, err := connect(parent, failoverTestConfig(), func(context.Context, string) (electrumClient, error) { + connections.Add(1) + return first, nil + }) + if err != nil { + t.Fatal(err) + } + _, err = requestWithRetry(caller, connection, func(context.Context, electrumClient) (int, error) { + cancelCaller() + return 0, context.Canceled + }, "cancelled") + if err == nil { + t.Fatal("expected cancellation") + } + if connection.client != first || connection.serverIndex != 0 || + first.IsShutdown() || connections.Load() != 1 { + t.Fatal("caller cancellation changed server health") + } +} + +func TestFailoverHonorsRequestBudget(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + config := failoverTestConfig() + config.RequestRetryTimeout = 60 * time.Millisecond + config.ConnectTimeout = time.Second + first := new(failoverTestClient) + connection, err := connect(ctx, config, func(ctx context.Context, url string) (electrumClient, error) { + if url == "first" { + return first, nil + } + <-ctx.Done() + return nil, ctx.Err() + }) + if err != nil { + t.Fatal(err) + } + first.Shutdown() + start := time.Now() + if _, err := connection.GetLatestBlockHeight(); err == nil { + t.Fatal("expected unavailable server error") + } + if elapsed := time.Since(start); elapsed > 1000*time.Millisecond { + t.Fatalf("reconnection exceeded request budget: %v", elapsed) + } +} + +func TestKeepAliveFailover(t *testing.T) { + t.Run("multiple servers", func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + pong := make(chan struct{}, 1) + first := &failoverTestClient{ping: func(context.Context) error { return electrum.ErrTimeout }} + second := &failoverTestClient{ping: func(context.Context) error { + select { + case pong <- struct{}{}: + default: + } + return nil + }} + config := failoverTestConfig() + config.KeepAliveInterval = time.Millisecond + _, err := connect(ctx, config, func( + _ context.Context, + url string, + ) (electrumClient, error) { + if url == "first" { + return first, nil + } + return second, nil + }) + if err != nil { + t.Fatal(err) + } + select { + case <-pong: + case <-time.After(5 * time.Second): + t.Fatal("keepalive did not reach the fallback server") + } + first.awaitShutdown(t) + }) + + t.Run("pinned single server recovers via retire and redial", func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + config := failoverTestConfig() + config.FallbackURLs = nil + config.KeepAliveInterval = time.Millisecond + var dials atomic.Int32 + var healthy atomic.Bool + pong := make(chan struct{}, 1) + var clientsMu sync.Mutex + var clients []*failoverTestClient + connection, err := connect(ctx, config, func(_ context.Context, url string) (electrumClient, error) { + dials.Add(1) + client := &failoverTestClient{ping: func(context.Context) error { + if !healthy.Load() { + return electrum.ErrTimeout + } + select { + case pong <- struct{}{}: + default: + } + return nil + }} + clientsMu.Lock() + clients = append(clients, client) + clientsMu.Unlock() + return client, nil + }) + if err != nil { + t.Fatal(err) + } + clientsMu.Lock() + initial := clients[0] + clientsMu.Unlock() + // A pinned single-URL connection must still retire and re-dial the + // same server on a failed ping, instead of wedging on the dead + // client forever. + initial.awaitShutdown(t) + healthy.Store(true) + select { + case <-pong: + case <-time.After(5 * time.Second): + t.Fatal("keepalive did not recover the pinned server after a failed ping") + } + if dials.Load() < 2 { + t.Fatal("pinned server was not re-dialed after the failed ping") + } + if connection.serverIndex != 0 { + t.Fatal("pinned single-URL connection must stay at index 0") + } + }) +} + +// TestKeepAliveHealsPrimaryAfterConsecutivePings verifies the D3 healing +// behavior: after healAfterConsecutivePings consecutive successful keepalive +// pings on a non-primary index, the connection actively re-probes the +// primary and swaps back to it once verified healthy. +func TestKeepAliveHealsPrimaryAfterConsecutivePings(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + config := failoverTestConfig() + config.KeepAliveInterval = time.Millisecond + firstAttemptFailed := &failoverTestClient{versionErr: errors.New("primary temporarily unavailable")} + second := new(failoverTestClient) + primaryHealthy := new(failoverTestClient) + var primaryDials atomic.Int32 + connection, err := connect(ctx, config, func(_ context.Context, url string) (electrumClient, error) { + if url == "first" { + if primaryDials.Add(1) == 1 { + return firstAttemptFailed, nil + } + return primaryHealthy, nil + } + return second, nil + }) + if err != nil { + t.Fatal(err) + } + if connection.serverIndex != 1 || connection.client != second { + t.Fatal("setup did not start on the fallback server") + } + firstAttemptFailed.awaitShutdown(t) + + timeout := time.NewTimer(5 * time.Second) + defer timeout.Stop() + tick := time.NewTicker(time.Millisecond) + defer tick.Stop() + healed := false + for !healed { + select { + case <-tick.C: + connection.clientMutex.Lock() + healed = connection.serverIndex == 0 && connection.client == primaryHealthy + connection.clientMutex.Unlock() + case <-timeout.C: + t.Fatal("keepalive did not re-canonicalize the primary server") + } + } + if primaryHealthy.versions.Load() != 1 { + t.Fatal("re-canonicalized primary was not verified") + } + second.awaitShutdown(t) +} + +func TestConcurrentRequestsShareFailover(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + first := &failoverTestClient{header: func(context.Context) (*electrum.SubscribeHeadersResult, error) { + return nil, electrum.ErrTimeout + }} + second := new(failoverTestClient) + var fallbackConnections atomic.Int32 + connection, err := connect(ctx, failoverTestConfig(), func( + _ context.Context, + url string, + ) (electrumClient, error) { + if url == "first" { + return first, nil + } + fallbackConnections.Add(1) + return second, nil + }) + if err != nil { + t.Fatal(err) + } + var requests sync.WaitGroup + for i := 0; i < 8; i++ { + requests.Add(1) + go func() { + defer requests.Done() + if height, err := connection.GetLatestBlockHeight(); err != nil || height != 42 { + t.Errorf("concurrent request: %d, %v", height, err) + } + }() + } + requests.Wait() + if fallbackConnections.Load() != 1 { + t.Fatal("concurrent requests replaced a healthy fallback") + } +} + +func TestFeeApplicationErrorDoesNotFailover(t *testing.T) { + for _, tc := range []struct { + name string + err error + }{ + {name: "no fee data text", err: errors.New("cannot estimate fee")}, + {name: "-32603 internal error", err: errors.New("errNo: -32603, errMsg: internal error")}, + } { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + client := &failoverTestClient{fee: func(context.Context) (float32, error) { + return 0, tc.err + }} + connection, err := connect(ctx, failoverTestConfig(), func(context.Context, string) (electrumClient, error) { + return client, nil + }) + if err != nil { + t.Fatal(err) + } + if _, err := connection.getFeeBtcPerKbOnce(ctx, 1); err == nil { + t.Fatal("expected unavailable fee estimate") + } + if connection.client != client || connection.serverIndex != 0 || client.IsShutdown() { + t.Fatal("a JSON-RPC application error incorrectly marked the server unhealthy") + } + }) + } +} + +func TestConnectFailureReturnsNilChain(t *testing.T) { + chain, err := Connect(context.Background(), Config{ + URL: "unsupported://server", + ConnectRetryTimeout: time.Millisecond, + }) + if err == nil || chain != nil { + t.Fatalf("expected nil chain and error, got %v, %v", chain, err) + } +} + +func TestFeeRequestFailover(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + first := &failoverTestClient{fee: func(context.Context) (float32, error) { + return 0, electrum.ErrServerShutdown + }} + second := new(failoverTestClient) + connection, err := connect(ctx, failoverTestConfig(), func( + _ context.Context, + url string, + ) (electrumClient, error) { + if url == "first" { + return first, nil + } + return second, nil + }) + if err != nil { + t.Fatal(err) + } + if _, err := connection.getFeeBtcPerKbOnce(ctx, 1); err == nil { + t.Fatal("expected transport error") + } + if fee, err := connection.getFeeBtcPerKbOnce(ctx, 6); err != nil || fee != 0.001 { + t.Fatalf("fee request on fallback: %v, %v", fee, err) + } + first.awaitShutdown(t) + if second.versions.Load() != 1 { + t.Fatal("fee request did not switch servers") + } +} + +func TestAllElectrumServersUnavailable(t *testing.T) { + config := failoverTestConfig() + config.ConnectRetryTimeout = 1500 * time.Millisecond + var attempts atomic.Int32 + connection, err := connect(context.Background(), config, func(context.Context, string) (electrumClient, error) { + attempts.Add(1) + return nil, errors.New("unavailable") + }) + if err == nil || connection != nil || attempts.Load() != 2 { + t.Fatalf("expected bounded retries across both servers, got %v, %v, %d attempts", + connection, err, attempts.Load()) + } +} + +func TestConnectFailsWithNoConfiguredServers(t *testing.T) { + connection, err := connect(context.Background(), Config{}, func(context.Context, string) (electrumClient, error) { + t.Fatal("dial must not be attempted with no configured server URLs") + return nil, nil + }) + if err == nil || connection != nil { + t.Fatalf("expected an error and a nil connection, got %v, %v", connection, err) + } +} + +// TestHealPrimaryDialFailureLeavesFallbackUntouched verifies a failed +// heal-time dial of the primary leaves the current fallback connection +// completely untouched. +func TestHealPrimaryDialFailureLeavesFallbackUntouched(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + config := failoverTestConfig() + config.KeepAliveInterval = time.Millisecond + firstAttemptFailed := &failoverTestClient{versionErr: errors.New("primary temporarily unavailable")} + fallback := new(failoverTestClient) + var primaryDials atomic.Int32 + connection, err := connect(ctx, config, func(_ context.Context, url string) (electrumClient, error) { + if url == "first" { + if primaryDials.Add(1) == 1 { + return firstAttemptFailed, nil + } + return nil, errors.New("primary still unreachable") + } + return fallback, nil + }) + if err != nil { + t.Fatal(err) + } + if connection.serverIndex != 1 || connection.client != fallback { + t.Fatal("setup did not start on the fallback server") + } + firstAttemptFailed.awaitShutdown(t) + + timeout := time.NewTimer(5 * time.Second) + defer timeout.Stop() + tick := time.NewTicker(time.Millisecond) + defer tick.Stop() + for primaryDials.Load() < 2 { + select { + case <-tick.C: + case <-timeout.C: + t.Fatal("heal attempt did not dial the primary") + } + } + time.Sleep(20 * time.Millisecond) + if connection.serverIndex != 1 || connection.client != fallback || fallback.IsShutdown() { + t.Fatal("a failed heal-time dial must leave the fallback connection untouched") + } +} + +// TestHealPrimaryVerificationFailureLeavesFallbackUntouched verifies a +// failed heal-time verification (a genesis hash mismatch) leaves the +// current fallback connection untouched and aborts the failed candidate +// exactly once. +func TestHealPrimaryVerificationFailureLeavesFallbackUntouched(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + config := failoverTestConfig() + config.KeepAliveInterval = time.Millisecond + firstAttemptFailed := &failoverTestClient{versionErr: errors.New("primary temporarily unavailable")} + fallback := new(failoverTestClient) + var wrongChainCandidate atomic.Pointer[failoverTestClient] + var primaryDials atomic.Int32 + connection, err := connect(ctx, config, func(_ context.Context, url string) (electrumClient, error) { + if url == "first" { + if primaryDials.Add(1) == 1 { + return firstAttemptFailed, nil + } + candidate := &failoverTestClient{ + serverFeatures: func(context.Context) (*electrum.ServerFeaturesResult, error) { + return &electrum.ServerFeaturesResult{GenesisHash: "different-chain"}, nil + }, + } + wrongChainCandidate.Store(candidate) + return candidate, nil + } + return fallback, nil + }) + if err != nil { + t.Fatal(err) + } + if connection.serverIndex != 1 || connection.client != fallback { + t.Fatal("setup did not start on the fallback server") + } + firstAttemptFailed.awaitShutdown(t) + + timeout := time.NewTimer(5 * time.Second) + defer timeout.Stop() + tick := time.NewTicker(time.Millisecond) + defer tick.Stop() + for wrongChainCandidate.Load() == nil { + select { + case <-tick.C: + case <-timeout.C: + t.Fatal("heal attempt did not dial the primary") + } + } + // The candidate reports a genesis hash that does not match this + // connection's chain reference; verification must reject it and abort + // it exactly once. + wrongChainCandidate.Load().awaitShutdown(t) + + if connection.serverIndex != 1 || connection.client != fallback || fallback.IsShutdown() { + t.Fatal("a failed heal-time verification must leave the fallback connection untouched") + } +} + +// TestHealPrimaryDiscardsOverlappingCandidateAfterFirstCommits verifies the +// c.serverIndex == 0 discard guard: when two heal attempts overlap and one +// has already restored the primary, the other discards its own +// (otherwise-healthy) candidate instead of clobbering the already-restored +// connection. +func TestHealPrimaryDiscardsOverlappingCandidateAfterFirstCommits(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + config := failoverTestConfig() + config.KeepAliveInterval = time.Hour // heal attempts are driven manually below + config.RequestTimeout = 5 * time.Second + firstAttemptFailed := &failoverTestClient{versionErr: errors.New("primary temporarily unavailable")} + fallback := new(failoverTestClient) + + committed := make(chan struct{}) + var unblockOnce sync.Once + unblock := func() { unblockOnce.Do(func() { close(committed) }) } + defer unblock() + + candidateBlocked := new(failoverTestClient) + candidateBlocked.version = func(ctx context.Context) error { + select { + case <-committed: + return nil + case <-ctx.Done(): + return ctx.Err() + } + } + var candidateWinning atomic.Pointer[failoverTestClient] + + var primaryDials atomic.Int32 + connection, err := connect(ctx, config, func(_ context.Context, url string) (electrumClient, error) { + if url == "first" { + switch primaryDials.Add(1) { + case 1: + return firstAttemptFailed, nil + case 2: + return candidateBlocked, nil + default: + winning := new(failoverTestClient) + candidateWinning.Store(winning) + return winning, nil + } + } + return fallback, nil + }) + if err != nil { + t.Fatal(err) + } + if connection.serverIndex != 1 || connection.client != fallback { + t.Fatal("setup did not start on the fallback server") + } + firstAttemptFailed.awaitShutdown(t) + + blockedDone := make(chan struct{}) + go func() { + connection.healPrimary() + close(blockedDone) + }() + + timeout := time.NewTimer(5 * time.Second) + defer timeout.Stop() + tick := time.NewTicker(time.Millisecond) + defer tick.Stop() + for primaryDials.Load() < 2 { + select { + case <-tick.C: + case <-timeout.C: + t.Fatal("the blocked heal attempt never dialed the primary") + } + } + // candidateBlocked is now dialed and stuck in verification; race the + // winning attempt in while it is still pending. + connection.healPrimary() + winning := candidateWinning.Load() + if winning == nil || connection.serverIndex != 0 || connection.client != winning { + t.Fatal("the winning heal attempt did not commit the primary connection") + } + + unblock() + select { + case <-blockedDone: + case <-time.After(5 * time.Second): + t.Fatal("the discarded heal attempt never returned") + } + candidateBlocked.awaitShutdown(t) + if connection.serverIndex != 0 || connection.client != winning { + t.Fatal("the discarded overlapping candidate must not replace the already-restored primary") + } +} + +// TestKeepAliveConsecutiveSuccessesResetsOnFailure verifies a single failed +// ping resets the consecutive-success streak: a success, a failure, and +// then only two more consecutive successes trigger exactly one heal +// attempt, firing only after the trailing pair - not after the lone +// success that preceded the failure. +func TestKeepAliveConsecutiveSuccessesResetsOnFailure(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + config := failoverTestConfig() + config.FallbackURLs = []string{"second", "third"} + config.KeepAliveInterval = time.Millisecond + config.RequestTimeout = 5 * time.Second + + pingResults := []error{nil, electrum.ErrTimeout, nil, nil} + var pingCalls atomic.Int32 + block := make(chan struct{}) + var unblockOnce sync.Once + unblock := func() { unblockOnce.Do(func() { close(block) }) } + defer unblock() + pingFn := func(ctx context.Context) error { + i := int(pingCalls.Add(1)) - 1 + if i < len(pingResults) { + return pingResults[i] + } + <-block + return ctx.Err() + } + + var primaryDials atomic.Int32 + connection, err := connect(ctx, config, func(_ context.Context, url string) (electrumClient, error) { + if url == "first" { + primaryDials.Add(1) + return &failoverTestClient{versionErr: errors.New("primary unavailable")}, nil + } + return &failoverTestClient{ping: pingFn}, nil + }) + if err != nil { + t.Fatal(err) + } + connection.clientMutex.Lock() + startedOnFallback := connection.serverIndex != 0 + connection.clientMutex.Unlock() + if !startedOnFallback { + t.Fatal("setup did not start on a fallback server") + } + + timeout := time.NewTimer(5 * time.Second) + defer timeout.Stop() + tick := time.NewTicker(time.Millisecond) + defer tick.Stop() + for pingCalls.Load() <= int32(len(pingResults)) { + select { + case <-tick.C: + case <-timeout.C: + t.Fatal("ping sequence did not complete") + } + } + // The next ping call is now blocked mid-flight; the sequence + // [success, failure, success, success] has fully resolved, and any heal + // attempt it triggers already ran synchronously within keepAlive before + // that next call could start. + unblock() + + if primaryDials.Load() != 2 { + t.Fatalf( + "expected exactly one heal attempt after the trailing consecutive pair (2 primary dials total), got [%d]", + primaryDials.Load(), + ) + } +} + +// TestHealPrimaryConsistentUnderConcurrentRequestFailover verifies that a +// concurrent request-driven failover moving serverIndex away from the +// server a heal attempt observed at start does not corrupt connection +// state: the heal attempt still commits cleanly and the client it displaces +// is retired exactly once, never left running or leaked. +func TestHealPrimaryConsistentUnderConcurrentRequestFailover(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + config := failoverTestConfig() + config.FallbackURLs = []string{"second", "third"} + config.KeepAliveInterval = time.Hour // heal is driven manually below + config.RequestTimeout = 5 * time.Second + + firstAttemptFailed := &failoverTestClient{versionErr: errors.New("primary temporarily unavailable")} + second := &failoverTestClient{header: func(context.Context) (*electrum.SubscribeHeadersResult, error) { + return nil, electrum.ErrTimeout + }} + third := new(failoverTestClient) + + committed := make(chan struct{}) + var unblockOnce sync.Once + unblock := func() { unblockOnce.Do(func() { close(committed) }) } + defer unblock() + primaryHealed := new(failoverTestClient) + primaryHealed.version = func(ctx context.Context) error { + select { + case <-committed: + return nil + case <-ctx.Done(): + return ctx.Err() + } + } + + var primaryDials atomic.Int32 + connection, err := connect(ctx, config, func(_ context.Context, url string) (electrumClient, error) { + switch url { + case "first": + if primaryDials.Add(1) == 1 { + return firstAttemptFailed, nil + } + return primaryHealed, nil + case "second": + return second, nil + default: + return third, nil + } + }) + if err != nil { + t.Fatal(err) + } + if connection.serverIndex != 1 || connection.client != second { + t.Fatal("setup did not start on the first fallback server") + } + firstAttemptFailed.awaitShutdown(t) + + healDone := make(chan struct{}) + go func() { + connection.healPrimary() + close(healDone) + }() + + timeout := time.NewTimer(5 * time.Second) + defer timeout.Stop() + tick := time.NewTicker(time.Millisecond) + defer tick.Stop() + for primaryDials.Load() < 2 { + select { + case <-tick.C: + case <-timeout.C: + t.Fatal("the heal attempt never dialed the primary") + } + } + + // A concurrent request against "second" fails and fails over to + // "third", moving serverIndex from 1 to 2 while the heal attempt above + // is still probing the primary. + if _, err := connection.GetLatestBlockHeight(); err != nil { + t.Fatalf("fallback rotation request failed: %v", err) + } + if connection.serverIndex != 2 || connection.client != third { + t.Fatal("request-driven failover did not move to the second fallback server") + } + second.awaitShutdown(t) + + unblock() + select { + case <-healDone: + case <-time.After(5 * time.Second): + t.Fatal("heal attempt never returned") + } + + // The serverIndex == 0 discard guard only fires when the connection has + // already been restored to the primary by someone else; a concurrent + // move to a different fallback index does not stop the heal attempt + // from completing, so it must now own the connection cleanly. + if connection.serverIndex != 0 || connection.client != primaryHealed { + t.Fatal("heal attempt did not consistently commit the primary despite concurrent request failover") + } + third.awaitShutdown(t) +} diff --git a/pkg/bitcoin/electrum/failover_verification_test.go b/pkg/bitcoin/electrum/failover_verification_test.go new file mode 100644 index 0000000000..1e11701a92 --- /dev/null +++ b/pkg/bitcoin/electrum/failover_verification_test.go @@ -0,0 +1,332 @@ +package electrum + +import ( + "context" + "errors" + "sync/atomic" + "testing" + "time" + + "github.com/checksum0/go-electrum/electrum" + + "github.com/keep-network/keep-core/pkg/bitcoin" +) + +func TestVerificationUsesRequestTimeout(t *testing.T) { + for _, explicitURL := range []bool{false, true} { + for _, reconnect := range []bool{false, true} { + name := "server pool" + if explicitURL { + name = "explicit URL" + } + if reconnect { + name += "/reconnect" + } else { + name += "/initial connection" + } + t.Run(name, func(t *testing.T) { + parent, cancel := context.WithCancel(context.Background()) + defer cancel() + config := failoverTestConfig() + config.ConnectTimeout = 40 * time.Millisecond + config.RequestTimeout = 300 * time.Millisecond + config.ConnectRetryTimeout = 500 * time.Millisecond + config.RequestRetryTimeout = 500 * time.Millisecond + if explicitURL { + config.FallbackURLs = nil + } + first := new(failoverTestClient) + verified := new(failoverTestClient) + var dialDeadline time.Time + verified.version = func(ctx context.Context) error { + deadline, ok := ctx.Deadline() + if !ok || !deadline.After(dialDeadline) { + t.Error("verification inherited the dial deadline") + } + // Reply after the dial deadline but within the RPC timeout. + response := time.NewTimer(time.Until(dialDeadline.Add(40 * time.Millisecond))) + defer response.Stop() + select { + case <-response.C: + return ctx.Err() + case <-ctx.Done(): + return ctx.Err() + } + } + attempts := 0 + connection, err := connect(parent, config, func(ctx context.Context, _ string) (electrumClient, error) { + attempts++ + if reconnect && attempts == 1 { + return first, nil + } + dialDeadline, _ = ctx.Deadline() + return verified, nil + }) + if err != nil { + t.Fatal(err) + } + if reconnect { + first.Shutdown() + if _, err := connection.GetLatestBlockHeight(); err != nil { + t.Fatal(err) + } + } + if connection.client != verified || verified.versions.Load() != 1 || verified.IsShutdown() { + t.Fatal("verification within the RPC timeout did not retain the client") + } + }) + } + } +} + +func TestReconnectCallerCancellationPreservesCandidate(t *testing.T) { + for _, phase := range []string{"dial", "verification"} { + for _, deadline := range []bool{false, true} { + name := phase + "/cancellation" + if deadline { + name = phase + "/deadline" + } + t.Run(name, func(t *testing.T) { + parent, cancelParent := context.WithCancel(context.Background()) + defer cancelParent() + config := failoverTestConfig() + config.ConnectTimeout = time.Second + config.RequestTimeout = time.Second + first := new(failoverTestClient) + interrupted := new(failoverTestClient) + healthy := new(failoverTestClient) + var cancelCaller context.CancelFunc + interrupt := func(ctx context.Context) error { + if !deadline { + cancelCaller() + } + <-ctx.Done() + return ctx.Err() + } + interrupted.version = interrupt + var attempts []string + connection, err := connect(parent, config, func(ctx context.Context, url string) (electrumClient, error) { + attempts = append(attempts, url) + if len(attempts) == 1 { + return first, nil + } + if len(attempts) == 2 { + if phase == "dial" { + return nil, interrupt(ctx) + } + return interrupted, nil + } + return healthy, nil + }) + if err != nil { + t.Fatal(err) + } + first.Shutdown() + var caller context.Context + wantErr := context.Canceled + if deadline { + caller, cancelCaller = context.WithTimeout(parent, 100*time.Millisecond) + wantErr = context.DeadlineExceeded + } else { + caller, cancelCaller = context.WithCancel(parent) + } + defer cancelCaller() + if _, err := connection.GetTransactionConfirmations(caller, bitcoin.Hash{}); !errors.Is(err, wantErr) { + t.Fatalf("expected caller interruption, got %v", err) + } + if connection.serverIndex != 1 || connection.client != nil { + t.Error("caller interruption discarded the reconnect candidate") + } + if height, err := connection.GetLatestBlockHeight(); err != nil || height != 42 { + t.Fatalf("independent request could not reconnect: %d, %v", height, err) + } + if len(attempts) != 3 || attempts[0] != "first" || attempts[1] != "second" || attempts[2] != "second" { + t.Fatalf("independent request did not retry the preserved candidate: %v", attempts) + } + if phase == "verification" { + interrupted.awaitShutdown(t) + } + }) + } + } +} + +// TestReconnectPerCandidateTimeoutAdvancesCandidate covers a genuine +// per-candidate timeout (the candidate's own ConnectTimeout/RequestTimeout +// elapses while the enclosing connect/request retry budget still has ample +// room) - the only case that should advance past the candidate as unhealthy. +func TestReconnectPerCandidateTimeoutAdvancesCandidate(t *testing.T) { + for _, test := range []struct { + phase string + budget string + }{ + {"dial", "dial"}, + {"verification", "RPC"}, + } { + t.Run(test.phase+"/"+test.budget, func(t *testing.T) { + parent, cancel := context.WithCancel(context.Background()) + defer cancel() + config := failoverTestConfig() + config.FallbackURLs = []string{"second", "third"} + config.ConnectTimeout = time.Second + config.RequestTimeout = time.Second + config.ConnectRetryTimeout = 300 * time.Millisecond + config.RequestRetryTimeout = 500 * time.Millisecond + switch test.budget { + case "dial": + config.ConnectTimeout = 40 * time.Millisecond + case "RPC": + config.RequestTimeout = 40 * time.Millisecond + } + first := new(failoverTestClient) + second := &failoverTestClient{version: func(ctx context.Context) error { + if deadline, ok := ctx.Deadline(); !ok || deadline.After(time.Now().Add(config.RequestTimeout)) { + t.Error("verification exceeded the configured RPC timeout") + } + <-ctx.Done() + return ctx.Err() + }} + third := new(failoverTestClient) + connection, err := connect(parent, config, func(ctx context.Context, url string) (electrumClient, error) { + switch url { + case "first": + return first, nil + case "second": + if test.phase == "dial" { + <-ctx.Done() + return nil, ctx.Err() + } + return second, nil + default: + return third, nil + } + }) + if err != nil { + t.Fatal(err) + } + first.Shutdown() + if _, err := connection.GetLatestBlockHeight(); err == nil { + t.Fatal("expected reconnection to exhaust a per-candidate timeout") + } + if parent.Err() != nil || connection.serverIndex != 2 || connection.client != nil { + t.Fatal("per-candidate timeout did not advance the reconnect candidate") + } + if height, err := connection.GetLatestBlockHeight(); err != nil || height != 42 { + t.Fatalf("independent request did not reach the third server: %d, %v", height, err) + } + if third.versions.Load() != 1 { + t.Fatal("replacement client was not verified") + } + if test.phase == "verification" { + second.awaitShutdown(t) + } + }) + } +} + +// TestReconnectRetryBudgetExhaustionPreservesCandidate covers the enclosing +// connect/request retry budget itself expiring mid-attempt (rather than the +// candidate's own per-request timeout). electrumConnect must not attribute +// that to the candidate's health: the candidate is preserved (retried on +// the next attempt), never advanced past as unhealthy. +func TestReconnectRetryBudgetExhaustionPreservesCandidate(t *testing.T) { + for _, test := range []struct { + phase string + budget string + }{ + {"dial", "connection retry"}, + {"verification", "connection retry"}, + {"dial", "request retry"}, + {"verification", "request retry"}, + } { + t.Run(test.phase+"/"+test.budget, func(t *testing.T) { + parent, cancel := context.WithCancel(context.Background()) + defer cancel() + config := failoverTestConfig() + config.FallbackURLs = []string{"second", "third"} + config.ConnectTimeout = time.Second + config.RequestTimeout = time.Second + config.ConnectRetryTimeout = 300 * time.Millisecond + config.RequestRetryTimeout = 500 * time.Millisecond + if test.budget == "request retry" { + config.ConnectRetryTimeout = time.Second + config.RequestRetryTimeout = 100 * time.Millisecond + } + first := new(failoverTestClient) + var verifyCalls atomic.Int32 + second := &failoverTestClient{version: func(ctx context.Context) error { + verifyCalls.Add(1) + <-ctx.Done() + return ctx.Err() + }} + third := new(failoverTestClient) + connection, err := connect(parent, config, func(ctx context.Context, url string) (electrumClient, error) { + switch url { + case "first": + return first, nil + case "second": + if test.phase == "dial" { + <-ctx.Done() + return nil, ctx.Err() + } + return second, nil + default: + return third, nil + } + }) + if err != nil { + t.Fatal(err) + } + first.Shutdown() + if _, err := connection.GetLatestBlockHeight(); err == nil { + t.Fatal("expected the retry budget to be exhausted") + } + if parent.Err() != nil { + t.Fatal("the caller must remain active after the internal timeout") + } + if connection.serverIndex != 1 || connection.client != nil { + t.Fatal("budget exhaustion incorrectly advanced past the preserved candidate") + } + if third.versions.Load() != 0 { + t.Fatal("budget exhaustion incorrectly reached an untried server") + } + }) + } +} + +// TestElectrumConnectRejectsGenesisMismatch verifies the D4 genesis identity +// behavior: the first successfully verified server's genesis hash becomes +// this connection's chain reference, and a later candidate reporting a +// different genesis hash is rejected outright rather than retained. +func TestElectrumConnectRejectsGenesisMismatch(t *testing.T) { + parent, cancel := context.WithCancel(context.Background()) + defer cancel() + config := failoverTestConfig() + config.FallbackURLs = []string{"second"} + config.RequestRetryTimeout = 200 * time.Millisecond + first := &failoverTestClient{serverFeatures: func(context.Context) (*electrum.ServerFeaturesResult, error) { + return &electrum.ServerFeaturesResult{GenesisHash: "aaaa"}, nil + }} + wrongChain := &failoverTestClient{serverFeatures: func(context.Context) (*electrum.ServerFeaturesResult, error) { + return &electrum.ServerFeaturesResult{GenesisHash: "bbbb"}, nil + }} + connection, err := connect(parent, config, func(_ context.Context, url string) (electrumClient, error) { + if url == "first" { + return first, nil + } + return wrongChain, nil + }) + if err != nil { + t.Fatal(err) + } + if connection.verifiedGenesisHash != "aaaa" { + t.Fatalf("expected the first server's genesis hash to be adopted, got %q", connection.verifiedGenesisHash) + } + first.Shutdown() + if _, err := connection.GetLatestBlockHeight(); err == nil { + t.Fatal("expected the wrong-chain candidate to be rejected") + } + if connection.client == wrongChain || !wrongChain.IsShutdown() { + t.Fatal("a candidate reporting a mismatched genesis hash must not be retained") + } +} diff --git a/pkg/bitcoin/electrum/integer_conversion_test.go b/pkg/bitcoin/electrum/integer_conversion_test.go new file mode 100644 index 0000000000..0dae642375 --- /dev/null +++ b/pkg/bitcoin/electrum/integer_conversion_test.go @@ -0,0 +1,41 @@ +package electrum + +import ( + "math" + "strconv" + "testing" + + "github.com/keep-network/keep-core/pkg/bitcoin" +) + +func TestElectrumBlockHeightBounds(t *testing.T) { + if strconv.IntSize < 64 { + t.Skip("uint cannot exceed the Electrum height range") + } + height64 := uint64(math.MaxUint32) + 1 + height := uint(height64) + connection := new(Connection) + if _, err := connection.GetBlockHeader(height); err == nil { + t.Fatal("accepted out-of-range block header height") + } + if _, err := connection.GetTransactionMerkleProof(bitcoin.Hash{}, height); err == nil { + t.Fatal("accepted out-of-range merkle proof height") + } + if _, err := connection.GetCoinbaseTxHash(height); err == nil { + t.Fatal("accepted out-of-range coinbase height") + } +} + +func TestConvertUtxoItemsAmountBounds(t *testing.T) { + for _, value := range []uint64{0, 1, math.MaxInt64, math.MaxInt64 + 1, math.MaxUint64} { + utxos, err := convertUtxoItems([]*scriptUtxoItem{{value: value, outputIndex: 3}}) + if value > math.MaxInt64 { + if err == nil { + t.Fatalf("accepted amount %d", value) + } + } else if err != nil || len(utxos) != 1 || + uint64(utxos[0].Value) != value || utxos[0].Outpoint.OutputIndex != 3 { + t.Fatalf("amount %d: got %v, %v", value, utxos, err) + } + } +} diff --git a/pkg/bitcoin/electrum/provisional_client_test.go b/pkg/bitcoin/electrum/provisional_client_test.go new file mode 100644 index 0000000000..af9cd4471f --- /dev/null +++ b/pkg/bitcoin/electrum/provisional_client_test.go @@ -0,0 +1,179 @@ +package electrum + +import ( + "context" + "testing" + "time" +) + +func TestProvisionalVerificationDeadlineUnblocksWrite(t *testing.T) { + for _, budget := range []string{"caller cancellation", "caller deadline", "RPC", "connection retry", "request retry"} { + t.Run(budget, func(t *testing.T) { + parent, cancelParent := context.WithCancel(context.Background()) + defer cancelParent() + config := failoverTestConfig() + config.FallbackURLs = []string{"second", "third"} + config.ConnectTimeout = time.Second + config.RequestTimeout = time.Second + config.ConnectRetryTimeout = 150 * time.Millisecond + config.RequestRetryTimeout = 250 * time.Millisecond + switch budget { + case "RPC": + config.RequestTimeout = 50 * time.Millisecond + case "connection retry": + config.ConnectRetryTimeout = 50 * time.Millisecond + case "request retry": + config.RequestRetryTimeout = 50 * time.Millisecond + } + first := new(failoverTestClient) + provisional := new(failoverTestClient) + write := newBlockedClientWrite(provisional) + provisional.version = write.call + healthy := new(failoverTestClient) + var attempts []string + connection, err := connect(parent, config, func(_ context.Context, url string) (electrumClient, error) { + attempts = append(attempts, url) + switch len(attempts) { + case 1: + return first, nil + case 2: + return provisional, nil + default: + return healthy, nil + } + }) + if err != nil { + t.Fatal(err) + } + first.Shutdown() + caller, cancelCaller := context.WithCancel(parent) + if budget == "caller deadline" { + cancelCaller() + caller, cancelCaller = context.WithTimeout(parent, 50*time.Millisecond) + } + defer cancelCaller() + result := make(chan error, 1) + finished := make(chan struct{}) + go func() { + defer close(finished) + _, err := requestWithRetry(caller, connection, func(context.Context, electrumClient) (int, error) { + return 42, nil + }, "provisional verification") + result <- err + }() + t.Cleanup(func() { + cancelCaller() + write.release() + awaitClientResult(t, finished) + }) + awaitClientResult(t, write.started) + if budget == "caller cancellation" { + cancelCaller() + } + select { + case <-finished: + case <-time.After(time.Second): + t.Fatal("verification deadline did not interrupt the provisional client's write") + } + if err := <-result; err == nil { + t.Fatal("expected interrupted verification to fail") + } + if parent.Err() != nil { + t.Fatal("connection cancellation must not be needed to unblock verification") + } + provisional.awaitShutdown(t) + if height, err := connection.GetLatestBlockHeight(); err != nil || height != 42 { + t.Fatalf("independent request remained blocked after verification: %d, %v", height, err) + } + wantURL := "third" + if budget == "caller cancellation" || budget == "caller deadline" || + budget == "connection retry" || budget == "request retry" { + // These sub-cases truncate the enclosing retry budget itself + // rather than the candidate's own per-request timeout, so + // the interrupted candidate is preserved (retried) instead + // of being advanced past as unhealthy. + wantURL = "second" + } + if len(attempts) != 3 || attempts[2] != wantURL { + t.Fatalf("unexpected candidate after verification timeout: %v", attempts) + } + }) + } +} + +func TestVerifiedClientOutlivesVerificationContext(t *testing.T) { + parent, cancel := context.WithCancel(context.Background()) + defer cancel() + config := failoverTestConfig() + var verification context.Context + client := &failoverTestClient{version: func(ctx context.Context) error { + verification = ctx + return nil + }} + connection, err := connect(parent, config, func(context.Context, string) (electrumClient, error) { + return client, nil + }) + if err != nil { + t.Fatal(err) + } + awaitClientResult(t, verification.Done()) + // Pass the former verification deadline before using the retained client. + deadline, _ := verification.Deadline() + <-time.After(time.Until(deadline) + 40*time.Millisecond) + if client.IsShutdown() { + t.Fatal("verification cancellation aborted a retained client") + } + if height, err := connection.GetLatestBlockHeight(); err != nil || height != 42 { + t.Fatalf("verified client did not remain usable: %d, %v", height, err) + } + if client.versions.Load() != 1 { + t.Fatal("verification cancellation forced an unnecessary reconnect") + } +} + +// TestVerificationSuccessAfterDeadlineIsNotRetained is a regression test for +// the verification-deadline race: a candidate's ServerVersion RPC can, in +// principle, return success just after its own requestCtx deadline passed. +// The re-check of requestCtx.Err() after stopVerification() must still +// reject that client rather than publish an aborted client as healthy. +func TestVerificationSuccessAfterDeadlineIsNotRetained(t *testing.T) { + parent, cancel := context.WithCancel(context.Background()) + defer cancel() + config := failoverTestConfig() + config.FallbackURLs = []string{"second", "third"} + config.RequestTimeout = 30 * time.Millisecond + first := new(failoverTestClient) + raced := &failoverTestClient{version: func(ctx context.Context) error { + if deadline, ok := ctx.Deadline(); ok { + <-time.After(time.Until(deadline) + 20*time.Millisecond) + } + // Success, but only after requestCtx's own deadline already passed. + return nil + }} + healthy := new(failoverTestClient) + attempts := 0 + connection, err := connect(parent, config, func(context.Context, string) (electrumClient, error) { + attempts++ + switch attempts { + case 1: + return first, nil + case 2: + return raced, nil + default: + return healthy, nil + } + }) + if err != nil { + t.Fatal(err) + } + first.Shutdown() + if height, err := connection.GetLatestBlockHeight(); err != nil || height != 42 { + t.Fatalf("reconnection did not recover past the raced candidate: %d, %v", height, err) + } + if connection.client == raced || !raced.IsShutdown() { + t.Fatal("a verification that succeeded after its deadline must not be retained") + } + if connection.client != healthy { + t.Fatal("connection did not advance past the raced candidate to the next server") + } +} diff --git a/pkg/bitcoin/electrum/skip_classifier_integration_test.go b/pkg/bitcoin/electrum/skip_classifier_integration_test.go new file mode 100644 index 0000000000..92f485676e --- /dev/null +++ b/pkg/bitcoin/electrum/skip_classifier_integration_test.go @@ -0,0 +1,98 @@ +//go:build integration + +package electrum_test + +import ( + "errors" + "fmt" + "testing" + + goelectrum "github.com/checksum0/go-electrum/electrum" + + "github.com/keep-network/keep-core/pkg/bitcoin/electrum" + "github.com/keep-network/keep-core/pkg/wrappers" +) + +// TestShouldSkipElectrumIntegrationError pins the transient-failure classifier +// used by the integration suite to decide whether a failure is the public +// Electrum service misbehaving (skip) or a real defect (fail). +// +// Matching is by typed sentinel, so these cases fail if the wrapping chain +// loses %w anywhere, or if the classifier starts swallowing unrelated errors; +// a reworded upstream error message cannot silently change what counts as +// transient. +func TestShouldSkipElectrumIntegrationError(t *testing.T) { + tests := map[string]struct { + err error + expectedSkip bool + }{ + "nil error": { + err: nil, + expectedSkip: false, + }, + "bare request timeout": { + err: goelectrum.ErrTimeout, + expectedSkip: true, + }, + "wrapped request timeout": { + err: fmt.Errorf( + "failed to get raw transaction with ID [abc]: [%w]", + goelectrum.ErrTimeout, + ), + expectedSkip: true, + }, + "bare retry timeout": { + err: wrappers.ErrRetryTimeout, + expectedSkip: true, + }, + "wrapped retry timeout": { + err: fmt.Errorf( + "failed to get the latest block height: [%w]", + wrappers.ErrRetryTimeout, + ), + expectedSkip: true, + }, + "bare missing fee estimate": { + err: electrum.ErrFeeEstimateUnavailable, + expectedSkip: true, + }, + "wrapped missing fee estimate": { + err: fmt.Errorf( + "failed to get fee: [%w]", + electrum.ErrFeeEstimateUnavailable, + ), + expectedSkip: true, + }, + "doubly wrapped sentinel": { + err: fmt.Errorf( + "outer: [%w]", + fmt.Errorf("inner: [%w]", wrappers.ErrRetryTimeout), + ), + expectedSkip: true, + }, + "unrelated error": { + err: errors.New("transaction not found"), + expectedSkip: false, + }, + "error whose text merely mentions a timeout": { + err: errors.New("server said: request timeout is 30s"), + expectedSkip: false, + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + actualSkip := shouldSkipElectrumIntegrationError(test.err) + if actualSkip != test.expectedSkip { + t.Errorf( + "unexpected skip decision for [%v]\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + test.err, + test.expectedSkip, + actualSkip, + ) + } + }) + } +} diff --git a/pkg/bitcoin/electrum/testdata_manifest_test.go b/pkg/bitcoin/electrum/testdata_manifest_test.go new file mode 100644 index 0000000000..41fc4f63de --- /dev/null +++ b/pkg/bitcoin/electrum/testdata_manifest_test.go @@ -0,0 +1,129 @@ +package electrum + +import ( + "testing" + + "github.com/keep-network/keep-core/pkg/bitcoin" + + testData "github.com/keep-network/keep-core/internal/testdata/bitcoin" +) + +// TestRequiredVectorsPresent guards the fixtures declared required by +// internal/testdata/bitcoin/manifest.go against accidental deletion. +// +// It deliberately lives here rather than beside the manifest: the Go tool +// excludes any directory named "testdata" from package patterns, so a test +// inside internal/testdata/bitcoin is never matched by `go test ./...` and +// would only run when named explicitly. Hosting it in the package that +// consumes the fixtures puts it in the ordinary suite, so deleting a vector +// the electrum integration suite depends on fails the default build rather +// than silently turning those integration tests into skips. +func TestRequiredVectorsPresent(t *testing.T) { + for _, network := range testData.RequiredBlocks { + data, ok := testData.Blocks[network] + if !ok { + t.Errorf( + "Blocks is missing a required entry for network [%s]; add it, "+ + "or remove [%s] from RequiredBlocks in manifest.go if the "+ + "electrum integration suite no longer needs it", + network, network, + ) + continue + } + if data.BlockHeight == 0 { + t.Errorf("Blocks[%s].BlockHeight is zero-valued", network) + } + if data.BlockHeader == nil { + t.Errorf("Blocks[%s].BlockHeader is nil", network) + } + if data.CoinbaseTxHash == (bitcoin.Hash{}) { + t.Errorf("Blocks[%s].CoinbaseTxHash is zero-valued", network) + } + } + + for _, network := range testData.RequiredTransactions { + transactions, ok := testData.Transactions[network] + if !ok || len(transactions) == 0 { + t.Errorf( + "Transactions is missing a required non-empty entry for "+ + "network [%s]; add it, or remove [%s] from "+ + "RequiredTransactions in manifest.go if the electrum "+ + "integration suite no longer needs it", + network, network, + ) + continue + } + for name, tx := range transactions { + if tx.TxHash == (bitcoin.Hash{}) { + t.Errorf("Transactions[%s][%s].TxHash is zero-valued", network, name) + } + if tx.BlockHeight == 0 { + t.Errorf( + "Transactions[%s][%s].BlockHeight is zero-valued", + network, + name, + ) + } + } + } + + for _, network := range testData.RequiredTxMerkleProofs { + data, ok := testData.TxMerkleProofs[network] + if !ok { + t.Errorf( + "TxMerkleProofs is missing a required entry for network [%s]; "+ + "add it, or remove [%s] from RequiredTxMerkleProofs in "+ + "manifest.go if the electrum integration suite no longer "+ + "needs it", + network, network, + ) + continue + } + if data.TxHash == (bitcoin.Hash{}) { + t.Errorf("TxMerkleProofs[%s].TxHash is zero-valued", network) + } + if data.BlockHeight == 0 { + t.Errorf("TxMerkleProofs[%s].BlockHeight is zero-valued", network) + } + if data.MerkleProof == nil { + t.Errorf("TxMerkleProofs[%s].MerkleProof is nil", network) + } else if len(data.MerkleProof.MerkleNodes) == 0 { + t.Errorf( + "TxMerkleProofs[%s].MerkleProof.MerkleNodes is empty", + network, + ) + } + } + + for _, network := range testData.RequiredTransactionsForPublicKeyHash { + data, ok := testData.TransactionsForPublicKeyHash[network] + if !ok { + t.Errorf( + "TransactionsForPublicKeyHash is missing a required entry for "+ + "network [%s]; add it, or remove [%s] from "+ + "RequiredTransactionsForPublicKeyHash in manifest.go if the "+ + "electrum integration suite no longer needs it", + network, network, + ) + continue + } + if len(data.PublicKeyHash) == 0 { + t.Errorf( + "TransactionsForPublicKeyHash[%s].PublicKeyHash is empty", + network, + ) + } + if len(data.Transactions) == 0 { + t.Errorf( + "TransactionsForPublicKeyHash[%s].Transactions is empty", + network, + ) + } + if len(data.Utxos) == 0 { + t.Errorf( + "TransactionsForPublicKeyHash[%s].Utxos is empty", + network, + ) + } + } +} diff --git a/pkg/bitcoin/estimator.go b/pkg/bitcoin/estimator.go index e8c61f7577..e31b3241e9 100644 --- a/pkg/bitcoin/estimator.go +++ b/pkg/bitcoin/estimator.go @@ -2,6 +2,8 @@ package bitcoin import ( "fmt" + "math" + "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/mempool" @@ -247,6 +249,18 @@ func (tfe *TransactionFeeEstimator) EstimateFee( return 0, fmt.Errorf("cannot get estimated sat/vbyte fee: [%v]", err) } + if transactionVirtualSize <= 0 { + return 0, fmt.Errorf( + "invalid transaction virtual size: [%v]", + transactionVirtualSize, + ) + } + if satPerVByteFee <= 0 { + return 0, fmt.Errorf("estimated sat/vbyte fee is less than or equal zero") + } + if satPerVByteFee > math.MaxInt64/transactionVirtualSize { + return 0, fmt.Errorf("estimated fee exceeds int64 range") + } fee := satPerVByteFee * transactionVirtualSize // Just in case check. diff --git a/pkg/bitcoin/integer_conversion_test.go b/pkg/bitcoin/integer_conversion_test.go new file mode 100644 index 0000000000..7288bcd689 --- /dev/null +++ b/pkg/bitcoin/integer_conversion_test.go @@ -0,0 +1,46 @@ +package bitcoin + +import ( + "bytes" + "math" + "testing" +) + +func TestSignedVersionWireCompatibility(t *testing.T) { + for _, tc := range []struct { + version int32 + bytes []byte + }{ + {0, []byte{0, 0, 0, 0}}, + {-1, []byte{255, 255, 255, 255}}, + {math.MinInt32, []byte{0, 0, 0, 128}}, + {math.MaxInt32, []byte{255, 255, 255, 127}}, + } { + header := (&BlockHeader{Version: tc.version}).Serialize() + version := (&Transaction{Version: tc.version}).SerializeVersion() + if !bytes.Equal(header[:4], tc.bytes) || !bytes.Equal(version[:], tc.bytes) { + t.Fatalf("version %d changed wire encoding", tc.version) + } + decoded := new(BlockHeader) + decoded.Deserialize(header) + if decoded.Version != tc.version { + t.Fatalf("version %d decoded as %d", tc.version, decoded.Version) + } + } +} + +func TestTransactionFeeEstimatorOverflow(t *testing.T) { + chain := newLocalChain() + for _, tc := range []struct{ rate, size int64 }{ + {math.MaxInt64, 2}, {1<<62 + 1, 4}, {-1, 1}, {1, -1}, + } { + chain.setSatPerVByteFee(tc.rate) + if fee, err := NewTransactionFeeEstimator(chain).EstimateFee(tc.size); err == nil { + t.Fatalf("accepted rate %d, size %d: %d", tc.rate, tc.size, fee) + } + } + chain.setSatPerVByteFee(math.MaxInt64) + if fee, err := NewTransactionFeeEstimator(chain).EstimateFee(1); err != nil || fee != math.MaxInt64 { + t.Fatalf("valid boundary: %d, %v", fee, err) + } +} diff --git a/pkg/bitcoin/script.go b/pkg/bitcoin/script.go index ecdb6be214..a9237c930b 100644 --- a/pkg/bitcoin/script.go +++ b/pkg/bitcoin/script.go @@ -53,7 +53,10 @@ func NewScriptFromVarLenData(varLenData []byte) (Script, error) { // Make sure the combined byte length of the script and the byte length // of the CompactSizeUint matches the total byte length of the variable // length data. Otherwise, the input data slice is malformed. - if uint64(scriptByteLength)+uint64(compactByteLength) != uint64(len(varLenData)) { + if compactByteLength < 0 || compactByteLength > len(varLenData) { + return nil, fmt.Errorf("malformed var len data") + } + if uint64(scriptByteLength) != uint64(len(varLenData))-uint64(compactByteLength) { return nil, fmt.Errorf("malformed var len data") } diff --git a/pkg/bitcoin/transaction.go b/pkg/bitcoin/transaction.go index f78f6a9ff5..08dfaf951d 100644 --- a/pkg/bitcoin/transaction.go +++ b/pkg/bitcoin/transaction.go @@ -122,6 +122,7 @@ func (t *Transaction) Serialize( // 4-byte array. func (t *Transaction) SerializeVersion() [4]byte { result := [4]byte{} + // #nosec G115 -- Bitcoin version fields encode the exact signed 32-bit bit pattern. binary.LittleEndian.PutUint32(result[:], uint32(t.Version)) return result } diff --git a/pkg/bitcoin/transaction_builder.go b/pkg/bitcoin/transaction_builder.go index 83bce0a6b0..d8cd5b1028 100644 --- a/pkg/bitcoin/transaction_builder.go +++ b/pkg/bitcoin/transaction_builder.go @@ -164,7 +164,7 @@ func (tb *TransactionBuilder) getScript( } outputIndex := utxo.Outpoint.OutputIndex - if outputIndex >= uint32(len(transaction.Outputs)) { + if uint64(outputIndex) >= uint64(len(transaction.Outputs)) { return nil, fmt.Errorf( "output index [%d] out of range for transaction [%s] "+ "with [%d] outputs", diff --git a/pkg/bitcoin/transaction_builder_test.go b/pkg/bitcoin/transaction_builder_test.go index b1acc70567..6965e8ce8a 100644 --- a/pkg/bitcoin/transaction_builder_test.go +++ b/pkg/bitcoin/transaction_builder_test.go @@ -1,6 +1,7 @@ package bitcoin import ( + "encoding/hex" "fmt" "math/big" "reflect" @@ -13,28 +14,6 @@ import ( "github.com/keep-network/keep-core/internal/testutils" ) -func TestNewTransactionBuilder(t *testing.T) { - localChain := newLocalChain() - builder := NewTransactionBuilder(localChain) - - if !reflect.DeepEqual(localChain, builder.chain) { - t.Error("unexpected chain reference") - } - - testutils.AssertIntsEqual( - t, - "internal version", - 1, - int(builder.internal.Version), - ) - testutils.AssertIntsEqual( - t, - "internal locktime", - 0, - int(builder.internal.LockTime), - ) -} - func TestTransactionBuilder_AddPublicKeyHashInput(t *testing.T) { var tests = map[string]struct { inputTransactionHex string @@ -601,3 +580,80 @@ func TestTransactionBuilder_ComputeSignatureHashesMissingPrevOut(t *testing.T) { t.Fatalf("unexpected error: [%v]", err) } } + +// --- Benchmarks --- + +// witnessP2WPKHTxHex is a P2WPKH transaction whose output[0] (value=35400) +// is used as the UTXO source for ComputeSignatureHashes benchmarks. +// https://live.blockcypher.com/btc-testnet/tx/f8eaf242a55ea15e602f9f990e33f67f99dfbe25d1802bbde63cc1caabf99668 +const witnessP2WPKHTxHex = "01000000000102bc187be612bc3db8cfcdec56b75e9bc0262ab6eacfe27cc1a699bacd53e3d07400000000c948304502210089a89aaf3fec97ac9ffa91cdff59829f0cb3ef852a468153e2c0e2b473466d2e022072902bb923ef016ac52e941ced78f816bf27991c2b73211e227db27ec200bc0a012103989d253b17a6a0f41838b84ff0d20e8898f9d7b1a98f2564da4cc29dcf8581d94c5c14934b98637ca318a4d6e7ca6ffd1690b8e77df6377508f9f0c90d000395237576a9148db50eb52063ea9d98b3eac91489a90f738986f68763ac6776a914e257eccafbc07c381642ce6e7e55120fb077fbed8804e0250162b175ac68ffffffffdc557e737b6688c5712649b86f7757a722dc3d42786f23b2fa826394dfec545c0000000000ffffffff01488a0000000000001600148db50eb52063ea9d98b3eac91489a90f738986f6000347304402203747f5ee31334b11ebac6a2a156b1584605de8d91a654cd703f9c8438634997402202059d680211776f93c25636266b02e059ed9fcc6209f7d3d9926c49a0d8750ed012103989d253b17a6a0f41838b84ff0d20e8898f9d7b1a98f2564da4cc29dcf8581d95c14934b98637ca318a4d6e7ca6ffd1690b8e77df6377508f9f0c90d000395237576a9148db50eb52063ea9d98b3eac91489a90f738986f68763ac6776a914e257eccafbc07c381642ce6e7e55120fb077fbed8804e0250162b175ac6800000000" + +// buildSigHashBuilder constructs a TransactionBuilder with n inputs all +// pointing to the same P2WPKH UTXO. ComputeSignatureHashes is non-mutating so +// the same builder can be reused across b.N iterations. +func buildSigHashBuilder(b *testing.B, n int) *TransactionBuilder { + b.Helper() + + txBytes, err := hex.DecodeString(witnessP2WPKHTxHex) + if err != nil { + b.Fatal(err) + } + + tx := new(Transaction) + if err := tx.Deserialize(txBytes); err != nil { + b.Fatal(err) + } + + localChain := newLocalChain() + if err := localChain.addTransaction(tx); err != nil { + b.Fatal(err) + } + + builder := NewTransactionBuilder(localChain) + utxo := &UnspentTransactionOutput{ + Outpoint: &TransactionOutpoint{ + TransactionHash: tx.Hash(), + OutputIndex: 0, + }, + Value: 35400, + } + for i := 0; i < n; i++ { + if err := builder.AddPublicKeyHashInput(utxo); err != nil { + b.Fatal(err) + } + } + return builder +} + +func BenchmarkComputeSignatureHashes_1Input(b *testing.B) { + builder := buildSigHashBuilder(b, 1) + if _, err := builder.ComputeSignatureHashes(); err != nil { + b.Fatal(err) + } + b.ResetTimer() + for range b.N { + _, _ = builder.ComputeSignatureHashes() + } +} + +func BenchmarkComputeSignatureHashes_5Inputs(b *testing.B) { + builder := buildSigHashBuilder(b, 5) + if _, err := builder.ComputeSignatureHashes(); err != nil { + b.Fatal(err) + } + b.ResetTimer() + for range b.N { + _, _ = builder.ComputeSignatureHashes() + } +} + +func BenchmarkComputeSignatureHashes_20Inputs(b *testing.B) { + builder := buildSigHashBuilder(b, 20) + if _, err := builder.ComputeSignatureHashes(); err != nil { + b.Fatal(err) + } + b.ResetTimer() + for range b.N { + _, _ = builder.ComputeSignatureHashes() + } +} diff --git a/pkg/bls/bls_test.go b/pkg/bls/bls_test.go index 0d3a6da03a..e0ca52d53c 100644 --- a/pkg/bls/bls_test.go +++ b/pkg/bls/bls_test.go @@ -2,8 +2,11 @@ package bls import ( "crypto/rand" + "fmt" "math/big" + "sort" "testing" + "time" bn256 "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare" @@ -185,3 +188,119 @@ func TestThresholdBLS(t *testing.T) { } } + +// --- Benchmarks --- + +func BenchmarkSign(b *testing.B) { + pi, _ := new(big.Int).SetString( + "31415926535897932384626433832795028841971693993751058209749445923078164062862", 10) + message := pi.Bytes() + secretKey := big.NewInt(123) + b.ResetTimer() + for range b.N { + Sign(secretKey, message) + } +} + +func BenchmarkVerify(b *testing.B) { + pi, _ := new(big.Int).SetString( + "31415926535897932384626433832795028841971693993751058209749445923078164062862", 10) + message := pi.Bytes() + secretKey := big.NewInt(123) + publicKey := new(bn256.G2).ScalarBaseMult(secretKey) + signature := Sign(secretKey, message) + b.ResetTimer() + for range b.N { + Verify(publicKey, message, signature) + } +} + +// BenchmarkAggregateBLS benchmarks aggregate signature verification for group +// sizes representative of small committees (10), medium (50), and production +// random beacon groups (100). +func BenchmarkAggregateBLS(b *testing.B) { + pi, _ := new(big.Int).SetString( + "31415926535897932384626433832795028841971693993751058209749445923078164062862", 10) + message := new(bn256.G1).ScalarBaseMult(pi) + + for _, n := range []int{10, 50, 100} { + n := n + var signatures []*bn256.G1 + var publicKeys []*bn256.G2 + for i := 0; i < n; i++ { + k, _, err := bn256.RandomG1(rand.Reader) + if err != nil { + b.Fatal(err) + } + pub := new(bn256.G2).ScalarBaseMult(k) + publicKeys = append(publicKeys, pub) + signatures = append(signatures, SignG1(k, message)) + } + b.Run(fmt.Sprintf("N=%d", n), func(b *testing.B) { + b.ResetTimer() + for range b.N { + aggSig := AggregateG1Points(signatures) + aggPub := AggregateG2Points(publicKeys) + VerifyG1(aggPub, message, aggSig) + } + }) + } +} + +// BenchmarkThresholdVerify benchmarks threshold signature recovery with the +// 33-of-64 configuration used by the production random beacon. +func BenchmarkThresholdVerify(b *testing.B) { + pi, _ := new(big.Int).SetString( + "31415926535897932384626433832795028841971693993751058209749445923078164062862", 10) + message := new(bn256.G1).ScalarBaseMult(pi) + + const numPlayers = 64 + const threshold = 33 + + var masterSecretKey []*big.Int + var signatureShares []*SignatureShare + + for i := 0; i < threshold; i++ { + sk, _, err := bn256.RandomG2(rand.Reader) + if err != nil { + b.Fatal(err) + } + masterSecretKey = append(masterSecretKey, sk) + } + for i := 1; i <= numPlayers; i++ { + share := GetSecretKeyShare(masterSecretKey, i) + signatureShares = append(signatureShares, &SignatureShare{ + I: i, + V: SignG1(share.V, message), + }) + } + + const minimumLatencySamples = 100 + latencies := make([]time.Duration, 0, max(b.N, minimumLatencySamples)) + b.ResetTimer() + for range b.N { + start := time.Now() + _, _ = RecoverSignature(signatureShares[:threshold], threshold) + latencies = append(latencies, time.Since(start)) + } + b.StopTimer() + + // Keep p99 meaningful even when Go calibrates a short benchmark run to + // fewer than 100 timed iterations. + for len(latencies) < minimumLatencySamples { + start := time.Now() + _, _ = RecoverSignature(signatureShares[:threshold], threshold) + latencies = append(latencies, time.Since(start)) + } + + sort.Slice(latencies, func(i, j int) bool { + return latencies[i] < latencies[j] + }) + reportPercentile := func(percentile int, unit string) { + index := (percentile*len(latencies)+99)/100 - 1 + b.ReportMetric(float64(latencies[index].Nanoseconds()), unit) + } + reportPercentile(50, "p50-ns/op") + reportPercentile(95, "p95-ns/op") + reportPercentile(99, "p99-ns/op") +} diff --git a/pkg/cache/cache.go b/pkg/cache/cache.go new file mode 100644 index 0000000000..4917a4d683 --- /dev/null +++ b/pkg/cache/cache.go @@ -0,0 +1,102 @@ +// Package cache provides a time cache implementation safe for concurrent use +// without the need of additional locking. +package cache + +import ( + "container/list" + "sync" + "time" + + "github.com/ipfs/go-log" +) + +var logger = log.Logger("keep-cache") + +// TimeCache provides a time cache safe for concurrent use by +// multiple goroutines without additional locking or coordination. +type TimeCache struct { + // all items in the cache in the order they were added + // most recent items are on the front of the indexer; + // it is used to optimize cache sweeping + indexer *list.List + // item in the cache with the timestamp it's been added + // to the cache the last time + cache map[string]time.Time + // the timespan after which entry in the cache is considered + // as outdated and can be removed from the cache + timespan time.Duration + mutex sync.RWMutex +} + +// NewTimeCache creates a new cache instance with provided timespan. +func NewTimeCache(timespan time.Duration) *TimeCache { + return &TimeCache{ + indexer: list.New(), + cache: make(map[string]time.Time), + timespan: timespan, + } +} + +// Add adds an entry to the cache. Returns `true` if entry was not present in +// the cache and was successfully added into it. Returns `false` if +// entry is already in the cache. This method is synchronized. +func (tc *TimeCache) Add(item string) bool { + tc.mutex.Lock() + defer tc.mutex.Unlock() + + _, ok := tc.cache[item] + if ok { + return false + } + + tc.sweep() + + tc.cache[item] = time.Now() + tc.indexer.PushFront(item) + return true +} + +// Has checks presence of an entry in the cache. Returns `true` if entry is +// present and `false` otherwise. +func (tc *TimeCache) Has(item string) bool { + tc.mutex.RLock() + defer tc.mutex.RUnlock() + + _, ok := tc.cache[item] + return ok +} + +// Sweep removes old entries. That is those for which caching timespan has +// passed. +func (tc *TimeCache) Sweep() { + tc.mutex.Lock() + defer tc.mutex.Unlock() + + tc.sweep() +} + +func (tc *TimeCache) sweep() { + for { + back := tc.indexer.Back() + if back == nil { + break + } + + item := back.Value.(string) + itemTime, ok := tc.cache[item] + if !ok { + logger.Errorf( + "inconsistent cache state - expected item [%v] is not present", + item, + ) + break + } + + if time.Since(itemTime) > tc.timespan { + tc.indexer.Remove(back) + delete(tc.cache, item) + } else { + break + } + } +} diff --git a/pkg/cache/cache_test.go b/pkg/cache/cache_test.go new file mode 100644 index 0000000000..9852ab5a44 --- /dev/null +++ b/pkg/cache/cache_test.go @@ -0,0 +1,69 @@ +package cache + +import ( + "strconv" + "sync" + "testing" + "time" +) + +func TestAdd(t *testing.T) { + cache := NewTimeCache(time.Minute) + + cache.Add("test") + + if !cache.Has("test") { + t.Fatal("should have 'test' key") + } +} + +func TestConcurrentAdd(t *testing.T) { + cache := NewTimeCache(time.Minute) + + var wg sync.WaitGroup + wg.Add(10) + + for i := 0; i < 10; i++ { + go func(item int) { + cache.Add(strconv.Itoa(item)) + wg.Done() + }(i) + } + + wg.Wait() + + for i := 0; i < 10; i++ { + if !cache.Has(strconv.Itoa(i)) { + t.Fatalf("should have '%v' key", i) + } + } +} + +func TestExpiration(t *testing.T) { + cache := NewTimeCache(500 * time.Millisecond) + for i := 0; i < 6; i++ { + cache.Add(strconv.Itoa(i)) + time.Sleep(100 * time.Millisecond) + } + + if cache.Has(strconv.Itoa(0)) { + t.Fatal("should have dropped '0' key from the cache") + } +} + +func TestSweep(t *testing.T) { + cache := NewTimeCache(500 * time.Millisecond) + cache.Add("old") + time.Sleep(100 * time.Millisecond) + cache.Add("new") + time.Sleep(400 * time.Millisecond) + + cache.Sweep() + + if cache.Has("old") { + t.Fatal("should have dropped 'old' key from the cache") + } + if !cache.Has("new") { + t.Fatal("should still have 'new' in the cache") + } +} diff --git a/pkg/cache/generic_cache.go b/pkg/cache/generic_cache.go new file mode 100644 index 0000000000..3d0d5d9a13 --- /dev/null +++ b/pkg/cache/generic_cache.go @@ -0,0 +1,112 @@ +// Package cache provides a time cache implementation safe for concurrent use +// without the need of additional locking. +package cache + +import ( + "container/list" + "sync" + "time" +) + +type genericCacheEntry[T any] struct { + value T + timestamp time.Time +} + +// GenericTimeCache provides a generic time cache safe for concurrent use by +// multiple goroutines without additional locking or coordination. +// The implementation is based on the simple TimeCache. +type GenericTimeCache[T any] struct { + // all keys in the cache in the order they were added + // most recent keys are on the front of the indexer; + // it is used to optimize cache sweeping + indexer *list.List + // key in the cache with the value and timestamp it's been added + // to the cache the last time + cache map[string]*genericCacheEntry[T] + // the timespan after which entry in the cache is considered + // as outdated and can be removed from the cache + timespan time.Duration + mutex sync.RWMutex +} + +// NewGenericTimeCache creates a new generic cache instance with provided timespan. +func NewGenericTimeCache[T any](timespan time.Duration) *GenericTimeCache[T] { + return &GenericTimeCache[T]{ + indexer: list.New(), + cache: make(map[string]*genericCacheEntry[T]), + timespan: timespan, + } +} + +// Add adds an entry to the cache. Returns `true` if entry was not present in +// the cache and was successfully added into it. Returns `false` if +// entry is already in the cache. This method is synchronized. +func (tc *GenericTimeCache[T]) Add(key string, value T) bool { + tc.mutex.Lock() + defer tc.mutex.Unlock() + + _, ok := tc.cache[key] + if ok { + return false + } + + tc.sweep() + + tc.cache[key] = &genericCacheEntry[T]{ + value: value, + timestamp: time.Now(), + } + tc.indexer.PushFront(key) + return true +} + +// Get gets an entry from the cache. Boolean flag is `true` if entry is +// present and `false` otherwise. +func (tc *GenericTimeCache[T]) Get(key string) (T, bool) { + tc.mutex.RLock() + defer tc.mutex.RUnlock() + + entry, ok := tc.cache[key] + if !ok { + var zeroValue T + return zeroValue, ok + } + + return entry.value, ok +} + +// Sweep removes old entries. That is those for which caching timespan has +// passed. +func (tc *GenericTimeCache[T]) Sweep() { + tc.mutex.Lock() + defer tc.mutex.Unlock() + + tc.sweep() +} + +func (tc *GenericTimeCache[T]) sweep() { + for { + back := tc.indexer.Back() + if back == nil { + break + } + + key := back.Value.(string) + entry, ok := tc.cache[key] + if !ok { + logger.Errorf( + "inconsistent cache state - expected key [%v] is not present", + key, + ) + break + } + + if time.Since(entry.timestamp) > tc.timespan { + tc.indexer.Remove(back) + delete(tc.cache, key) + } else { + break + } + } +} diff --git a/pkg/cache/generic_cache_test.go b/pkg/cache/generic_cache_test.go new file mode 100644 index 0000000000..545ed01aee --- /dev/null +++ b/pkg/cache/generic_cache_test.go @@ -0,0 +1,98 @@ +package cache + +import ( + "reflect" + "strconv" + "sync" + "testing" + "time" +) + +type valueType struct { + field int +} + +func TestGenericTimeCache_Add(t *testing.T) { + cache := NewGenericTimeCache[*valueType](time.Minute) + + cache.Add("test", &valueType{10}) + + value, ok := cache.Get("test") + if !ok { + t.Fatal("should have 'test' key") + } + + expectedValue := &valueType{10} + if !reflect.DeepEqual(expectedValue, value) { + t.Errorf( + "unexpected value: \n"+ + "exptected: %v\n"+ + "actual: %v", + expectedValue, + value, + ) + } +} + +func TestGenericTimeCache_ConcurrentAdd(t *testing.T) { + cache := NewGenericTimeCache[*valueType](time.Minute) + + var wg sync.WaitGroup + wg.Add(10) + + for i := 0; i < 10; i++ { + go func(item int) { + cache.Add(strconv.Itoa(item), &valueType{item}) + wg.Done() + }(i) + } + + wg.Wait() + + for i := 0; i < 10; i++ { + value, ok := cache.Get(strconv.Itoa(i)) + if !ok { + t.Fatalf("should have '%v' key", i) + } + + expectedValue := &valueType{i} + if !reflect.DeepEqual(expectedValue, value) { + t.Errorf( + "unexpected value: \n"+ + "exptected: %v\n"+ + "actual: %v", + expectedValue, + value, + ) + } + } +} + +func TestGenericTimeCache_Expiration(t *testing.T) { + cache := NewGenericTimeCache[*valueType](500 * time.Millisecond) + for i := 0; i < 6; i++ { + cache.Add(strconv.Itoa(i), &valueType{i}) + time.Sleep(100 * time.Millisecond) + } + + if _, ok := cache.Get(strconv.Itoa(0)); ok { + t.Fatal("should have dropped '0' key from the cache") + } +} + +func TestGenericTimeCache_Sweep(t *testing.T) { + cache := NewGenericTimeCache[*valueType](500 * time.Millisecond) + cache.Add("old", &valueType{10}) + time.Sleep(100 * time.Millisecond) + cache.Add("new", &valueType{20}) + time.Sleep(400 * time.Millisecond) + + cache.Sweep() + + if _, ok := cache.Get("old"); ok { + t.Fatal("should have dropped 'old' key from the cache") + } + if _, ok := cache.Get("new"); !ok { + t.Fatal("should still have 'new' in the cache") + } +} diff --git a/pkg/chain/address.go b/pkg/chain/address.go index b856527b6d..81496adc1a 100644 --- a/pkg/chain/address.go +++ b/pkg/chain/address.go @@ -39,7 +39,7 @@ func (a Addresses) String() string { } var sb strings.Builder - var i = 0 + var i int sb.WriteString("[") for i = 0; i < len(a)-1; i++ { diff --git a/pkg/chain/ethereum/beacon.go b/pkg/chain/ethereum/beacon.go index 6f37143e62..75df23f033 100644 --- a/pkg/chain/ethereum/beacon.go +++ b/pkg/chain/ethereum/beacon.go @@ -10,9 +10,9 @@ import ( "github.com/keep-network/keep-core/pkg/subscription" "github.com/ethereum/go-ethereum/common" - "github.com/keep-network/keep-common/pkg/chain/ethereum" "github.com/keep-network/keep-core/pkg/chain" "github.com/keep-network/keep-core/pkg/chain/ethereum/beacon/gen/contract" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil" "github.com/keep-network/keep-core/pkg/operator" ) diff --git a/pkg/chain/ethereum/beacon/gen/cmd/BeaconSortitionPool.go b/pkg/chain/ethereum/beacon/gen/cmd/BeaconSortitionPool.go index a969a44d81..c88ce7fdd8 100644 --- a/pkg/chain/ethereum/beacon/gen/cmd/BeaconSortitionPool.go +++ b/pkg/chain/ethereum/beacon/gen/cmd/BeaconSortitionPool.go @@ -13,10 +13,10 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" - chainutil "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/cmd" - "github.com/keep-network/keep-common/pkg/utils/decode" "github.com/keep-network/keep-core/pkg/chain/ethereum/beacon/gen/contract" + chainutil "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + "github.com/keep-network/keep-core/pkg/cmd" + "github.com/keep-network/keep-core/pkg/decode" "github.com/spf13/cobra" ) diff --git a/pkg/chain/ethereum/beacon/gen/cmd/RandomBeacon.go b/pkg/chain/ethereum/beacon/gen/cmd/RandomBeacon.go index 43c6694d09..0d6f0b9a2b 100644 --- a/pkg/chain/ethereum/beacon/gen/cmd/RandomBeacon.go +++ b/pkg/chain/ethereum/beacon/gen/cmd/RandomBeacon.go @@ -14,11 +14,11 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" - chainutil "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/cmd" - "github.com/keep-network/keep-common/pkg/utils/decode" "github.com/keep-network/keep-core/pkg/chain/ethereum/beacon/gen/abi" "github.com/keep-network/keep-core/pkg/chain/ethereum/beacon/gen/contract" + chainutil "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + "github.com/keep-network/keep-core/pkg/cmd" + "github.com/keep-network/keep-core/pkg/decode" "github.com/spf13/cobra" ) diff --git a/pkg/chain/ethereum/beacon/gen/contract/BeaconSortitionPool.go b/pkg/chain/ethereum/beacon/gen/contract/BeaconSortitionPool.go index 68037a24b3..e3d9757055 100644 --- a/pkg/chain/ethereum/beacon/gen/contract/BeaconSortitionPool.go +++ b/pkg/chain/ethereum/beacon/gen/contract/BeaconSortitionPool.go @@ -20,10 +20,10 @@ import ( "github.com/ipfs/go-log" - "github.com/keep-network/keep-common/pkg/chain/ethereum" - chainutil "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/subscription" "github.com/keep-network/keep-core/pkg/chain/ethereum/beacon/gen/abi" + ethereum "github.com/keep-network/keep-core/pkg/chain/ethereumutil" + chainutil "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + "github.com/keep-network/keep-core/pkg/subscription" ) // Create a package-level logger for this contract. The logger exists at diff --git a/pkg/chain/ethereum/beacon/gen/contract/RandomBeacon.go b/pkg/chain/ethereum/beacon/gen/contract/RandomBeacon.go index 24de221104..9373be50bd 100644 --- a/pkg/chain/ethereum/beacon/gen/contract/RandomBeacon.go +++ b/pkg/chain/ethereum/beacon/gen/contract/RandomBeacon.go @@ -20,10 +20,10 @@ import ( "github.com/ipfs/go-log" - "github.com/keep-network/keep-common/pkg/chain/ethereum" - chainutil "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/subscription" "github.com/keep-network/keep-core/pkg/chain/ethereum/beacon/gen/abi" + ethereum "github.com/keep-network/keep-core/pkg/chain/ethereumutil" + chainutil "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + "github.com/keep-network/keep-core/pkg/subscription" ) // Create a package-level logger for this contract. The logger exists at diff --git a/pkg/chain/ethereum/bitcoin_difficulty.go b/pkg/chain/ethereum/bitcoin_difficulty.go index 75852f0e6d..770797277d 100644 --- a/pkg/chain/ethereum/bitcoin_difficulty.go +++ b/pkg/chain/ethereum/bitcoin_difficulty.go @@ -10,11 +10,11 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/keep-network/keep-common/pkg/chain/ethereum" - "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" "github.com/keep-network/keep-core/pkg/bitcoin" "github.com/keep-network/keep-core/pkg/chain" "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen/contract" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" "github.com/keep-network/keep-core/pkg/maintainer" ) @@ -295,9 +295,7 @@ func (bdc *BitcoinDifficultyChain) RetargetWithRefund(headers []*bitcoin.BlockHe ) } - // Add 20% to the gas estimate as the transaction tends to fail with the - // original gas estimate. - gasEstimateWithMargin := float64(gasEstimate) * float64(1.2) + gasEstimateWithMargin := gasEstimateWithMargin(gasEstimate) // Update Bitcoin difficulty via LightRelayMaintainerProxy. tx, err := bdc.lightRelayMaintainerProxy.Retarget( diff --git a/pkg/chain/ethereum/block_counter.go b/pkg/chain/ethereum/block_counter.go index fcd0934c6a..1936da0b97 100644 --- a/pkg/chain/ethereum/block_counter.go +++ b/pkg/chain/ethereum/block_counter.go @@ -1,7 +1,26 @@ package ethereum -import "github.com/keep-network/keep-core/pkg/chain" +import ( + "context" + "fmt" + + "github.com/keep-network/keep-core/pkg/chain" +) func (bc *baseChain) BlockCounter() (chain.BlockCounter, error) { return bc.blockCounter, nil } + +// LatestBlockNumber fetches the latest header through the Ethereum RPC client. +// Unlike BlockCounter().CurrentBlock(), it does not read subscription cache +// state, so an unavailable endpoint returns an error even after prior success. +func (bc *baseChain) LatestBlockNumber(ctx context.Context) (uint64, error) { + header, err := bc.client.HeaderByNumber(ctx, nil) + if err != nil { + return 0, fmt.Errorf("failed to fetch latest Ethereum header: [%w]", err) + } + if header == nil || header.Number == nil || !header.Number.IsUint64() { + return 0, fmt.Errorf("latest Ethereum header has no valid block number") + } + return header.Number.Uint64(), nil +} diff --git a/pkg/chain/ethereum/cmd.go b/pkg/chain/ethereum/cmd.go index 8f13455b82..ee3e6ea10e 100644 --- a/pkg/chain/ethereum/cmd.go +++ b/pkg/chain/ethereum/cmd.go @@ -3,7 +3,7 @@ package ethereum import ( "github.com/spf13/cobra" - commonEthereum "github.com/keep-network/keep-common/pkg/chain/ethereum" + commonEthereum "github.com/keep-network/keep-core/pkg/chain/ethereumutil" ) // Command if a wrapper for cobra.Command that holds Ethereum config used by the diff --git a/pkg/chain/ethereum/common/gen/Makefile b/pkg/chain/ethereum/common/gen/Makefile index b05300e34f..085b0e1884 100644 --- a/pkg/chain/ethereum/common/gen/Makefile +++ b/pkg/chain/ethereum/common/gen/Makefile @@ -3,6 +3,8 @@ override environment = development endif root_dir := $(realpath ../../../../..) +module_path := $(shell go list -m) +gen_package := ${module_path}/$(patsubst ${root_dir}/%,%,$(CURDIR)) artifacts_dir := ${root_dir}/tmp/contracts/${environment}/${npm_package_name}/artifacts $(info Package ${npm_package_name}) @@ -56,7 +58,7 @@ endif contract/%.go cmd/%.go: abi/%.abi abi/%.go _address/% ${artifacts_dir}/%.json $(info $* - generating Keep bindings) - @go run github.com/keep-network/keep-common/tools/generators/ethereum $< contract/$*.go cmd/$*.go + @go run github.com/keep-network/keep-core/tools/generators/ethereum -gen-package=${gen_package} $< contract/$*.go cmd/$*.go $(call after_contract_hook,$*) # Don't remove intermediate files that got generated. diff --git a/pkg/chain/ethereum/ecdsa/gen/cmd/EcdsaSortitionPool.go b/pkg/chain/ethereum/ecdsa/gen/cmd/EcdsaSortitionPool.go index bda083899d..f09debd475 100644 --- a/pkg/chain/ethereum/ecdsa/gen/cmd/EcdsaSortitionPool.go +++ b/pkg/chain/ethereum/ecdsa/gen/cmd/EcdsaSortitionPool.go @@ -13,10 +13,10 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" - chainutil "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/cmd" - "github.com/keep-network/keep-common/pkg/utils/decode" "github.com/keep-network/keep-core/pkg/chain/ethereum/ecdsa/gen/contract" + chainutil "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + "github.com/keep-network/keep-core/pkg/cmd" + "github.com/keep-network/keep-core/pkg/decode" "github.com/spf13/cobra" ) diff --git a/pkg/chain/ethereum/ecdsa/gen/cmd/WalletRegistry.go b/pkg/chain/ethereum/ecdsa/gen/cmd/WalletRegistry.go index 81877a37e5..46ba944a3a 100644 --- a/pkg/chain/ethereum/ecdsa/gen/cmd/WalletRegistry.go +++ b/pkg/chain/ethereum/ecdsa/gen/cmd/WalletRegistry.go @@ -13,11 +13,11 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" - chainutil "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/cmd" - "github.com/keep-network/keep-common/pkg/utils/decode" "github.com/keep-network/keep-core/pkg/chain/ethereum/ecdsa/gen/abi" "github.com/keep-network/keep-core/pkg/chain/ethereum/ecdsa/gen/contract" + chainutil "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + "github.com/keep-network/keep-core/pkg/cmd" + "github.com/keep-network/keep-core/pkg/decode" "github.com/spf13/cobra" ) diff --git a/pkg/chain/ethereum/ecdsa/gen/contract/EcdsaSortitionPool.go b/pkg/chain/ethereum/ecdsa/gen/contract/EcdsaSortitionPool.go index b77cdd4274..ba46d3c302 100644 --- a/pkg/chain/ethereum/ecdsa/gen/contract/EcdsaSortitionPool.go +++ b/pkg/chain/ethereum/ecdsa/gen/contract/EcdsaSortitionPool.go @@ -20,10 +20,10 @@ import ( "github.com/ipfs/go-log" - "github.com/keep-network/keep-common/pkg/chain/ethereum" - chainutil "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/subscription" "github.com/keep-network/keep-core/pkg/chain/ethereum/ecdsa/gen/abi" + ethereum "github.com/keep-network/keep-core/pkg/chain/ethereumutil" + chainutil "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + "github.com/keep-network/keep-core/pkg/subscription" ) // Create a package-level logger for this contract. The logger exists at diff --git a/pkg/chain/ethereum/ecdsa/gen/contract/WalletRegistry.go b/pkg/chain/ethereum/ecdsa/gen/contract/WalletRegistry.go index 3b4288559c..0260243366 100644 --- a/pkg/chain/ethereum/ecdsa/gen/contract/WalletRegistry.go +++ b/pkg/chain/ethereum/ecdsa/gen/contract/WalletRegistry.go @@ -20,10 +20,10 @@ import ( "github.com/ipfs/go-log" - "github.com/keep-network/keep-common/pkg/chain/ethereum" - chainutil "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/subscription" "github.com/keep-network/keep-core/pkg/chain/ethereum/ecdsa/gen/abi" + ethereum "github.com/keep-network/keep-core/pkg/chain/ethereumutil" + chainutil "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + "github.com/keep-network/keep-core/pkg/subscription" ) // Create a package-level logger for this contract. The logger exists at diff --git a/pkg/chain/ethereum/ecdsa_dkg_validator_chain.go b/pkg/chain/ethereum/ecdsa_dkg_validator_chain.go index 45bac4a074..bbe5760723 100644 --- a/pkg/chain/ethereum/ecdsa_dkg_validator_chain.go +++ b/pkg/chain/ethereum/ecdsa_dkg_validator_chain.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" "github.com/keep-network/keep-core/pkg/tbtc" ) diff --git a/pkg/chain/ethereum/ethereum.go b/pkg/chain/ethereum/ethereum.go index d0f9657cf0..c842bf2e4d 100644 --- a/pkg/chain/ethereum/ethereum.go +++ b/pkg/chain/ethereum/ethereum.go @@ -14,13 +14,13 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/ipfs/go-log" - "github.com/keep-network/keep-common/pkg/chain/ethereum" - "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/rate" "github.com/keep-network/keep-core/pkg/chain" "github.com/keep-network/keep-core/pkg/chain/ethereum/threshold/gen/contract" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" "github.com/keep-network/keep-core/pkg/maintainer" "github.com/keep-network/keep-core/pkg/operator" + "github.com/keep-network/keep-core/pkg/rate" ) // Definitions of contract names. @@ -344,13 +344,13 @@ func (bc *baseChain) GetBlockNumberByTimestamp( return 0, fmt.Errorf("cannot get current block: [%v]", err) } - if block.Time() < timestamp { + if block.Time < timestamp { return 0, fmt.Errorf("requested timestamp is in the future") } // Corner case shortcut. - if block.Time() == timestamp { - return block.NumberU64(), nil + if block.Time == timestamp { + return block.Number.Uint64(), nil } // The Ethereum average block time (https://etherscan.io/chart/blocktime) @@ -366,9 +366,9 @@ func (bc *baseChain) GetBlockNumberByTimestamp( // the better one. const averageBlockTime = 13 - for block.Time() > timestamp { + for block.Time > timestamp { // timeDiff is always >0 due to the for-loop condition. - timeDiff := block.Time() - timestamp + timeDiff := block.Time - timestamp // blockDiff is an integer whose value can be: // - >=1 if timeDiff >= averageBlockTime // - ==0 if timeDiff < averageBlockTime @@ -380,21 +380,21 @@ func (bc *baseChain) GetBlockNumberByTimestamp( break } - block, err = bc.blockByNumber(block.NumberU64() - blockDiff) + block, err = bc.blockByNumber(block.Number.Uint64() - blockDiff) if err != nil { return 0, fmt.Errorf("cannot get block: [%v]", err) } } // Once we quit the above for-loop, the following cases are possible: - // - Case 1: block.Time() < timestamp - // - Case 2: block.Time() > timestamp (difference is < averageBlockTime) - // - Case 3: block.Time() == timestamp + // - Case 1: block.Time < timestamp + // - Case 2: block.Time > timestamp (difference is < averageBlockTime) + // - Case 3: block.Time == timestamp // // First, try to reduce Case 1 by walking forward block by block until // we achieve Case 2 or 3. - for block.Time() < timestamp { - block, err = bc.blockByNumber(block.NumberU64() + 1) + for block.Time < timestamp { + block, err = bc.blockByNumber(block.Number.Uint64() + 1) if err != nil { return 0, fmt.Errorf("cannot get block: [%v]", err) } @@ -402,16 +402,16 @@ func (bc *baseChain) GetBlockNumberByTimestamp( // At this point, only Case 2 or 3 are possible. If we have Case 2, // just get the previous block and compare which one lies closer to // the requested timestamp. - if block.Time() > timestamp { - previousBlock, err := bc.blockByNumber(block.NumberU64() - 1) + if block.Time > timestamp { + previousBlock, err := bc.blockByNumber(block.Number.Uint64() - 1) if err != nil { return 0, fmt.Errorf("cannot get block: [%v]", err) } - return closerBlock(timestamp, previousBlock, block).NumberU64(), nil + return closerBlock(timestamp, previousBlock, block).Number.Uint64(), nil } - return block.NumberU64(), nil + return block.Number.Uint64(), nil } // GetBlockHashByNumber gets the block hash for the given block number. @@ -427,8 +427,11 @@ func (bc *baseChain) GetBlockHashByNumber(blockNumber uint64) ( return header.Hash(), nil } -// currentBlock fetches the current block. -func (bc *baseChain) currentBlock() (*types.Block, error) { +// currentBlock fetches the current block header. Times out if the underlying +// client call takes more than 30 seconds. The returned *types.Header carries +// only header fields; callers that need transactions, uncles or receipts must +// fetch the full block separately. +func (bc *baseChain) currentBlock() (*types.Header, error) { // Use the latest header instead of block counter state. Some modern mainnet // blocks contain transaction types not supported by older block-counting // code paths, while this method only needs the latest block number/time as an @@ -436,21 +439,16 @@ func (bc *baseChain) currentBlock() (*types.Block, error) { ctx, cancelCtx := context.WithTimeout(context.Background(), 30*time.Second) defer cancelCtx() - header, err := bc.client.HeaderByNumber(ctx, nil) - if err != nil { - return nil, err - } - - return types.NewBlockWithHeader(header), nil + return bc.client.HeaderByNumber(ctx, nil) } -// blockByNumber returns the block for the given block number. Times out +// blockByNumber returns the header for the given block number. Times out // if the underlying client call takes more than 30 seconds. -func (bc *baseChain) blockByNumber(number uint64) (*types.Block, error) { +func (bc *baseChain) blockByNumber(number uint64) (*types.Header, error) { ctx, cancelCtx := context.WithTimeout(context.Background(), 30*time.Second) defer cancelCtx() - return bc.client.BlockByNumber(ctx, big.NewInt(int64(number))) + return bc.client.HeaderByNumber(ctx, new(big.Int).SetUint64(number)) } // headerByNumber returns the header for the given block number. Times out @@ -459,26 +457,26 @@ func (bc *baseChain) headerByNumber(number uint64) (*types.Header, error) { ctx, cancelCtx := context.WithTimeout(context.Background(), 30*time.Second) defer cancelCtx() - return bc.client.HeaderByNumber(ctx, big.NewInt(int64(number))) + return bc.client.HeaderByNumber(ctx, new(big.Int).SetUint64(number)) } -// closerBlock check timestamps of blocks b1 and b2 and returns the block -// whose timestamp lies closer to the requested timestamp. If the distance -// is same for both blocks, the block with greater block number is returned. -func closerBlock(timestamp uint64, b1, b2 *types.Block) *types.Block { - abs := func(x int64) int64 { - if x < 0 { - return -x +// closerBlock check timestamps of block headers b1 and b2 and returns the one +// whose timestamp lies closer to the requested timestamp. If the distance is +// the same for both headers, the one with greater block number is returned. +func closerBlock(timestamp uint64, b1, b2 *types.Header) *types.Header { + distance := func(blockTime uint64) uint64 { + if blockTime > timestamp { + return blockTime - timestamp } - return x + return timestamp - blockTime } - b1Diff := abs(int64(b1.Time() - timestamp)) - b2Diff := abs(int64(b2.Time() - timestamp)) + b1Diff := distance(b1.Time) + b2Diff := distance(b2.Time) // If the differences are same, return the block with greater number. if b1Diff == b2Diff { - if b2.NumberU64() > b1.NumberU64() { + if b2.Number.Uint64() > b1.Number.Uint64() { return b2 } return b1 @@ -531,3 +529,12 @@ func decryptKey(config ethereum.Config) (*keystore.Key, error) { config.Account.KeyFilePassword, ) } + +// gasEstimateWithMargin returns the given gas estimate multiplied by a fixed +// 20% safety margin. The original contract estimates for some transactions +// (notably reimbursement flows) turned out to be too low and caused the +// calls to run out of gas before reimbursement completed. +func gasEstimateWithMargin(gasEstimate uint64) uint64 { + const marginMultiplier = 1.2 + return uint64(float64(gasEstimate) * marginMultiplier) +} diff --git a/pkg/chain/ethereum/ethereum_integration_test.go b/pkg/chain/ethereum/ethereum_integration_test.go index 3c21f04a40..42df6b335f 100644 --- a/pkg/chain/ethereum/ethereum_integration_test.go +++ b/pkg/chain/ethereum/ethereum_integration_test.go @@ -12,8 +12,8 @@ import ( "time" "github.com/ethereum/go-ethereum/ethclient" - "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" "github.com/keep-network/keep-core/internal/testutils" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" ) // To run the tests execute: @@ -30,7 +30,7 @@ import ( func TestBaseChain_GetBlockNumberByTimestamp(t *testing.T) { ethereumURL := os.Getenv("ETHEREUM_MAINNET_RPC_URL") if ethereumURL == "" { - t.Skip("ETHEREUM_MAINNET_RPC_URL not set; skipping integration test") + t.Skip("ETHEREUM_MAINNET_RPC_URL not set; skipping mainnet integration test") } client, err := ethclient.Dial(ethereumURL) diff --git a/pkg/chain/ethereum/ethereum_timestamp_test.go b/pkg/chain/ethereum/ethereum_timestamp_test.go new file mode 100644 index 0000000000..0da1366ab5 --- /dev/null +++ b/pkg/chain/ethereum/ethereum_timestamp_test.go @@ -0,0 +1,227 @@ +package ethereum + +import ( + "context" + "errors" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/core/types" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" +) + +// timestampMockClient is a minimal ethutil.EthereumClient used to exercise the +// timestamp-based block search. It embeds the interface so it satisfies the +// full contract while implementing only HeaderByNumber; any other call +// would panic, which keeps the test honest about what the searched code +// actually touches. +type timestampMockClient struct { + ethutil.EthereumClient + // blockTimes maps a block number to its timestamp. + blockTimes map[uint64]uint64 + // latest is the number of the current (highest) block. + latest uint64 +} + +func newTimestampMockClient(baseTime, spacing, latest uint64) *timestampMockClient { + blockTimes := make(map[uint64]uint64) + for n := uint64(0); n <= latest; n++ { + blockTimes[n] = baseTime + n*spacing + } + return ×tampMockClient{blockTimes: blockTimes, latest: latest} +} + +func (m *timestampMockClient) header(number uint64) (*types.Header, error) { + time, ok := m.blockTimes[number] + if !ok { + return nil, errBlockOutOfRange + } + return &types.Header{ + Number: new(big.Int).SetUint64(number), + Time: time, + }, nil +} + +// HeaderByNumber returns the latest header when number is nil, matching the +// behavior currentBlock relies on. +func (m *timestampMockClient) HeaderByNumber( + _ context.Context, + number *big.Int, +) (*types.Header, error) { + if number == nil { + return m.header(m.latest) + } + return m.header(number.Uint64()) +} + +var errBlockOutOfRange = errors.New("block out of range") + +func TestGetBlockNumberByTimestamp(t *testing.T) { + const ( + baseTime = uint64(1_600_000_000) + spacing = uint64(12) + latest = uint64(100) + ) + latestTime := baseTime + latest*spacing + + tests := map[string]struct { + timestamp uint64 + expectedBlock uint64 + expectingError bool + }{ + "timestamp of the latest block": { + timestamp: latestTime, + expectedBlock: latest, + }, + "timestamp exactly matching a middle block": { + timestamp: baseTime + 50*spacing, + expectedBlock: 50, + }, + "timestamp closer to the lower block": { + // Between block 50 (t=+600) and 51 (t=+612); +605 is 5s from 50 + // and 7s from 51, so the lower block wins. + timestamp: baseTime + 50*spacing + 5, + expectedBlock: 50, + }, + "timestamp closer to the higher block": { + // +607 is 7s from 50 and 5s from 51, so the higher block wins. + timestamp: baseTime + 50*spacing + 7, + expectedBlock: 51, + }, + "timestamp equidistant between two blocks": { + // +606 is 6s from both 50 and 51; closerBlock returns the greater + // block number on a tie. + timestamp: baseTime + 50*spacing + 6, + expectedBlock: 51, + }, + "timestamp of the earliest block": { + timestamp: baseTime, + expectedBlock: 0, + }, + "timestamp in the future": { + timestamp: latestTime + 1, + expectingError: true, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + bc := &baseChain{ + client: newTimestampMockClient(baseTime, spacing, latest), + } + + block, err := bc.GetBlockNumberByTimestamp(test.timestamp) + + if test.expectingError { + if err == nil { + t.Fatalf("expected an error but got none") + } + return + } + + if err != nil { + t.Fatalf("unexpected error: [%v]", err) + } + + if block != test.expectedBlock { + t.Errorf( + "unexpected block number\nexpected: [%d]\nactual: [%d]", + test.expectedBlock, + block, + ) + } + }) + } +} + +// TestGetBlockNumberByTimestamp_ForwardCompensation exercises the forward +// compensation loop in GetBlockNumberByTimestamp. When the actual block spacing +// (15s) is greater than the assumed averageBlockTime (13s), the initial backward +// jump overshoots below the target timestamp, so the search must walk forward +// block by block to converge. The main table above uses a 12s spacing, where the +// backward jump always lands at or after the target and the forward loop never +// runs. +func TestGetBlockNumberByTimestamp_ForwardCompensation(t *testing.T) { + const ( + baseTime = uint64(1_600_000_000) + spacing = uint64(15) + latest = uint64(100) + ) + + bc := &baseChain{ + client: newTimestampMockClient(baseTime, spacing, latest), + } + + // Target a point 7s after block 50 (t=+757), between block 50 (t=+750) and + // block 51 (t=+765). The backward jump from the tip lands on block 43 + // (t=+645, before the target), so the forward loop walks 43->51 and the + // closer-block comparison then selects block 50 (7s away vs. 8s). + timestamp := baseTime + 50*spacing + 7 + expectedBlock := uint64(50) + + block, err := bc.GetBlockNumberByTimestamp(timestamp) + if err != nil { + t.Fatalf("unexpected error: [%v]", err) + } + + if block != expectedBlock { + t.Errorf( + "unexpected block number\nexpected: [%d]\nactual: [%d]", + expectedBlock, + block, + ) + } +} + +func TestCloserBlock(t *testing.T) { + block := func(number, time uint64) *types.Header { + return &types.Header{ + Number: new(big.Int).SetUint64(number), + Time: time, + } + } + + tests := map[string]struct { + timestamp uint64 + b1, b2 *types.Header + expectedNumber uint64 + }{ + "first block closer": { + timestamp: 100, + b1: block(5, 100), + b2: block(6, 110), + expectedNumber: 5, + }, + "second block closer": { + timestamp: 110, + b1: block(5, 100), + b2: block(6, 110), + expectedNumber: 6, + }, + "equidistant returns the greater block number (b2)": { + timestamp: 105, + b1: block(5, 100), + b2: block(6, 110), + expectedNumber: 6, + }, + "equidistant returns the greater block number (b1)": { + timestamp: 105, + b1: block(6, 110), + b2: block(5, 100), + expectedNumber: 6, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + result := closerBlock(test.timestamp, test.b1, test.b2) + if result.Number.Uint64() != test.expectedNumber { + t.Errorf( + "unexpected block number\nexpected: [%d]\nactual: [%d]", + test.expectedNumber, + result.Number.Uint64(), + ) + } + }) + } +} diff --git a/pkg/chain/ethereum/integer_conversion_test.go b/pkg/chain/ethereum/integer_conversion_test.go new file mode 100644 index 0000000000..825eaf70dc --- /dev/null +++ b/pkg/chain/ethereum/integer_conversion_test.go @@ -0,0 +1,60 @@ +package ethereum + +import ( + "math" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/core/types" + "github.com/keep-network/keep-core/pkg/bitcoin" +) + +func TestCloserBlockUnsignedDistances(t *testing.T) { + for _, tc := range []struct { + timestamp, first, second uint64 + wantSecond bool + }{ + {0, math.MaxUint64, 1, true}, + {math.MaxUint64, 0, math.MaxUint64 - 1, true}, + {10, 9, 11, true}, + {math.MaxInt64, math.MaxInt64 - 1, math.MaxUint64, false}, + } { + first := &types.Header{Number: big.NewInt(1), Time: tc.first} + second := &types.Header{Number: big.NewInt(2), Time: tc.second} + actual := closerBlock(tc.timestamp, first, second) + if (actual == second) != tc.wantSecond { + t.Fatalf("wrong block for timestamp %d, block times %d/%d", tc.timestamp, tc.first, tc.second) + } + } +} + +func TestChainMemberIndexBounds(t *testing.T) { + for _, value := range []*big.Int{nil, big.NewInt(-1), big.NewInt(0), big.NewInt(256), new(big.Int).Lsh(big.NewInt(1), 64)} { + if _, err := memberIndexFromChain(value); err == nil { + t.Fatalf("accepted index %v", value) + } + } + for _, value := range []int64{1, 255} { + index, err := memberIndexFromChain(big.NewInt(value)) + if err != nil || int64(index) != value { + t.Fatalf("index %d: %d, %v", value, index, err) + } + } +} + +func TestProofSubmissionsRejectNegativeUtxo(t *testing.T) { + chain := new(TbtcChain) + utxo := bitcoin.UnspentTransactionOutput{Value: -1} + calls := []func() error{ + func() error { return chain.SubmitRedemptionProofWithReimbursement(nil, nil, utxo, [20]byte{}) }, + func() error { return chain.SubmitDepositSweepProofWithReimbursement(nil, nil, utxo, [20]byte{}) }, + func() error { return chain.SubmitMovingFundsProofWithReimbursement(nil, nil, utxo, [20]byte{}) }, + func() error { return chain.SubmitMovedFundsSweepProofWithReimbursement(nil, nil, utxo) }, + func() error { return chain.ValidateMovingFundsProposal([20]byte{}, &utxo, nil) }, + } + for i, call := range calls { + if err := call(); err == nil { + t.Fatalf("submission %d accepted negative UTXO", i) + } + } +} diff --git a/pkg/chain/ethereum/rpc_health_test.go b/pkg/chain/ethereum/rpc_health_test.go new file mode 100644 index 0000000000..3d50ae83f9 --- /dev/null +++ b/pkg/chain/ethereum/rpc_health_test.go @@ -0,0 +1,128 @@ +package ethereum + +import ( + "context" + "encoding/json" + "errors" + "math/big" + "net/http" + "net/http/httptest" + "sync/atomic" + "testing" + + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" +) + +func TestLatestBlockNumberContactsRPCOnEveryCall(t *testing.T) { + var unavailable atomic.Bool + var calls atomic.Int32 + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + calls.Add(1) + if unavailable.Load() { + http.Error(w, "Ethereum unavailable", http.StatusServiceUnavailable) + return + } + var request struct { + ID json.RawMessage + Method string + Params []json.RawMessage + } + if err := json.NewDecoder(r.Body).Decode(&request); err != nil { + t.Errorf("invalid JSON-RPC request: %v", err) + http.Error(w, "invalid request", http.StatusBadRequest) + return + } + if request.Method != "eth_getBlockByNumber" || len(request.Params) != 2 || + string(request.Params[0]) != `"latest"` || string(request.Params[1]) != "false" { + t.Errorf("expected latest-header RPC, got %+v", request) + http.Error(w, "unexpected RPC", http.StatusBadRequest) + return + } + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(map[string]any{ + "jsonrpc": "2.0", + "id": request.ID, + "result": &types.Header{ + Number: big.NewInt(100), + Difficulty: big.NewInt(1), + Extra: []byte{}, + }, + }); err != nil { + t.Errorf("cannot write JSON-RPC response: %v", err) + } + })) + defer server.Close() + client, err := ethclient.Dial(server.URL) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + // Deliberately omit the cached block counter. TbtcChain, as passed by both + // startup paths, must use its existing RPC client for every health probe. + chain := &TbtcChain{baseChain: &baseChain{client: client}} + for i := 0; i < 2; i++ { + height, err := chain.LatestBlockNumber(context.Background()) + if err != nil || height != 100 { + t.Fatalf("expected live height 100, got %d, %v", height, err) + } + } + unavailable.Store(true) + if _, err := chain.LatestBlockNumber(context.Background()); err == nil { + t.Fatal("RPC outage was hidden by the previous nonzero height") + } + unavailable.Store(false) + if height, err := chain.LatestBlockNumber(context.Background()); err != nil || height != 100 { + t.Fatalf("expected recovery at the same height, got %d, %v", height, err) + } + if got := calls.Load(); got != 4 { + t.Fatalf("expected four RPC requests, got %d", got) + } +} + +type latestHeaderClient struct { + ethutil.EthereumClient + getHeader func(context.Context, *big.Int) (*types.Header, error) +} + +func (c *latestHeaderClient) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { + return c.getHeader(ctx, number) +} + +func TestLatestBlockNumberRejectsInvalidHeaders(t *testing.T) { + for name, header := range map[string]*types.Header{ + "missing header": nil, + "missing number": {}, + "negative number": {Number: big.NewInt(-1)}, + "overflow": {Number: new(big.Int).Lsh(big.NewInt(1), 64)}, + } { + t.Run(name, func(t *testing.T) { + chain := &baseChain{client: &latestHeaderClient{ + getHeader: func(context.Context, *big.Int) (*types.Header, error) { + return header, nil + }, + }} + if _, err := chain.LatestBlockNumber(context.Background()); err == nil { + t.Fatal("invalid header must fail the health probe") + } + }) + } +} + +func TestLatestBlockNumberForwardsCancellation(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + chain := &baseChain{client: &latestHeaderClient{ + getHeader: func(received context.Context, number *big.Int) (*types.Header, error) { + if received != ctx || number != nil { + t.Fatal("expected caller context and latest-header query") + } + return nil, received.Err() + }, + }} + if _, err := chain.LatestBlockNumber(ctx); !errors.Is(err, context.Canceled) { + t.Fatalf("expected wrapped context cancellation, got %v", err) + } +} diff --git a/pkg/chain/ethereum/signer.go b/pkg/chain/ethereum/signer.go index 636a410867..2bed88c89a 100644 --- a/pkg/chain/ethereum/signer.go +++ b/pkg/chain/ethereum/signer.go @@ -6,12 +6,12 @@ import ( "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" - "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" "github.com/keep-network/keep-core/pkg/chain" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" "github.com/keep-network/keep-core/pkg/operator" ) -// TODO: Consider moving the `EthereumSigner` out of `keep-common` to this file. +// TODO: Consider moving the `EthereumSigner` out of `ethutil` to this file. type signer struct { *ethutil.EthereumSigner } diff --git a/pkg/chain/ethereum/tbtc.go b/pkg/chain/ethereum/tbtc.go index 50e42be20e..90667876c6 100644 --- a/pkg/chain/ethereum/tbtc.go +++ b/pkg/chain/ethereum/tbtc.go @@ -1,38 +1,35 @@ +// tbtc.go: TbtcChain adapter construction and shared state. See tbtc_*.go for +// per-concern implementations (tbtc_deposit.go, tbtc_dkg.go, tbtc_moving_funds.go, +// tbtc_redemption.go, tbtc_wallet.go, tbtc_sortition.go, tbtc_inactivity.go). +// +// These files were split out of a single monolithic tbtc.go with no rename +// markers git can detect (each file is a fresh addition, not a tracked move), +// so a plain `git revert` of the split commit cannot be applied cleanly on +// top of any later commit that also touches this package: it would re-delete +// the per-concern files and reintroduce the old tbtc.go, silently dropping +// whatever those later commits changed. Reconstructing the pre-split state +// requires a manual merge, not a mechanical revert. package ethereum import ( - "context" "crypto/ecdsa" "encoding/binary" "errors" "fmt" "math/big" - "reflect" - "sort" "time" - "github.com/keep-network/keep-common/pkg/cache" + "github.com/keep-network/keep-core/pkg/cache" - "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" - "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-core/pkg/bitcoin" - "github.com/keep-network/keep-common/pkg/chain/ethereum" - "github.com/keep-network/keep-core/pkg/chain" - ecdsaabi "github.com/keep-network/keep-core/pkg/chain/ethereum/ecdsa/gen/abi" + "github.com/keep-network/keep-core/pkg/bitcoin" ecdsacontract "github.com/keep-network/keep-core/pkg/chain/ethereum/ecdsa/gen/contract" - tbtcabi "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen/abi" tbtccontract "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen/contract" - "github.com/keep-network/keep-core/pkg/crypto/secp256k1" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil" "github.com/keep-network/keep-core/pkg/internal/byteutils" - "github.com/keep-network/keep-core/pkg/operator" - "github.com/keep-network/keep-core/pkg/protocol/group" - "github.com/keep-network/keep-core/pkg/protocol/inactivity" - "github.com/keep-network/keep-core/pkg/subscription" "github.com/keep-network/keep-core/pkg/tbtc" - "github.com/keep-network/keep-core/pkg/tecdsa/dkg" ) // Definitions of contract names. @@ -279,562 +276,6 @@ func newTbtcChain( }, nil } -// EcdsaWalletGroupParametersFromChain mirrors EcdsaDkgValidator sizing constants -// when EcdsaDkgValidator contract address was configured under [ethereum] -// contract addresses or developer.ecdsaDkgValidatorAddress alias. When absent, -// returns (nil, nil) and callers use defaultGroupParameters(network). -func (tc *TbtcChain) EcdsaWalletGroupParametersFromChain( - ctx context.Context, -) (*tbtc.GroupParameters, error) { - if tc.ecdsaDkgValidatorAddress == (common.Address{}) { - return nil, nil - } - return ecdsaWalletGroupParametersFromValidator( - ctx, - tc.baseChain.client, - tc.ecdsaDkgValidatorAddress, - ) -} - -// Staking returns address of the TokenStaking contract the WalletRegistry is -// connected to. -func (tc *TbtcChain) Staking() (chain.Address, error) { - stakingContractAddress, err := tc.walletRegistry.Staking() - if err != nil { - return "", fmt.Errorf( - "failed to get the token staking address: [%w]", - err, - ) - } - - return chain.Address(stakingContractAddress.String()), nil -} - -// IsRecognized checks whether the given operator is recognized by the TbtcChain -// as eligible to join the network. If the operator has a stake delegation or -// had a stake delegation in the past, it will be recognized. -func (tc *TbtcChain) IsRecognized(operatorPublicKey *operator.PublicKey) (bool, error) { - operatorAddress, err := operatorPublicKeyToChainAddress(operatorPublicKey) - if err != nil { - return false, fmt.Errorf( - "cannot convert from operator key to chain address: [%v]", - err, - ) - } - - stakingProvider, err := tc.walletRegistry.OperatorToStakingProvider( - operatorAddress, - ) - if err != nil { - return false, fmt.Errorf( - "failed to map operator [%v] to a staking provider: [%v]", - operatorAddress, - err, - ) - } - - if (stakingProvider == common.Address{}) { - return false, nil - } - - // Check if the staking provider has an owner. This check ensures that there - // is/was a stake delegation for the given staking provider. - _, _, _, hasStakeDelegation, err := tc.baseChain.RolesOf( - chain.Address(stakingProvider.Hex()), - ) - if err != nil { - return false, fmt.Errorf( - "failed to check stake delegation for staking provider [%v]: [%v]", - stakingProvider, - err, - ) - } - - if !hasStakeDelegation { - return false, nil - } - - return true, nil -} - -// OperatorToStakingProvider returns the staking provider address for the -// operator. If the staking provider has not been registered for the -// operator, the returned address is empty and the boolean flag is set to -// false. If the staking provider has been registered, the address is not -// empty and the boolean flag indicates true. -func (tc *TbtcChain) OperatorToStakingProvider() (chain.Address, bool, error) { - stakingProvider, err := tc.walletRegistry.OperatorToStakingProvider(tc.key.Address) - if err != nil { - return "", false, fmt.Errorf( - "failed to map operator [%v] to a staking provider: [%v]", - tc.key.Address, - err, - ) - } - - if (stakingProvider == common.Address{}) { - return "", false, nil - } - - return chain.Address(stakingProvider.Hex()), true, nil -} - -// EligibleStake returns the current value of the staking provider's -// eligible stake. Eligible stake is defined as the currently authorized -// stake minus the pending authorization decrease. Eligible stake -// is what is used for operator's weight in the sortition pool. -// If the authorized stake minus the pending authorization decrease -// is below the minimum authorization, eligible stake is 0. -func (tc *TbtcChain) EligibleStake(stakingProvider chain.Address) (*big.Int, error) { - eligibleStake, err := tc.walletRegistry.EligibleStake( - common.HexToAddress(stakingProvider.String()), - ) - if err != nil { - return nil, fmt.Errorf( - "failed to get eligible stake for staking provider %s: [%w]", - stakingProvider, - err, - ) - } - - return eligibleStake, nil -} - -// IsPoolLocked returns true if the sortition pool is locked and no state -// changes are allowed. -func (tc *TbtcChain) IsPoolLocked() (bool, error) { - return tc.sortitionPool.IsLocked() -} - -// IsOperatorInPool returns true if the operator is registered in -// the sortition pool. -func (tc *TbtcChain) IsOperatorInPool() (bool, error) { - return tc.walletRegistry.IsOperatorInPool(tc.key.Address) -} - -// IsOperatorUpToDate checks if the operator's authorized stake is in sync -// with operator's weight in the sortition pool. -// If the operator's authorized stake is not in sync with sortition pool -// weight, function returns false. -// If the operator is not in the sortition pool and their authorized stake -// is non-zero, function returns false. -func (tc *TbtcChain) IsOperatorUpToDate() (bool, error) { - return tc.walletRegistry.IsOperatorUpToDate(tc.key.Address) -} - -// JoinSortitionPool executes a transaction to have the operator join the -// sortition pool. -func (tc *TbtcChain) JoinSortitionPool() error { - _, err := tc.walletRegistry.JoinSortitionPool() - return err -} - -// UpdateOperatorStatus executes a transaction to update the operator's -// state in the sortition pool. -func (tc *TbtcChain) UpdateOperatorStatus() error { - _, err := tc.walletRegistry.UpdateOperatorStatus(tc.key.Address) - return err -} - -// IsEligibleForRewards checks whether the operator is eligible for rewards -// or not. -func (tc *TbtcChain) IsEligibleForRewards() (bool, error) { - return tc.sortitionPool.IsEligibleForRewards(tc.key.Address) -} - -// Checks whether the operator is able to restore their eligibility for -// rewards right away. -func (tc *TbtcChain) CanRestoreRewardEligibility() (bool, error) { - return tc.sortitionPool.CanRestoreRewardEligibility(tc.key.Address) -} - -// Restores reward eligibility for the operator. -func (tc *TbtcChain) RestoreRewardEligibility() error { - _, err := tc.sortitionPool.RestoreRewardEligibility(tc.key.Address) - return err -} - -// Returns true if the chaosnet phase is active, false otherwise. -func (tc *TbtcChain) IsChaosnetActive() (bool, error) { - return tc.sortitionPool.IsChaosnetActive() -} - -// Returns true if operator is a beta operator, false otherwise. -// Chaosnet status does not matter. -func (tc *TbtcChain) IsBetaOperator() (bool, error) { - return tc.sortitionPool.IsBetaOperator(tc.key.Address) -} - -// GetOperatorID returns the ID number of the given operator address. An ID -// number of 0 means the operator has not been allocated an ID number yet. -func (tc *TbtcChain) GetOperatorID( - operatorAddress chain.Address, -) (chain.OperatorID, error) { - return tc.sortitionPool.GetOperatorID( - common.HexToAddress(operatorAddress.String()), - ) -} - -// SelectGroup returns the group members selected for the current group -// selection. The function returns an error if the chain's state does not allow -// for group selection at the moment. -func (tc *TbtcChain) SelectGroup() (*tbtc.GroupSelectionResult, error) { - operatorsIDs, err := tc.walletRegistry.SelectGroup() - if err != nil { - return nil, fmt.Errorf( - "cannot select group in the sortition pool: [%v]", - err, - ) - } - - operatorsAddresses, err := tc.sortitionPool.GetIDOperators(operatorsIDs) - if err != nil { - return nil, fmt.Errorf( - "cannot convert operators' IDs to addresses: [%v]", - err, - ) - } - - // Should not happen as this is guaranteed by the contract but, just in case. - if len(operatorsIDs) != len(operatorsAddresses) { - return nil, fmt.Errorf("operators IDs and addresses mismatch") - } - - ids := make([]chain.OperatorID, len(operatorsIDs)) - addresses := make([]chain.Address, len(operatorsIDs)) - for i := range ids { - ids[i] = operatorsIDs[i] - addresses[i] = chain.Address(operatorsAddresses[i].String()) - } - - return &tbtc.GroupSelectionResult{ - OperatorsIDs: ids, - OperatorsAddresses: addresses, - }, nil -} - -func (tc *TbtcChain) OnDKGStarted( - handler func(event *tbtc.DKGStartedEvent), -) subscription.EventSubscription { - onEvent := func( - seed *big.Int, - blockNumber uint64, - ) { - handler(&tbtc.DKGStartedEvent{ - Seed: seed, - BlockNumber: blockNumber, - }) - } - - return tc.walletRegistry.DkgStartedEvent(nil, nil).OnEvent(onEvent) -} - -func (tc *TbtcChain) PastDKGStartedEvents( - filter *tbtc.DKGStartedEventFilter, -) ([]*tbtc.DKGStartedEvent, error) { - var startBlock uint64 - var endBlock *uint64 - var seed []*big.Int - - if filter != nil { - startBlock = filter.StartBlock - endBlock = filter.EndBlock - seed = filter.Seed - } - - events, err := tc.walletRegistry.PastDkgStartedEvents( - startBlock, - endBlock, - seed, - ) - if err != nil { - return nil, err - } - - dkgStartedEvents := make([]*tbtc.DKGStartedEvent, len(events)) - for i, event := range events { - dkgStartedEvents[i] = &tbtc.DKGStartedEvent{ - Seed: event.Seed, - BlockNumber: event.Raw.BlockNumber, - } - } - - sort.SliceStable(dkgStartedEvents, func(i, j int) bool { - return dkgStartedEvents[i].BlockNumber < dkgStartedEvents[j].BlockNumber - }) - - return dkgStartedEvents, err -} - -func (tc *TbtcChain) OnDKGResultSubmitted( - handler func(event *tbtc.DKGResultSubmittedEvent), -) subscription.EventSubscription { - onEvent := func( - resultHash [32]byte, - seed *big.Int, - result ecdsaabi.EcdsaDkgResult, - blockNumber uint64, - ) { - tbtcResult, err := convertDkgResultFromAbiType(result) - if err != nil { - logger.Errorf( - "unexpected DKG result in DKGResultSubmitted event: [%v]", - err, - ) - return - } - - handler(&tbtc.DKGResultSubmittedEvent{ - Seed: seed, - ResultHash: resultHash, - Result: tbtcResult, - BlockNumber: blockNumber, - }) - } - - return tc.walletRegistry. - DkgResultSubmittedEvent(nil, nil, nil). - OnEvent(onEvent) -} - -// convertDkgResultFromAbiType converts the WalletRegistry-specific DKG -// result to the format applicable for the TBTC application. -func convertDkgResultFromAbiType( - result ecdsaabi.EcdsaDkgResult, -) (*tbtc.DKGChainResult, error) { - if err := validateMemberIndex(result.SubmitterMemberIndex); err != nil { - return nil, fmt.Errorf( - "unexpected submitter member index: [%v]", - err, - ) - } - - signingMembersIndexes := make( - []group.MemberIndex, - len(result.SigningMembersIndices), - ) - for i, memberIndex := range result.SigningMembersIndices { - if err := validateMemberIndex(memberIndex); err != nil { - return nil, fmt.Errorf( - "unexpected signing member index: [%v]", - err, - ) - } - - signingMembersIndexes[i] = group.MemberIndex(memberIndex.Uint64()) - } - - return &tbtc.DKGChainResult{ - SubmitterMemberIndex: group.MemberIndex(result.SubmitterMemberIndex.Uint64()), - GroupPublicKey: result.GroupPubKey, - MisbehavedMembersIndexes: result.MisbehavedMembersIndices, - Signatures: result.Signatures, - SigningMembersIndexes: signingMembersIndexes, - Members: result.Members, - MembersHash: result.MembersHash, - }, nil -} - -// convertDkgResultToAbiType converts the TBTC-specific DKG result to -// the format applicable for the WalletRegistry ABI. -func convertDkgResultToAbiType( - result *tbtc.DKGChainResult, -) ecdsaabi.EcdsaDkgResult { - signingMembersIndices := make([]*big.Int, len(result.SigningMembersIndexes)) - for i, memberIndex := range result.SigningMembersIndexes { - signingMembersIndices[i] = big.NewInt(int64(memberIndex)) - } - - return ecdsaabi.EcdsaDkgResult{ - SubmitterMemberIndex: big.NewInt(int64(result.SubmitterMemberIndex)), - GroupPubKey: result.GroupPublicKey, - MisbehavedMembersIndices: result.MisbehavedMembersIndexes, - Signatures: result.Signatures, - SigningMembersIndices: signingMembersIndices, - Members: result.Members, - MembersHash: result.MembersHash, - } -} - -func validateMemberIndex(chainMemberIndex *big.Int) error { - maxMemberIndex := big.NewInt(group.MaxMemberIndex) - if chainMemberIndex.Cmp(maxMemberIndex) > 0 { - return fmt.Errorf("invalid member index value: [%v]", chainMemberIndex) - } - - return nil -} - -func (tc *TbtcChain) OnDKGResultChallenged( - handler func(event *tbtc.DKGResultChallengedEvent), -) subscription.EventSubscription { - onEvent := func( - resultHash [32]byte, - challenger common.Address, - reason string, - blockNumber uint64, - ) { - handler(&tbtc.DKGResultChallengedEvent{ - ResultHash: resultHash, - Challenger: chain.Address(challenger.Hex()), - Reason: reason, - BlockNumber: blockNumber, - }) - } - - return tc.walletRegistry. - DkgResultChallengedEvent(nil, nil, nil). - OnEvent(onEvent) -} - -func (tc *TbtcChain) OnDKGResultApproved( - handler func(event *tbtc.DKGResultApprovedEvent), -) subscription.EventSubscription { - onEvent := func( - resultHash [32]byte, - approver common.Address, - blockNumber uint64, - ) { - handler(&tbtc.DKGResultApprovedEvent{ - ResultHash: resultHash, - Approver: chain.Address(approver.Hex()), - BlockNumber: blockNumber, - }) - } - - return tc.walletRegistry. - DkgResultApprovedEvent(nil, nil, nil). - OnEvent(onEvent) -} - -// AssembleDKGResult assembles the DKG chain result according to the rules -// expected by the given chain. -func (tc *TbtcChain) AssembleDKGResult( - submitterMemberIndex group.MemberIndex, - groupPublicKey *ecdsa.PublicKey, - operatingMembersIndexes []group.MemberIndex, - misbehavedMembersIndexes []group.MemberIndex, - signatures map[group.MemberIndex][]byte, - groupSelectionResult *tbtc.GroupSelectionResult, -) (*tbtc.DKGChainResult, error) { - serializedGroupPublicKey, err := convertPubKeyToChainFormat(groupPublicKey) - if err != nil { - return nil, fmt.Errorf( - "could not convert group public key to chain format: [%v]", - err, - ) - } - - // Sort misbehavedMembersIndexes slice in ascending order as expected - // by the on-chain contract. - sort.Slice(misbehavedMembersIndexes[:], func(i, j int) bool { - return misbehavedMembersIndexes[i] < misbehavedMembersIndexes[j] - }) - - signingMemberIndices, signatureBytes, err := convertSignaturesToChainFormat( - signatures, - ) - if err != nil { - return nil, fmt.Errorf( - "could not convert signatures to chain format: [%v]", - err, - ) - } - - // Sort operatingOperatorsIDs slice in ascending order as the slice - // holding the operators IDs used to compute the members hash is - // expected to be sorted in the same way. - sort.Slice(operatingMembersIndexes[:], func(i, j int) bool { - return operatingMembersIndexes[i] < operatingMembersIndexes[j] - }) - - operatingOperatorsIDs := make([]chain.OperatorID, len(operatingMembersIndexes)) - for i, operatingMemberIndex := range operatingMembersIndexes { - operatingOperatorsIDs[i] = - groupSelectionResult.OperatorsIDs[operatingMemberIndex-1] - } - - membersHash, err := computeOperatorsIDsHash(operatingOperatorsIDs) - if err != nil { - return nil, fmt.Errorf("could not compute members hash: [%v]", err) - } - - return &tbtc.DKGChainResult{ - SubmitterMemberIndex: submitterMemberIndex, - GroupPublicKey: serializedGroupPublicKey[:], - MisbehavedMembersIndexes: misbehavedMembersIndexes, - Signatures: signatureBytes, - SigningMembersIndexes: signingMemberIndices, - Members: groupSelectionResult.OperatorsIDs, - MembersHash: membersHash, - }, nil -} - -func (tc *TbtcChain) SubmitDKGResult( - dkgResult *tbtc.DKGChainResult, -) error { - _, err := tc.walletRegistry.SubmitDkgResult( - convertDkgResultToAbiType(dkgResult), - ) - - return err -} - -// computeOperatorsIDsHash computes the keccak256 hash for the given list -// of operators IDs. -func computeOperatorsIDsHash(operatorsIDs chain.OperatorIDs) ([32]byte, error) { - uint32SliceType, err := abi.NewType("uint32[]", "uint32[]", nil) - if err != nil { - return [32]byte{}, err - } - - bytes, err := abi.Arguments{{Type: uint32SliceType}}.Pack(operatorsIDs) - if err != nil { - return [32]byte{}, err - } - - return crypto.Keccak256Hash(bytes), nil -} - -// convertSignaturesToChainFormat converts signatures map to two slices. The -// first slice contains indices of members from the map, sorted in ascending order -// as required by the contract. The second slice is a slice of concatenated -// signatures. Signatures and member indices are returned in the matching order. -// It requires each signature to be exactly 65-byte long. -func convertSignaturesToChainFormat( - signatures map[group.MemberIndex][]byte, -) ([]group.MemberIndex, []byte, error) { - membersIndexes := make([]group.MemberIndex, 0) - for memberIndex := range signatures { - membersIndexes = append(membersIndexes, memberIndex) - } - - sort.Slice(membersIndexes, func(i, j int) bool { - return membersIndexes[i] < membersIndexes[j] - }) - - signatureSize := 65 - - var signaturesSlice []byte - - for _, memberIndex := range membersIndexes { - signature := signatures[memberIndex] - - if len(signature) != signatureSize { - return nil, nil, fmt.Errorf( - "invalid signature size for member [%v] got [%d] bytes but [%d] bytes required", - memberIndex, - len(signature), - signatureSize, - ) - } - - signaturesSlice = append(signaturesSlice, signature...) - } - - return membersIndexes, signaturesSlice, nil -} - // convertPubKeyToChainFormat takes X and Y coordinates of a signer's public key // and concatenates it to a 64-byte long array. If any of coordinates is shorter // than 32-byte it is preceded with zeros. @@ -858,1553 +299,16 @@ func convertPubKeyToChainFormat(publicKey *ecdsa.PublicKey) ([64]byte, error) { return serialized, nil } -func (tc *TbtcChain) GetDKGState() (tbtc.DKGState, error) { - walletCreationState, err := tc.walletRegistry.GetWalletCreationState() - if err != nil { - return 0, err - } - - var state tbtc.DKGState - - switch walletCreationState { - case 0: - state = tbtc.Idle - case 1: - state = tbtc.AwaitingSeed - case 2: - state = tbtc.AwaitingResult - case 3: - state = tbtc.Challenge - default: - err = fmt.Errorf( - "unexpected wallet creation state: [%v]", - walletCreationState, - ) - } - - return state, err -} - -// CalculateDKGResultSignatureHash calculates a 32-byte hash that is used -// to produce a signature supporting the given groupPublicKey computed -// as result of the given DKG process. The misbehavedMembersIndexes parameter -// should contain indexes of members that were considered as misbehaved -// during the DKG process. The startBlock argument is the block at which -// the given DKG process started. -func (tc *TbtcChain) CalculateDKGResultSignatureHash( - groupPublicKey *ecdsa.PublicKey, - misbehavedMembersIndexes []group.MemberIndex, - startBlock uint64, -) (dkg.ResultSignatureHash, error) { - groupPublicKeyBytes := secp256k1.Marshal(groupPublicKey) - // Crop the 04 prefix as the calculateDKGResultSignatureHash function - // expects an unprefixed 64-byte public key, - unprefixedGroupPublicKeyBytes := groupPublicKeyBytes[1:] - - // Sort misbehavedMembersIndexes slice in ascending order as expected - // by the calculateDKGResultSignatureHash function. - sort.Slice(misbehavedMembersIndexes[:], func(i, j int) bool { - return misbehavedMembersIndexes[i] < misbehavedMembersIndexes[j] - }) - - return calculateDKGResultSignatureHash( - tc.chainID, - unprefixedGroupPublicKeyBytes, - misbehavedMembersIndexes, - big.NewInt(int64(startBlock)), - ) -} - -// calculateDKGResultSignatureHash computes the keccak256 hash for the given DKG -// result parameters. It expects that the groupPublicKey is a 64-byte uncompressed -// public key without the 04 prefix and misbehavedMembersIndexes slice is -// sorted in ascending order. Those expectations are forced by the contract. -func calculateDKGResultSignatureHash( - chainID *big.Int, - groupPublicKey []byte, - misbehavedMembersIndexes []group.MemberIndex, - startBlock *big.Int, -) (dkg.ResultSignatureHash, error) { - publicKeySize := 64 - - if len(groupPublicKey) != publicKeySize { - return dkg.ResultSignatureHash{}, fmt.Errorf( - "wrong group public key length", - ) - } - - uint256Type, err := abi.NewType("uint256", "uint256", nil) - if err != nil { - return dkg.ResultSignatureHash{}, err - } - bytesType, err := abi.NewType("bytes", "bytes", nil) - if err != nil { - return dkg.ResultSignatureHash{}, err - } - uint8SliceType, err := abi.NewType("uint8[]", "uint8[]", nil) - if err != nil { - return dkg.ResultSignatureHash{}, err - } - - bytes, err := abi.Arguments{ - {Type: uint256Type}, - {Type: bytesType}, - {Type: uint8SliceType}, - {Type: uint256Type}, - }.Pack( - chainID, - groupPublicKey, - misbehavedMembersIndexes, - startBlock, - ) - if err != nil { - return dkg.ResultSignatureHash{}, err - } - - return dkg.ResultSignatureHash(crypto.Keccak256Hash(bytes)), nil -} - -func (tc *TbtcChain) IsDKGResultValid( - dkgResult *tbtc.DKGChainResult, -) (bool, error) { - outcome, err := tc.walletRegistry.IsDkgResultValid( - convertDkgResultToAbiType(dkgResult), - ) - if err != nil { - return false, fmt.Errorf("cannot check result validity: [%v]", err) - } - - return parseDkgResultValidationOutcome(&outcome) -} - -// parseDkgResultValidationOutcome parses the DKG validation outcome and returns -// a boolean indicating whether the result is valid or not. The outcome parameter -// must be a pointer to a struct containing a boolean flag as the first field. -// -// TODO: Find a better way to get the validity flag. This would require changes -// in the contracts binding generator. -func parseDkgResultValidationOutcome( - outcome interface{}, -) (bool, error) { - value := reflect.ValueOf(outcome) - switch value.Kind() { - case reflect.Pointer: - default: - return false, fmt.Errorf("result validation outcome is not a pointer") - } - - field := value.Elem().Field(0) - switch field.Kind() { - case reflect.Bool: - return field.Bool(), nil - default: - return false, fmt.Errorf("cannot parse result validation outcome") - } -} - -func (tc *TbtcChain) ChallengeDKGResult(dkgResult *tbtc.DKGChainResult) error { - _, err := tc.walletRegistry.ChallengeDkgResult( - convertDkgResultToAbiType(dkgResult), - ) +// buildTxOutpointKey computes keccak256(txHash || uint32BE(outputIndex)) and +// returns it as a *big.Int. Used by both the deposit and moved-funds request +// lookup paths; the contract-side mapping is identical for both. +func buildTxOutpointKey(txHash bitcoin.Hash, outputIndex uint32) *big.Int { + indexBytes := make([]byte, 4) + binary.BigEndian.PutUint32(indexBytes, outputIndex) - return err -} - -func (tc *TbtcChain) ApproveDKGResult(dkgResult *tbtc.DKGChainResult) error { - result := convertDkgResultToAbiType(dkgResult) - - gasEstimate, err := tc.walletRegistry.ApproveDkgResultGasEstimate(result) - if err != nil { - return err - } - - // The original estimate for this contract call turned out to be too low. - // Here we add a 20% margin to overcome the gas problems. - gasEstimateWithMargin := float64(gasEstimate) * float64(1.2) - - _, err = tc.walletRegistry.ApproveDkgResult( - result, - ethutil.TransactionOptions{ - GasLimit: uint64(gasEstimateWithMargin), - }, - ) - - return err -} - -func (tc *TbtcChain) DKGParameters() (*tbtc.DKGParameters, error) { - parameters, err := tc.walletRegistry.DkgParameters() - if err != nil { - return nil, err - } - - return &tbtc.DKGParameters{ - SubmissionTimeoutBlocks: parameters.ResultSubmissionTimeout.Uint64(), - ChallengePeriodBlocks: parameters.ResultChallengePeriodLength.Uint64(), - ApprovePrecedencePeriodBlocks: parameters.SubmitterPrecedencePeriodLength.Uint64(), - }, nil -} - -func (tc *TbtcChain) OnInactivityClaimed( - handler func(event *tbtc.InactivityClaimedEvent), -) subscription.EventSubscription { - onEvent := func( - walletID [32]byte, - nonce *big.Int, - notifier common.Address, - blockNumber uint64, - ) { - handler(&tbtc.InactivityClaimedEvent{ - WalletID: walletID, - Nonce: nonce, - Notifier: chain.Address(notifier.Hex()), - BlockNumber: blockNumber, - }) - } - - return tc.walletRegistry.InactivityClaimedEvent(nil, nil).OnEvent(onEvent) -} - -func (tc *TbtcChain) AssembleInactivityClaim( - walletID [32]byte, - inactiveMembersIndices []group.MemberIndex, - signatures map[group.MemberIndex][]byte, - heartbeatFailed bool, -) ( - *tbtc.InactivityClaim, - error, -) { - signingMemberIndices, signatureBytes, err := convertSignaturesToChainFormat( - signatures, - ) - if err != nil { - return nil, fmt.Errorf( - "could not convert signatures to chain format: [%v]", - err, - ) - } - - return &tbtc.InactivityClaim{ - WalletID: walletID, - InactiveMembersIndices: inactiveMembersIndices, - HeartbeatFailed: heartbeatFailed, - Signatures: signatureBytes, - SigningMembersIndices: signingMemberIndices, - }, nil -} - -// convertInactivityClaimToAbiType converts the TBTC-specific inactivity claim -// to the format applicable for the WalletRegistry ABI. -func convertInactivityClaimToAbiType( - claim *tbtc.InactivityClaim, -) ecdsaabi.EcdsaInactivityClaim { - inactiveMembersIndices := make([]*big.Int, len(claim.InactiveMembersIndices)) - for i, memberIndex := range claim.InactiveMembersIndices { - inactiveMembersIndices[i] = big.NewInt(int64(memberIndex)) - } - - signingMembersIndices := make([]*big.Int, len(claim.SigningMembersIndices)) - for i, memberIndex := range claim.SigningMembersIndices { - signingMembersIndices[i] = big.NewInt(int64(memberIndex)) - } - - return ecdsaabi.EcdsaInactivityClaim{ - WalletID: claim.WalletID, - InactiveMembersIndices: inactiveMembersIndices, - HeartbeatFailed: claim.HeartbeatFailed, - Signatures: claim.Signatures, - SigningMembersIndices: signingMembersIndices, - } -} - -func (tc *TbtcChain) SubmitInactivityClaim( - claim *tbtc.InactivityClaim, - nonce *big.Int, - groupMembers []uint32, -) error { - _, err := tc.walletRegistry.NotifyOperatorInactivity( - convertInactivityClaimToAbiType(claim), - nonce, - groupMembers, - ) - - return err -} - -func (tc *TbtcChain) CalculateInactivityClaimHash( - claim *inactivity.ClaimPreimage, -) (inactivity.ClaimHash, error) { - walletPublicKeyBytes := secp256k1.Marshal(claim.WalletPublicKey) - // Crop the 04 prefix as the calculateInactivityClaimHash function expects - // an unprefixed 64-byte public key, - unprefixedGroupPublicKeyBytes := walletPublicKeyBytes[1:] - - // The type representing inactive member index should be `big.Int` as the - // smart contract reading the calculated hash uses `uint256` for inactive - // member indexes. - inactiveMembersIndexes := make([]*big.Int, len(claim.InactiveMembersIndexes)) - for i, index := range claim.InactiveMembersIndexes { - inactiveMembersIndexes[i] = big.NewInt(int64(index)) - } - - return calculateInactivityClaimHash( - tc.chainID, - claim.Nonce, - unprefixedGroupPublicKeyBytes, - inactiveMembersIndexes, - claim.HeartbeatFailed, - ) -} - -func calculateInactivityClaimHash( - chainID *big.Int, - nonce *big.Int, - walletPublicKey []byte, - inactiveMembersIndexes []*big.Int, - heartbeatFailed bool, -) (inactivity.ClaimHash, error) { - publicKeySize := 64 - - if len(walletPublicKey) != publicKeySize { - return inactivity.ClaimHash{}, fmt.Errorf( - "wrong wallet public key length", - ) - } - - uint256Type, err := abi.NewType("uint256", "uint256", nil) - if err != nil { - return inactivity.ClaimHash{}, err - } - bytesType, err := abi.NewType("bytes", "bytes", nil) - if err != nil { - return inactivity.ClaimHash{}, err - } - uint256SliceType, err := abi.NewType("uint256[]", "uint256[]", nil) - if err != nil { - return inactivity.ClaimHash{}, err - } - boolType, err := abi.NewType("bool", "bool", nil) - if err != nil { - return inactivity.ClaimHash{}, err - } - - bytes, err := abi.Arguments{ - {Type: uint256Type}, - {Type: uint256Type}, - {Type: bytesType}, - {Type: uint256SliceType}, - {Type: boolType}, - }.Pack( - chainID, - nonce, - walletPublicKey, - inactiveMembersIndexes, - heartbeatFailed, - ) - if err != nil { - return inactivity.ClaimHash{}, err - } - - return inactivity.ClaimHash(crypto.Keccak256Hash(bytes)), nil -} - -func (tc *TbtcChain) GetInactivityClaimNonce( - walletID [32]byte, -) (*big.Int, error) { - nonce, err := tc.walletRegistry.InactivityClaimNonce(walletID) - if err != nil { - return nil, fmt.Errorf( - "failed to get inactivity claim nonce: [%w]", - err, - ) - } - - return nonce, nil -} - -func (tc *TbtcChain) PastDepositRevealedEvents( - filter *tbtc.DepositRevealedEventFilter, -) ([]*tbtc.DepositRevealedEvent, error) { - var startBlock uint64 - var endBlock *uint64 - var depositor []common.Address - var walletPublicKeyHash [][20]byte - - if filter != nil { - startBlock = filter.StartBlock - endBlock = filter.EndBlock - - for _, d := range filter.Depositor { - depositor = append(depositor, common.HexToAddress(d.String())) - } - - walletPublicKeyHash = filter.WalletPublicKeyHash - } - - events, err := tc.bridge.PastDepositRevealedEvents( - startBlock, - endBlock, - depositor, - walletPublicKeyHash, - ) - if err != nil { - return nil, err - } - - convertedEvents := make([]*tbtc.DepositRevealedEvent, 0) - for _, event := range events { - var vault *chain.Address - if event.Vault != [20]byte{} { - v := chain.Address(event.Vault.Hex()) - vault = &v - } - - convertedEvent := &tbtc.DepositRevealedEvent{ - // We can map the event.FundingTxHash field directly to the - // bitcoin.Hash type. This is because event.FundingTxHash is - // a [32]byte type representing a hash in the bitcoin.InternalByteOrder, - // just as bitcoin.Hash assumes. - FundingTxHash: event.FundingTxHash, - FundingOutputIndex: event.FundingOutputIndex, - Depositor: chain.Address(event.Depositor.Hex()), - Amount: event.Amount, - BlindingFactor: event.BlindingFactor, - WalletPublicKeyHash: event.WalletPubKeyHash, - RefundPublicKeyHash: event.RefundPubKeyHash, - RefundLocktime: event.RefundLocktime, - Vault: vault, - BlockNumber: event.Raw.BlockNumber, - } - - convertedEvents = append(convertedEvents, convertedEvent) - } - - sort.SliceStable( - convertedEvents, - func(i, j int) bool { - return convertedEvents[i].BlockNumber < convertedEvents[j].BlockNumber - }, - ) - - return convertedEvents, err -} - -func (tc *TbtcChain) PastRedemptionRequestedEvents( - filter *tbtc.RedemptionRequestedEventFilter, -) ([]*tbtc.RedemptionRequestedEvent, error) { - var startBlock uint64 - var endBlock *uint64 - var redeemers []common.Address - var walletPublicKeyHash [][20]byte - - if filter != nil { - startBlock = filter.StartBlock - endBlock = filter.EndBlock - - for _, r := range filter.Redeemer { - redeemers = append(redeemers, common.HexToAddress(r.String())) - } - - walletPublicKeyHash = filter.WalletPublicKeyHash - } - - events, err := tc.bridge.PastRedemptionRequestedEvents( - startBlock, - endBlock, - walletPublicKeyHash, - redeemers, - ) - if err != nil { - return nil, err - } - - convertedEvents := make([]*tbtc.RedemptionRequestedEvent, 0) - for _, event := range events { - redeemerOutputScript, err := bitcoin.NewScriptFromVarLenData( - event.RedeemerOutputScript, - ) - if err != nil { - return nil, err - } - - convertedEvent := &tbtc.RedemptionRequestedEvent{ - WalletPublicKeyHash: event.WalletPubKeyHash, - RedeemerOutputScript: redeemerOutputScript, - Redeemer: chain.Address(event.Redeemer.Hex()), - RequestedAmount: event.RequestedAmount, - TreasuryFee: event.TreasuryFee, - TxMaxFee: event.TreasuryFee, - BlockNumber: event.Raw.BlockNumber, - } - - convertedEvents = append(convertedEvents, convertedEvent) - } - - sort.SliceStable( - convertedEvents, - func(i, j int) bool { - return convertedEvents[i].BlockNumber < convertedEvents[j].BlockNumber - }, - ) - - return convertedEvents, err -} - -func (tc *TbtcChain) GetDepositRequest( - fundingTxHash bitcoin.Hash, - fundingOutputIndex uint32, -) (*tbtc.DepositChainRequest, bool, error) { - depositKey := buildDepositKey(fundingTxHash, fundingOutputIndex) - depositCacheKey := depositKey.Text(16) - - tc.sweptDepositsCache.Sweep() - if cachedRequest, ok := tc.sweptDepositsCache.Get(depositCacheKey); ok { - return cachedRequest, true, nil - } - - chainRequest, err := tc.bridge.Deposits(depositKey) - if err != nil { - return nil, false, fmt.Errorf( - "cannot get deposit request for key [0x%x]: [%v]", - depositKey.Text(16), - err, - ) - } - - // Deposit not found. - if chainRequest.RevealedAt == 0 { - return nil, false, nil - } - - var vault *chain.Address - if chainRequest.Vault != [20]byte{} { - v := chain.Address(chainRequest.Vault.Hex()) - vault = &v - } - - var extraData *[32]byte - if chainRequest.ExtraData != [32]byte{} { - extraData = &chainRequest.ExtraData - } - - request := &tbtc.DepositChainRequest{ - Depositor: chain.Address(chainRequest.Depositor.Hex()), - Amount: chainRequest.Amount, - RevealedAt: time.Unix(int64(chainRequest.RevealedAt), 0), - Vault: vault, - TreasuryFee: chainRequest.TreasuryFee, - SweptAt: time.Unix(int64(chainRequest.SweptAt), 0), - ExtraData: extraData, - } - - // If the request was swept on-chain, there is a guarantee that no - // further changes will occur regarding its parameters. - // Such a request can be cached. - if isSwept := request.SweptAt.Unix() != 0; isSwept { - tc.sweptDepositsCache.Add(depositCacheKey, request) - } - - return request, true, nil -} - -func (tc *TbtcChain) PastNewWalletRegisteredEvents( - filter *tbtc.NewWalletRegisteredEventFilter, -) ([]*tbtc.NewWalletRegisteredEvent, error) { - var startBlock uint64 - var endBlock *uint64 - var ecdsaWalletID [][32]byte - var walletPublicKeyHash [][20]byte - - if filter != nil { - startBlock = filter.StartBlock - endBlock = filter.EndBlock - ecdsaWalletID = filter.EcdsaWalletID - walletPublicKeyHash = filter.WalletPublicKeyHash - } - - events, err := tc.bridge.PastNewWalletRegisteredEvents( - startBlock, - endBlock, - ecdsaWalletID, - walletPublicKeyHash, - ) - if err != nil { - return nil, err - } - - convertedEvents := make([]*tbtc.NewWalletRegisteredEvent, 0) - for _, event := range events { - convertedEvent := &tbtc.NewWalletRegisteredEvent{ - EcdsaWalletID: event.EcdsaWalletID, - WalletPublicKeyHash: event.WalletPubKeyHash, - BlockNumber: event.Raw.BlockNumber, - } - - convertedEvents = append(convertedEvents, convertedEvent) - } - - sort.SliceStable( - convertedEvents, - func(i, j int) bool { - return convertedEvents[i].BlockNumber < convertedEvents[j].BlockNumber - }, - ) - - return convertedEvents, err -} - -func (tc *TbtcChain) CalculateWalletID( - walletPublicKey *ecdsa.PublicKey, -) ([32]byte, error) { - return calculateWalletID(walletPublicKey) -} - -func calculateWalletID(walletPublicKey *ecdsa.PublicKey) ([32]byte, error) { - walletPublicKeyBytes, err := convertPubKeyToChainFormat(walletPublicKey) - if err != nil { - return [32]byte{}, fmt.Errorf( - "error while converting wallet public key to chain format: [%v]", - err, - ) - } - - return crypto.Keccak256Hash(walletPublicKeyBytes[:]), nil -} - -func (tc *TbtcChain) IsWalletRegistered(EcdsaWalletID [32]byte) (bool, error) { - isWalletRegistered, err := tc.walletRegistry.IsWalletRegistered( - EcdsaWalletID, - ) - if err != nil { - return false, fmt.Errorf( - "cannot check if wallet with ECDSA ID [0x%x] is registered: [%v]", - EcdsaWalletID, - err, - ) - } - - return isWalletRegistered, nil -} - -func (tc *TbtcChain) GetWallet( - walletPublicKeyHash [20]byte, -) (*tbtc.WalletChainData, error) { - wallet, err := tc.bridge.Wallets(walletPublicKeyHash) - if err != nil { - return nil, fmt.Errorf( - "cannot get wallet for public key hash [0x%x]: [%v]", - walletPublicKeyHash, - err, - ) - } - - // Wallet not found. - if wallet.CreatedAt == 0 { - return nil, fmt.Errorf( - "no wallet for public key hash [0x%x]", - wallet, - ) - } - - walletState, err := parseWalletState(wallet.State) - if err != nil { - return nil, fmt.Errorf("cannot parse wallet state: [%v]", err) - } - - return &tbtc.WalletChainData{ - EcdsaWalletID: wallet.EcdsaWalletID, - MainUtxoHash: wallet.MainUtxoHash, - PendingRedemptionsValue: wallet.PendingRedemptionsValue, - CreatedAt: time.Unix(int64(wallet.CreatedAt), 0), - MovingFundsRequestedAt: time.Unix(int64(wallet.MovingFundsRequestedAt), 0), - ClosingStartedAt: time.Unix(int64(wallet.ClosingStartedAt), 0), - PendingMovedFundsSweepRequestsCount: wallet.PendingMovedFundsSweepRequestsCount, - State: walletState, - MovingFundsTargetWalletsCommitmentHash: wallet.MovingFundsTargetWalletsCommitmentHash, - }, nil -} - -func (tc *TbtcChain) OnWalletClosed( - handler func(event *tbtc.WalletClosedEvent), -) subscription.EventSubscription { - onEvent := func( - walletID [32]byte, - blockNumber uint64, - ) { - handler(&tbtc.WalletClosedEvent{ - WalletID: walletID, - BlockNumber: blockNumber, - }) - } - return tc.walletRegistry.WalletClosedEvent(nil, nil).OnEvent(onEvent) -} - -func (tc *TbtcChain) ComputeMainUtxoHash( - mainUtxo *bitcoin.UnspentTransactionOutput, -) [32]byte { - return computeMainUtxoHash(mainUtxo) -} - -func computeMainUtxoHash(mainUtxo *bitcoin.UnspentTransactionOutput) [32]byte { - outputIndexBytes := make([]byte, 4) - binary.BigEndian.PutUint32(outputIndexBytes, mainUtxo.Outpoint.OutputIndex) - - valueBytes := make([]byte, 8) - binary.BigEndian.PutUint64(valueBytes, uint64(mainUtxo.Value)) - - mainUtxoHash := crypto.Keccak256Hash( - append( - append( - mainUtxo.Outpoint.TransactionHash[:], - outputIndexBytes..., - ), valueBytes..., - ), - ) - - return mainUtxoHash -} - -func (tc *TbtcChain) ComputeMovingFundsCommitmentHash( - targetWallets [][20]byte, -) [32]byte { - return computeMovingFundsCommitmentHash(targetWallets) -} - -func computeMovingFundsCommitmentHash(targetWallets [][20]byte) [32]byte { - packedWallets := []byte{} - - for _, wallet := range targetWallets { - packedWallets = append(packedWallets, wallet[:]...) - // Each wallet hash must be padded with 12 zero bytes following the - // actual hash. - packedWallets = append(packedWallets, make([]byte, 12)...) - } - - return crypto.Keccak256Hash(packedWallets) -} - -func (tc *TbtcChain) BuildDepositKey( - fundingTxHash bitcoin.Hash, - fundingOutputIndex uint32, -) *big.Int { - return buildDepositKey(fundingTxHash, fundingOutputIndex) -} - -func (tc *TbtcChain) BuildRedemptionKey( - walletPublicKeyHash [20]byte, - redeemerOutputScript bitcoin.Script, -) (*big.Int, error) { - return buildRedemptionKey(walletPublicKeyHash, redeemerOutputScript) -} - -func (tc *TbtcChain) GetDepositParameters() (tbtc.DepositParameters, error) { - parameters, err := tc.bridge.DepositParameters() - if err != nil { - return tbtc.DepositParameters{}, err - } - - return tbtc.DepositParameters{ - DustThreshold: parameters.DepositDustThreshold, - TreasuryFeeDivisor: parameters.DepositTreasuryFeeDivisor, - TxMaxFee: parameters.DepositTxMaxFee, - RevealAheadPeriod: parameters.DepositRevealAheadPeriod, - }, nil -} - -func (tc *TbtcChain) GetPendingRedemptionRequest( - walletPublicKeyHash [20]byte, - redeemerOutputScript bitcoin.Script, -) (*tbtc.RedemptionRequest, bool, error) { - redemptionKey, err := buildRedemptionKey(walletPublicKeyHash, redeemerOutputScript) - if err != nil { - return nil, false, fmt.Errorf("cannot build redemption key: [%v]", err) - } - - redemptionRequest, err := tc.bridge.PendingRedemptions(redemptionKey) - if err != nil { - return nil, false, fmt.Errorf( - "cannot get pending redemption request for key [0x%x]: [%v]", - redemptionKey.Text(16), - err, - ) - } - - // Redemption not found. - if redemptionRequest.RequestedAt == 0 { - return nil, false, nil - } - - return &tbtc.RedemptionRequest{ - Redeemer: chain.Address(redemptionRequest.Redeemer.Hex()), - RedeemerOutputScript: redeemerOutputScript, - RequestedAmount: redemptionRequest.RequestedAmount, - TreasuryFee: redemptionRequest.TreasuryFee, - TxMaxFee: redemptionRequest.TxMaxFee, - RequestedAt: time.Unix(int64(redemptionRequest.RequestedAt), 0), - }, true, nil -} - -func (tc *TbtcChain) SubmitRedemptionProofWithReimbursement( - transaction *bitcoin.Transaction, - proof *bitcoin.SpvProof, - mainUTXO bitcoin.UnspentTransactionOutput, - walletPublicKeyHash [20]byte, -) error { - bitcoinTxInfo := tbtcabi.BitcoinTxInfo3{ - Version: transaction.SerializeVersion(), - InputVector: transaction.SerializeInputs(), - OutputVector: transaction.SerializeOutputs(), - Locktime: transaction.SerializeLocktime(), - } - redemptionProof := tbtcabi.BitcoinTxProof2{ - MerkleProof: proof.MerkleProof, - TxIndexInBlock: big.NewInt(int64(proof.TxIndexInBlock)), - BitcoinHeaders: proof.BitcoinHeaders, - CoinbasePreimage: proof.CoinbasePreimage, - CoinbaseProof: proof.CoinbaseProof, - } - utxo := tbtcabi.BitcoinTxUTXO2{ - TxHash: mainUTXO.Outpoint.TransactionHash, - TxOutputIndex: mainUTXO.Outpoint.OutputIndex, - TxOutputValue: uint64(mainUTXO.Value), - } - - gasEstimate, err := tc.maintainerProxy.SubmitRedemptionProofGasEstimate( - bitcoinTxInfo, - redemptionProof, - utxo, - walletPublicKeyHash, - ) - if err != nil { - return err - } - - // The original estimate for this contract call is too low and the call - // fails on reimbursing the submitter. Example: - // 0xe27a92883e0e64da8a3a54a15a260ea2f4d3d48470129ac5c09bfe9637d7e114 - // Here we add a 20% margin to overcome the gas problems. - gasEstimateWithMargin := float64(gasEstimate) * float64(1.2) - - _, err = tc.maintainerProxy.SubmitRedemptionProof( - bitcoinTxInfo, - redemptionProof, - utxo, - walletPublicKeyHash, - ethutil.TransactionOptions{ - GasLimit: uint64(gasEstimateWithMargin), - }, - ) - - return err -} - -func buildRedemptionKey( - walletPublicKeyHash [20]byte, - redeemerOutputScript bitcoin.Script, -) (*big.Int, error) { - // The Bridge contract builds the redemption key using the length-prefixed - // redeemer output script. - prefixedRedeemerOutputScript, err := redeemerOutputScript.ToVarLenData() - if err != nil { - return nil, fmt.Errorf("cannot build prefixed redeemer output script: [%v]", err) - } - - redeemerOutputScriptHash := crypto.Keccak256Hash(prefixedRedeemerOutputScript) - - redemptionKey := crypto.Keccak256Hash( - append(redeemerOutputScriptHash[:], walletPublicKeyHash[:]...), - ) - - return redemptionKey.Big(), nil + return crypto.Keccak256Hash(append(txHash[:], indexBytes...)).Big() } func (tc *TbtcChain) TxProofDifficultyFactor() (*big.Int, error) { return tc.bridge.TxProofDifficultyFactor() } - -func (tc *TbtcChain) SubmitDepositSweepProofWithReimbursement( - transaction *bitcoin.Transaction, - proof *bitcoin.SpvProof, - mainUTXO bitcoin.UnspentTransactionOutput, - vault common.Address, -) error { - bitcoinTxInfo := tbtcabi.BitcoinTxInfo3{ - Version: transaction.SerializeVersion(), - InputVector: transaction.SerializeInputs(), - OutputVector: transaction.SerializeOutputs(), - Locktime: transaction.SerializeLocktime(), - } - sweepProof := tbtcabi.BitcoinTxProof2{ - MerkleProof: proof.MerkleProof, - TxIndexInBlock: big.NewInt(int64(proof.TxIndexInBlock)), - BitcoinHeaders: proof.BitcoinHeaders, - CoinbasePreimage: proof.CoinbasePreimage, - CoinbaseProof: proof.CoinbaseProof, - } - utxo := tbtcabi.BitcoinTxUTXO2{ - TxHash: mainUTXO.Outpoint.TransactionHash, - TxOutputIndex: mainUTXO.Outpoint.OutputIndex, - TxOutputValue: uint64(mainUTXO.Value), - } - - gasEstimate, err := tc.maintainerProxy.SubmitDepositSweepProofGasEstimate( - bitcoinTxInfo, - sweepProof, - utxo, - vault, - ) - if err != nil { - return err - } - - // The original estimate for this contract call is too low and the call - // fails on reimbursing the submitter. Example: - // 0xe27a92883e0e64da8a3a54a15a260ea2f4d3d48470129ac5c09bfe9637d7e114 - // Here we add a 20% margin to overcome the gas problems. - gasEstimateWithMargin := float64(gasEstimate) * float64(1.2) - - _, err = tc.maintainerProxy.SubmitDepositSweepProof( - bitcoinTxInfo, - sweepProof, - utxo, - vault, - ethutil.TransactionOptions{ - GasLimit: uint64(gasEstimateWithMargin), - }, - ) - - return err -} - -func (tc *TbtcChain) GetRedemptionParameters() (tbtc.RedemptionParameters, error) { - parameters, err := tc.bridge.RedemptionParameters() - if err != nil { - return tbtc.RedemptionParameters{}, err - } - - return tbtc.RedemptionParameters{ - DustThreshold: parameters.RedemptionDustThreshold, - TreasuryFeeDivisor: parameters.RedemptionTreasuryFeeDivisor, - TxMaxFee: parameters.RedemptionTxMaxFee, - TxMaxTotalFee: parameters.RedemptionTxMaxTotalFee, - Timeout: parameters.RedemptionTimeout, - TimeoutSlashingAmount: parameters.RedemptionTimeoutSlashingAmount, - TimeoutNotifierRewardMultiplier: parameters.RedemptionTimeoutNotifierRewardMultiplier, - }, nil -} - -func (tc *TbtcChain) GetWalletParameters() (tbtc.WalletParameters, error) { - parameters, err := tc.bridge.WalletParameters() - if err != nil { - return tbtc.WalletParameters{}, err - } - - return tbtc.WalletParameters{ - CreationPeriod: parameters.WalletCreationPeriod, - CreationMinBtcBalance: parameters.WalletCreationMinBtcBalance, - CreationMaxBtcBalance: parameters.WalletCreationMaxBtcBalance, - ClosureMinBtcBalance: parameters.WalletClosureMinBtcBalance, - MaxAge: parameters.WalletMaxAge, - MaxBtcTransfer: parameters.WalletMaxBtcTransfer, - ClosingPeriod: parameters.WalletClosingPeriod, - }, nil -} - -func (tc *TbtcChain) GetLiveWalletsCount() (uint32, error) { - return tc.bridge.LiveWalletsCount() -} - -func (tc *TbtcChain) PastMovingFundsCommitmentSubmittedEvents( - filter *tbtc.MovingFundsCommitmentSubmittedEventFilter, -) ([]*tbtc.MovingFundsCommitmentSubmittedEvent, error) { - var startBlock uint64 - var endBlock *uint64 - var walletPublicKeyHash [][20]byte - - if filter != nil { - startBlock = filter.StartBlock - endBlock = filter.EndBlock - walletPublicKeyHash = filter.WalletPublicKeyHash - } - - events, err := tc.bridge.PastMovingFundsCommitmentSubmittedEvents( - startBlock, - endBlock, - walletPublicKeyHash, - ) - if err != nil { - return nil, err - } - - convertedEvents := make([]*tbtc.MovingFundsCommitmentSubmittedEvent, 0) - for _, event := range events { - convertedEvent := &tbtc.MovingFundsCommitmentSubmittedEvent{ - WalletPublicKeyHash: event.WalletPubKeyHash, - TargetWallets: event.TargetWallets, - Submitter: chain.Address(event.Submitter.Hex()), - BlockNumber: event.Raw.BlockNumber, - } - - convertedEvents = append(convertedEvents, convertedEvent) - } - - sort.SliceStable( - convertedEvents, - func(i, j int) bool { - return convertedEvents[i].BlockNumber < convertedEvents[j].BlockNumber - }, - ) - - return convertedEvents, err -} - -func (tc *TbtcChain) PastMovingFundsCompletedEvents( - filter *tbtc.MovingFundsCompletedEventFilter, -) ([]*tbtc.MovingFundsCompletedEvent, error) { - var startBlock uint64 - var endBlock *uint64 - var walletPublicKeyHash [][20]byte - - if filter != nil { - startBlock = filter.StartBlock - endBlock = filter.EndBlock - walletPublicKeyHash = filter.WalletPublicKeyHash - } - - events, err := tc.bridge.PastMovingFundsCompletedEvents( - startBlock, - endBlock, - walletPublicKeyHash, - ) - if err != nil { - return nil, err - } - - convertedEvents := make([]*tbtc.MovingFundsCompletedEvent, 0) - for _, event := range events { - convertedEvent := &tbtc.MovingFundsCompletedEvent{ - WalletPublicKeyHash: event.WalletPubKeyHash, - MovingFundsTxHash: event.MovingFundsTxHash, - BlockNumber: event.Raw.BlockNumber, - } - - convertedEvents = append(convertedEvents, convertedEvent) - } - - sort.SliceStable( - convertedEvents, - func(i, j int) bool { - return convertedEvents[i].BlockNumber < convertedEvents[j].BlockNumber - }, - ) - - return convertedEvents, err -} - -func buildDepositKey( - fundingTxHash bitcoin.Hash, - fundingOutputIndex uint32, -) *big.Int { - fundingOutputIndexBytes := make([]byte, 4) - binary.BigEndian.PutUint32(fundingOutputIndexBytes, fundingOutputIndex) - - depositKey := crypto.Keccak256Hash( - append(fundingTxHash[:], fundingOutputIndexBytes...), - ) - - return depositKey.Big() -} - -func convertDepositSweepProposalToAbiType( - walletPublicKeyHash [20]byte, - proposal *tbtc.DepositSweepProposal, -) tbtcabi.WalletProposalValidatorDepositSweepProposal { - depositsKeys := make( - []tbtcabi.WalletProposalValidatorDepositKey, - len(proposal.DepositsKeys), - ) - - for i, depositKey := range proposal.DepositsKeys { - // We can map the depositKey.FundingTxHash field directly to the - // [32]byte type. This is because depositKey.FundingTxHash is - // a bitcoin.Hash type representing a hash in the - // bitcoin.InternalByteOrder, just as the on-chain contract assumes. - depositsKeys[i] = tbtcabi.WalletProposalValidatorDepositKey{ - FundingTxHash: depositKey.FundingTxHash, - FundingOutputIndex: depositKey.FundingOutputIndex, - } - } - - return tbtcabi.WalletProposalValidatorDepositSweepProposal{ - WalletPubKeyHash: walletPublicKeyHash, - DepositsKeys: depositsKeys, - SweepTxFee: proposal.SweepTxFee, - DepositsRevealBlocks: proposal.DepositsRevealBlocks, - } -} - -func parseWalletState(value uint8) (tbtc.WalletState, error) { - switch value { - case 0: - return tbtc.StateUnknown, nil - case 1: - return tbtc.StateLive, nil - case 2: - return tbtc.StateMovingFunds, nil - case 3: - return tbtc.StateClosing, nil - case 4: - return tbtc.StateClosed, nil - case 5: - return tbtc.StateTerminated, nil - default: - return 0, fmt.Errorf("unexpected wallet state value: [%v]", value) - } -} - -func (tc *TbtcChain) ValidateDepositSweepProposal( - walletPublicKeyHash [20]byte, - proposal *tbtc.DepositSweepProposal, - depositsExtraInfo []struct { - *tbtc.Deposit - FundingTx *bitcoin.Transaction - }, -) error { - dei := make([]tbtcabi.WalletProposalValidatorDepositExtraInfo, len(depositsExtraInfo)) - for i, depositExtraInfo := range depositsExtraInfo { - fundingTx := tbtcabi.BitcoinTxInfo2{ - Version: depositExtraInfo.FundingTx.SerializeVersion(), - InputVector: depositExtraInfo.FundingTx.SerializeInputs(), - OutputVector: depositExtraInfo.FundingTx.SerializeOutputs(), - Locktime: depositExtraInfo.FundingTx.SerializeLocktime(), - } - - dei[i] = tbtcabi.WalletProposalValidatorDepositExtraInfo{ - FundingTx: fundingTx, - BlindingFactor: depositExtraInfo.Deposit.BlindingFactor, - WalletPubKeyHash: depositExtraInfo.Deposit.WalletPublicKeyHash, - RefundPubKeyHash: depositExtraInfo.Deposit.RefundPublicKeyHash, - RefundLocktime: depositExtraInfo.Deposit.RefundLocktime, - } - } - - valid, err := tc.walletProposalValidator.ValidateDepositSweepProposal( - convertDepositSweepProposalToAbiType(walletPublicKeyHash, proposal), - dei, - ) - if err != nil { - return fmt.Errorf("validation failed: [%v]", err) - } - - // Should never happen because `validateDepositSweepProposal` returns true - // or reverts (returns an error) but do the check just in case. - if !valid { - return fmt.Errorf("unexpected validation result") - } - - return nil -} - -func (tc *TbtcChain) GetDepositSweepMaxSize() (uint16, error) { - return tc.walletProposalValidator.DEPOSITSWEEPMAXSIZE() -} - -func (tc *TbtcChain) SubmitMovingFundsCommitment( - walletPublicKeyHash [20]byte, - walletMainUTXO bitcoin.UnspentTransactionOutput, - walletMembersIDs []uint32, - walletMemberIndex uint32, - targetWallets [][20]byte, -) error { - mainUtxo := tbtcabi.BitcoinTxUTXO{ - TxHash: walletMainUTXO.Outpoint.TransactionHash, - TxOutputIndex: walletMainUTXO.Outpoint.OutputIndex, - TxOutputValue: uint64(walletMainUTXO.Value), - } - _, err := tc.bridge.SubmitMovingFundsCommitment( - walletPublicKeyHash, - mainUtxo, - walletMembersIDs, - big.NewInt(int64(walletMemberIndex)), - targetWallets, - ) - return err -} - -func (tc *TbtcChain) SubmitMovingFundsProofWithReimbursement( - transaction *bitcoin.Transaction, - proof *bitcoin.SpvProof, - mainUTXO bitcoin.UnspentTransactionOutput, - walletPublicKeyHash [20]byte, -) error { - bitcoinTxInfo := tbtcabi.BitcoinTxInfo3{ - Version: transaction.SerializeVersion(), - InputVector: transaction.SerializeInputs(), - OutputVector: transaction.SerializeOutputs(), - Locktime: transaction.SerializeLocktime(), - } - movingFundsProof := tbtcabi.BitcoinTxProof2{ - MerkleProof: proof.MerkleProof, - TxIndexInBlock: big.NewInt(int64(proof.TxIndexInBlock)), - BitcoinHeaders: proof.BitcoinHeaders, - CoinbasePreimage: proof.CoinbasePreimage, - CoinbaseProof: proof.CoinbaseProof, - } - utxo := tbtcabi.BitcoinTxUTXO2{ - TxHash: mainUTXO.Outpoint.TransactionHash, - TxOutputIndex: mainUTXO.Outpoint.OutputIndex, - TxOutputValue: uint64(mainUTXO.Value), - } - - gasEstimate, err := tc.maintainerProxy.SubmitMovingFundsProofGasEstimate( - bitcoinTxInfo, - movingFundsProof, - utxo, - walletPublicKeyHash, - ) - if err != nil { - return err - } - - // The original estimate for this contract call is too low and the call - // fails on reimbursing the submitter. Example: - // 0xe27a92883e0e64da8a3a54a15a260ea2f4d3d48470129ac5c09bfe9637d7e114 - // Here we add a 20% margin to overcome the gas problems. - gasEstimateWithMargin := float64(gasEstimate) * float64(1.2) - - _, err = tc.maintainerProxy.SubmitMovingFundsProof( - bitcoinTxInfo, - movingFundsProof, - utxo, - walletPublicKeyHash, - ethutil.TransactionOptions{ - GasLimit: uint64(gasEstimateWithMargin), - }, - ) - - return err -} - -func (tc *TbtcChain) SubmitMovedFundsSweepProofWithReimbursement( - transaction *bitcoin.Transaction, - proof *bitcoin.SpvProof, - mainUTXO bitcoin.UnspentTransactionOutput, -) error { - bitcoinTxInfo := tbtcabi.BitcoinTxInfo3{ - Version: transaction.SerializeVersion(), - InputVector: transaction.SerializeInputs(), - OutputVector: transaction.SerializeOutputs(), - Locktime: transaction.SerializeLocktime(), - } - movedFundsSweepProof := tbtcabi.BitcoinTxProof2{ - MerkleProof: proof.MerkleProof, - TxIndexInBlock: big.NewInt(int64(proof.TxIndexInBlock)), - BitcoinHeaders: proof.BitcoinHeaders, - CoinbasePreimage: proof.CoinbasePreimage, - CoinbaseProof: proof.CoinbaseProof, - } - utxo := tbtcabi.BitcoinTxUTXO2{ - TxHash: mainUTXO.Outpoint.TransactionHash, - TxOutputIndex: mainUTXO.Outpoint.OutputIndex, - TxOutputValue: uint64(mainUTXO.Value), - } - - gasEstimate, err := tc.maintainerProxy.SubmitMovedFundsSweepProofGasEstimate( - bitcoinTxInfo, - movedFundsSweepProof, - utxo, - ) - if err != nil { - return err - } - - // The original estimate for this contract call is too low and the call - // fails on reimbursing the submitter. Example: - // 0xe27a92883e0e64da8a3a54a15a260ea2f4d3d48470129ac5c09bfe9637d7e114 - // Here we add a 20% margin to overcome the gas problems. - gasEstimateWithMargin := float64(gasEstimate) * float64(1.2) - - _, err = tc.maintainerProxy.SubmitMovedFundsSweepProof( - bitcoinTxInfo, - movedFundsSweepProof, - utxo, - ethutil.TransactionOptions{ - GasLimit: uint64(gasEstimateWithMargin), - }, - ) - - return err -} - -func (tc *TbtcChain) ValidateMovedFundsSweepProposal( - walletPublicKeyHash [20]byte, - proposal *tbtc.MovedFundsSweepProposal, -) error { - abiProposal := tbtcabi.WalletProposalValidatorMovedFundsSweepProposal{ - WalletPubKeyHash: walletPublicKeyHash, - MovingFundsTxHash: proposal.MovingFundsTxHash, - MovingFundsTxOutputIndex: proposal.MovingFundsTxOutputIndex, - MovedFundsSweepTxFee: proposal.SweepTxFee, - } - - valid, err := tc.walletProposalValidator.ValidateMovedFundsSweepProposal( - abiProposal, - ) - if err != nil { - return fmt.Errorf("validation failed: [%v]", err) - } - - // Should never happen because `validateMovedFundsSweepProposal` returns - // true or reverts (returns an error) but do the check just in case. - if !valid { - return fmt.Errorf("unexpected validation result") - } - - return nil -} - -func (tc *TbtcChain) ValidateRedemptionProposal( - walletPublicKeyHash [20]byte, - proposal *tbtc.RedemptionProposal, -) error { - abiProposal, err := convertRedemptionProposalToAbiType( - walletPublicKeyHash, - proposal, - ) - if err != nil { - return fmt.Errorf("cannot convert proposal to abi type: [%v]", err) - } - - valid, err := tc.walletProposalValidator.ValidateRedemptionProposal( - abiProposal, - ) - if err != nil { - return fmt.Errorf("validation failed: [%v]", err) - } - - // Should never happen because `validateRedemptionProposal` returns true - // or reverts (returns an error) but do the check just in case. - if !valid { - return fmt.Errorf("unexpected validation result") - } - - return nil -} - -func convertRedemptionProposalToAbiType( - walletPublicKeyHash [20]byte, - proposal *tbtc.RedemptionProposal, -) (tbtcabi.WalletProposalValidatorRedemptionProposal, error) { - redeemersOutputScripts := make( - [][]byte, - len(proposal.RedeemersOutputScripts), - ) - - for i, script := range proposal.RedeemersOutputScripts { - // The on-chain script representation must be prepended with the script's - // byte-length while bitcoin.Script is not. We need to add the - // length prefix. - prefixedScript, err := script.ToVarLenData() - if err != nil { - return tbtcabi.WalletProposalValidatorRedemptionProposal{}, fmt.Errorf( - "cannot convert redeemer output script: [%v]", - err, - ) - } - - redeemersOutputScripts[i] = prefixedScript - } - - return tbtcabi.WalletProposalValidatorRedemptionProposal{ - WalletPubKeyHash: walletPublicKeyHash, - RedeemersOutputScripts: redeemersOutputScripts, - RedemptionTxFee: proposal.RedemptionTxFee, - }, nil -} - -func (tc *TbtcChain) GetRedemptionMaxSize() (uint16, error) { - return tc.walletProposalValidator.REDEMPTIONMAXSIZE() -} - -func (tc *TbtcChain) GetRedemptionRequestMinAge() (uint32, error) { - return tc.walletProposalValidator.REDEMPTIONREQUESTMINAGE() -} - -func (tc *TbtcChain) ValidateHeartbeatProposal( - walletPublicKeyHash [20]byte, - proposal *tbtc.HeartbeatProposal, -) error { - valid, err := tc.walletProposalValidator.ValidateHeartbeatProposal( - tbtcabi.WalletProposalValidatorHeartbeatProposal{ - WalletPubKeyHash: walletPublicKeyHash, - Message: proposal.Message[:], - }, - ) - if err != nil { - return fmt.Errorf("validation failed: [%v]", err) - } - - // Should never happen because `validateHeartbeatProposal` returns true - // or reverts (returns an error) but do the check just in case. - if !valid { - return fmt.Errorf("unexpected validation result") - } - - return nil -} - -func (tc *TbtcChain) GetMovingFundsParameters() (tbtc.MovingFundsParameters, error) { - parameters, err := tc.bridge.MovingFundsParameters() - if err != nil { - return tbtc.MovingFundsParameters{}, err - } - - return tbtc.MovingFundsParameters{ - TxMaxTotalFee: parameters.MovingFundsTxMaxTotalFee, - DustThreshold: parameters.MovingFundsDustThreshold, - TimeoutResetDelay: parameters.MovingFundsTimeoutResetDelay, - Timeout: parameters.MovingFundsTimeout, - TimeoutSlashingAmount: parameters.MovingFundsTimeoutSlashingAmount, - TimeoutNotifierRewardMultiplier: parameters.MovingFundsTimeoutNotifierRewardMultiplier, - CommitmentGasOffset: parameters.MovingFundsCommitmentGasOffset, - SweepTxMaxTotalFee: parameters.MovedFundsSweepTxMaxTotalFee, - SweepTimeout: parameters.MovedFundsSweepTimeout, - SweepTimeoutSlashingAmount: parameters.MovedFundsSweepTimeoutSlashingAmount, - SweepTimeoutNotifierRewardMultiplier: parameters.MovedFundsSweepTimeoutNotifierRewardMultiplier, - }, nil -} - -func (tc *TbtcChain) GetMovedFundsSweepRequest( - movingFundsTxHash bitcoin.Hash, - movingFundsTxOutpointIndex uint32, -) (*tbtc.MovedFundsSweepRequest, bool, error) { - movedFundsKey := buildMovedFundsKey( - movingFundsTxHash, - movingFundsTxOutpointIndex, - ) - - movedFundsSweepRequest, err := tc.bridge.MovedFundsSweepRequests( - movedFundsKey, - ) - if err != nil { - return nil, false, fmt.Errorf( - "cannot get moved funds sweep request for key [0x%x]: [%v]", - movedFundsKey.Text(16), - err, - ) - } - - // Moved funds sweep request not found. - if movedFundsSweepRequest.CreatedAt == 0 { - return nil, false, nil - } - - state, err := parseMovedFundsSweepRequestState(movedFundsSweepRequest.State) - if err != nil { - return nil, false, fmt.Errorf( - "cannot parse state for moved funds sweep request [0x%x]: [%v]", - movedFundsKey.Text(16), - err, - ) - } - - return &tbtc.MovedFundsSweepRequest{ - WalletPublicKeyHash: movedFundsSweepRequest.WalletPubKeyHash, - Value: movedFundsSweepRequest.Value, - CreatedAt: time.Unix(int64(movedFundsSweepRequest.CreatedAt), 0), - State: state, - }, true, nil -} - -func parseMovedFundsSweepRequestState(value uint8) ( - tbtc.MovedFundsSweepRequestState, - error, -) { - switch value { - case 0: - return tbtc.MovedFundsStateUnknown, nil - case 1: - return tbtc.MovedFundsStatePending, nil - case 2: - return tbtc.MovedFundsStateProcessed, nil - case 3: - return tbtc.MovedFundsStateTimedOut, nil - default: - return 0, fmt.Errorf( - "unexpected moved funds sweep request state value: [%v]", - value, - ) - } -} - -func buildMovedFundsKey( - movingFundsTxHash bitcoin.Hash, - movingFundsTxOutpointIndex uint32, -) *big.Int { - indexBytes := make([]byte, 4) - binary.BigEndian.PutUint32(indexBytes, movingFundsTxOutpointIndex) - - movedFundsKey := crypto.Keccak256Hash( - append(movingFundsTxHash[:], indexBytes...), - ) - - return movedFundsKey.Big() -} - -func (tc *TbtcChain) ValidateMovingFundsProposal( - walletPublicKeyHash [20]byte, - mainUTXO *bitcoin.UnspentTransactionOutput, - proposal *tbtc.MovingFundsProposal, -) error { - abiProposal := tbtcabi.WalletProposalValidatorMovingFundsProposal{ - WalletPubKeyHash: walletPublicKeyHash, - TargetWallets: proposal.TargetWallets, - MovingFundsTxFee: proposal.MovingFundsTxFee, - } - abiMainUTXO := tbtcabi.BitcoinTxUTXO3{ - TxHash: mainUTXO.Outpoint.TransactionHash, - TxOutputIndex: mainUTXO.Outpoint.OutputIndex, - TxOutputValue: uint64(mainUTXO.Value), - } - - valid, err := tc.walletProposalValidator.ValidateMovingFundsProposal( - abiProposal, - abiMainUTXO, - ) - if err != nil { - return fmt.Errorf("validation failed: [%v]", err) - } - - // Should never happen because `validateMovingFundsProposal` returns true - // or reverts (returns an error) but do the check just in case. - if !valid { - return fmt.Errorf("unexpected validation result") - } - - return nil -} - -func (tc *TbtcChain) GetRedemptionDelay( - walletPublicKeyHash [20]byte, - redeemerOutputScript bitcoin.Script, -) (time.Duration, error) { - if tc.redemptionWatchtower == nil { - return 0, nil - } - - redemptionKey, err := tc.BuildRedemptionKey(walletPublicKeyHash, redeemerOutputScript) - if err != nil { - return 0, fmt.Errorf("cannot build redemption key: [%v]", err) - } - - delay, err := tc.redemptionWatchtower.GetRedemptionDelay(redemptionKey) - if err != nil { - return 0, fmt.Errorf("cannot get redemption delay: [%v]", err) - } - - return time.Duration(delay) * time.Second, nil -} - -func (tc *TbtcChain) GetDepositMinAge() (uint32, error) { - return tc.walletProposalValidator.DEPOSITMINAGE() -} diff --git a/pkg/chain/ethereum/tbtc/gen/cmd/Bridge.go b/pkg/chain/ethereum/tbtc/gen/cmd/Bridge.go index f7a5944669..6394ee9298 100644 --- a/pkg/chain/ethereum/tbtc/gen/cmd/Bridge.go +++ b/pkg/chain/ethereum/tbtc/gen/cmd/Bridge.go @@ -14,11 +14,11 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" - chainutil "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/cmd" - "github.com/keep-network/keep-common/pkg/utils/decode" "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen/abi" "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen/contract" + chainutil "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + "github.com/keep-network/keep-core/pkg/cmd" + "github.com/keep-network/keep-core/pkg/decode" "github.com/spf13/cobra" ) diff --git a/pkg/chain/ethereum/tbtc/gen/cmd/LightRelay.go b/pkg/chain/ethereum/tbtc/gen/cmd/LightRelay.go index 721e19da72..eefa93045a 100644 --- a/pkg/chain/ethereum/tbtc/gen/cmd/LightRelay.go +++ b/pkg/chain/ethereum/tbtc/gen/cmd/LightRelay.go @@ -13,10 +13,10 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" - chainutil "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/cmd" - "github.com/keep-network/keep-common/pkg/utils/decode" "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen/contract" + chainutil "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + "github.com/keep-network/keep-core/pkg/cmd" + "github.com/keep-network/keep-core/pkg/decode" "github.com/spf13/cobra" ) diff --git a/pkg/chain/ethereum/tbtc/gen/cmd/LightRelayMaintainerProxy.go b/pkg/chain/ethereum/tbtc/gen/cmd/LightRelayMaintainerProxy.go index b27107b3b5..69e2a70dae 100644 --- a/pkg/chain/ethereum/tbtc/gen/cmd/LightRelayMaintainerProxy.go +++ b/pkg/chain/ethereum/tbtc/gen/cmd/LightRelayMaintainerProxy.go @@ -12,9 +12,9 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" - chainutil "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/cmd" "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen/contract" + chainutil "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + "github.com/keep-network/keep-core/pkg/cmd" "github.com/spf13/cobra" ) diff --git a/pkg/chain/ethereum/tbtc/gen/cmd/MaintainerProxy.go b/pkg/chain/ethereum/tbtc/gen/cmd/MaintainerProxy.go index afa3102320..9f9017d4ab 100644 --- a/pkg/chain/ethereum/tbtc/gen/cmd/MaintainerProxy.go +++ b/pkg/chain/ethereum/tbtc/gen/cmd/MaintainerProxy.go @@ -14,11 +14,11 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" - chainutil "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/cmd" - "github.com/keep-network/keep-common/pkg/utils/decode" "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen/abi" "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen/contract" + chainutil "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + "github.com/keep-network/keep-core/pkg/cmd" + "github.com/keep-network/keep-core/pkg/decode" "github.com/spf13/cobra" ) diff --git a/pkg/chain/ethereum/tbtc/gen/cmd/RedemptionWatchtower.go b/pkg/chain/ethereum/tbtc/gen/cmd/RedemptionWatchtower.go index ccbddec189..b493c091a3 100644 --- a/pkg/chain/ethereum/tbtc/gen/cmd/RedemptionWatchtower.go +++ b/pkg/chain/ethereum/tbtc/gen/cmd/RedemptionWatchtower.go @@ -12,10 +12,10 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" - chainutil "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/cmd" - "github.com/keep-network/keep-common/pkg/utils/decode" "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen/contract" + chainutil "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + "github.com/keep-network/keep-core/pkg/cmd" + "github.com/keep-network/keep-core/pkg/decode" "github.com/spf13/cobra" ) diff --git a/pkg/chain/ethereum/tbtc/gen/cmd/WalletProposalValidator.go b/pkg/chain/ethereum/tbtc/gen/cmd/WalletProposalValidator.go index d86d97458f..660b5a70c3 100644 --- a/pkg/chain/ethereum/tbtc/gen/cmd/WalletProposalValidator.go +++ b/pkg/chain/ethereum/tbtc/gen/cmd/WalletProposalValidator.go @@ -11,10 +11,10 @@ import ( "github.com/ethereum/go-ethereum/ethclient" - chainutil "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/cmd" "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen/abi" "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen/contract" + chainutil "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + "github.com/keep-network/keep-core/pkg/cmd" "github.com/spf13/cobra" ) diff --git a/pkg/chain/ethereum/tbtc/gen/contract/Bridge.go b/pkg/chain/ethereum/tbtc/gen/contract/Bridge.go index ae73c92607..1276107423 100644 --- a/pkg/chain/ethereum/tbtc/gen/contract/Bridge.go +++ b/pkg/chain/ethereum/tbtc/gen/contract/Bridge.go @@ -20,10 +20,10 @@ import ( "github.com/ipfs/go-log" - "github.com/keep-network/keep-common/pkg/chain/ethereum" - chainutil "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/subscription" "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen/abi" + ethereum "github.com/keep-network/keep-core/pkg/chain/ethereumutil" + chainutil "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + "github.com/keep-network/keep-core/pkg/subscription" ) // Create a package-level logger for this contract. The logger exists at diff --git a/pkg/chain/ethereum/tbtc/gen/contract/LightRelay.go b/pkg/chain/ethereum/tbtc/gen/contract/LightRelay.go index 8337363521..09107b342d 100644 --- a/pkg/chain/ethereum/tbtc/gen/contract/LightRelay.go +++ b/pkg/chain/ethereum/tbtc/gen/contract/LightRelay.go @@ -20,10 +20,10 @@ import ( "github.com/ipfs/go-log" - "github.com/keep-network/keep-common/pkg/chain/ethereum" - chainutil "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/subscription" "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen/abi" + ethereum "github.com/keep-network/keep-core/pkg/chain/ethereumutil" + chainutil "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + "github.com/keep-network/keep-core/pkg/subscription" ) // Create a package-level logger for this contract. The logger exists at diff --git a/pkg/chain/ethereum/tbtc/gen/contract/LightRelayMaintainerProxy.go b/pkg/chain/ethereum/tbtc/gen/contract/LightRelayMaintainerProxy.go index 31d60dad7a..c9cf8486d2 100644 --- a/pkg/chain/ethereum/tbtc/gen/contract/LightRelayMaintainerProxy.go +++ b/pkg/chain/ethereum/tbtc/gen/contract/LightRelayMaintainerProxy.go @@ -20,10 +20,10 @@ import ( "github.com/ipfs/go-log" - "github.com/keep-network/keep-common/pkg/chain/ethereum" - chainutil "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/subscription" "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen/abi" + ethereum "github.com/keep-network/keep-core/pkg/chain/ethereumutil" + chainutil "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + "github.com/keep-network/keep-core/pkg/subscription" ) // Create a package-level logger for this contract. The logger exists at diff --git a/pkg/chain/ethereum/tbtc/gen/contract/MaintainerProxy.go b/pkg/chain/ethereum/tbtc/gen/contract/MaintainerProxy.go index dc29d77ec0..437132d9c4 100644 --- a/pkg/chain/ethereum/tbtc/gen/contract/MaintainerProxy.go +++ b/pkg/chain/ethereum/tbtc/gen/contract/MaintainerProxy.go @@ -20,10 +20,10 @@ import ( "github.com/ipfs/go-log" - "github.com/keep-network/keep-common/pkg/chain/ethereum" - chainutil "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/subscription" "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen/abi" + ethereum "github.com/keep-network/keep-core/pkg/chain/ethereumutil" + chainutil "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + "github.com/keep-network/keep-core/pkg/subscription" ) // Create a package-level logger for this contract. The logger exists at diff --git a/pkg/chain/ethereum/tbtc/gen/contract/RedemptionWatchtower.go b/pkg/chain/ethereum/tbtc/gen/contract/RedemptionWatchtower.go index 9e49a30418..01c622a90d 100644 --- a/pkg/chain/ethereum/tbtc/gen/contract/RedemptionWatchtower.go +++ b/pkg/chain/ethereum/tbtc/gen/contract/RedemptionWatchtower.go @@ -20,10 +20,10 @@ import ( "github.com/ipfs/go-log" - "github.com/keep-network/keep-common/pkg/chain/ethereum" - chainutil "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/subscription" "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen/abi" + ethereum "github.com/keep-network/keep-core/pkg/chain/ethereumutil" + chainutil "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + "github.com/keep-network/keep-core/pkg/subscription" ) // Create a package-level logger for this contract. The logger exists at diff --git a/pkg/chain/ethereum/tbtc/gen/contract/WalletProposalValidator.go b/pkg/chain/ethereum/tbtc/gen/contract/WalletProposalValidator.go index b5d3591e01..af54eeabbb 100644 --- a/pkg/chain/ethereum/tbtc/gen/contract/WalletProposalValidator.go +++ b/pkg/chain/ethereum/tbtc/gen/contract/WalletProposalValidator.go @@ -16,9 +16,9 @@ import ( "github.com/ipfs/go-log" - "github.com/keep-network/keep-common/pkg/chain/ethereum" - chainutil "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen/abi" + ethereum "github.com/keep-network/keep-core/pkg/chain/ethereumutil" + chainutil "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" ) // Create a package-level logger for this contract. The logger exists at diff --git a/pkg/chain/ethereum/tbtc_deposit.go b/pkg/chain/ethereum/tbtc_deposit.go new file mode 100644 index 0000000000..1be7f78fc7 --- /dev/null +++ b/pkg/chain/ethereum/tbtc_deposit.go @@ -0,0 +1,305 @@ +// tbtc_deposit.go: deposit lifecycle (request, reveal, funding) for the TbtcChain adapter. +package ethereum + +import ( + "fmt" + "math/big" + "sort" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/keep-network/keep-core/pkg/bitcoin" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + + "github.com/keep-network/keep-core/pkg/chain" + tbtcabi "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen/abi" + "github.com/keep-network/keep-core/pkg/tbtc" +) + +func (tc *TbtcChain) PastDepositRevealedEvents( + filter *tbtc.DepositRevealedEventFilter, +) ([]*tbtc.DepositRevealedEvent, error) { + var startBlock uint64 + var endBlock *uint64 + var depositor []common.Address + var walletPublicKeyHash [][20]byte + + if filter != nil { + startBlock = filter.StartBlock + endBlock = filter.EndBlock + + for _, d := range filter.Depositor { + depositor = append(depositor, common.HexToAddress(d.String())) + } + + walletPublicKeyHash = filter.WalletPublicKeyHash + } + + events, err := tc.bridge.PastDepositRevealedEvents( + startBlock, + endBlock, + depositor, + walletPublicKeyHash, + ) + if err != nil { + return nil, err + } + + convertedEvents := make([]*tbtc.DepositRevealedEvent, 0) + for _, event := range events { + var vault *chain.Address + if event.Vault != [20]byte{} { + v := chain.Address(event.Vault.Hex()) + vault = &v + } + + convertedEvent := &tbtc.DepositRevealedEvent{ + // We can map the event.FundingTxHash field directly to the + // bitcoin.Hash type. This is because event.FundingTxHash is + // a [32]byte type representing a hash in the bitcoin.InternalByteOrder, + // just as bitcoin.Hash assumes. + FundingTxHash: event.FundingTxHash, + FundingOutputIndex: event.FundingOutputIndex, + Depositor: chain.Address(event.Depositor.Hex()), + Amount: event.Amount, + BlindingFactor: event.BlindingFactor, + WalletPublicKeyHash: event.WalletPubKeyHash, + RefundPublicKeyHash: event.RefundPubKeyHash, + RefundLocktime: event.RefundLocktime, + Vault: vault, + BlockNumber: event.Raw.BlockNumber, + } + + convertedEvents = append(convertedEvents, convertedEvent) + } + + sort.SliceStable( + convertedEvents, + func(i, j int) bool { + return convertedEvents[i].BlockNumber < convertedEvents[j].BlockNumber + }, + ) + + return convertedEvents, err +} + +func (tc *TbtcChain) GetDepositRequest( + fundingTxHash bitcoin.Hash, + fundingOutputIndex uint32, +) (*tbtc.DepositChainRequest, bool, error) { + depositKey := buildDepositKey(fundingTxHash, fundingOutputIndex) + depositCacheKey := depositKey.Text(16) + + tc.sweptDepositsCache.Sweep() + if cachedRequest, ok := tc.sweptDepositsCache.Get(depositCacheKey); ok { + return cachedRequest, true, nil + } + + chainRequest, err := tc.bridge.Deposits(depositKey) + if err != nil { + return nil, false, fmt.Errorf( + "cannot get deposit request for key [0x%x]: [%v]", + depositKey.Text(16), + err, + ) + } + + // Deposit not found. + if chainRequest.RevealedAt == 0 { + return nil, false, nil + } + + var vault *chain.Address + if chainRequest.Vault != [20]byte{} { + v := chain.Address(chainRequest.Vault.Hex()) + vault = &v + } + + var extraData *[32]byte + if chainRequest.ExtraData != [32]byte{} { + extraData = &chainRequest.ExtraData + } + + request := &tbtc.DepositChainRequest{ + Depositor: chain.Address(chainRequest.Depositor.Hex()), + Amount: chainRequest.Amount, + RevealedAt: time.Unix(int64(chainRequest.RevealedAt), 0), + Vault: vault, + TreasuryFee: chainRequest.TreasuryFee, + SweptAt: time.Unix(int64(chainRequest.SweptAt), 0), + ExtraData: extraData, + } + + // If the request was swept on-chain, there is a guarantee that no + // further changes will occur regarding its parameters. + // Such a request can be cached. + if isSwept := request.SweptAt.Unix() != 0; isSwept { + tc.sweptDepositsCache.Add(depositCacheKey, request) + } + + return request, true, nil +} + +func (tc *TbtcChain) BuildDepositKey( + fundingTxHash bitcoin.Hash, + fundingOutputIndex uint32, +) *big.Int { + return buildDepositKey(fundingTxHash, fundingOutputIndex) +} + +func (tc *TbtcChain) GetDepositParameters() (tbtc.DepositParameters, error) { + parameters, err := tc.bridge.DepositParameters() + if err != nil { + return tbtc.DepositParameters{}, err + } + + return tbtc.DepositParameters{ + DustThreshold: parameters.DepositDustThreshold, + TreasuryFeeDivisor: parameters.DepositTreasuryFeeDivisor, + TxMaxFee: parameters.DepositTxMaxFee, + RevealAheadPeriod: parameters.DepositRevealAheadPeriod, + }, nil +} + +func (tc *TbtcChain) SubmitDepositSweepProofWithReimbursement( + transaction *bitcoin.Transaction, + proof *bitcoin.SpvProof, + mainUTXO bitcoin.UnspentTransactionOutput, + vault common.Address, +) error { + if mainUTXO.Value < 0 { + return fmt.Errorf("invalid main UTXO value: [%v]", mainUTXO.Value) + } + + bitcoinTxInfo := tbtcabi.BitcoinTxInfo3{ + Version: transaction.SerializeVersion(), + InputVector: transaction.SerializeInputs(), + OutputVector: transaction.SerializeOutputs(), + Locktime: transaction.SerializeLocktime(), + } + sweepProof := tbtcabi.BitcoinTxProof2{ + MerkleProof: proof.MerkleProof, + TxIndexInBlock: new(big.Int).SetUint64(uint64(proof.TxIndexInBlock)), + BitcoinHeaders: proof.BitcoinHeaders, + CoinbasePreimage: proof.CoinbasePreimage, + CoinbaseProof: proof.CoinbaseProof, + } + utxo := tbtcabi.BitcoinTxUTXO2{ + TxHash: mainUTXO.Outpoint.TransactionHash, + TxOutputIndex: mainUTXO.Outpoint.OutputIndex, + TxOutputValue: uint64(mainUTXO.Value), + } + + gasEstimate, err := tc.maintainerProxy.SubmitDepositSweepProofGasEstimate( + bitcoinTxInfo, + sweepProof, + utxo, + vault, + ) + if err != nil { + return err + } + + // The original estimate for this contract call is too low and the call + // fails on reimbursing the submitter. Example: + // 0xe27a92883e0e64da8a3a54a15a260ea2f4d3d48470129ac5c09bfe9637d7e114 + gasEstimateWithMargin := gasEstimateWithMargin(gasEstimate) + + _, err = tc.maintainerProxy.SubmitDepositSweepProof( + bitcoinTxInfo, + sweepProof, + utxo, + vault, + ethutil.TransactionOptions{ + GasLimit: uint64(gasEstimateWithMargin), + }, + ) + + return err +} + +func buildDepositKey( + fundingTxHash bitcoin.Hash, + fundingOutputIndex uint32, +) *big.Int { + return buildTxOutpointKey(fundingTxHash, fundingOutputIndex) +} + +func convertDepositSweepProposalToAbiType( + walletPublicKeyHash [20]byte, + proposal *tbtc.DepositSweepProposal, +) tbtcabi.WalletProposalValidatorDepositSweepProposal { + depositsKeys := make( + []tbtcabi.WalletProposalValidatorDepositKey, + len(proposal.DepositsKeys), + ) + + for i, depositKey := range proposal.DepositsKeys { + // We can map the depositKey.FundingTxHash field directly to the + // [32]byte type. This is because depositKey.FundingTxHash is + // a bitcoin.Hash type representing a hash in the + // bitcoin.InternalByteOrder, just as the on-chain contract assumes. + depositsKeys[i] = tbtcabi.WalletProposalValidatorDepositKey{ + FundingTxHash: depositKey.FundingTxHash, + FundingOutputIndex: depositKey.FundingOutputIndex, + } + } + + return tbtcabi.WalletProposalValidatorDepositSweepProposal{ + WalletPubKeyHash: walletPublicKeyHash, + DepositsKeys: depositsKeys, + SweepTxFee: proposal.SweepTxFee, + DepositsRevealBlocks: proposal.DepositsRevealBlocks, + } +} + +func (tc *TbtcChain) ValidateDepositSweepProposal( + walletPublicKeyHash [20]byte, + proposal *tbtc.DepositSweepProposal, + depositsExtraInfo []struct { + *tbtc.Deposit + FundingTx *bitcoin.Transaction + }, +) error { + dei := make([]tbtcabi.WalletProposalValidatorDepositExtraInfo, len(depositsExtraInfo)) + for i, depositExtraInfo := range depositsExtraInfo { + fundingTx := tbtcabi.BitcoinTxInfo2{ + Version: depositExtraInfo.FundingTx.SerializeVersion(), + InputVector: depositExtraInfo.FundingTx.SerializeInputs(), + OutputVector: depositExtraInfo.FundingTx.SerializeOutputs(), + Locktime: depositExtraInfo.FundingTx.SerializeLocktime(), + } + + dei[i] = tbtcabi.WalletProposalValidatorDepositExtraInfo{ + FundingTx: fundingTx, + BlindingFactor: depositExtraInfo.Deposit.BlindingFactor, + WalletPubKeyHash: depositExtraInfo.Deposit.WalletPublicKeyHash, + RefundPubKeyHash: depositExtraInfo.Deposit.RefundPublicKeyHash, + RefundLocktime: depositExtraInfo.Deposit.RefundLocktime, + } + } + + valid, err := tc.walletProposalValidator.ValidateDepositSweepProposal( + convertDepositSweepProposalToAbiType(walletPublicKeyHash, proposal), + dei, + ) + if err != nil { + return fmt.Errorf("validation failed: [%v]", err) + } + + // Should never happen because `validateDepositSweepProposal` returns true + // or reverts (returns an error) but do the check just in case. + if !valid { + return fmt.Errorf("unexpected validation result") + } + + return nil +} + +func (tc *TbtcChain) GetDepositSweepMaxSize() (uint16, error) { + return tc.walletProposalValidator.DEPOSITSWEEPMAXSIZE() +} + +func (tc *TbtcChain) GetDepositMinAge() (uint32, error) { + return tc.walletProposalValidator.DEPOSITMINAGE() +} diff --git a/pkg/chain/ethereum/tbtc_deposit_test.go b/pkg/chain/ethereum/tbtc_deposit_test.go new file mode 100644 index 0000000000..4ccdc7328e --- /dev/null +++ b/pkg/chain/ethereum/tbtc_deposit_test.go @@ -0,0 +1,31 @@ +package ethereum + +import ( + "testing" + + "github.com/keep-network/keep-core/internal/testutils" + "github.com/keep-network/keep-core/pkg/bitcoin" +) + +// Test data based on: https://etherscan.io/tx/0x97c7a293127a604da77f7ef8daf4b19da2bf04327dd891b6d717eaef89bd8bca +func TestBuildDepositKey(t *testing.T) { + fundingTxHash, err := bitcoin.NewHashFromString( + "585b6699f42291d1a9d0776b75f04c295ea203f83504349db11e94fdae7d1b2c", + bitcoin.InternalByteOrder, + ) + if err != nil { + t.Fatal(err) + } + + fundingOutputIndex := uint32(1) + + depositKey := buildDepositKey(fundingTxHash, fundingOutputIndex) + + expectedDepositKey := "3e84c1ea6aeaf2f45fb49623a88affe653b798ea6f675805acc0ec3965b6f317" + testutils.AssertStringsEqual( + t, + "deposit key", + expectedDepositKey, + depositKey.Text(16), + ) +} diff --git a/pkg/chain/ethereum/tbtc_dkg.go b/pkg/chain/ethereum/tbtc_dkg.go new file mode 100644 index 0000000000..95135c0982 --- /dev/null +++ b/pkg/chain/ethereum/tbtc_dkg.go @@ -0,0 +1,565 @@ +// tbtc_dkg.go: DKG lifecycle, result assembly and validation for the TbtcChain adapter. +package ethereum + +import ( + "crypto/ecdsa" + "fmt" + "math/big" + "reflect" + "sort" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + + "github.com/keep-network/keep-core/pkg/chain" + ecdsaabi "github.com/keep-network/keep-core/pkg/chain/ethereum/ecdsa/gen/abi" + "github.com/keep-network/keep-core/pkg/crypto/secp256k1" + "github.com/keep-network/keep-core/pkg/protocol/group" + "github.com/keep-network/keep-core/pkg/subscription" + "github.com/keep-network/keep-core/pkg/tbtc" + "github.com/keep-network/keep-core/pkg/tecdsa/dkg" +) + +func (tc *TbtcChain) OnDKGStarted( + handler func(event *tbtc.DKGStartedEvent), +) subscription.EventSubscription { + onEvent := func( + seed *big.Int, + blockNumber uint64, + ) { + handler(&tbtc.DKGStartedEvent{ + Seed: seed, + BlockNumber: blockNumber, + }) + } + + return tc.walletRegistry.DkgStartedEvent(nil, nil).OnEvent(onEvent) +} + +func (tc *TbtcChain) PastDKGStartedEvents( + filter *tbtc.DKGStartedEventFilter, +) ([]*tbtc.DKGStartedEvent, error) { + var startBlock uint64 + var endBlock *uint64 + var seed []*big.Int + + if filter != nil { + startBlock = filter.StartBlock + endBlock = filter.EndBlock + seed = filter.Seed + } + + events, err := tc.walletRegistry.PastDkgStartedEvents( + startBlock, + endBlock, + seed, + ) + if err != nil { + return nil, err + } + + dkgStartedEvents := make([]*tbtc.DKGStartedEvent, len(events)) + for i, event := range events { + dkgStartedEvents[i] = &tbtc.DKGStartedEvent{ + Seed: event.Seed, + BlockNumber: event.Raw.BlockNumber, + } + } + + sort.SliceStable(dkgStartedEvents, func(i, j int) bool { + return dkgStartedEvents[i].BlockNumber < dkgStartedEvents[j].BlockNumber + }) + + return dkgStartedEvents, err +} + +func (tc *TbtcChain) OnDKGResultSubmitted( + handler func(event *tbtc.DKGResultSubmittedEvent), +) subscription.EventSubscription { + onEvent := func( + resultHash [32]byte, + seed *big.Int, + result ecdsaabi.EcdsaDkgResult, + blockNumber uint64, + ) { + tbtcResult, err := convertDkgResultFromAbiType(result) + if err != nil { + // Surface the raw event payload alongside the conversion + // error so the bad event is recoverable from logs instead + // of being silently discarded (the conversion failure + // drops the event before the handler ever sees it). + logger.Errorf( + "unexpected DKG result in DKGResultSubmitted event "+ + "resultHash=[0x%x] seed=[%v] blockNumber=[%d] "+ + "submitterMemberIndex=[%v] signingMembersIndices=[%v]: [%v]", + resultHash, + seed, + blockNumber, + result.SubmitterMemberIndex, + result.SigningMembersIndices, + err, + ) + return + } + + handler(&tbtc.DKGResultSubmittedEvent{ + Seed: seed, + ResultHash: resultHash, + Result: tbtcResult, + BlockNumber: blockNumber, + }) + } + + return tc.walletRegistry. + DkgResultSubmittedEvent(nil, nil, nil). + OnEvent(onEvent) +} + +// convertDkgResultFromAbiType converts the WalletRegistry-specific DKG +// result to the format applicable for the TBTC application. +func convertDkgResultFromAbiType( + result ecdsaabi.EcdsaDkgResult, +) (*tbtc.DKGChainResult, error) { + submitterIndex, err := memberIndexFromChain(result.SubmitterMemberIndex) + if err != nil { + return nil, fmt.Errorf( + "unexpected submitter member index: [%v]", + err, + ) + } + + signingMembersIndexes := make( + []group.MemberIndex, + len(result.SigningMembersIndices), + ) + for i, memberIndex := range result.SigningMembersIndices { + index, err := memberIndexFromChain(memberIndex) + if err != nil { + return nil, fmt.Errorf( + "unexpected signing member index: [%v]", + err, + ) + } + + signingMembersIndexes[i] = index + } + + return &tbtc.DKGChainResult{ + SubmitterMemberIndex: submitterIndex, + GroupPublicKey: result.GroupPubKey, + MisbehavedMembersIndexes: result.MisbehavedMembersIndices, + Signatures: result.Signatures, + SigningMembersIndexes: signingMembersIndexes, + Members: result.Members, + MembersHash: result.MembersHash, + }, nil +} + +// convertDkgResultToAbiType converts the TBTC-specific DKG result to +// the format applicable for the WalletRegistry ABI. +func convertDkgResultToAbiType( + result *tbtc.DKGChainResult, +) ecdsaabi.EcdsaDkgResult { + signingMembersIndices := make([]*big.Int, len(result.SigningMembersIndexes)) + for i, memberIndex := range result.SigningMembersIndexes { + signingMembersIndices[i] = big.NewInt(int64(memberIndex)) + } + + return ecdsaabi.EcdsaDkgResult{ + SubmitterMemberIndex: big.NewInt(int64(result.SubmitterMemberIndex)), + GroupPubKey: result.GroupPublicKey, + MisbehavedMembersIndices: result.MisbehavedMembersIndexes, + Signatures: result.Signatures, + SigningMembersIndices: signingMembersIndices, + Members: result.Members, + MembersHash: result.MembersHash, + } +} + +// memberIndexFromChain checks that a chain member index fits the 1-based +// group index range before converting it. +func memberIndexFromChain(value *big.Int) (group.MemberIndex, error) { + if value == nil || !value.IsUint64() { + return 0, fmt.Errorf("invalid member index value: [%v]", value) + } + index := value.Uint64() + if index == 0 || index > group.MaxMemberIndex { + return 0, fmt.Errorf("invalid member index value: [%v]", value) + } + return group.MemberIndex(index), nil +} + +func (tc *TbtcChain) OnDKGResultChallenged( + handler func(event *tbtc.DKGResultChallengedEvent), +) subscription.EventSubscription { + onEvent := func( + resultHash [32]byte, + challenger common.Address, + reason string, + blockNumber uint64, + ) { + handler(&tbtc.DKGResultChallengedEvent{ + ResultHash: resultHash, + Challenger: chain.Address(challenger.Hex()), + Reason: reason, + BlockNumber: blockNumber, + }) + } + + return tc.walletRegistry. + DkgResultChallengedEvent(nil, nil, nil). + OnEvent(onEvent) +} + +func (tc *TbtcChain) OnDKGResultApproved( + handler func(event *tbtc.DKGResultApprovedEvent), +) subscription.EventSubscription { + onEvent := func( + resultHash [32]byte, + approver common.Address, + blockNumber uint64, + ) { + handler(&tbtc.DKGResultApprovedEvent{ + ResultHash: resultHash, + Approver: chain.Address(approver.Hex()), + BlockNumber: blockNumber, + }) + } + + return tc.walletRegistry. + DkgResultApprovedEvent(nil, nil, nil). + OnEvent(onEvent) +} + +// AssembleDKGResult assembles the DKG chain result according to the rules +// expected by the given chain. +func (tc *TbtcChain) AssembleDKGResult( + submitterMemberIndex group.MemberIndex, + groupPublicKey *ecdsa.PublicKey, + operatingMembersIndexes []group.MemberIndex, + misbehavedMembersIndexes []group.MemberIndex, + signatures map[group.MemberIndex][]byte, + groupSelectionResult *tbtc.GroupSelectionResult, +) (*tbtc.DKGChainResult, error) { + serializedGroupPublicKey, err := convertPubKeyToChainFormat(groupPublicKey) + if err != nil { + return nil, fmt.Errorf( + "could not convert group public key to chain format: [%v]", + err, + ) + } + + // Sort misbehavedMembersIndexes slice in ascending order as expected + // by the on-chain contract. + sort.Slice(misbehavedMembersIndexes[:], func(i, j int) bool { + return misbehavedMembersIndexes[i] < misbehavedMembersIndexes[j] + }) + + signingMemberIndices, signatureBytes, err := convertSignaturesToChainFormat( + signatures, + ) + if err != nil { + return nil, fmt.Errorf( + "could not convert signatures to chain format: [%v]", + err, + ) + } + + // Sort operatingOperatorsIDs slice in ascending order as the slice + // holding the operators IDs used to compute the members hash is + // expected to be sorted in the same way. + sort.Slice(operatingMembersIndexes[:], func(i, j int) bool { + return operatingMembersIndexes[i] < operatingMembersIndexes[j] + }) + + operatingOperatorsIDs := make([]chain.OperatorID, len(operatingMembersIndexes)) + for i, operatingMemberIndex := range operatingMembersIndexes { + operatingOperatorsIDs[i] = + groupSelectionResult.OperatorsIDs[operatingMemberIndex-1] + } + + membersHash, err := computeOperatorsIDsHash(operatingOperatorsIDs) + if err != nil { + return nil, fmt.Errorf("could not compute members hash: [%v]", err) + } + + return &tbtc.DKGChainResult{ + SubmitterMemberIndex: submitterMemberIndex, + GroupPublicKey: serializedGroupPublicKey[:], + MisbehavedMembersIndexes: misbehavedMembersIndexes, + Signatures: signatureBytes, + SigningMembersIndexes: signingMemberIndices, + Members: groupSelectionResult.OperatorsIDs, + MembersHash: membersHash, + }, nil +} + +func (tc *TbtcChain) SubmitDKGResult( + dkgResult *tbtc.DKGChainResult, +) error { + _, err := tc.walletRegistry.SubmitDkgResult( + convertDkgResultToAbiType(dkgResult), + ) + + return err +} + +// computeOperatorsIDsHash computes the keccak256 hash for the given list +// of operators IDs. +func computeOperatorsIDsHash(operatorsIDs chain.OperatorIDs) ([32]byte, error) { + uint32SliceType, err := abi.NewType("uint32[]", "uint32[]", nil) + if err != nil { + return [32]byte{}, err + } + + bytes, err := abi.Arguments{{Type: uint32SliceType}}.Pack(operatorsIDs) + if err != nil { + return [32]byte{}, err + } + + return crypto.Keccak256Hash(bytes), nil +} + +// convertSignaturesToChainFormat converts signatures map to two slices. The +// first slice contains indices of members from the map, sorted in ascending order +// as required by the contract. The second slice is a slice of concatenated +// signatures. Signatures and member indices are returned in the matching order. +// It requires each signature to be exactly 65-byte long. +func convertSignaturesToChainFormat( + signatures map[group.MemberIndex][]byte, +) ([]group.MemberIndex, []byte, error) { + membersIndexes := make([]group.MemberIndex, 0) + for memberIndex := range signatures { + membersIndexes = append(membersIndexes, memberIndex) + } + + sort.Slice(membersIndexes, func(i, j int) bool { + return membersIndexes[i] < membersIndexes[j] + }) + + signatureSize := 65 + + var signaturesSlice []byte + + for _, memberIndex := range membersIndexes { + signature := signatures[memberIndex] + + if len(signature) != signatureSize { + return nil, nil, fmt.Errorf( + "invalid signature size for member [%v] got [%d] bytes but [%d] bytes required", + memberIndex, + len(signature), + signatureSize, + ) + } + + signaturesSlice = append(signaturesSlice, signature...) + } + + return membersIndexes, signaturesSlice, nil +} + +func (tc *TbtcChain) GetDKGState() (tbtc.DKGState, error) { + walletCreationState, err := tc.walletRegistry.GetWalletCreationState() + if err != nil { + return 0, err + } + + var state tbtc.DKGState + + switch walletCreationState { + case 0: + state = tbtc.Idle + case 1: + state = tbtc.AwaitingSeed + case 2: + state = tbtc.AwaitingResult + case 3: + state = tbtc.Challenge + default: + err = fmt.Errorf( + "unexpected wallet creation state: [%v]", + walletCreationState, + ) + } + + return state, err +} + +// CalculateDKGResultSignatureHash calculates a 32-byte hash that is used +// to produce a signature supporting the given groupPublicKey computed +// as result of the given DKG process. The misbehavedMembersIndexes parameter +// should contain indexes of members that were considered as misbehaved +// during the DKG process. The startBlock argument is the block at which +// the given DKG process started. +func (tc *TbtcChain) CalculateDKGResultSignatureHash( + groupPublicKey *ecdsa.PublicKey, + misbehavedMembersIndexes []group.MemberIndex, + startBlock uint64, +) (dkg.ResultSignatureHash, error) { + groupPublicKeyBytes := secp256k1.Marshal(groupPublicKey) + // Crop the 04 prefix as the calculateDKGResultSignatureHash function + // expects an unprefixed 64-byte public key, + unprefixedGroupPublicKeyBytes := groupPublicKeyBytes[1:] + + // Sort misbehavedMembersIndexes slice in ascending order as expected + // by the calculateDKGResultSignatureHash function. + sort.Slice(misbehavedMembersIndexes[:], func(i, j int) bool { + return misbehavedMembersIndexes[i] < misbehavedMembersIndexes[j] + }) + + return calculateDKGResultSignatureHash( + tc.chainID, + unprefixedGroupPublicKeyBytes, + misbehavedMembersIndexes, + new(big.Int).SetUint64(startBlock), + ) +} + +// calculateDKGResultSignatureHash computes the keccak256 hash for the given DKG +// result parameters. It expects that the groupPublicKey is a 64-byte uncompressed +// public key without the 04 prefix and misbehavedMembersIndexes slice is +// sorted in ascending order. Those expectations are forced by the contract. +func calculateDKGResultSignatureHash( + chainID *big.Int, + groupPublicKey []byte, + misbehavedMembersIndexes []group.MemberIndex, + startBlock *big.Int, +) (dkg.ResultSignatureHash, error) { + publicKeySize := 64 + + if len(groupPublicKey) != publicKeySize { + return dkg.ResultSignatureHash{}, fmt.Errorf( + "wrong group public key length", + ) + } + + uint256Type, err := abi.NewType("uint256", "uint256", nil) + if err != nil { + return dkg.ResultSignatureHash{}, err + } + bytesType, err := abi.NewType("bytes", "bytes", nil) + if err != nil { + return dkg.ResultSignatureHash{}, err + } + uint8SliceType, err := abi.NewType("uint8[]", "uint8[]", nil) + if err != nil { + return dkg.ResultSignatureHash{}, err + } + + bytes, err := abi.Arguments{ + {Type: uint256Type}, + {Type: bytesType}, + {Type: uint8SliceType}, + {Type: uint256Type}, + }.Pack( + chainID, + groupPublicKey, + misbehavedMembersIndexes, + startBlock, + ) + if err != nil { + return dkg.ResultSignatureHash{}, err + } + + return dkg.ResultSignatureHash(crypto.Keccak256Hash(bytes)), nil +} + +func (tc *TbtcChain) IsDKGResultValid( + dkgResult *tbtc.DKGChainResult, +) (bool, error) { + outcome, err := tc.walletRegistry.IsDkgResultValid( + convertDkgResultToAbiType(dkgResult), + ) + if err != nil { + return false, fmt.Errorf("cannot check result validity: [%v]", err) + } + + return parseDkgResultValidationOutcome(&outcome) +} + +// parseDkgResultValidationOutcome parses the DKG validation outcome and returns +// a boolean indicating whether the result is valid or not. The outcome parameter +// must be a pointer to a struct containing a boolean flag as the first field. +// +// TODO: Find a better way to get the validity flag. This would require changes +// in the contracts binding generator. +// +// The nil-pointer, non-struct-element, and zero-field-count guards below are +// an intentional improvement added during the #4191 file split; they did not +// exist in the pre-split monolithic tbtc.go. They are strict supersets of the +// original behavior (the original code would panic on these inputs) and have +// no equivalent caller contract that relied on the panic, so callers that +// pass well-formed ABI outcomes see no change. +func parseDkgResultValidationOutcome( + outcome interface{}, +) (bool, error) { + value := reflect.ValueOf(outcome) + switch value.Kind() { + case reflect.Pointer: + if value.IsNil() { + return false, fmt.Errorf("result validation outcome is nil") + } + elem := value.Elem() + if elem.Kind() != reflect.Struct { + return false, fmt.Errorf("result validation outcome is not a struct") + } + if elem.NumField() == 0 { + return false, fmt.Errorf("result validation outcome has no fields") + } + default: + return false, fmt.Errorf("result validation outcome is not a pointer") + } + + field := value.Elem().Field(0) + switch field.Kind() { + case reflect.Bool: + return field.Bool(), nil + default: + return false, fmt.Errorf("cannot parse result validation outcome") + } +} + +func (tc *TbtcChain) ChallengeDKGResult(dkgResult *tbtc.DKGChainResult) error { + _, err := tc.walletRegistry.ChallengeDkgResult( + convertDkgResultToAbiType(dkgResult), + ) + + return err +} + +func (tc *TbtcChain) ApproveDKGResult(dkgResult *tbtc.DKGChainResult) error { + result := convertDkgResultToAbiType(dkgResult) + + gasEstimate, err := tc.walletRegistry.ApproveDkgResultGasEstimate(result) + if err != nil { + return err + } + + // The original estimate for this contract call turned out to be too low. + gasEstimateWithMargin := gasEstimateWithMargin(gasEstimate) + + _, err = tc.walletRegistry.ApproveDkgResult( + result, + ethutil.TransactionOptions{ + GasLimit: uint64(gasEstimateWithMargin), + }, + ) + + return err +} + +func (tc *TbtcChain) DKGParameters() (*tbtc.DKGParameters, error) { + parameters, err := tc.walletRegistry.DkgParameters() + if err != nil { + return nil, err + } + + return &tbtc.DKGParameters{ + SubmissionTimeoutBlocks: parameters.ResultSubmissionTimeout.Uint64(), + ChallengePeriodBlocks: parameters.ResultChallengePeriodLength.Uint64(), + ApprovePrecedencePeriodBlocks: parameters.SubmitterPrecedencePeriodLength.Uint64(), + }, nil +} diff --git a/pkg/chain/ethereum/tbtc_dkg_test.go b/pkg/chain/ethereum/tbtc_dkg_test.go new file mode 100644 index 0000000000..0499f09c06 --- /dev/null +++ b/pkg/chain/ethereum/tbtc_dkg_test.go @@ -0,0 +1,268 @@ +package ethereum + +import ( + "bytes" + "encoding/hex" + "fmt" + "math/big" + "reflect" + "testing" + + "github.com/ethereum/go-ethereum/common" + + "github.com/keep-network/keep-core/internal/testutils" + "github.com/keep-network/keep-core/pkg/chain" + "github.com/keep-network/keep-core/pkg/protocol/group" +) + +func TestComputeOperatorsIDsHash(t *testing.T) { + operatorIDs := []chain.OperatorID{ + 5, 1, 55, 45435534, 33, 345, 23, 235, 3333, 2, + } + + hash, err := computeOperatorsIDsHash(operatorIDs) + if err != nil { + t.Fatal(err) + } + + expectedHash := "8cd41effd4ee91b56d6b2f836efdcac11ab1ef2ae228e348814d0e6c2966d01e" + + testutils.AssertStringsEqual( + t, + "hash", + expectedHash, + hex.EncodeToString(hash[:]), + ) +} + +func TestConvertSignaturesToChainFormat(t *testing.T) { + signatureSize := 65 + + signature1 := common.LeftPadBytes([]byte{1, 2, 3}, signatureSize) + signature2 := common.LeftPadBytes([]byte{4, 5, 6}, signatureSize) + signature3 := common.LeftPadBytes([]byte{7}, signatureSize) + signature4 := common.LeftPadBytes([]byte{8, 9, 10}, signatureSize) + signature5 := common.LeftPadBytes([]byte{11, 12, 13}, signatureSize) + + invalidSignature := common.LeftPadBytes([]byte("invalid"), signatureSize-1) + + var tests = map[string]struct { + signaturesMap map[group.MemberIndex][]byte + expectedIndices []group.MemberIndex + expectedError error + }{ + "one valid signature": { + signaturesMap: map[uint8][]byte{ + 1: signature1, + }, + expectedIndices: []group.MemberIndex{1}, + }, + "five valid signatures": { + signaturesMap: map[group.MemberIndex][]byte{ + 3: signature3, + 1: signature1, + 4: signature4, + 5: signature5, + 2: signature2, + }, + expectedIndices: []group.MemberIndex{1, 2, 3, 4, 5}, + }, + "invalid signature": { + signaturesMap: map[group.MemberIndex][]byte{ + 1: signature1, + 2: invalidSignature, + }, + expectedError: fmt.Errorf("invalid signature size for member [2] got [64] bytes but [65] bytes required"), + }, + } + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + indicesSlice, signaturesSlice, err := + convertSignaturesToChainFormat(test.signaturesMap) + + if !reflect.DeepEqual(err, test.expectedError) { + t.Errorf( + "unexpected error\nexpected: [%v]\nactual: [%v]\n", + test.expectedError, + err, + ) + } + + if test.expectedError == nil { + if !reflect.DeepEqual(test.expectedIndices, indicesSlice) { + t.Errorf( + "unexpected indices\n"+ + "expected: [%v]\n"+ + "actual: [%v]\n", + test.expectedIndices, + indicesSlice, + ) + } + + testutils.AssertIntsEqual( + t, + "signatures slice length", + signatureSize*len(test.signaturesMap), + len(signaturesSlice), + ) + } + + for i, memberIndex := range indicesSlice { + actualSignature := signaturesSlice[signatureSize*i : signatureSize*(i+1)] + if !bytes.Equal( + test.signaturesMap[memberIndex], + actualSignature, + ) { + t.Errorf( + "invalid signatures for member %v\nexpected: %v\nactual: %v\n", + memberIndex, + test.signaturesMap[memberIndex], + actualSignature, + ) + } + } + }) + } +} + +func TestMemberIndexFromChain(t *testing.T) { + one := big.NewInt(1) + maxMemberIndex := big.NewInt(255) + + var tests = map[string]struct { + chainMemberIndex *big.Int + expectedError error + }{ + "less than max member index": { + chainMemberIndex: new(big.Int).Sub(maxMemberIndex, one), + expectedError: nil, + }, + "max member index": { + chainMemberIndex: maxMemberIndex, + expectedError: nil, + }, + "greater than max member index": { + chainMemberIndex: new(big.Int).Add(maxMemberIndex, one), + expectedError: fmt.Errorf("invalid member index value: [256]"), + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + _, err := memberIndexFromChain(test.chainMemberIndex) + + if !reflect.DeepEqual(err, test.expectedError) { + t.Errorf( + "unexpected error\nexpected: [%v]\nactual: [%v]\n", + test.expectedError, + err, + ) + } + }) + } +} + +func TestCalculateDKGResultSignatureHash(t *testing.T) { + chainID := big.NewInt(1) + + groupPublicKey, err := hex.DecodeString( + "989d253b17a6a0f41838b84ff0d20e8898f9d7b1a98f2564da4cc29dcf8581d9d" + + "218b65e7d91c752f7b22eaceb771a9af3a6f3d3f010a5d471a1aeef7d7713af", + ) + if err != nil { + t.Fatal(err) + } + + misbehavedMembersIndexes := []group.MemberIndex{2, 55} + + startBlock := big.NewInt(2000) + + hash, err := calculateDKGResultSignatureHash( + chainID, + groupPublicKey, + misbehavedMembersIndexes, + startBlock, + ) + if err != nil { + t.Fatal(err) + } + + expectedHash := "25f917154586c2be0b6364f5c4758580e535bc01ed4881211000c9267aef3a3b" + + testutils.AssertStringsEqual( + t, + "hash", + expectedHash, + hex.EncodeToString(hash[:]), + ) +} + +func TestParseDkgResultValidationOutcome(t *testing.T) { + isValid, err := parseDkgResultValidationOutcome( + &struct { + bool + string + }{ + true, + "", + }, + ) + if err != nil { + t.Fatal(err) + } + testutils.AssertBoolsEqual(t, "validation outcome", true, isValid) + + isValid, err = parseDkgResultValidationOutcome( + &struct { + bool + string + }{ + false, + "", + }, + ) + if err != nil { + t.Fatal(err) + } + testutils.AssertBoolsEqual(t, "validation outcome", false, isValid) + + _, err = parseDkgResultValidationOutcome( + struct { + bool + string + }{ + true, + "", + }, + ) + expectedErr := fmt.Errorf("result validation outcome is not a pointer") + if !reflect.DeepEqual(expectedErr, err) { + t.Errorf( + "unexpected error\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + expectedErr, + err, + ) + } + + _, err = parseDkgResultValidationOutcome( + &struct { + string + bool + }{ + "", + true, + }, + ) + expectedErr = fmt.Errorf("cannot parse result validation outcome") + if !reflect.DeepEqual(expectedErr, err) { + t.Errorf( + "unexpected error\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + expectedErr, + err, + ) + } +} diff --git a/pkg/chain/ethereum/tbtc_inactivity.go b/pkg/chain/ethereum/tbtc_inactivity.go new file mode 100644 index 0000000000..2c4c2e09c4 --- /dev/null +++ b/pkg/chain/ethereum/tbtc_inactivity.go @@ -0,0 +1,196 @@ +// tbtc_inactivity.go: inactivity-claim lifecycle for the TbtcChain adapter. +package ethereum + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + + "github.com/keep-network/keep-core/pkg/chain" + ecdsaabi "github.com/keep-network/keep-core/pkg/chain/ethereum/ecdsa/gen/abi" + "github.com/keep-network/keep-core/pkg/crypto/secp256k1" + "github.com/keep-network/keep-core/pkg/protocol/group" + "github.com/keep-network/keep-core/pkg/protocol/inactivity" + "github.com/keep-network/keep-core/pkg/subscription" + "github.com/keep-network/keep-core/pkg/tbtc" +) + +func (tc *TbtcChain) OnInactivityClaimed( + handler func(event *tbtc.InactivityClaimedEvent), +) subscription.EventSubscription { + onEvent := func( + walletID [32]byte, + nonce *big.Int, + notifier common.Address, + blockNumber uint64, + ) { + handler(&tbtc.InactivityClaimedEvent{ + WalletID: walletID, + Nonce: nonce, + Notifier: chain.Address(notifier.Hex()), + BlockNumber: blockNumber, + }) + } + + return tc.walletRegistry.InactivityClaimedEvent(nil, nil).OnEvent(onEvent) +} + +func (tc *TbtcChain) AssembleInactivityClaim( + walletID [32]byte, + inactiveMembersIndices []group.MemberIndex, + signatures map[group.MemberIndex][]byte, + heartbeatFailed bool, +) ( + *tbtc.InactivityClaim, + error, +) { + signingMemberIndices, signatureBytes, err := convertSignaturesToChainFormat( + signatures, + ) + if err != nil { + return nil, fmt.Errorf( + "could not convert signatures to chain format: [%v]", + err, + ) + } + + return &tbtc.InactivityClaim{ + WalletID: walletID, + InactiveMembersIndices: inactiveMembersIndices, + HeartbeatFailed: heartbeatFailed, + Signatures: signatureBytes, + SigningMembersIndices: signingMemberIndices, + }, nil +} + +// convertInactivityClaimToAbiType converts the TBTC-specific inactivity claim +// to the format applicable for the WalletRegistry ABI. +func convertInactivityClaimToAbiType( + claim *tbtc.InactivityClaim, +) ecdsaabi.EcdsaInactivityClaim { + inactiveMembersIndices := make([]*big.Int, len(claim.InactiveMembersIndices)) + for i, memberIndex := range claim.InactiveMembersIndices { + inactiveMembersIndices[i] = big.NewInt(int64(memberIndex)) + } + + signingMembersIndices := make([]*big.Int, len(claim.SigningMembersIndices)) + for i, memberIndex := range claim.SigningMembersIndices { + signingMembersIndices[i] = big.NewInt(int64(memberIndex)) + } + + return ecdsaabi.EcdsaInactivityClaim{ + WalletID: claim.WalletID, + InactiveMembersIndices: inactiveMembersIndices, + HeartbeatFailed: claim.HeartbeatFailed, + Signatures: claim.Signatures, + SigningMembersIndices: signingMembersIndices, + } +} + +func (tc *TbtcChain) SubmitInactivityClaim( + claim *tbtc.InactivityClaim, + nonce *big.Int, + groupMembers []uint32, +) error { + _, err := tc.walletRegistry.NotifyOperatorInactivity( + convertInactivityClaimToAbiType(claim), + nonce, + groupMembers, + ) + + return err +} + +func (tc *TbtcChain) CalculateInactivityClaimHash( + claim *inactivity.ClaimPreimage, +) (inactivity.ClaimHash, error) { + walletPublicKeyBytes := secp256k1.Marshal(claim.WalletPublicKey) + // Crop the 04 prefix as the calculateInactivityClaimHash function expects + // an unprefixed 64-byte public key, + unprefixedGroupPublicKeyBytes := walletPublicKeyBytes[1:] + + // The type representing inactive member index should be `big.Int` as the + // smart contract reading the calculated hash uses `uint256` for inactive + // member indexes. + inactiveMembersIndexes := make([]*big.Int, len(claim.InactiveMembersIndexes)) + for i, index := range claim.InactiveMembersIndexes { + inactiveMembersIndexes[i] = big.NewInt(int64(index)) + } + + return calculateInactivityClaimHash( + tc.chainID, + claim.Nonce, + unprefixedGroupPublicKeyBytes, + inactiveMembersIndexes, + claim.HeartbeatFailed, + ) +} + +func calculateInactivityClaimHash( + chainID *big.Int, + nonce *big.Int, + walletPublicKey []byte, + inactiveMembersIndexes []*big.Int, + heartbeatFailed bool, +) (inactivity.ClaimHash, error) { + publicKeySize := 64 + + if len(walletPublicKey) != publicKeySize { + return inactivity.ClaimHash{}, fmt.Errorf( + "wrong wallet public key length", + ) + } + + uint256Type, err := abi.NewType("uint256", "uint256", nil) + if err != nil { + return inactivity.ClaimHash{}, err + } + bytesType, err := abi.NewType("bytes", "bytes", nil) + if err != nil { + return inactivity.ClaimHash{}, err + } + uint256SliceType, err := abi.NewType("uint256[]", "uint256[]", nil) + if err != nil { + return inactivity.ClaimHash{}, err + } + boolType, err := abi.NewType("bool", "bool", nil) + if err != nil { + return inactivity.ClaimHash{}, err + } + + bytes, err := abi.Arguments{ + {Type: uint256Type}, + {Type: uint256Type}, + {Type: bytesType}, + {Type: uint256SliceType}, + {Type: boolType}, + }.Pack( + chainID, + nonce, + walletPublicKey, + inactiveMembersIndexes, + heartbeatFailed, + ) + if err != nil { + return inactivity.ClaimHash{}, err + } + + return inactivity.ClaimHash(crypto.Keccak256Hash(bytes)), nil +} + +func (tc *TbtcChain) GetInactivityClaimNonce( + walletID [32]byte, +) (*big.Int, error) { + nonce, err := tc.walletRegistry.InactivityClaimNonce(walletID) + if err != nil { + return nil, fmt.Errorf( + "failed to get inactivity claim nonce: [%w]", + err, + ) + } + + return nonce, nil +} diff --git a/pkg/chain/ethereum/tbtc_inactivity_test.go b/pkg/chain/ethereum/tbtc_inactivity_test.go new file mode 100644 index 0000000000..ed3c306bee --- /dev/null +++ b/pkg/chain/ethereum/tbtc_inactivity_test.go @@ -0,0 +1,48 @@ +package ethereum + +import ( + "encoding/hex" + "math/big" + "testing" + + "github.com/keep-network/keep-core/internal/testutils" +) + +func TestCalculateInactivityClaimHash(t *testing.T) { + chainID := big.NewInt(31337) + nonce := big.NewInt(3) + + walletPublicKey, err := hex.DecodeString( + "9a0544440cc47779235ccb76d669590c2cd20c7e431f97e17a1093faf03291c473e" + + "661a208a8a565ca1e384059bd2ff7ff6886df081ff1229250099d388c83df", + ) + if err != nil { + t.Fatal(err) + } + + inactiveMembersIndexes := []*big.Int{ + big.NewInt(1), big.NewInt(2), big.NewInt(30), + } + + heartbeatFailed := true + + hash, err := calculateInactivityClaimHash( + chainID, + nonce, + walletPublicKey, + inactiveMembersIndexes, + heartbeatFailed, + ) + if err != nil { + t.Fatal(err) + } + + expectedHash := "f3210008cba186e90386a1bd0c63b6f29a67666f632350be22ce63ab39fc506e" + + testutils.AssertStringsEqual( + t, + "hash", + expectedHash, + hex.EncodeToString(hash[:]), + ) +} diff --git a/pkg/chain/ethereum/tbtc_moving_funds.go b/pkg/chain/ethereum/tbtc_moving_funds.go new file mode 100644 index 0000000000..78d725d21f --- /dev/null +++ b/pkg/chain/ethereum/tbtc_moving_funds.go @@ -0,0 +1,414 @@ +// tbtc_moving_funds.go: moving-funds lifecycle for the TbtcChain adapter. +package ethereum + +import ( + "fmt" + "math/big" + "sort" + "time" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/keep-network/keep-core/pkg/bitcoin" + "github.com/keep-network/keep-core/pkg/chain" + tbtcabi "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen/abi" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + "github.com/keep-network/keep-core/pkg/tbtc" +) + +func (tc *TbtcChain) ComputeMovingFundsCommitmentHash( + targetWallets [][20]byte, +) [32]byte { + return computeMovingFundsCommitmentHash(targetWallets) +} + +func computeMovingFundsCommitmentHash(targetWallets [][20]byte) [32]byte { + packedWallets := []byte{} + + for _, wallet := range targetWallets { + packedWallets = append(packedWallets, wallet[:]...) + // Each wallet hash must be padded with 12 zero bytes following the + // actual hash. + packedWallets = append(packedWallets, make([]byte, 12)...) + } + + return crypto.Keccak256Hash(packedWallets) +} + +func (tc *TbtcChain) PastMovingFundsCommitmentSubmittedEvents( + filter *tbtc.MovingFundsCommitmentSubmittedEventFilter, +) ([]*tbtc.MovingFundsCommitmentSubmittedEvent, error) { + var startBlock uint64 + var endBlock *uint64 + var walletPublicKeyHash [][20]byte + + if filter != nil { + startBlock = filter.StartBlock + endBlock = filter.EndBlock + walletPublicKeyHash = filter.WalletPublicKeyHash + } + + events, err := tc.bridge.PastMovingFundsCommitmentSubmittedEvents( + startBlock, + endBlock, + walletPublicKeyHash, + ) + if err != nil { + return nil, err + } + + convertedEvents := make([]*tbtc.MovingFundsCommitmentSubmittedEvent, 0) + for _, event := range events { + convertedEvent := &tbtc.MovingFundsCommitmentSubmittedEvent{ + WalletPublicKeyHash: event.WalletPubKeyHash, + TargetWallets: event.TargetWallets, + Submitter: chain.Address(event.Submitter.Hex()), + BlockNumber: event.Raw.BlockNumber, + } + + convertedEvents = append(convertedEvents, convertedEvent) + } + + sort.SliceStable( + convertedEvents, + func(i, j int) bool { + return convertedEvents[i].BlockNumber < convertedEvents[j].BlockNumber + }, + ) + + return convertedEvents, err +} + +func (tc *TbtcChain) PastMovingFundsCompletedEvents( + filter *tbtc.MovingFundsCompletedEventFilter, +) ([]*tbtc.MovingFundsCompletedEvent, error) { + var startBlock uint64 + var endBlock *uint64 + var walletPublicKeyHash [][20]byte + + if filter != nil { + startBlock = filter.StartBlock + endBlock = filter.EndBlock + walletPublicKeyHash = filter.WalletPublicKeyHash + } + + events, err := tc.bridge.PastMovingFundsCompletedEvents( + startBlock, + endBlock, + walletPublicKeyHash, + ) + if err != nil { + return nil, err + } + + convertedEvents := make([]*tbtc.MovingFundsCompletedEvent, 0) + for _, event := range events { + convertedEvent := &tbtc.MovingFundsCompletedEvent{ + WalletPublicKeyHash: event.WalletPubKeyHash, + MovingFundsTxHash: event.MovingFundsTxHash, + BlockNumber: event.Raw.BlockNumber, + } + + convertedEvents = append(convertedEvents, convertedEvent) + } + + sort.SliceStable( + convertedEvents, + func(i, j int) bool { + return convertedEvents[i].BlockNumber < convertedEvents[j].BlockNumber + }, + ) + + return convertedEvents, err +} + +func (tc *TbtcChain) SubmitMovingFundsCommitment( + walletPublicKeyHash [20]byte, + walletMainUTXO bitcoin.UnspentTransactionOutput, + walletMembersIDs []uint32, + walletMemberIndex uint32, + targetWallets [][20]byte, +) error { + if walletMainUTXO.Value < 0 { + return fmt.Errorf("invalid main UTXO value: [%v]", walletMainUTXO.Value) + } + + mainUtxo := tbtcabi.BitcoinTxUTXO{ + TxHash: walletMainUTXO.Outpoint.TransactionHash, + TxOutputIndex: walletMainUTXO.Outpoint.OutputIndex, + TxOutputValue: uint64(walletMainUTXO.Value), + } + _, err := tc.bridge.SubmitMovingFundsCommitment( + walletPublicKeyHash, + mainUtxo, + walletMembersIDs, + big.NewInt(int64(walletMemberIndex)), + targetWallets, + ) + return err +} + +func (tc *TbtcChain) SubmitMovingFundsProofWithReimbursement( + transaction *bitcoin.Transaction, + proof *bitcoin.SpvProof, + mainUTXO bitcoin.UnspentTransactionOutput, + walletPublicKeyHash [20]byte, +) error { + if mainUTXO.Value < 0 { + return fmt.Errorf("invalid main UTXO value: [%v]", mainUTXO.Value) + } + + bitcoinTxInfo := tbtcabi.BitcoinTxInfo3{ + Version: transaction.SerializeVersion(), + InputVector: transaction.SerializeInputs(), + OutputVector: transaction.SerializeOutputs(), + Locktime: transaction.SerializeLocktime(), + } + movingFundsProof := tbtcabi.BitcoinTxProof2{ + MerkleProof: proof.MerkleProof, + TxIndexInBlock: new(big.Int).SetUint64(uint64(proof.TxIndexInBlock)), + BitcoinHeaders: proof.BitcoinHeaders, + CoinbasePreimage: proof.CoinbasePreimage, + CoinbaseProof: proof.CoinbaseProof, + } + utxo := tbtcabi.BitcoinTxUTXO2{ + TxHash: mainUTXO.Outpoint.TransactionHash, + TxOutputIndex: mainUTXO.Outpoint.OutputIndex, + TxOutputValue: uint64(mainUTXO.Value), + } + + gasEstimate, err := tc.maintainerProxy.SubmitMovingFundsProofGasEstimate( + bitcoinTxInfo, + movingFundsProof, + utxo, + walletPublicKeyHash, + ) + if err != nil { + return err + } + + // The original estimate for this contract call is too low and the call + // fails on reimbursing the submitter. Example: + // 0xe27a92883e0e64da8a3a54a15a260ea2f4d3d48470129ac5c09bfe9637d7e114 + gasEstimateWithMargin := gasEstimateWithMargin(gasEstimate) + + _, err = tc.maintainerProxy.SubmitMovingFundsProof( + bitcoinTxInfo, + movingFundsProof, + utxo, + walletPublicKeyHash, + ethutil.TransactionOptions{ + GasLimit: uint64(gasEstimateWithMargin), + }, + ) + + return err +} + +func (tc *TbtcChain) SubmitMovedFundsSweepProofWithReimbursement( + transaction *bitcoin.Transaction, + proof *bitcoin.SpvProof, + mainUTXO bitcoin.UnspentTransactionOutput, +) error { + if mainUTXO.Value < 0 { + return fmt.Errorf("invalid main UTXO value: [%v]", mainUTXO.Value) + } + + bitcoinTxInfo := tbtcabi.BitcoinTxInfo3{ + Version: transaction.SerializeVersion(), + InputVector: transaction.SerializeInputs(), + OutputVector: transaction.SerializeOutputs(), + Locktime: transaction.SerializeLocktime(), + } + movedFundsSweepProof := tbtcabi.BitcoinTxProof2{ + MerkleProof: proof.MerkleProof, + TxIndexInBlock: new(big.Int).SetUint64(uint64(proof.TxIndexInBlock)), + BitcoinHeaders: proof.BitcoinHeaders, + CoinbasePreimage: proof.CoinbasePreimage, + CoinbaseProof: proof.CoinbaseProof, + } + utxo := tbtcabi.BitcoinTxUTXO2{ + TxHash: mainUTXO.Outpoint.TransactionHash, + TxOutputIndex: mainUTXO.Outpoint.OutputIndex, + TxOutputValue: uint64(mainUTXO.Value), + } + + gasEstimate, err := tc.maintainerProxy.SubmitMovedFundsSweepProofGasEstimate( + bitcoinTxInfo, + movedFundsSweepProof, + utxo, + ) + if err != nil { + return err + } + + // The original estimate for this contract call is too low and the call + // fails on reimbursing the submitter. Example: + // 0xe27a92883e0e64da8a3a54a15a260ea2f4d3d48470129ac5c09bfe9637d7e114 + gasEstimateWithMargin := gasEstimateWithMargin(gasEstimate) + + _, err = tc.maintainerProxy.SubmitMovedFundsSweepProof( + bitcoinTxInfo, + movedFundsSweepProof, + utxo, + ethutil.TransactionOptions{ + GasLimit: uint64(gasEstimateWithMargin), + }, + ) + + return err +} + +func (tc *TbtcChain) ValidateMovedFundsSweepProposal( + walletPublicKeyHash [20]byte, + proposal *tbtc.MovedFundsSweepProposal, +) error { + abiProposal := tbtcabi.WalletProposalValidatorMovedFundsSweepProposal{ + WalletPubKeyHash: walletPublicKeyHash, + MovingFundsTxHash: proposal.MovingFundsTxHash, + MovingFundsTxOutputIndex: proposal.MovingFundsTxOutputIndex, + MovedFundsSweepTxFee: proposal.SweepTxFee, + } + + valid, err := tc.walletProposalValidator.ValidateMovedFundsSweepProposal( + abiProposal, + ) + if err != nil { + return fmt.Errorf("validation failed: [%v]", err) + } + + // Should never happen because `validateMovedFundsSweepProposal` returns + // true or reverts (returns an error) but do the check just in case. + if !valid { + return fmt.Errorf("unexpected validation result") + } + + return nil +} + +func (tc *TbtcChain) GetMovingFundsParameters() (tbtc.MovingFundsParameters, error) { + parameters, err := tc.bridge.MovingFundsParameters() + if err != nil { + return tbtc.MovingFundsParameters{}, err + } + + return tbtc.MovingFundsParameters{ + TxMaxTotalFee: parameters.MovingFundsTxMaxTotalFee, + DustThreshold: parameters.MovingFundsDustThreshold, + TimeoutResetDelay: parameters.MovingFundsTimeoutResetDelay, + Timeout: parameters.MovingFundsTimeout, + TimeoutSlashingAmount: parameters.MovingFundsTimeoutSlashingAmount, + TimeoutNotifierRewardMultiplier: parameters.MovingFundsTimeoutNotifierRewardMultiplier, + CommitmentGasOffset: parameters.MovingFundsCommitmentGasOffset, + SweepTxMaxTotalFee: parameters.MovedFundsSweepTxMaxTotalFee, + SweepTimeout: parameters.MovedFundsSweepTimeout, + SweepTimeoutSlashingAmount: parameters.MovedFundsSweepTimeoutSlashingAmount, + SweepTimeoutNotifierRewardMultiplier: parameters.MovedFundsSweepTimeoutNotifierRewardMultiplier, + }, nil +} + +func (tc *TbtcChain) GetMovedFundsSweepRequest( + movingFundsTxHash bitcoin.Hash, + movingFundsTxOutpointIndex uint32, +) (*tbtc.MovedFundsSweepRequest, bool, error) { + movedFundsKey := buildMovedFundsKey( + movingFundsTxHash, + movingFundsTxOutpointIndex, + ) + + movedFundsSweepRequest, err := tc.bridge.MovedFundsSweepRequests( + movedFundsKey, + ) + if err != nil { + return nil, false, fmt.Errorf( + "cannot get moved funds sweep request for key [0x%x]: [%v]", + movedFundsKey.Text(16), + err, + ) + } + + // Moved funds sweep request not found. + if movedFundsSweepRequest.CreatedAt == 0 { + return nil, false, nil + } + + state, err := parseMovedFundsSweepRequestState(movedFundsSweepRequest.State) + if err != nil { + return nil, false, fmt.Errorf( + "cannot parse state for moved funds sweep request [0x%x]: [%v]", + movedFundsKey.Text(16), + err, + ) + } + + return &tbtc.MovedFundsSweepRequest{ + WalletPublicKeyHash: movedFundsSweepRequest.WalletPubKeyHash, + Value: movedFundsSweepRequest.Value, + CreatedAt: time.Unix(int64(movedFundsSweepRequest.CreatedAt), 0), + State: state, + }, true, nil +} + +func parseMovedFundsSweepRequestState(value uint8) ( + tbtc.MovedFundsSweepRequestState, + error, +) { + switch value { + case 0: + return tbtc.MovedFundsStateUnknown, nil + case 1: + return tbtc.MovedFundsStatePending, nil + case 2: + return tbtc.MovedFundsStateProcessed, nil + case 3: + return tbtc.MovedFundsStateTimedOut, nil + default: + return 0, fmt.Errorf( + "unexpected moved funds sweep request state value: [%v]", + value, + ) + } +} + +func buildMovedFundsKey( + movingFundsTxHash bitcoin.Hash, + movingFundsTxOutpointIndex uint32, +) *big.Int { + return buildTxOutpointKey(movingFundsTxHash, movingFundsTxOutpointIndex) +} + +func (tc *TbtcChain) ValidateMovingFundsProposal( + walletPublicKeyHash [20]byte, + mainUTXO *bitcoin.UnspentTransactionOutput, + proposal *tbtc.MovingFundsProposal, +) error { + if mainUTXO.Value < 0 { + return fmt.Errorf("invalid main UTXO value: [%v]", mainUTXO.Value) + } + + abiProposal := tbtcabi.WalletProposalValidatorMovingFundsProposal{ + WalletPubKeyHash: walletPublicKeyHash, + TargetWallets: proposal.TargetWallets, + MovingFundsTxFee: proposal.MovingFundsTxFee, + } + abiMainUTXO := tbtcabi.BitcoinTxUTXO3{ + TxHash: mainUTXO.Outpoint.TransactionHash, + TxOutputIndex: mainUTXO.Outpoint.OutputIndex, + TxOutputValue: uint64(mainUTXO.Value), + } + + valid, err := tc.walletProposalValidator.ValidateMovingFundsProposal( + abiProposal, + abiMainUTXO, + ) + if err != nil { + return fmt.Errorf("validation failed: [%v]", err) + } + + // Should never happen because `validateMovingFundsProposal` returns true + // or reverts (returns an error) but do the check just in case. + if !valid { + return fmt.Errorf("unexpected validation result") + } + + return nil +} diff --git a/pkg/chain/ethereum/tbtc_moving_funds_test.go b/pkg/chain/ethereum/tbtc_moving_funds_test.go new file mode 100644 index 0000000000..87e7a594ea --- /dev/null +++ b/pkg/chain/ethereum/tbtc_moving_funds_test.go @@ -0,0 +1,70 @@ +package ethereum + +import ( + "encoding/hex" + "testing" + + "github.com/keep-network/keep-core/internal/testutils" + "github.com/keep-network/keep-core/pkg/bitcoin" +) + +func TestComputeMovingFundsCommitmentHash(t *testing.T) { + toByte20 := func(s string) [20]byte { + bytes, err := hex.DecodeString(s) + if err != nil { + t.Fatal(err) + } + + if len(bytes) != 20 { + t.Fatal("incorrect hexstring length") + } + + var result [20]byte + copy(result[:], bytes[:]) + return result + } + + targetWallets := [][20]byte{ + toByte20("4b440cb29c80c3f256212d8fdd4f2125366f3c91"), + toByte20("888f01315e0268bfa05d5e522f8d63f6824d9a96"), + toByte20("b2a89e53a4227dbe530a52a1c419040735fa636c"), + } + + movingFundsCommitmentHash := computeMovingFundsCommitmentHash( + targetWallets, + ) + + expectedMovingFundsCommitmentHash, err := hex.DecodeString( + "8ba62d1d754a3429e2ff1fb4f523b5fad2b605c873a2968bb5985a625eb96202", + ) + if err != nil { + t.Fatal(err) + } + testutils.AssertBytesEqual( + t, + expectedMovingFundsCommitmentHash, + movingFundsCommitmentHash[:], + ) +} + +func TestBuildMovedFundsKey(t *testing.T) { + fundingTxHash, err := bitcoin.NewHashFromString( + "7cff663e3e08847a5579913f6a66bc6c01f5f48c6ae1783be77418ed188021e6", + bitcoin.InternalByteOrder, + ) + if err != nil { + t.Fatal(err) + } + + fundingOutputIndex := uint32(2) + + movedFundsKey := buildMovedFundsKey(fundingTxHash, fundingOutputIndex) + + expectedMovedFundsKey := "24509b8a853476ebe77af3707bd7ce017d527680e941b6eeaac2d5b712df4f8d" + testutils.AssertStringsEqual( + t, + "moved funds key", + expectedMovedFundsKey, + movedFundsKey.Text(16), + ) +} diff --git a/pkg/chain/ethereum/tbtc_redemption.go b/pkg/chain/ethereum/tbtc_redemption.go new file mode 100644 index 0000000000..4d7c9a6978 --- /dev/null +++ b/pkg/chain/ethereum/tbtc_redemption.go @@ -0,0 +1,301 @@ +// tbtc_redemption.go: redemption request lifecycle for the TbtcChain adapter. +package ethereum + +import ( + "fmt" + "math/big" + "sort" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/keep-network/keep-core/pkg/bitcoin" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + + "github.com/keep-network/keep-core/pkg/chain" + tbtcabi "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen/abi" + "github.com/keep-network/keep-core/pkg/tbtc" +) + +func (tc *TbtcChain) PastRedemptionRequestedEvents( + filter *tbtc.RedemptionRequestedEventFilter, +) ([]*tbtc.RedemptionRequestedEvent, error) { + var startBlock uint64 + var endBlock *uint64 + var redeemers []common.Address + var walletPublicKeyHash [][20]byte + + if filter != nil { + startBlock = filter.StartBlock + endBlock = filter.EndBlock + + for _, r := range filter.Redeemer { + redeemers = append(redeemers, common.HexToAddress(r.String())) + } + + walletPublicKeyHash = filter.WalletPublicKeyHash + } + + events, err := tc.bridge.PastRedemptionRequestedEvents( + startBlock, + endBlock, + walletPublicKeyHash, + redeemers, + ) + if err != nil { + return nil, err + } + + convertedEvents := make([]*tbtc.RedemptionRequestedEvent, 0) + for _, event := range events { + redeemerOutputScript, err := bitcoin.NewScriptFromVarLenData( + event.RedeemerOutputScript, + ) + if err != nil { + return nil, err + } + + convertedEvent := &tbtc.RedemptionRequestedEvent{ + WalletPublicKeyHash: event.WalletPubKeyHash, + RedeemerOutputScript: redeemerOutputScript, + Redeemer: chain.Address(event.Redeemer.Hex()), + RequestedAmount: event.RequestedAmount, + TreasuryFee: event.TreasuryFee, + TxMaxFee: event.TxMaxFee, + BlockNumber: event.Raw.BlockNumber, + } + + convertedEvents = append(convertedEvents, convertedEvent) + } + + sort.SliceStable( + convertedEvents, + func(i, j int) bool { + return convertedEvents[i].BlockNumber < convertedEvents[j].BlockNumber + }, + ) + + return convertedEvents, err +} + +func (tc *TbtcChain) BuildRedemptionKey( + walletPublicKeyHash [20]byte, + redeemerOutputScript bitcoin.Script, +) (*big.Int, error) { + return buildRedemptionKey(walletPublicKeyHash, redeemerOutputScript) +} + +func (tc *TbtcChain) GetPendingRedemptionRequest( + walletPublicKeyHash [20]byte, + redeemerOutputScript bitcoin.Script, +) (*tbtc.RedemptionRequest, bool, error) { + redemptionKey, err := buildRedemptionKey(walletPublicKeyHash, redeemerOutputScript) + if err != nil { + return nil, false, fmt.Errorf("cannot build redemption key: [%v]", err) + } + + redemptionRequest, err := tc.bridge.PendingRedemptions(redemptionKey) + if err != nil { + return nil, false, fmt.Errorf( + "cannot get pending redemption request for key [0x%x]: [%v]", + redemptionKey, + err, + ) + } + + // Redemption not found. + if redemptionRequest.RequestedAt == 0 { + return nil, false, nil + } + + return &tbtc.RedemptionRequest{ + Redeemer: chain.Address(redemptionRequest.Redeemer.Hex()), + RedeemerOutputScript: redeemerOutputScript, + RequestedAmount: redemptionRequest.RequestedAmount, + TreasuryFee: redemptionRequest.TreasuryFee, + TxMaxFee: redemptionRequest.TxMaxFee, + RequestedAt: time.Unix(int64(redemptionRequest.RequestedAt), 0), + }, true, nil +} + +func (tc *TbtcChain) SubmitRedemptionProofWithReimbursement( + transaction *bitcoin.Transaction, + proof *bitcoin.SpvProof, + mainUTXO bitcoin.UnspentTransactionOutput, + walletPublicKeyHash [20]byte, +) error { + if mainUTXO.Value < 0 { + return fmt.Errorf("invalid main UTXO value: [%v]", mainUTXO.Value) + } + + bitcoinTxInfo := tbtcabi.BitcoinTxInfo3{ + Version: transaction.SerializeVersion(), + InputVector: transaction.SerializeInputs(), + OutputVector: transaction.SerializeOutputs(), + Locktime: transaction.SerializeLocktime(), + } + redemptionProof := tbtcabi.BitcoinTxProof2{ + MerkleProof: proof.MerkleProof, + TxIndexInBlock: new(big.Int).SetUint64(uint64(proof.TxIndexInBlock)), + BitcoinHeaders: proof.BitcoinHeaders, + CoinbasePreimage: proof.CoinbasePreimage, + CoinbaseProof: proof.CoinbaseProof, + } + utxo := tbtcabi.BitcoinTxUTXO2{ + TxHash: mainUTXO.Outpoint.TransactionHash, + TxOutputIndex: mainUTXO.Outpoint.OutputIndex, + TxOutputValue: uint64(mainUTXO.Value), + } + + gasEstimate, err := tc.maintainerProxy.SubmitRedemptionProofGasEstimate( + bitcoinTxInfo, + redemptionProof, + utxo, + walletPublicKeyHash, + ) + if err != nil { + return err + } + + // The original estimate for this contract call is too low and the call + // fails on reimbursing the submitter. Example: + // 0xe27a92883e0e64da8a3a54a15a260ea2f4d3d48470129ac5c09bfe9637d7e114 + gasEstimateWithMargin := gasEstimateWithMargin(gasEstimate) + + _, err = tc.maintainerProxy.SubmitRedemptionProof( + bitcoinTxInfo, + redemptionProof, + utxo, + walletPublicKeyHash, + ethutil.TransactionOptions{ + GasLimit: uint64(gasEstimateWithMargin), + }, + ) + + return err +} + +func buildRedemptionKey( + walletPublicKeyHash [20]byte, + redeemerOutputScript bitcoin.Script, +) (*big.Int, error) { + // The Bridge contract builds the redemption key using the length-prefixed + // redeemer output script. + prefixedRedeemerOutputScript, err := redeemerOutputScript.ToVarLenData() + if err != nil { + return nil, fmt.Errorf("cannot build prefixed redeemer output script: [%v]", err) + } + + redeemerOutputScriptHash := crypto.Keccak256Hash(prefixedRedeemerOutputScript) + + redemptionKey := crypto.Keccak256Hash( + append(redeemerOutputScriptHash[:], walletPublicKeyHash[:]...), + ) + + return redemptionKey.Big(), nil +} + +func (tc *TbtcChain) GetRedemptionParameters() (tbtc.RedemptionParameters, error) { + parameters, err := tc.bridge.RedemptionParameters() + if err != nil { + return tbtc.RedemptionParameters{}, err + } + + return tbtc.RedemptionParameters{ + DustThreshold: parameters.RedemptionDustThreshold, + TreasuryFeeDivisor: parameters.RedemptionTreasuryFeeDivisor, + TxMaxFee: parameters.RedemptionTxMaxFee, + TxMaxTotalFee: parameters.RedemptionTxMaxTotalFee, + Timeout: parameters.RedemptionTimeout, + TimeoutSlashingAmount: parameters.RedemptionTimeoutSlashingAmount, + TimeoutNotifierRewardMultiplier: parameters.RedemptionTimeoutNotifierRewardMultiplier, + }, nil +} + +func (tc *TbtcChain) ValidateRedemptionProposal( + walletPublicKeyHash [20]byte, + proposal *tbtc.RedemptionProposal, +) error { + abiProposal, err := convertRedemptionProposalToAbiType( + walletPublicKeyHash, + proposal, + ) + if err != nil { + return fmt.Errorf("cannot convert proposal to abi type: [%v]", err) + } + + valid, err := tc.walletProposalValidator.ValidateRedemptionProposal( + abiProposal, + ) + if err != nil { + return fmt.Errorf("validation failed: [%v]", err) + } + + // Should never happen because `validateRedemptionProposal` returns true + // or reverts (returns an error) but do the check just in case. + if !valid { + return fmt.Errorf("unexpected validation result") + } + + return nil +} + +func convertRedemptionProposalToAbiType( + walletPublicKeyHash [20]byte, + proposal *tbtc.RedemptionProposal, +) (tbtcabi.WalletProposalValidatorRedemptionProposal, error) { + redeemersOutputScripts := make( + [][]byte, + len(proposal.RedeemersOutputScripts), + ) + + for i, script := range proposal.RedeemersOutputScripts { + // The on-chain script representation must be prepended with the script's + // byte-length while bitcoin.Script is not. We need to add the + // length prefix. + prefixedScript, err := script.ToVarLenData() + if err != nil { + return tbtcabi.WalletProposalValidatorRedemptionProposal{}, fmt.Errorf( + "cannot convert redeemer output script: [%v]", + err, + ) + } + + redeemersOutputScripts[i] = prefixedScript + } + + return tbtcabi.WalletProposalValidatorRedemptionProposal{ + WalletPubKeyHash: walletPublicKeyHash, + RedeemersOutputScripts: redeemersOutputScripts, + RedemptionTxFee: proposal.RedemptionTxFee, + }, nil +} + +func (tc *TbtcChain) GetRedemptionMaxSize() (uint16, error) { + return tc.walletProposalValidator.REDEMPTIONMAXSIZE() +} + +func (tc *TbtcChain) GetRedemptionRequestMinAge() (uint32, error) { + return tc.walletProposalValidator.REDEMPTIONREQUESTMINAGE() +} + +func (tc *TbtcChain) GetRedemptionDelay( + walletPublicKeyHash [20]byte, + redeemerOutputScript bitcoin.Script, +) (time.Duration, error) { + if tc.redemptionWatchtower == nil { + return 0, nil + } + + redemptionKey, err := tc.BuildRedemptionKey(walletPublicKeyHash, redeemerOutputScript) + if err != nil { + return 0, fmt.Errorf("cannot build redemption key: [%v]", err) + } + + delay, err := tc.redemptionWatchtower.GetRedemptionDelay(redemptionKey) + if err != nil { + return 0, fmt.Errorf("cannot get redemption delay: [%v]", err) + } + + return time.Duration(delay) * time.Second, nil +} diff --git a/pkg/chain/ethereum/tbtc_redemption_test.go b/pkg/chain/ethereum/tbtc_redemption_test.go new file mode 100644 index 0000000000..0dca443af1 --- /dev/null +++ b/pkg/chain/ethereum/tbtc_redemption_test.go @@ -0,0 +1,37 @@ +package ethereum + +import ( + "encoding/hex" + "testing" + + "github.com/keep-network/keep-core/internal/testutils" +) + +func TestBuildRedemptionKey(t *testing.T) { + fromHex := func(hexString string) []byte { + b, err := hex.DecodeString(hexString) + if err != nil { + t.Fatal(err) + } + return b + } + + walletPublicKeyHashBytes := fromHex("8db50eb52063ea9d98b3eac91489a90f738986f6") + var walletPublicKeyHash [20]byte + copy(walletPublicKeyHash[:], walletPublicKeyHashBytes) + + redeemerOutputScript := fromHex("76a9144130879211c54df460e484ddf9aac009cb38ee7488ac") + + redemptionKey, err := buildRedemptionKey(walletPublicKeyHash, redeemerOutputScript) + if err != nil { + t.Fatal(err) + } + + expectedRedemptionKey := "cb493004c645792101cfa4cc5da4c16aa3148065034371a6f1478b7df4b92d39" + testutils.AssertStringsEqual( + t, + "redemption key", + expectedRedemptionKey, + redemptionKey.Text(16), + ) +} diff --git a/pkg/chain/ethereum/tbtc_sortition.go b/pkg/chain/ethereum/tbtc_sortition.go new file mode 100644 index 0000000000..ba33dc2e96 --- /dev/null +++ b/pkg/chain/ethereum/tbtc_sortition.go @@ -0,0 +1,248 @@ +// tbtc_sortition.go: sortition pool membership and unwinding for the TbtcChain adapter. +package ethereum + +import ( + "context" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + + "github.com/keep-network/keep-core/pkg/chain" + "github.com/keep-network/keep-core/pkg/operator" + "github.com/keep-network/keep-core/pkg/tbtc" +) + +// EcdsaWalletGroupParametersFromChain mirrors EcdsaDkgValidator sizing constants +// when EcdsaDkgValidator contract address was configured under [ethereum] +// contract addresses or developer.ecdsaDkgValidatorAddress alias. When absent, +// returns (nil, nil) and callers use defaultGroupParameters(network). +func (tc *TbtcChain) EcdsaWalletGroupParametersFromChain( + ctx context.Context, +) (*tbtc.GroupParameters, error) { + if tc.ecdsaDkgValidatorAddress == (common.Address{}) { + return nil, nil + } + return ecdsaWalletGroupParametersFromValidator( + ctx, + tc.baseChain.client, + tc.ecdsaDkgValidatorAddress, + ) +} + +// Staking returns address of the TokenStaking contract the WalletRegistry is +// connected to. +func (tc *TbtcChain) Staking() (chain.Address, error) { + stakingContractAddress, err := tc.walletRegistry.Staking() + if err != nil { + return "", fmt.Errorf( + "failed to get the token staking address: [%w]", + err, + ) + } + + return chain.Address(stakingContractAddress.String()), nil +} + +// IsRecognized checks whether the given operator is recognized by the TbtcChain +// as eligible to join the network. If the operator has a stake delegation or +// had a stake delegation in the past, it will be recognized. +func (tc *TbtcChain) IsRecognized(operatorPublicKey *operator.PublicKey) (bool, error) { + operatorAddress, err := operatorPublicKeyToChainAddress(operatorPublicKey) + if err != nil { + return false, fmt.Errorf( + "cannot convert from operator key to chain address: [%v]", + err, + ) + } + + stakingProvider, err := tc.walletRegistry.OperatorToStakingProvider( + operatorAddress, + ) + if err != nil { + return false, fmt.Errorf( + "failed to map operator [%v] to a staking provider: [%v]", + operatorAddress, + err, + ) + } + + if (stakingProvider == common.Address{}) { + return false, nil + } + + // Check if the staking provider has an owner. This check ensures that there + // is/was a stake delegation for the given staking provider. + _, _, _, hasStakeDelegation, err := tc.baseChain.RolesOf( + chain.Address(stakingProvider.Hex()), + ) + if err != nil { + return false, fmt.Errorf( + "failed to check stake delegation for staking provider [%v]: [%v]", + stakingProvider, + err, + ) + } + + if !hasStakeDelegation { + return false, nil + } + + return true, nil +} + +// OperatorToStakingProvider returns the staking provider address for the +// operator. If the staking provider has not been registered for the +// operator, the returned address is empty and the boolean flag is set to +// false. If the staking provider has been registered, the address is not +// empty and the boolean flag indicates true. +func (tc *TbtcChain) OperatorToStakingProvider() (chain.Address, bool, error) { + stakingProvider, err := tc.walletRegistry.OperatorToStakingProvider(tc.key.Address) + if err != nil { + return "", false, fmt.Errorf( + "failed to map operator [%v] to a staking provider: [%v]", + tc.key.Address, + err, + ) + } + + if (stakingProvider == common.Address{}) { + return "", false, nil + } + + return chain.Address(stakingProvider.Hex()), true, nil +} + +// EligibleStake returns the current value of the staking provider's +// eligible stake. Eligible stake is defined as the currently authorized +// stake minus the pending authorization decrease. Eligible stake +// is what is used for operator's weight in the sortition pool. +// If the authorized stake minus the pending authorization decrease +// is below the minimum authorization, eligible stake is 0. +func (tc *TbtcChain) EligibleStake(stakingProvider chain.Address) (*big.Int, error) { + eligibleStake, err := tc.walletRegistry.EligibleStake( + common.HexToAddress(stakingProvider.String()), + ) + if err != nil { + return nil, fmt.Errorf( + "failed to get eligible stake for staking provider %s: [%w]", + stakingProvider, + err, + ) + } + + return eligibleStake, nil +} + +// IsPoolLocked returns true if the sortition pool is locked and no state +// changes are allowed. +func (tc *TbtcChain) IsPoolLocked() (bool, error) { + return tc.sortitionPool.IsLocked() +} + +// IsOperatorInPool returns true if the operator is registered in +// the sortition pool. +func (tc *TbtcChain) IsOperatorInPool() (bool, error) { + return tc.walletRegistry.IsOperatorInPool(tc.key.Address) +} + +// IsOperatorUpToDate checks if the operator's authorized stake is in sync +// with operator's weight in the sortition pool. +// If the operator's authorized stake is not in sync with sortition pool +// weight, function returns false. +// If the operator is not in the sortition pool and their authorized stake +// is non-zero, function returns false. +func (tc *TbtcChain) IsOperatorUpToDate() (bool, error) { + return tc.walletRegistry.IsOperatorUpToDate(tc.key.Address) +} + +// JoinSortitionPool executes a transaction to have the operator join the +// sortition pool. +func (tc *TbtcChain) JoinSortitionPool() error { + _, err := tc.walletRegistry.JoinSortitionPool() + return err +} + +// UpdateOperatorStatus executes a transaction to update the operator's +// state in the sortition pool. +func (tc *TbtcChain) UpdateOperatorStatus() error { + _, err := tc.walletRegistry.UpdateOperatorStatus(tc.key.Address) + return err +} + +// IsEligibleForRewards checks whether the operator is eligible for rewards +// or not. +func (tc *TbtcChain) IsEligibleForRewards() (bool, error) { + return tc.sortitionPool.IsEligibleForRewards(tc.key.Address) +} + +// Checks whether the operator is able to restore their eligibility for +// rewards right away. +func (tc *TbtcChain) CanRestoreRewardEligibility() (bool, error) { + return tc.sortitionPool.CanRestoreRewardEligibility(tc.key.Address) +} + +// Restores reward eligibility for the operator. +func (tc *TbtcChain) RestoreRewardEligibility() error { + _, err := tc.sortitionPool.RestoreRewardEligibility(tc.key.Address) + return err +} + +// Returns true if the chaosnet phase is active, false otherwise. +func (tc *TbtcChain) IsChaosnetActive() (bool, error) { + return tc.sortitionPool.IsChaosnetActive() +} + +// Returns true if operator is a beta operator, false otherwise. +// Chaosnet status does not matter. +func (tc *TbtcChain) IsBetaOperator() (bool, error) { + return tc.sortitionPool.IsBetaOperator(tc.key.Address) +} + +// GetOperatorID returns the ID number of the given operator address. An ID +// number of 0 means the operator has not been allocated an ID number yet. +func (tc *TbtcChain) GetOperatorID( + operatorAddress chain.Address, +) (chain.OperatorID, error) { + return tc.sortitionPool.GetOperatorID( + common.HexToAddress(operatorAddress.String()), + ) +} + +// SelectGroup returns the group members selected for the current group +// selection. The function returns an error if the chain's state does not allow +// for group selection at the moment. +func (tc *TbtcChain) SelectGroup() (*tbtc.GroupSelectionResult, error) { + operatorsIDs, err := tc.walletRegistry.SelectGroup() + if err != nil { + return nil, fmt.Errorf( + "cannot select group in the sortition pool: [%v]", + err, + ) + } + + operatorsAddresses, err := tc.sortitionPool.GetIDOperators(operatorsIDs) + if err != nil { + return nil, fmt.Errorf( + "cannot convert operators' IDs to addresses: [%v]", + err, + ) + } + + // Should not happen as this is guaranteed by the contract but, just in case. + if len(operatorsIDs) != len(operatorsAddresses) { + return nil, fmt.Errorf("operators IDs and addresses mismatch") + } + + ids := make([]chain.OperatorID, len(operatorsIDs)) + addresses := make([]chain.Address, len(operatorsIDs)) + for i := range ids { + ids[i] = operatorsIDs[i] + addresses[i] = chain.Address(operatorsAddresses[i].String()) + } + + return &tbtc.GroupSelectionResult{ + OperatorsIDs: ids, + OperatorsAddresses: addresses, + }, nil +} diff --git a/pkg/chain/ethereum/tbtc_test.go b/pkg/chain/ethereum/tbtc_test.go index 1c9eef1be0..aac5f4c8e4 100644 --- a/pkg/chain/ethereum/tbtc_test.go +++ b/pkg/chain/ethereum/tbtc_test.go @@ -1,135 +1,13 @@ package ethereum import ( - "bytes" "crypto/ecdsa" - "encoding/hex" - "fmt" "math/big" - "reflect" "testing" - "github.com/keep-network/keep-core/pkg/bitcoin" - - "github.com/keep-network/keep-core/pkg/chain" - - "github.com/ethereum/go-ethereum/common" - "github.com/keep-network/keep-core/internal/testutils" - "github.com/keep-network/keep-core/pkg/chain/local_v1" - "github.com/keep-network/keep-core/pkg/protocol/group" ) -func TestComputeOperatorsIDsHash(t *testing.T) { - operatorIDs := []chain.OperatorID{ - 5, 1, 55, 45435534, 33, 345, 23, 235, 3333, 2, - } - - hash, err := computeOperatorsIDsHash(operatorIDs) - if err != nil { - t.Fatal(err) - } - - expectedHash := "8cd41effd4ee91b56d6b2f836efdcac11ab1ef2ae228e348814d0e6c2966d01e" - - testutils.AssertStringsEqual( - t, - "hash", - expectedHash, - hex.EncodeToString(hash[:]), - ) -} - -func TestConvertSignaturesToChainFormat(t *testing.T) { - signatureSize := 65 - - signature1 := common.LeftPadBytes([]byte{1, 2, 3}, signatureSize) - signature2 := common.LeftPadBytes([]byte{4, 5, 6}, signatureSize) - signature3 := common.LeftPadBytes([]byte{7}, signatureSize) - signature4 := common.LeftPadBytes([]byte{8, 9, 10}, signatureSize) - signature5 := common.LeftPadBytes([]byte{11, 12, 13}, signatureSize) - - invalidSignature := common.LeftPadBytes([]byte("invalid"), signatureSize-1) - - var tests = map[string]struct { - signaturesMap map[group.MemberIndex][]byte - expectedIndices []group.MemberIndex - expectedError error - }{ - "one valid signature": { - signaturesMap: map[uint8][]byte{ - 1: signature1, - }, - expectedIndices: []group.MemberIndex{1}, - }, - "five valid signatures": { - signaturesMap: map[group.MemberIndex][]byte{ - 3: signature3, - 1: signature1, - 4: signature4, - 5: signature5, - 2: signature2, - }, - expectedIndices: []group.MemberIndex{1, 2, 3, 4, 5}, - }, - "invalid signature": { - signaturesMap: map[group.MemberIndex][]byte{ - 1: signature1, - 2: invalidSignature, - }, - expectedError: fmt.Errorf("invalid signature size for member [2] got [64] bytes but [65] bytes required"), - }, - } - for testName, test := range tests { - t.Run(testName, func(t *testing.T) { - indicesSlice, signaturesSlice, err := - convertSignaturesToChainFormat(test.signaturesMap) - - if !reflect.DeepEqual(err, test.expectedError) { - t.Errorf( - "unexpected error\nexpected: [%v]\nactual: [%v]\n", - test.expectedError, - err, - ) - } - - if test.expectedError == nil { - if !reflect.DeepEqual(test.expectedIndices, indicesSlice) { - t.Errorf( - "unexpected indices\n"+ - "expected: [%v]\n"+ - "actual: [%v]\n", - test.expectedIndices, - indicesSlice, - ) - } - - testutils.AssertIntsEqual( - t, - "signatures slice length", - signatureSize*len(test.signaturesMap), - len(signaturesSlice), - ) - } - - for i, memberIndex := range indicesSlice { - actualSignature := signaturesSlice[signatureSize*i : signatureSize*(i+1)] - if !bytes.Equal( - test.signaturesMap[memberIndex], - actualSignature, - ) { - t.Errorf( - "invalid signatures for member %v\nexpected: %v\nactual: %v\n", - memberIndex, - test.signaturesMap[memberIndex], - actualSignature, - ) - } - } - }) - } -} - func TestConvertPubKeyToChainFormat(t *testing.T) { bytes30 := []byte{229, 19, 136, 216, 125, 157, 135, 142, 67, 130, 136, 13, 76, 188, 32, 218, 243, 134, 95, 73, 155, 24, 38, 73, 117, 90, @@ -168,368 +46,3 @@ func TestConvertPubKeyToChainFormat(t *testing.T) { actualResult[:], ) } - -func TestValidateMemberIndex(t *testing.T) { - one := big.NewInt(1) - maxMemberIndex := big.NewInt(255) - - var tests = map[string]struct { - chainMemberIndex *big.Int - expectedError error - }{ - "less than max member index": { - chainMemberIndex: new(big.Int).Sub(maxMemberIndex, one), - expectedError: nil, - }, - "max member index": { - chainMemberIndex: maxMemberIndex, - expectedError: nil, - }, - "greater than max member index": { - chainMemberIndex: new(big.Int).Add(maxMemberIndex, one), - expectedError: fmt.Errorf("invalid member index value: [256]"), - }, - } - - for testName, test := range tests { - t.Run(testName, func(t *testing.T) { - err := validateMemberIndex(test.chainMemberIndex) - - if !reflect.DeepEqual(err, test.expectedError) { - t.Errorf( - "unexpected error\nexpected: [%v]\nactual: [%v]\n", - test.expectedError, - err, - ) - } - }) - } -} - -func TestCalculateDKGResultSignatureHash(t *testing.T) { - chainID := big.NewInt(1) - - groupPublicKey, err := hex.DecodeString( - "989d253b17a6a0f41838b84ff0d20e8898f9d7b1a98f2564da4cc29dcf8581d9d" + - "218b65e7d91c752f7b22eaceb771a9af3a6f3d3f010a5d471a1aeef7d7713af", - ) - if err != nil { - t.Fatal(err) - } - - misbehavedMembersIndexes := []group.MemberIndex{2, 55} - - startBlock := big.NewInt(2000) - - hash, err := calculateDKGResultSignatureHash( - chainID, - groupPublicKey, - misbehavedMembersIndexes, - startBlock, - ) - if err != nil { - t.Fatal(err) - } - - expectedHash := "25f917154586c2be0b6364f5c4758580e535bc01ed4881211000c9267aef3a3b" - - testutils.AssertStringsEqual( - t, - "hash", - expectedHash, - hex.EncodeToString(hash[:]), - ) -} - -func TestCalculateInactivityClaimHash(t *testing.T) { - chainID := big.NewInt(31337) - nonce := big.NewInt(3) - - walletPublicKey, err := hex.DecodeString( - "9a0544440cc47779235ccb76d669590c2cd20c7e431f97e17a1093faf03291c473e" + - "661a208a8a565ca1e384059bd2ff7ff6886df081ff1229250099d388c83df", - ) - if err != nil { - t.Fatal(err) - } - - inactiveMembersIndexes := []*big.Int{ - big.NewInt(1), big.NewInt(2), big.NewInt(30), - } - - heartbeatFailed := true - - hash, err := calculateInactivityClaimHash( - chainID, - nonce, - walletPublicKey, - inactiveMembersIndexes, - heartbeatFailed, - ) - if err != nil { - t.Fatal(err) - } - - expectedHash := "f3210008cba186e90386a1bd0c63b6f29a67666f632350be22ce63ab39fc506e" - - testutils.AssertStringsEqual( - t, - "hash", - expectedHash, - hex.EncodeToString(hash[:]), - ) -} - -func TestCalculateWalletID(t *testing.T) { - hexToByte32 := func(hexStr string) [32]byte { - if len(hexStr) != 64 { - t.Fatal("hex string length incorrect") - } - - decoded, err := hex.DecodeString(hexStr) - if err != nil { - t.Fatal(err) - } - - var result [32]byte - copy(result[:], decoded) - - return result - } - - xBytes := hexToByte32( - "9a0544440cc47779235ccb76d669590c2cd20c7e431f97e17a1093faf03291c4", - ) - - yBytes := hexToByte32( - "73e661a208a8a565ca1e384059bd2ff7ff6886df081ff1229250099d388c83df", - ) - - walletPublicKey := &ecdsa.PublicKey{ - Curve: local_v1.DefaultCurve, - X: new(big.Int).SetBytes(xBytes[:]), - Y: new(big.Int).SetBytes(yBytes[:]), - } - - actualWalletID, err := calculateWalletID(walletPublicKey) - if err != nil { - t.Fatal(err) - } - - expectedWalletID := hexToByte32( - "a6602e554b8cf7c23538fd040e4ff3520ec680e5e5ce9a075259e613a3e5aa79", - ) - - testutils.AssertBytesEqual(t, expectedWalletID[:], actualWalletID[:]) -} - -func TestParseDkgResultValidationOutcome(t *testing.T) { - isValid, err := parseDkgResultValidationOutcome( - &struct { - bool - string - }{ - true, - "", - }, - ) - if err != nil { - t.Fatal(err) - } - testutils.AssertBoolsEqual(t, "validation outcome", true, isValid) - - isValid, err = parseDkgResultValidationOutcome( - &struct { - bool - string - }{ - false, - "", - }, - ) - if err != nil { - t.Fatal(err) - } - testutils.AssertBoolsEqual(t, "validation outcome", false, isValid) - - _, err = parseDkgResultValidationOutcome( - struct { - bool - string - }{ - true, - "", - }, - ) - expectedErr := fmt.Errorf("result validation outcome is not a pointer") - if !reflect.DeepEqual(expectedErr, err) { - t.Errorf( - "unexpected error\n"+ - "expected: [%v]\n"+ - "actual: [%v]", - expectedErr, - err, - ) - } - - _, err = parseDkgResultValidationOutcome( - &struct { - string - bool - }{ - "", - true, - }, - ) - expectedErr = fmt.Errorf("cannot parse result validation outcome") - if !reflect.DeepEqual(expectedErr, err) { - t.Errorf( - "unexpected error\n"+ - "expected: [%v]\n"+ - "actual: [%v]", - expectedErr, - err, - ) - } -} - -func TestComputeMainUtxoHash(t *testing.T) { - transactionHash, err := bitcoin.NewHashFromString( - "089bd0671a4481c3584919b4b9b6751cb3f8586dab41cb157adec43fd10ccc00", - bitcoin.InternalByteOrder, - ) - if err != nil { - t.Fatal(err) - } - - mainUtxo := &bitcoin.UnspentTransactionOutput{ - Outpoint: &bitcoin.TransactionOutpoint{ - TransactionHash: transactionHash, - OutputIndex: 5, - }, - Value: 143565433, - } - - mainUtxoHash := computeMainUtxoHash(mainUtxo) - - expectedMainUtxoHash, err := hex.DecodeString( - "1216f8e993c4c57d3c4c971c0d2651140fc4ab09d41960d9ccd7b41fdcd270d6", - ) - if err != nil { - t.Fatal(err) - } - testutils.AssertBytesEqual(t, expectedMainUtxoHash, mainUtxoHash[:]) -} - -func TestComputeMovingFundsCommitmentHash(t *testing.T) { - toByte20 := func(s string) [20]byte { - bytes, err := hex.DecodeString(s) - if err != nil { - t.Fatal(err) - } - - if len(bytes) != 20 { - t.Fatal("incorrect hexstring length") - } - - var result [20]byte - copy(result[:], bytes[:]) - return result - } - - targetWallets := [][20]byte{ - toByte20("4b440cb29c80c3f256212d8fdd4f2125366f3c91"), - toByte20("888f01315e0268bfa05d5e522f8d63f6824d9a96"), - toByte20("b2a89e53a4227dbe530a52a1c419040735fa636c"), - } - - movingFundsCommitmentHash := computeMovingFundsCommitmentHash( - targetWallets, - ) - - expectedMovingFundsCommitmentHash, err := hex.DecodeString( - "8ba62d1d754a3429e2ff1fb4f523b5fad2b605c873a2968bb5985a625eb96202", - ) - if err != nil { - t.Fatal(err) - } - testutils.AssertBytesEqual( - t, - expectedMovingFundsCommitmentHash, - movingFundsCommitmentHash[:], - ) -} - -// Test data based on: https://etherscan.io/tx/0x97c7a293127a604da77f7ef8daf4b19da2bf04327dd891b6d717eaef89bd8bca -func TestBuildDepositKey(t *testing.T) { - fundingTxHash, err := bitcoin.NewHashFromString( - "585b6699f42291d1a9d0776b75f04c295ea203f83504349db11e94fdae7d1b2c", - bitcoin.InternalByteOrder, - ) - if err != nil { - t.Fatal(err) - } - - fundingOutputIndex := uint32(1) - - depositKey := buildDepositKey(fundingTxHash, fundingOutputIndex) - - expectedDepositKey := "3e84c1ea6aeaf2f45fb49623a88affe653b798ea6f675805acc0ec3965b6f317" - testutils.AssertStringsEqual( - t, - "deposit key", - expectedDepositKey, - depositKey.Text(16), - ) -} - -func TestBuildRedemptionKey(t *testing.T) { - fromHex := func(hexString string) []byte { - b, err := hex.DecodeString(hexString) - if err != nil { - t.Fatal(err) - } - return b - } - - walletPublicKeyHashBytes := fromHex("8db50eb52063ea9d98b3eac91489a90f738986f6") - var walletPublicKeyHash [20]byte - copy(walletPublicKeyHash[:], walletPublicKeyHashBytes) - - redeemerOutputScript := fromHex("76a9144130879211c54df460e484ddf9aac009cb38ee7488ac") - - redemptionKey, err := buildRedemptionKey(walletPublicKeyHash, redeemerOutputScript) - if err != nil { - t.Fatal(err) - } - - expectedRedemptionKey := "cb493004c645792101cfa4cc5da4c16aa3148065034371a6f1478b7df4b92d39" - testutils.AssertStringsEqual( - t, - "redemption key", - expectedRedemptionKey, - redemptionKey.Text(16), - ) -} - -func TestBuildMovedFundsKey(t *testing.T) { - fundingTxHash, err := bitcoin.NewHashFromString( - "7cff663e3e08847a5579913f6a66bc6c01f5f48c6ae1783be77418ed188021e6", - bitcoin.InternalByteOrder, - ) - if err != nil { - t.Fatal(err) - } - - fundingOutputIndex := uint32(2) - - movedFundsKey := buildMovedFundsKey(fundingTxHash, fundingOutputIndex) - - expectedMovedFundsKey := "24509b8a853476ebe77af3707bd7ce017d527680e941b6eeaac2d5b712df4f8d" - testutils.AssertStringsEqual( - t, - "moved funds key", - expectedMovedFundsKey, - movedFundsKey.Text(16), - ) -} diff --git a/pkg/chain/ethereum/tbtc_wallet.go b/pkg/chain/ethereum/tbtc_wallet.go new file mode 100644 index 0000000000..021d0720fc --- /dev/null +++ b/pkg/chain/ethereum/tbtc_wallet.go @@ -0,0 +1,243 @@ +// tbtc_wallet.go: wallet registry read/write methods for the TbtcChain adapter. +package ethereum + +import ( + "crypto/ecdsa" + "encoding/binary" + "fmt" + "sort" + "time" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/keep-network/keep-core/pkg/bitcoin" + + tbtcabi "github.com/keep-network/keep-core/pkg/chain/ethereum/tbtc/gen/abi" + "github.com/keep-network/keep-core/pkg/subscription" + "github.com/keep-network/keep-core/pkg/tbtc" +) + +func (tc *TbtcChain) PastNewWalletRegisteredEvents( + filter *tbtc.NewWalletRegisteredEventFilter, +) ([]*tbtc.NewWalletRegisteredEvent, error) { + var startBlock uint64 + var endBlock *uint64 + var ecdsaWalletID [][32]byte + var walletPublicKeyHash [][20]byte + + if filter != nil { + startBlock = filter.StartBlock + endBlock = filter.EndBlock + ecdsaWalletID = filter.EcdsaWalletID + walletPublicKeyHash = filter.WalletPublicKeyHash + } + + events, err := tc.bridge.PastNewWalletRegisteredEvents( + startBlock, + endBlock, + ecdsaWalletID, + walletPublicKeyHash, + ) + if err != nil { + return nil, err + } + + convertedEvents := make([]*tbtc.NewWalletRegisteredEvent, 0) + for _, event := range events { + convertedEvent := &tbtc.NewWalletRegisteredEvent{ + EcdsaWalletID: event.EcdsaWalletID, + WalletPublicKeyHash: event.WalletPubKeyHash, + BlockNumber: event.Raw.BlockNumber, + } + + convertedEvents = append(convertedEvents, convertedEvent) + } + + sort.SliceStable( + convertedEvents, + func(i, j int) bool { + return convertedEvents[i].BlockNumber < convertedEvents[j].BlockNumber + }, + ) + + return convertedEvents, err +} + +func (tc *TbtcChain) CalculateWalletID( + walletPublicKey *ecdsa.PublicKey, +) ([32]byte, error) { + return calculateWalletID(walletPublicKey) +} + +func calculateWalletID(walletPublicKey *ecdsa.PublicKey) ([32]byte, error) { + walletPublicKeyBytes, err := convertPubKeyToChainFormat(walletPublicKey) + if err != nil { + return [32]byte{}, fmt.Errorf( + "error while converting wallet public key to chain format: [%v]", + err, + ) + } + + return crypto.Keccak256Hash(walletPublicKeyBytes[:]), nil +} + +func (tc *TbtcChain) IsWalletRegistered(EcdsaWalletID [32]byte) (bool, error) { + isWalletRegistered, err := tc.walletRegistry.IsWalletRegistered( + EcdsaWalletID, + ) + if err != nil { + return false, fmt.Errorf( + "cannot check if wallet with ECDSA ID [0x%x] is registered: [%v]", + EcdsaWalletID, + err, + ) + } + + return isWalletRegistered, nil +} + +func (tc *TbtcChain) GetWallet( + walletPublicKeyHash [20]byte, +) (*tbtc.WalletChainData, error) { + wallet, err := tc.bridge.Wallets(walletPublicKeyHash) + if err != nil { + return nil, fmt.Errorf( + "cannot get wallet for public key hash [0x%x]: [%v]", + walletPublicKeyHash, + err, + ) + } + + // Wallet not found. + if wallet.CreatedAt == 0 { + return nil, fmt.Errorf( + "no wallet for public key hash [0x%x]", + walletPublicKeyHash, + ) + } + + walletState, err := parseWalletState(wallet.State) + if err != nil { + return nil, fmt.Errorf("cannot parse wallet state: [%v]", err) + } + + return &tbtc.WalletChainData{ + EcdsaWalletID: wallet.EcdsaWalletID, + MainUtxoHash: wallet.MainUtxoHash, + PendingRedemptionsValue: wallet.PendingRedemptionsValue, + CreatedAt: time.Unix(int64(wallet.CreatedAt), 0), + MovingFundsRequestedAt: time.Unix(int64(wallet.MovingFundsRequestedAt), 0), + ClosingStartedAt: time.Unix(int64(wallet.ClosingStartedAt), 0), + PendingMovedFundsSweepRequestsCount: wallet.PendingMovedFundsSweepRequestsCount, + State: walletState, + MovingFundsTargetWalletsCommitmentHash: wallet.MovingFundsTargetWalletsCommitmentHash, + }, nil +} + +func (tc *TbtcChain) OnWalletClosed( + handler func(event *tbtc.WalletClosedEvent), +) subscription.EventSubscription { + onEvent := func( + walletID [32]byte, + blockNumber uint64, + ) { + handler(&tbtc.WalletClosedEvent{ + WalletID: walletID, + BlockNumber: blockNumber, + }) + } + return tc.walletRegistry.WalletClosedEvent(nil, nil).OnEvent(onEvent) +} + +func (tc *TbtcChain) ComputeMainUtxoHash( + mainUtxo *bitcoin.UnspentTransactionOutput, +) [32]byte { + return computeMainUtxoHash(mainUtxo) +} + +func computeMainUtxoHash(mainUtxo *bitcoin.UnspentTransactionOutput) [32]byte { + outputIndexBytes := make([]byte, 4) + binary.BigEndian.PutUint32(outputIndexBytes, mainUtxo.Outpoint.OutputIndex) + + valueBytes := make([]byte, 8) + // #nosec G115 -- Hash the exact 64-bit Bitcoin amount encoding. This + // value is set by ComputeMainUtxoHash's real callers - the wallet main + // UTXO lookup in pkg/tbtc/wallet.go and isInputCurrentWalletsMainUTXO in + // pkg/maintainer/spv/spv.go - directly from a parsed Bitcoin transaction + // output; neither caller currently guards against a negative Value + // before invoking this function. + binary.BigEndian.PutUint64(valueBytes, uint64(mainUtxo.Value)) + + mainUtxoHash := crypto.Keccak256Hash( + append( + append( + mainUtxo.Outpoint.TransactionHash[:], + outputIndexBytes..., + ), valueBytes..., + ), + ) + + return mainUtxoHash +} + +func (tc *TbtcChain) GetWalletParameters() (tbtc.WalletParameters, error) { + parameters, err := tc.bridge.WalletParameters() + if err != nil { + return tbtc.WalletParameters{}, err + } + + return tbtc.WalletParameters{ + CreationPeriod: parameters.WalletCreationPeriod, + CreationMinBtcBalance: parameters.WalletCreationMinBtcBalance, + CreationMaxBtcBalance: parameters.WalletCreationMaxBtcBalance, + ClosureMinBtcBalance: parameters.WalletClosureMinBtcBalance, + MaxAge: parameters.WalletMaxAge, + MaxBtcTransfer: parameters.WalletMaxBtcTransfer, + ClosingPeriod: parameters.WalletClosingPeriod, + }, nil +} + +func (tc *TbtcChain) GetLiveWalletsCount() (uint32, error) { + return tc.bridge.LiveWalletsCount() +} + +func parseWalletState(value uint8) (tbtc.WalletState, error) { + switch value { + case 0: + return tbtc.StateUnknown, nil + case 1: + return tbtc.StateLive, nil + case 2: + return tbtc.StateMovingFunds, nil + case 3: + return tbtc.StateClosing, nil + case 4: + return tbtc.StateClosed, nil + case 5: + return tbtc.StateTerminated, nil + default: + return 0, fmt.Errorf("unexpected wallet state value: [%v]", value) + } +} + +func (tc *TbtcChain) ValidateHeartbeatProposal( + walletPublicKeyHash [20]byte, + proposal *tbtc.HeartbeatProposal, +) error { + valid, err := tc.walletProposalValidator.ValidateHeartbeatProposal( + tbtcabi.WalletProposalValidatorHeartbeatProposal{ + WalletPubKeyHash: walletPublicKeyHash, + Message: proposal.Message[:], + }, + ) + if err != nil { + return fmt.Errorf("validation failed: [%v]", err) + } + + // Should never happen because `validateHeartbeatProposal` returns true + // or reverts (returns an error) but do the check just in case. + if !valid { + return fmt.Errorf("unexpected validation result") + } + + return nil +} diff --git a/pkg/chain/ethereum/tbtc_wallet_test.go b/pkg/chain/ethereum/tbtc_wallet_test.go new file mode 100644 index 0000000000..06f1a9b6e8 --- /dev/null +++ b/pkg/chain/ethereum/tbtc_wallet_test.go @@ -0,0 +1,83 @@ +package ethereum + +import ( + "crypto/ecdsa" + "encoding/hex" + "math/big" + "testing" + + "github.com/keep-network/keep-core/internal/testutils" + "github.com/keep-network/keep-core/pkg/bitcoin" + "github.com/keep-network/keep-core/pkg/chain/local_v1" +) + +func TestCalculateWalletID(t *testing.T) { + hexToByte32 := func(hexStr string) [32]byte { + if len(hexStr) != 64 { + t.Fatal("hex string length incorrect") + } + + decoded, err := hex.DecodeString(hexStr) + if err != nil { + t.Fatal(err) + } + + var result [32]byte + copy(result[:], decoded) + + return result + } + + xBytes := hexToByte32( + "9a0544440cc47779235ccb76d669590c2cd20c7e431f97e17a1093faf03291c4", + ) + + yBytes := hexToByte32( + "73e661a208a8a565ca1e384059bd2ff7ff6886df081ff1229250099d388c83df", + ) + + walletPublicKey := &ecdsa.PublicKey{ + Curve: local_v1.DefaultCurve, + X: new(big.Int).SetBytes(xBytes[:]), + Y: new(big.Int).SetBytes(yBytes[:]), + } + + actualWalletID, err := calculateWalletID(walletPublicKey) + if err != nil { + t.Fatal(err) + } + + expectedWalletID := hexToByte32( + "a6602e554b8cf7c23538fd040e4ff3520ec680e5e5ce9a075259e613a3e5aa79", + ) + + testutils.AssertBytesEqual(t, expectedWalletID[:], actualWalletID[:]) +} + +func TestComputeMainUtxoHash(t *testing.T) { + transactionHash, err := bitcoin.NewHashFromString( + "089bd0671a4481c3584919b4b9b6751cb3f8586dab41cb157adec43fd10ccc00", + bitcoin.InternalByteOrder, + ) + if err != nil { + t.Fatal(err) + } + + mainUtxo := &bitcoin.UnspentTransactionOutput{ + Outpoint: &bitcoin.TransactionOutpoint{ + TransactionHash: transactionHash, + OutputIndex: 5, + }, + Value: 143565433, + } + + mainUtxoHash := computeMainUtxoHash(mainUtxo) + + expectedMainUtxoHash, err := hex.DecodeString( + "1216f8e993c4c57d3c4c971c0d2651140fc4ab09d41960d9ccd7b41fdcd270d6", + ) + if err != nil { + t.Fatal(err) + } + testutils.AssertBytesEqual(t, expectedMainUtxoHash, mainUtxoHash[:]) +} diff --git a/pkg/chain/ethereum/threshold/gen/cmd/TokenStaking.go b/pkg/chain/ethereum/threshold/gen/cmd/TokenStaking.go index 43f3eda9e0..2bd65f876c 100644 --- a/pkg/chain/ethereum/threshold/gen/cmd/TokenStaking.go +++ b/pkg/chain/ethereum/threshold/gen/cmd/TokenStaking.go @@ -13,10 +13,10 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" - chainutil "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/cmd" - "github.com/keep-network/keep-common/pkg/utils/decode" "github.com/keep-network/keep-core/pkg/chain/ethereum/threshold/gen/contract" + chainutil "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + "github.com/keep-network/keep-core/pkg/cmd" + "github.com/keep-network/keep-core/pkg/decode" "github.com/spf13/cobra" ) diff --git a/pkg/chain/ethereum/threshold/gen/contract/TokenStaking.go b/pkg/chain/ethereum/threshold/gen/contract/TokenStaking.go index 633094047c..32c82e0120 100644 --- a/pkg/chain/ethereum/threshold/gen/contract/TokenStaking.go +++ b/pkg/chain/ethereum/threshold/gen/contract/TokenStaking.go @@ -20,10 +20,10 @@ import ( "github.com/ipfs/go-log" - "github.com/keep-network/keep-common/pkg/chain/ethereum" - chainutil "github.com/keep-network/keep-common/pkg/chain/ethereum/ethutil" - "github.com/keep-network/keep-common/pkg/subscription" "github.com/keep-network/keep-core/pkg/chain/ethereum/threshold/gen/abi" + ethereum "github.com/keep-network/keep-core/pkg/chain/ethereumutil" + chainutil "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + "github.com/keep-network/keep-core/pkg/subscription" ) // Create a package-level logger for this contract. The logger exists at diff --git a/pkg/chain/ethereumutil/balance_monitor.go b/pkg/chain/ethereumutil/balance_monitor.go new file mode 100644 index 0000000000..c7e64810d6 --- /dev/null +++ b/pkg/chain/ethereumutil/balance_monitor.go @@ -0,0 +1,86 @@ +package ethereum + +import ( + "context" + "fmt" + "time" + + "github.com/keep-network/keep-core/pkg/wrappers" +) + +// BalanceSource provides a balance info for the given address. +type BalanceSource func(address Address) (*Token, error) + +// BalanceMonitor provides the possibility to monitor balances for given +// accounts. +type BalanceMonitor struct { + balanceSource BalanceSource +} + +// NewBalanceMonitor creates a new instance of the balance monitor. +func NewBalanceMonitor(balanceSource BalanceSource) *BalanceMonitor { + return &BalanceMonitor{balanceSource} +} + +// Observe starts a process which checks the address balance with the given +// tick and triggers an alert in case the balance falls below the +// alert threshold value. +// The balance check will be retried in case of an error up to the retry timeout. +func (bm *BalanceMonitor) Observe( + ctx context.Context, + address Address, + alertThreshold *Token, + tick time.Duration, + retryTimeout time.Duration, +) { + check := func(ctx context.Context) error { + balance, err := bm.balanceSource(address) + if err != nil { + wrappedErr := fmt.Errorf( + "failed to get balance for account [%s]: [%w]", + address.TerminalString(), + err, + ) + + logger.Warning(wrappedErr) + + return wrappedErr + } + + if balance.Cmp(alertThreshold.Int) == -1 { + logger.Errorf( + "balance for account [%v] is below [%v]; "+ + "account should be funded", + address.TerminalString(), + alertThreshold.Text(10), + ) + } + + return nil + } + + go func() { + ticker := time.NewTicker(tick) + defer ticker.Stop() + + checkBalance := func() { + err := wrappers.DoWithDefaultRetry(ctx, retryTimeout, check) + if err != nil { + logger.Errorf("balance monitor error: [%v]", err) + } + } + + // Initial balance check at monitoring start. + checkBalance() + + for { + select { + // Balance check at ticks. + case <-ticker.C: + checkBalance() + case <-ctx.Done(): + return + } + } + }() +} diff --git a/pkg/chain/ethereumutil/balance_monitor_test.go b/pkg/chain/ethereumutil/balance_monitor_test.go new file mode 100644 index 0000000000..7def9c2663 --- /dev/null +++ b/pkg/chain/ethereumutil/balance_monitor_test.go @@ -0,0 +1,59 @@ +package ethereum + +import ( + "context" + "fmt" + "math/big" + "sync" + "time" + + "testing" + + "github.com/ipfs/go-log" +) + +func TestBalanceMonitor_Retries(t *testing.T) { + log.SetDebugLogging() + + attemptsCount := 0 + expectedAttempts := 3 + + wg := &sync.WaitGroup{} + wg.Add(expectedAttempts) + + balanceSource := func(address Address) (*Token, error) { + attemptsCount++ + wg.Done() + + if attemptsCount < expectedAttempts { + return nil, fmt.Errorf("not this time") + } + + return &Token{big.NewInt(10)}, nil + } + + balanceMonitor := NewBalanceMonitor(balanceSource) + + address := Address{1, 2} + alertThreshold := &Token{big.NewInt(15)} + tick := 1 * time.Minute + retryTimeout := 5 * time.Second + + balanceMonitor.Observe( + context.Background(), + address, + alertThreshold, + tick, + retryTimeout, + ) + + wg.Wait() + + if expectedAttempts != attemptsCount { + t.Errorf( + "unexpected retries count\nexpected: %d\nactual: %d", + expectedAttempts, + attemptsCount, + ) + } +} diff --git a/pkg/chain/ethereumutil/block_confirmations.go b/pkg/chain/ethereumutil/block_confirmations.go new file mode 100644 index 0000000000..4f47d82b9b --- /dev/null +++ b/pkg/chain/ethereumutil/block_confirmations.go @@ -0,0 +1,37 @@ +package ethereum + +import ( + "fmt" +) + +// BlockHeightWaiter provides the ability to wait for a given block height. +type BlockHeightWaiter interface { + WaitForBlockHeight(blockNumber uint64) error +} + +// WaitForBlockConfirmations ensures that after receiving specific number of block +// confirmations the state of the chain is actually as expected. It waits for +// predefined number of blocks since the start block number provided. After the +// required block number is reached it performs a check of the chain state with +// a provided function returning a boolean value. +func WaitForBlockConfirmations( + blockHeightWaiter BlockHeightWaiter, + startBlockNumber uint64, + blockConfirmations uint64, + stateCheck func() (bool, error), +) (bool, error) { + blockHeight := startBlockNumber + blockConfirmations + logger.Infof("waiting for block [%d] to confirm chain state", blockHeight) + + err := blockHeightWaiter.WaitForBlockHeight(blockHeight) + if err != nil { + return false, fmt.Errorf("failed to wait for block height: [%v]", err) + } + + result, err := stateCheck() + if err != nil { + return false, fmt.Errorf("failed to get chain state confirmation: [%v]", err) + } + + return result, nil +} diff --git a/pkg/chain/ethereumutil/block_counter.go b/pkg/chain/ethereumutil/block_counter.go new file mode 100644 index 0000000000..c80c575fb2 --- /dev/null +++ b/pkg/chain/ethereumutil/block_counter.go @@ -0,0 +1,239 @@ +package ethereum + +import ( + "context" + "fmt" + "strconv" + "sync" + "time" +) + +// BlockCounter represents a block counter. +type BlockCounter struct { + structMutex sync.Mutex + latestBlockHeight uint64 + subscriptionChannel chan block + waiters map[uint64][]chan uint64 + watchers []*watcher +} + +type block struct { + Number string +} + +type watcher struct { + ctx context.Context + channel chan uint64 +} + +// WaitForBlockHeight waits for a given block height. +func (bc *BlockCounter) WaitForBlockHeight(blockNumber uint64) error { + waiter, err := bc.BlockHeightWaiter(blockNumber) + if err != nil { + return err + } + <-waiter + return nil +} + +// BlockHeightWaiter returns a waiter for the given block. +func (bc *BlockCounter) BlockHeightWaiter( + blockNumber uint64, +) (<-chan uint64, error) { + newWaiter := make(chan uint64) + + bc.structMutex.Lock() + defer bc.structMutex.Unlock() + + if blockNumber <= bc.latestBlockHeight { + go func() { newWaiter <- blockNumber }() + } else { + waiterList, exists := bc.waiters[blockNumber] + if !exists { + waiterList = make([]chan uint64, 0) + } + + bc.waiters[blockNumber] = append(waiterList, newWaiter) + } + + return newWaiter, nil +} + +// CurrentBlock returns the current block. +func (bc *BlockCounter) CurrentBlock() (uint64, error) { + return bc.latestBlockHeight, nil +} + +// WatchBlocks watches the blocks. +func (bc *BlockCounter) WatchBlocks(ctx context.Context) <-chan uint64 { + watcher := &watcher{ + ctx: ctx, + channel: make(chan uint64), + } + + bc.structMutex.Lock() + bc.watchers = append(bc.watchers, watcher) + bc.structMutex.Unlock() + + go func() { + <-ctx.Done() + + bc.structMutex.Lock() + for i, w := range bc.watchers { + if w == watcher { + bc.watchers[i] = bc.watchers[len(bc.watchers)-1] + bc.watchers = bc.watchers[:len(bc.watchers)-1] + break + } + } + bc.structMutex.Unlock() + }() + + return watcher.channel +} + +// receiveBlocks gets each new block back from Geth and extracts the +// block height (topBlockNumber) form it. For each block height that is being +// waited on a message will be sent. +func (bc *BlockCounter) receiveBlocks() { + for block := range bc.subscriptionChannel { + receivedBlockHeight, err := strconv.ParseUint(block.Number, 0, 64) + if err != nil { + logger.Errorf("error receiving a new block: [%v]", err) + continue + } + + // receivedBlockHeight is the current blockchain height as just + // received in the notification. latestBlockHeightSeen is the + // blockchain height as observed in the previous invocation of + // receiveBlocks(). + // + // If we have already received notification about this block, + // we do nothing. All handlers were already called for this block + // height. + if receivedBlockHeight == bc.latestBlockHeight { + continue + } + + // We have already seen latestBlockHeightSeen during the previous + // execution of receiveBlocks() function and all handlers for + // latestBlockHeightSeen were called. Now we start from the next block + // after it and that's latestBlockHeightSeen + 1. + for unseenBlockNumber := bc.latestBlockHeight + 1; unseenBlockNumber <= receivedBlockHeight; unseenBlockNumber++ { + bc.structMutex.Lock() + height := unseenBlockNumber + bc.latestBlockHeight++ + waiters := bc.waiters[height] + delete(bc.waiters, height) + bc.structMutex.Unlock() + + for _, waiter := range waiters { + go func(w chan uint64) { w <- height }(waiter) + } + + bc.structMutex.Lock() + watchers := make([]*watcher, len(bc.watchers)) + copy(watchers, bc.watchers) + bc.structMutex.Unlock() + + for _, watcher := range watchers { + if watcher.ctx.Err() != nil { + close(watcher.channel) + continue + } + + select { + case watcher.channel <- height: // perfect + default: // we don't care, let's drop it + } + } + } + } +} + +// subscribeBlocks creates a subscription to Geth to get each block. +func (bc *BlockCounter) subscribeBlocks( + ctx context.Context, + chainReader ChainReader, +) error { + errorChan := make(chan error) + newHeadChan := make(chan *Header) + + subscribe := func() { + logger.Debugf("subscribing to new blocks") + + subscribeContext, cancel := context.WithTimeout( + ctx, + 10*time.Second, // timeout for subscription request + ) + defer cancel() + + subscription, err := chainReader.SubscribeNewHead( + subscribeContext, + newHeadChan, + ) + if err != nil { + logger.Warningf("could not create subscription to new blocks: [%v]", err) + errorChan <- err + return + } + + for { + select { + case header := <-newHeadChan: + bc.subscriptionChannel <- block{header.Number.String()} + case err = <-subscription.Err(): + logger.Warningf("subscription to new blocks interrupted: [%v]", err) + subscription.Unsubscribe() + errorChan <- err + return + } + } + + } + + go func() { + for { + go subscribe() + <-errorChan + time.Sleep(5 * time.Second) + } + }() + + lastHeader, err := chainReader.HeaderByNumber(ctx, nil) + if err != nil { + return err + } + + bc.subscriptionChannel <- block{lastHeader.Number.String()} + + return nil +} + +// CreateBlockCounter creates a block counter. +func CreateBlockCounter(chainReader ChainReader) (*BlockCounter, error) { + ctx := context.Background() + + startupHeader, err := chainReader.HeaderByNumber(ctx, nil) + if err != nil { + return nil, + fmt.Errorf( + "failed to get initial block header from the chain: [%v]", + err, + ) + } + + blockCounter := &BlockCounter{ + latestBlockHeight: startupHeader.Number.Uint64(), + waiters: make(map[uint64][]chan uint64), + subscriptionChannel: make(chan block), + } + + go blockCounter.receiveBlocks() + err = blockCounter.subscribeBlocks(ctx, chainReader) + if err != nil { + return nil, fmt.Errorf("failed to subscribe to new blocks: [%v]", err) + } + + return blockCounter, nil +} diff --git a/pkg/chain/ethereumutil/block_counter_test.go b/pkg/chain/ethereumutil/block_counter_test.go new file mode 100644 index 0000000000..65aee653fb --- /dev/null +++ b/pkg/chain/ethereumutil/block_counter_test.go @@ -0,0 +1,186 @@ +package ethereum + +import ( + "context" + "sync/atomic" + "testing" + "time" +) + +func TestWaitForNewMinedBlock(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) + defer cancel() + + blockCounter := &BlockCounter{ + latestBlockHeight: uint64(1), + waiters: make(map[uint64][]chan uint64), + subscriptionChannel: make(chan block), + } + + block2Waiter, err := blockCounter.BlockHeightWaiter(2) + if err != nil { + t.Fatal(err) + } + + go func() { + blockCounter.subscriptionChannel <- block{Number: "1"} + blockCounter.subscriptionChannel <- block{Number: "2"} + }() + + go blockCounter.receiveBlocks() + + select { + case block := <-block2Waiter: + if block != 2 { + t.Fatalf( + "unexpected block number\nexpected: [2]\nactual: [%v]\n", + block, + ) + } + + case <-ctx.Done(): + t.Fatal(ctx.Err()) + } +} + +func TestExecuteBlockHandlerOnlyOnce(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + + blockCounter := &BlockCounter{ + latestBlockHeight: uint64(1), + waiters: make(map[uint64][]chan uint64), + subscriptionChannel: make(chan block), + } + + block2Waiter, err := blockCounter.BlockHeightWaiter(2) + if err != nil { + t.Fatal(err) + } + + block3Waiter, err := blockCounter.BlockHeightWaiter(3) + if err != nil { + t.Fatal(err) + } + + go func() { + blockCounter.subscriptionChannel <- block{Number: "1"} + blockCounter.subscriptionChannel <- block{Number: "2"} + blockCounter.subscriptionChannel <- block{Number: "2"} + blockCounter.subscriptionChannel <- block{Number: "3"} + blockCounter.subscriptionChannel <- block{Number: "4"} + }() + + go blockCounter.receiveBlocks() + + var waiter2CallCounter uint64 + var waiter3CallCounter uint64 + + for { + select { + case <-block2Waiter: + atomic.AddUint64(&waiter2CallCounter, 1) + + case <-block3Waiter: + atomic.AddUint64(&waiter3CallCounter, 1) + + case <-ctx.Done(): + if waiter2CallCounter != 1 { + t.Errorf( + "handler for block 2 should be called only once; was [%v]", + waiter2CallCounter, + ) + } + if waiter3CallCounter != 1 { + t.Errorf( + "handler for block 3 should be called only once; was [%v]", + waiter3CallCounter, + ) + } + + return + } + } +} + +func TestWatchBlocks(t *testing.T) { + blockCounter := &BlockCounter{ + latestBlockHeight: uint64(1), + waiters: make(map[uint64][]chan uint64), + subscriptionChannel: make(chan block), + } + go blockCounter.receiveBlocks() + + ctx1, cancel1 := context.WithCancel(context.Background()) + defer cancel1() + + ctx2, cancel2 := context.WithCancel(context.Background()) + defer cancel2() + + watcher1 := blockCounter.WatchBlocks(ctx1) + watcher2 := blockCounter.WatchBlocks(ctx2) + + watcher1ReceivedCount := 0 + watcher2ReceivedCount := 0 + go func() { + for range watcher1 { + watcher1ReceivedCount++ + } + }() + go func() { + for range watcher2 { + watcher2ReceivedCount++ + } + }() + // give some time for watcher goroutine to initialize + time.Sleep(50 * time.Millisecond) + + blockCounter.subscriptionChannel <- block{Number: "2"} + time.Sleep(50 * time.Millisecond) + cancel1() + blockCounter.subscriptionChannel <- block{Number: "3"} + time.Sleep(50 * time.Millisecond) + cancel2() + blockCounter.subscriptionChannel <- block{Number: "4"} + time.Sleep(50 * time.Millisecond) + + if watcher1ReceivedCount != 1 { + t.Errorf("watcher 1 should receive [1] block, has [%v]", watcher1ReceivedCount) + } + if watcher2ReceivedCount != 2 { + t.Errorf("watcher 2 should receive [2] block, has [%v]", watcher2ReceivedCount) + } +} + +func TestWatchBlocksIsNonBlocking(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + blockCounter := &BlockCounter{ + latestBlockHeight: uint64(1), + waiters: make(map[uint64][]chan uint64), + subscriptionChannel: make(chan block), + } + go blockCounter.receiveBlocks() + + _ = blockCounter.WatchBlocks(ctx) // does not read blocks + watcher := blockCounter.WatchBlocks(ctx) // does read blocks + + var receivedCount uint64 + go func() { + for range watcher { + receivedCount++ + } + }() + // give some time for watcher goroutine to initialize + time.Sleep(50 * time.Millisecond) + + blockCounter.subscriptionChannel <- block{Number: "2"} + time.Sleep(10 * time.Millisecond) + blockCounter.subscriptionChannel <- block{Number: "3"} + time.Sleep(10 * time.Millisecond) + + if receivedCount != 2 { + t.Fatalf("watcher should receive [2] blocks, has [%v]", receivedCount) + } +} diff --git a/pkg/chain/ethereumutil/chain.go b/pkg/chain/ethereumutil/chain.go new file mode 100644 index 0000000000..4688d6aa7f --- /dev/null +++ b/pkg/chain/ethereumutil/chain.go @@ -0,0 +1,66 @@ +package ethereum + +import ( + "context" + "fmt" + "math/big" +) + +// Address represents the 20 byte address of an Ethereum account. +type Address [20]byte + +// TerminalString returns the address as a console string. +func (a Address) TerminalString() string { + return fmt.Sprintf("%x…%x", a[:3], a[17:]) +} + +// Header represents a block header in the Ethereum blockchain. +type Header struct { + Number *big.Int +} + +// Block represents an entire block in the Ethereum blockchain. +type Block struct { + *Header +} + +// Subscription represents an event subscription where events are delivered +// on a data channel. +type Subscription interface { + // Unsubscribe cancels the sending of events to the data channel and closes + // the error channel. + Unsubscribe() + + // Err returns the subscription error channel. The error channel receives + // a value if there is an issue with the subscription. Only one value will + // ever be sent. The error channel is closed by Unsubscribe. + Err() <-chan error +} + +// ChainReader provides access to the blockchain. +type ChainReader interface { + // HeaderByNumber gets the block header by its number. The block header + // number argument can be nil to select the latest block header. + HeaderByNumber(ctx context.Context, number *big.Int) (*Header, error) + + // SubscribeNewHead subscribes to notifications about changes of the + // head block of the canonical chain. + SubscribeNewHead( + ctx context.Context, + ch chan<- *Header, + ) (Subscription, error) +} + +// ContractTransactor defines the methods needed to allow operating with +// contract on a write only basis. +type ContractTransactor interface { + // PendingNonceAt retrieves the current pending nonce associated + // with an account. + PendingNonceAt(ctx context.Context, account Address) (uint64, error) +} + +// Chain represents an Ethereum chain handle. +type Chain interface { + ChainReader + ContractTransactor +} diff --git a/pkg/chain/ethereumutil/config.go b/pkg/chain/ethereumutil/config.go new file mode 100644 index 0000000000..e5e489750c --- /dev/null +++ b/pkg/chain/ethereumutil/config.go @@ -0,0 +1,103 @@ +package ethereum + +import ( + "errors" + "fmt" + "strings" + "time" + + "github.com/ethereum/go-ethereum/common" +) + +// Config is a struct that contains the configuration needed to connect to an +// Ethereum node. This information will give access to an Ethereum network. +type Config struct { + Network + + Account `mapstructure:",squash"` + + // Example: "ws://192.168.0.157:8546". + URL string + + // Example: "http://192.168.0.157:8545". + URLRPC string + + // A map from contract names to contract addresses. The keys in the map are + // expected to be lowercase contract names. + ContractAddresses map[string]string + + // MiningCheckInterval is the interval in which transaction + // mining status is checked. If the transaction is not mined within this + // time, the gas price is increased and transaction is resubmitted. + MiningCheckInterval time.Duration + + // RequestsPerSecondLimit sets the maximum average number of requests + // per second which can be executed against the Ethereum node. + // All types of chain requests are rate-limited, + // including view function calls. + RequestsPerSecondLimit int + + // ConcurrencyLimit sets the maximum number of concurrent requests which + // can be executed against the Ethereum node at the same time. + // This limit affects all types of chain requests, + // including view function calls. + ConcurrencyLimit int + + // MaxGasFeeCap specifies the maximum gas fee cap the client is + // willing to pay for the transaction to be mined. The offered transaction + // gas cost can not be higher than the max gas fee cap value. If the maximum + // allowed gas fee cap is reached, no further resubmission attempts are + // performed. This value is used for all types of Ethereum transactions. + // For legacy transactions, this value works as a maximum gas price + // and for EIP-1559 transactions, this value works as max gas fee cap. + MaxGasFeeCap Wei + + // BalanceAlertThreshold defines a minimum value of the operator's + // account balance below which an alert will be triggered. + BalanceAlertThreshold Wei +} + +// Account is a struct that contains the configuration for accessing an +// Ethereum network and a contract on the network. +type Account struct { + // Keyfile is a full path to a key file. Normally this file is one of the + // imported keys in your local chain node. It can normally be found in + // a directory /data/keystore/ and starts with its creation date + // "UTC--.*". + KeyFile string + + // KeyFilePassword is the password used to unlock the account specified in + // KeyFile. + KeyFilePassword string +} + +// ErrAddressNotConfigured is an error that is returned when an address for the given +// contract name was not found in the Config. +var ErrAddressNotConfigured = errors.New("address not configured") + +// ContractAddress finds a given contract's address configuration and returns it +// as Ethereum address. +func (c *Config) ContractAddress(contractName string) (common.Address, error) { + addressString, exists := c.ContractAddresses[strings.ToLower(contractName)] + if !exists || addressString == "" { + return common.Address{}, ErrAddressNotConfigured + } + + if !common.IsHexAddress(addressString) { + return common.Address{}, fmt.Errorf( + "configured address [%v] for contract [%v] "+ + "is not valid hex address", + addressString, + contractName, + ) + } + + address := common.HexToAddress(addressString) + return address, nil +} + +// SetContractAddress sets address for a contract in the contracts addresses +// mapping. +func (c *Config) SetContractAddress(contractName string, address string) { + c.ContractAddresses[strings.ToLower(contractName)] = address +} diff --git a/pkg/chain/ethereumutil/config_test.go b/pkg/chain/ethereumutil/config_test.go new file mode 100644 index 0000000000..48843ae2c1 --- /dev/null +++ b/pkg/chain/ethereumutil/config_test.go @@ -0,0 +1,73 @@ +package ethereum + +import ( + "fmt" + "reflect" + "strings" + "testing" + + "github.com/ethereum/go-ethereum/common" +) + +func TestContractAddress(t *testing.T) { + contractName1 := "KeepECDSAContract" + validContractAddressString := "0xbb2Ea17985f13D43e3AEC3963506A1B25ADDd57F" + validContractAddress := common.HexToAddress(validContractAddressString) + + contractName2 := "InvalidContract" + invalidHex := "0xZZZ" + + config := &Config{ + ContractAddresses: map[string]string{ + strings.ToLower(contractName1): validContractAddressString, + strings.ToLower(contractName2): invalidHex, + }, + } + + var tests = map[string]struct { + contractName string + expectedAddress common.Address + expectedError error + }{ + "contract name matching valid configuration": { + contractName: contractName1, + expectedAddress: validContractAddress, + }, + "invalid contract hex address": { + contractName: contractName2, + expectedAddress: common.Address{}, + expectedError: fmt.Errorf( + "configured address [%v] for contract [%v] "+ + "is not valid hex address", + invalidHex, + contractName2, + ), + }, + "missing contract configuration": { + contractName: "Peekaboo", + expectedAddress: common.Address{}, + expectedError: ErrAddressNotConfigured, + }, + } + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + + actualAddress, err := config.ContractAddress(test.contractName) + if !reflect.DeepEqual(test.expectedError, err) { + t.Errorf( + "unexpected error\nexpected: %v\nactual: %v\n", + test.expectedError, + err, + ) + } + + if !reflect.DeepEqual(test.expectedAddress, actualAddress) { + t.Errorf( + "unexpected address\nexpected: %v\nactual: %v\n", + test.expectedAddress, + actualAddress, + ) + } + }) + } +} diff --git a/pkg/chain/ethereumutil/ethutil/adapter.go b/pkg/chain/ethereumutil/ethutil/adapter.go new file mode 100644 index 0000000000..72021cbf5f --- /dev/null +++ b/pkg/chain/ethereumutil/ethutil/adapter.go @@ -0,0 +1,84 @@ +package ethutil + +import ( + "context" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + + chainEthereum "github.com/keep-network/keep-core/pkg/chain/ethereumutil" +) + +type ethereumAdapter struct { + delegate EthereumClient +} + +func (ea *ethereumAdapter) HeaderByNumber( + ctx context.Context, + number *big.Int, +) (*chainEthereum.Header, error) { + header, err := ea.delegate.HeaderByNumber(ctx, number) + if err != nil { + return nil, err + } + + return &chainEthereum.Header{ + Number: header.Number, + }, nil +} + +func (ea *ethereumAdapter) SubscribeNewHead( + ctx context.Context, + headersChan chan<- *chainEthereum.Header, +) (chainEthereum.Subscription, error) { + internalHeadersChan := make(chan *types.Header) + + subscription, err := ea.delegate.SubscribeNewHead(ctx, internalHeadersChan) + if err != nil { + return nil, err + } + + stop := make(chan struct{}) + + go func() { + for { + select { + case header := <-internalHeadersChan: + headersChan <- &chainEthereum.Header{ + Number: header.Number, + } + case <-stop: + return + } + } + }() + + return &subscriptionWrapper{ + unsubscribeFn: func() { + close(stop) + subscription.Unsubscribe() + }, + errChan: subscription.Err(), + }, nil +} + +type subscriptionWrapper struct { + unsubscribeFn func() + errChan <-chan error +} + +func (sw *subscriptionWrapper) Unsubscribe() { + sw.unsubscribeFn() +} + +func (sw *subscriptionWrapper) Err() <-chan error { + return sw.errChan +} + +func (ea *ethereumAdapter) PendingNonceAt( + ctx context.Context, + account chainEthereum.Address, +) (uint64, error) { + return ea.delegate.PendingNonceAt(ctx, common.Address(account)) +} diff --git a/pkg/chain/ethereumutil/ethutil/adapter_test.go b/pkg/chain/ethereumutil/ethutil/adapter_test.go new file mode 100644 index 0000000000..e74934f51b --- /dev/null +++ b/pkg/chain/ethereumutil/ethutil/adapter_test.go @@ -0,0 +1,210 @@ +package ethutil + +import ( + "context" + "fmt" + "math/big" + "reflect" + "testing" + "time" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + + chainEthereum "github.com/keep-network/keep-core/pkg/chain/ethereumutil" +) + +func TestEthereumAdapter_HeaderByNumber(t *testing.T) { + client := &mockAdaptedEthereumClient{ + blocks: []*big.Int{ + big.NewInt(0), + big.NewInt(1), + big.NewInt(2), + }, + blocksBaseFee: []*big.Int{ + big.NewInt(10), + big.NewInt(11), + big.NewInt(12), + }, + } + + adapter := ðereumAdapter{client} + + headerOne, err := adapter.HeaderByNumber(context.Background(), big.NewInt(1)) + if err != nil { + t.Fatal(err) + } + + lastHeader, err := adapter.HeaderByNumber(context.Background(), nil) + if err != nil { + t.Fatal(err) + } + + expectedHeaderOneNumber := big.NewInt(1) + if expectedHeaderOneNumber.Cmp(headerOne.Number) != 0 { + t.Errorf( + "unexpected header number\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + expectedHeaderOneNumber, + headerOne.Number, + ) + } + + expectedLastHeaderNumber := big.NewInt(2) + if expectedLastHeaderNumber.Cmp(lastHeader.Number) != 0 { + t.Errorf( + "unexpected last header number\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + expectedLastHeaderNumber, + lastHeader.Number, + ) + } +} + +func TestEthereumAdapter_SubscribeNewHead(t *testing.T) { + ctx, cancelCtx := context.WithTimeout( + context.Background(), + 10*time.Millisecond, + ) + defer cancelCtx() + + client := &mockAdaptedEthereumClient{ + blocks: []*big.Int{ + big.NewInt(0), + big.NewInt(1), + big.NewInt(2), + }, + } + + adapter := ðereumAdapter{client} + + // no more than 3 elements should be put into this + // channel by SubscribeNewHead + headerChan := make(chan *chainEthereum.Header, 100) + _, err := adapter.SubscribeNewHead(ctx, headerChan) + if err != nil { + t.Fatal(err) + } + + <-ctx.Done() + + expectedHeaderChanLen := 3 + headerChanLen := len(headerChan) + if expectedHeaderChanLen != headerChanLen { + t.Errorf( + "unexpected number of blocks\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + expectedHeaderChanLen, + headerChanLen, + ) + } + + blocks := make([]*big.Int, 0) + for header := range headerChan { + blocks = append(blocks, header.Number) + + // headerChan is not closed so we have to break manually + if len(blocks) == 3 { + break + } + } + + expectedBlocks := []*big.Int{ + big.NewInt(0), + big.NewInt(1), + big.NewInt(2), + } + if !reflect.DeepEqual(expectedBlocks, blocks) { + t.Errorf( + "unexpected blocks\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + expectedBlocks, + blocks, + ) + } +} + +func TestEthereumAdapter_PendingNonceAt(t *testing.T) { + var address [20]byte + copy(address[:], []byte{255}) + + client := &mockAdaptedEthereumClient{ + nonces: map[common.Address]uint64{ + common.BytesToAddress(address[:]): 100, + }, + } + + adapter := ðereumAdapter{client} + + nonce, err := adapter.PendingNonceAt(context.Background(), address) + if err != nil { + t.Fatal(err) + } + + expectedNonce := uint64(100) + if expectedNonce != nonce { + t.Errorf( + "unexpected nonce\n"+ + "expected: [%+v]\n"+ + "actual: [%+v]", + expectedNonce, + nonce, + ) + } +} + +type mockAdaptedEthereumClient struct { + *mockEthereumClient + + blocks []*big.Int + blocksBaseFee []*big.Int + nonces map[common.Address]uint64 +} + +func (maec *mockAdaptedEthereumClient) HeaderByNumber( + ctx context.Context, + number *big.Int, +) (*types.Header, error) { + index := len(maec.blocks) - 1 + + if number != nil { + index = int(number.Int64()) + } + + return &types.Header{ + Number: maec.blocks[index], + BaseFee: maec.blocksBaseFee[index], + }, nil +} + +func (maec *mockAdaptedEthereumClient) SubscribeNewHead( + ctx context.Context, + ch chan<- *types.Header, +) (ethereum.Subscription, error) { + go func() { + for _, block := range maec.blocks { + ch <- &types.Header{Number: block} + } + }() + + return &subscriptionWrapper{ + unsubscribeFn: func() {}, + errChan: make(chan error), + }, nil +} + +func (maec *mockAdaptedEthereumClient) PendingNonceAt( + ctx context.Context, + account common.Address, +) (uint64, error) { + if nonce, ok := maec.nonces[account]; ok { + return nonce, nil + } + + return 0, fmt.Errorf("no nonce for given account") +} diff --git a/pkg/chain/ethereumutil/ethutil/balance_monitor.go b/pkg/chain/ethereumutil/ethutil/balance_monitor.go new file mode 100644 index 0000000000..635fd936bf --- /dev/null +++ b/pkg/chain/ethereumutil/ethutil/balance_monitor.go @@ -0,0 +1,56 @@ +package ethutil + +import ( + "context" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil" +) + +// BalanceSource provides a balance info for the given address. +type BalanceSource func(address common.Address) (*ethereum.Wei, error) + +// BalanceMonitor provides the possibility to monitor balances for given +// accounts. +type BalanceMonitor struct { + delegate *ethereum.BalanceMonitor +} + +// NewBalanceMonitor creates a new instance of the balance monitor. +func NewBalanceMonitor(balanceSource BalanceSource) *BalanceMonitor { + balanceSourceAdapter := func( + address ethereum.Address, + ) (*ethereum.Token, error) { + balance, err := balanceSource(common.Address(address)) + if err != nil { + return nil, err + } + + return &balance.Token, err + } + + return &BalanceMonitor{ + ethereum.NewBalanceMonitor(balanceSourceAdapter), + } +} + +// Observe starts a process which checks the address balance with the given +// tick and triggers an alert in case the balance falls below the +// alert threshold value. +// The balance check will be retried in case of an error up to the retry timeout. +func (bm *BalanceMonitor) Observe( + ctx context.Context, + address common.Address, + alertThreshold *ethereum.Wei, + tick time.Duration, + retryTimeout time.Duration, +) { + bm.delegate.Observe( + ctx, + ethereum.Address(address), + &alertThreshold.Token, + tick, + retryTimeout, + ) +} diff --git a/pkg/chain/ethereumutil/ethutil/error_resolver.go b/pkg/chain/ethereumutil/ethutil/error_resolver.go new file mode 100644 index 0000000000..d75ea1e360 --- /dev/null +++ b/pkg/chain/ethereumutil/ethutil/error_resolver.go @@ -0,0 +1,122 @@ +package ethutil + +import ( + "context" + "fmt" + "math/big" + "strings" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" +) + +// ABI for errors bubbled out from revert calls. Not used directly as errors are +// neither encoded strictly as method calls nor strictly as return values, nor +// strictly as events, but some various bits of it are used for unpacking the +// errors. See ResolveError below. +const errorABIString = "[{\"constant\":true,\"outputs\":[{\"type\":\"string\"}],\"inputs\":[{\"name\":\"message\", \"type\":\"string\"}],\"name\":\"Error\", \"type\": \"function\"}]" + +var errorABI abi.ABI + +func init() { + var err error + errorABI, err = abi.JSON(strings.NewReader(errorABIString)) + if err != nil { + panic(fmt.Sprintf("Failed to parse error ABI string: [%v] (ABI was: [%v])", err, errorABIString)) + } +} + +// ErrorResolver bundles up the bits needed to turn errors like "failed to +// estimate gas needed" that are triggered by contract reverts but don't include +// revert causes into proper revert error messages from a contract by calling +// the contract method without trying to commit it. +// +// It has one method, ResolveError, that does the heavy lifting. +type ErrorResolver struct { + contractCaller ethereum.ContractCaller + abi *abi.ABI + address *common.Address +} + +// NewErrorResolver returns an ErroResolver for the given Ethereum client, +// contract ABI, and contract address combination. +func NewErrorResolver( + contractCaller ethereum.ContractCaller, + abi *abi.ABI, + address *common.Address, +) *ErrorResolver { + return &ErrorResolver{contractCaller, abi, address} +} + +// ResolveError resolves the given transaction error to a standard error that, +// if available, contains the error message the transaction produced when +// reverting. +// +// ResolveError achieves this by re-calling the transaction (not submitting it +// for block inclusion, just calling it for its results). `value` is the value +// in gwei to send along with the simulated call. +func (er *ErrorResolver) ResolveError( + originalErr error, + from common.Address, + value *big.Int, + methodName string, + parameters ...interface{}, +) error { + logger.Debugf( + "packing parameters for method [%s] with ABI [%v]: [%+v]", + methodName, + er.abi.Methods[methodName], + parameters, + ) + + packed, err := er.abi.Pack(methodName, parameters...) + msg := ethereum.CallMsg{ + From: from, + To: er.address, + Data: packed, + Value: value, + } + + logger.Debugf( + "resolving error for contract call [%+v]", + msg, + ) + + response, err := er.contractCaller.CallContract(context.TODO(), msg, nil) + if err != nil { + return fmt.Errorf("got error [%v] while resolving original error [%v]", err, originalErr) + } + + // An error is returned as a 4-byte error id (same encoding as a method id) + // followed by a set of ABI-encoded values as if the error were a method + // that returned those values. + // + // Current spec-ish @ https://github.com/ethereum/EIPs/issues/838#issuecomment-458919375 + // Bless Ethereum's heart. + if len(response) < 4 { + return fmt.Errorf( + "response [%v] was not long enough to interpret while resolving original error [%v]", + response, + originalErr, + ) + } + + errorID, encodedReturns := response[0:4], response[4:] + + errorMethod, err := errorABI.MethodById(errorID) + if err != nil { + return fmt.Errorf("got [%v] while resolving original error [%v] on return [%v]", err, originalErr, response) + } + + errorValues, err := errorMethod.Outputs.UnpackValues(encodedReturns) + if err != nil { + return fmt.Errorf("got [%v] while resolving original error [%v] on return [%v]", err, originalErr, response) + } + + return fmt.Errorf( + "contract failed with: [%v] (original error [%v])", + errorValues, + originalErr, + ) +} diff --git a/pkg/chain/ethereumutil/ethutil/error_resolver_test.go b/pkg/chain/ethereumutil/ethutil/error_resolver_test.go new file mode 100644 index 0000000000..3dad7c42b3 --- /dev/null +++ b/pkg/chain/ethereumutil/ethutil/error_resolver_test.go @@ -0,0 +1,329 @@ +package ethutil_test + +import ( + "context" + "fmt" + "math/big" + "reflect" + "strings" + "testing" + + "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" +) + +var testABIMethods = map[string]abi.Method{ + "Test": abi.Method{ + Constant: false, + Name: "Test", + Inputs: []abi.Argument{}, + Outputs: []abi.Argument{}, + }, +} +var testABI = abi.ABI{ + Constructor: testABIMethods["Test"], + Events: map[string]abi.Event{}, + Methods: testABIMethods, +} +var testAddress = common.Address([20]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) + +var errOriginal = fmt.Errorf("OG") +var errCall = fmt.Errorf("call error") + +func assertErrorContains(t *testing.T, err error, substrings ...string) { + t.Helper() + + if err == nil { + t.Errorf("\nexpected: {error}\nactual: nil") + return + } + + for _, substring := range substrings { + if !strings.Contains(err.Error(), substring) { + t.Errorf( + "\nexpected: {error containing [%#v]}\nactual: %v", + substring, + err, + ) + } + } +} + +// Helper caller type that always returns errCall. +type erroringCaller struct{} + +func (*erroringCaller) CallContract(_ context.Context, _ ethereum.CallMsg, _ *big.Int) ([]byte, error) { + return nil, errCall +} + +// Helper caller type that always returns a nil error and the provided +// returnedBytes. +type fixedReturnCaller struct { + returnedBytes []byte +} + +func (frc *fixedReturnCaller) CallContract(_ context.Context, _ ethereum.CallMsg, _ *big.Int) ([]byte, error) { + return frc.returnedBytes, nil +} + +// Helper caller type that calls a referenced callback function for each +// CallContract call. +type callbackCaller struct { + callbackCalled bool + callback contractCallFn +} + +type contractCallFn func(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) + +func callbackCallerWith(fn contractCallFn) *callbackCaller { + return &callbackCaller{false, fn} +} + +func (cc *callbackCaller) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { + cc.callbackCalled = true + return cc.callback(ctx, call, blockNumber) +} + +func TestErrorResolverHandlesErrorCall(t *testing.T) { + caller := &erroringCaller{} + resolver := ethutil.NewErrorResolver(caller, &testABI, &testAddress) + + err := resolver.ResolveError(errOriginal, common.Address{}, nil, "Test") + if err == nil { + t.Errorf("\nexpected: {error}\nactual: nil") + return + } + + assertErrorContains( + t, + err, + errOriginal.Error(), + errCall.Error(), + ) +} + +func TestErrorResolverHandlesShortResponses(t *testing.T) { + caller := &fixedReturnCaller{} + resolver := ethutil.NewErrorResolver(caller, &testABI, &testAddress) + + for returnLength := 0; returnLength < 4; returnLength++ { + caller.returnedBytes = make([]byte, returnLength) + err := resolver.ResolveError(errOriginal, common.Address{}, nil, "Test") + assertErrorContains( + t, + err, + errOriginal.Error(), + fmt.Sprintf("%v", caller.returnedBytes), + "was not long enough", + ) + } +} + +func TestErrorResolverHandlesUnknownMethodResponses(t *testing.T) { + caller := &fixedReturnCaller{[]byte{0, 0, 0, 1}} + resolver := ethutil.NewErrorResolver(caller, &testABI, &testAddress) + + err := resolver.ResolveError(errOriginal, common.Address{}, nil, "Test") + assertErrorContains( + t, + err, + errOriginal.Error(), + fmt.Sprintf("%v", caller.returnedBytes), + "no method with id", + ) +} + +func TestErrorResolverHandlesBadParameterResponses(t *testing.T) { + // method ABI signature for the basic error construction we get back in case + // of a require failing. + caller := &fixedReturnCaller{[]byte{8, 195, 121, 160}} + resolver := ethutil.NewErrorResolver(caller, &testABI, &testAddress) + + // bad response length + err := resolver.ResolveError(errOriginal, common.Address{}, nil, "Test") + assertErrorContains( + t, + err, + errOriginal.Error(), + fmt.Sprintf("%v", caller.returnedBytes), + "length insufficient", + ) + + // good response length, bad data offset in response + buildingBlock := [32]byte{} + caller.returnedBytes = append(caller.returnedBytes, buildingBlock[:]...) + caller.returnedBytes[len(caller.returnedBytes)-1] = 1 + err = resolver.ResolveError(errOriginal, common.Address{}, nil, "Test") + assertErrorContains( + t, + err, + errOriginal.Error(), + fmt.Sprintf("%v", caller.returnedBytes), + "would go over slice boundary", + ) + + // good response length, good data offset, bad string length in response + caller.returnedBytes = []byte{8, 195, 121, 160} + caller.returnedBytes = append(caller.returnedBytes, buildingBlock[:]...) + caller.returnedBytes[len(caller.returnedBytes)-1] = 32 + caller.returnedBytes = append(caller.returnedBytes, buildingBlock[:]...) + caller.returnedBytes[len(caller.returnedBytes)-1] = 1 + err = resolver.ResolveError(errOriginal, common.Address{}, nil, "Test") + assertErrorContains( + t, + err, + errOriginal.Error(), + fmt.Sprintf("%v", caller.returnedBytes), + "length insufficient", + ) +} + +func TestErrorResolverHandlesGoodErrorResponse(t *testing.T) { + caller := &fixedReturnCaller{[]byte{8, 195, 121, 160}} + + // Build a blank error message. + buildingBlock := [32]byte{} + caller.returnedBytes = append(caller.returnedBytes, buildingBlock[:]...) + caller.returnedBytes[len(caller.returnedBytes)-1] = 32 // data offset, fixed + caller.returnedBytes = append(caller.returnedBytes, buildingBlock[:]...) + caller.returnedBytes[len(caller.returnedBytes)-1] = 0 + + resolver := ethutil.NewErrorResolver(caller, &testABI, &testAddress) + err := resolver.ResolveError(errOriginal, common.Address{}, nil, "Test") + assertErrorContains( + t, + err, + errOriginal.Error(), + "[]", + ) + + // Build an error message. + errorMessage := "Something's gone awry." + caller.returnedBytes = []byte{8, 195, 121, 160} + caller.returnedBytes = append(caller.returnedBytes, buildingBlock[:]...) + caller.returnedBytes[len(caller.returnedBytes)-1] = 32 // data offset, fixed + caller.returnedBytes = append(caller.returnedBytes, buildingBlock[:]...) + caller.returnedBytes[len(caller.returnedBytes)-1] = byte(len(errorMessage)) + caller.returnedBytes = append(caller.returnedBytes, errorMessage[:]...) + + err = resolver.ResolveError(errOriginal, common.Address{}, nil, "Test") + assertErrorContains( + t, + err, + errOriginal.Error(), + errorMessage, + ) +} + +func TestErrorResolverPropagateFromAddress(t *testing.T) { + fromAddress := common.HexToAddress("0xA86c468475EF9C2ce851Ea4125424672C3F7e0C8") + + assertingCaller := callbackCallerWith(func( + ctx context.Context, + msg ethereum.CallMsg, + blockNumber *big.Int, + ) ([]byte, error) { + if fromAddress.Hex() != msg.From.Hex() { + t.Errorf( + "Unexpected From address\nExpected: [%v]\nActual: [%v]\n", + fromAddress.Hex(), + msg.From.Hex(), + ) + } + + return nil, fmt.Errorf("I don't care") + }) + + resolver := ethutil.NewErrorResolver(assertingCaller, &testABI, &testAddress) + resolver.ResolveError(errOriginal, fromAddress, nil, "Test") + + if !assertingCaller.callbackCalled { + t.Error("CallContract not invoked") + } +} + +func TestErrorResolverPropagateToAddress(t *testing.T) { + toAddress := common.HexToAddress("0x524f2E0176350d950fA630D9A5a59A0a190DAf48") + + assertingCaller := callbackCallerWith(func( + ctx context.Context, + msg ethereum.CallMsg, + blockNumber *big.Int, + ) ([]byte, error) { + if toAddress.Hex() != msg.To.Hex() { + t.Errorf( + "Unexpected To address\nExpected: [%v]\nActual: [%v]\n", + toAddress.Hex(), + msg.To.Hex(), + ) + } + + return (&erroringCaller{}).CallContract(ctx, msg, blockNumber) + }) + + resolver := ethutil.NewErrorResolver(assertingCaller, &testABI, &toAddress) + resolver.ResolveError(errOriginal, common.Address{}, nil, "Test") + + if !assertingCaller.callbackCalled { + t.Error("CallContract not invoked") + } +} + +func TestErrorResolverPropagateValue(t *testing.T) { + value := big.NewInt(123111) + + assertingCaller := callbackCallerWith(func( + ctx context.Context, + msg ethereum.CallMsg, + blockNumber *big.Int, + ) ([]byte, error) { + if value.Cmp(msg.Value) != 0 { + t.Errorf( + "Unexpected Value\nExpected: [%v]\nActual: [%v]\n", + value, + msg.Value, + ) + } + + return (&erroringCaller{}).CallContract(ctx, msg, blockNumber) + }) + + resolver := ethutil.NewErrorResolver(assertingCaller, &testABI, &testAddress) + resolver.ResolveError(errOriginal, common.Address{}, value, "Test") + + if !assertingCaller.callbackCalled { + t.Error("CallContract not invoked") + } +} + +func TestErrorResolverPropagateData(t *testing.T) { + methodName := "Test" + parameters := []interface{}{} + + assertingCaller := callbackCallerWith(func( + ctx context.Context, + msg ethereum.CallMsg, + blockNumber *big.Int, + ) ([]byte, error) { + expectedData, err := (&testABI).Pack(methodName, parameters...) + if err != nil { + panic(err) + } + + if !reflect.DeepEqual(expectedData, msg.Data) { + t.Errorf("Unexpected packed transaction Data") + } + + return (&erroringCaller{}).CallContract(ctx, msg, blockNumber) + }) + + resolver := ethutil.NewErrorResolver(assertingCaller, &testABI, &testAddress) + resolver.ResolveError(errOriginal, common.Address{}, nil, "Test") + + if !assertingCaller.callbackCalled { + t.Error("CallContract not invoked") + } +} diff --git a/pkg/chain/ethereumutil/ethutil/ethutil.go b/pkg/chain/ethereumutil/ethutil/ethutil.go new file mode 100644 index 0000000000..39b3f35613 --- /dev/null +++ b/pkg/chain/ethereumutil/ethutil/ethutil.go @@ -0,0 +1,204 @@ +// Package ethutil provides utilities used for dealing with Ethereum concerns in +// the context of implementing cross-chain interfaces defined in pkg/chain. +package ethutil + +import ( + "context" + "fmt" + "io/ioutil" + "math/big" + + chainEthereum "github.com/keep-network/keep-core/pkg/chain/ethereumutil" + + "github.com/ipfs/go-log" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/rpc" +) + +var logger = log.Logger("keep-ethutil") + +// EthereumClient wraps the core `bind.ContractBackend` interface with +// some other interfaces allowing to expose additional methods provided +// by client implementations. +type EthereumClient interface { + bind.ContractBackend + ethereum.ChainReader + ethereum.TransactionReader + + BalanceAt( + ctx context.Context, + account common.Address, + blockNumber *big.Int, + ) (*big.Int, error) +} + +// AddressFromHex converts the passed string to a common.Address and returns it, +// unless it is not a valid address, in which case it returns an error. Compare +// to common.HexToAddress, which assumes the address is valid and does not +// provide for an error return. +func AddressFromHex(hex string) (common.Address, error) { + if common.IsHexAddress(hex) { + return common.HexToAddress(hex), nil + } + + return common.Address{}, fmt.Errorf("[%v] is not a valid Ethereum address", hex) +} + +// DecryptKeyFile reads in a key file and uses the password to decrypt it. +func DecryptKeyFile(keyFile, password string) (*keystore.Key, error) { + // #nosec G304 (file path provided as taint input) + // This line is used to read a local key file. There is no user input. + data, err := ioutil.ReadFile(keyFile) + if err != nil { + return nil, fmt.Errorf("unable to read KeyFile %s [%v]", keyFile, err) + } + key, err := keystore.DecryptKey(data, password) + if err != nil { + return nil, fmt.Errorf("unable to decrypt %s [%v]", keyFile, err) + } + return key, nil +} + +// ConnectClients takes HTTP and RPC URLs and returns initialized versions of +// standard, WebSocket, and RPC clients for the Ethereum node at that address. +func ConnectClients(url string, urlRPC string) (*ethclient.Client, *rpc.Client, *rpc.Client, error) { + client, err := ethclient.Dial(url) + if err != nil { + return nil, nil, nil, fmt.Errorf( + "error Connecting to Geth Server: %s [%v]", + url, + err, + ) + } + + clientWS, err := rpc.Dial(url) + if err != nil { + return nil, nil, nil, fmt.Errorf( + "error Connecting to Geth Server: %s [%v]", + url, + err, + ) + } + + clientRPC, err := rpc.Dial(urlRPC) + if err != nil { + return nil, nil, nil, fmt.Errorf( + "error Connecting to Geth Server: %s [%v]", + url, + err, + ) + } + + return client, clientWS, clientRPC, nil +} + +// CallAtBlock allows the invocation of a particular contract method at a +// particular block. It papers over the fact that abigen bindings don't directly +// support calling at a particular block, and is mostly meant for use from +// generated contract code. +func CallAtBlock( + fromAddress common.Address, + blockNumber *big.Int, + value *big.Int, + contractABI *abi.ABI, + caller bind.ContractCaller, + errorResolver *ErrorResolver, + contractAddress common.Address, + method string, + result interface{}, + parameters ...interface{}, +) error { + input, err := contractABI.Pack(method, parameters...) + if err != nil { + return err + } + + var ( + msg = ethereum.CallMsg{ + From: fromAddress, + To: &contractAddress, + Data: input, + Value: value, + } + code []byte + output []byte + ) + + output, err = caller.CallContract(context.TODO(), msg, blockNumber) + if err == nil && len(output) == 0 { + // Make sure we have a contract to operate on, and bail out otherwise. + if code, err = caller.CodeAt(context.TODO(), contractAddress, nil); err != nil { + return err + } else if len(code) == 0 { + return bind.ErrNoCode + } + } + + err = contractABI.UnpackIntoInterface(result, method, output) + if err != nil { + return errorResolver.ResolveError( + err, + fromAddress, + value, + method, + parameters..., + ) + } + + return nil +} + +// EstimateGas tries to estimate the gas needed to execute a specific transaction based on +// the current pending state of the backend blockchain. There is no guarantee that this is +// the true gas limit requirement as other transactions may be added or removed by miners, +// but it should provide a basis for setting a reasonable default. +func EstimateGas( + from common.Address, + to common.Address, + method string, + contractABI *abi.ABI, + transactor bind.ContractTransactor, + parameters ...interface{}, +) (uint64, error) { + input, err := contractABI.Pack(method, parameters...) + if err != nil { + return 0, err + } + + msg := ethereum.CallMsg{ + From: from, + To: &to, + Data: input, + } + + gas, err := transactor.EstimateGas(context.TODO(), msg) + if err != nil { + return 0, err + } + + return gas, nil +} + +// NewBlockCounter creates a new BlockCounter instance for the provided +// Ethereum client. +func NewBlockCounter(client EthereumClient) (*chainEthereum.BlockCounter, error) { + return chainEthereum.CreateBlockCounter(ðereumAdapter{client}) +} + +// NewNonceManager creates NonceManager instance for the provided account +// using the provided Ethereum client. +func NewNonceManager( + client EthereumClient, + account common.Address, +) *chainEthereum.NonceManager { + return chainEthereum.NewNonceManager( + ðereumAdapter{client}, + chainEthereum.Address(account), + ) +} diff --git a/pkg/chain/ethereumutil/ethutil/ethutil_test.go b/pkg/chain/ethereumutil/ethutil/ethutil_test.go new file mode 100644 index 0000000000..d818e67a77 --- /dev/null +++ b/pkg/chain/ethereumutil/ethutil/ethutil_test.go @@ -0,0 +1,127 @@ +package ethutil_test + +import ( + "fmt" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil/ethutil" +) + +func TestKeyFileDecryption(t *testing.T) { + goodKeyFile := "./testdata/UTC--2018-02-15T19-57-35.216297214Z--6ffba2d0f4c8fd7961f516af43c55fe2d56f6044" + badKeyFile := "./testdata/nonexistent-file.booyan" + + tests := map[string]struct { + keyFile string + password string + errorMessage string + }{ + "good password": { + keyFile: goodKeyFile, + password: "password", + errorMessage: "", + }, + "bad file": { + keyFile: badKeyFile, + password: "", + errorMessage: fmt.Sprintf( + "unable to read KeyFile %v [open %v: no such file or directory]", + badKeyFile, + badKeyFile, + ), + }, + "bad password": { + keyFile: goodKeyFile, + password: "nanananana", + errorMessage: fmt.Sprintf( + "unable to decrypt %v [could not decrypt key with given password]", + goodKeyFile, + ), + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + _, err := ethutil.DecryptKeyFile(test.keyFile, test.password) + message := "" + if err != nil { + message = err.Error() + } + + if message != test.errorMessage { + t.Errorf( + "\nexpected: [%v]\nactual: [%v]", + test.errorMessage, + err, + ) + } + }) + } +} + +func TestAddressFromHex(t *testing.T) { + tests := map[string]struct { + hex string + errorMessage string + address common.Address + }{ + "valid address": { + hex: "0x0000000000000000000000000000000000001234", + errorMessage: "", + address: common.Address([20]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 52}), + }, + "short address": { + hex: "0x1234", + errorMessage: "[0x1234] is not a valid Ethereum address", + address: common.Address{}, + }, + "long address": { + hex: "0x000000000000000000000000000000000000001234", + errorMessage: "[0x000000000000000000000000000000000000001234] is not a valid Ethereum address", + address: common.Address{}, + }, + "decimal number": { + hex: "000000000000000000000000000000000000001234", + errorMessage: "[000000000000000000000000000000000000001234] is not a valid Ethereum address", + address: common.Address{}, + }, + "blank string": { + hex: "", + errorMessage: "[] is not a valid Ethereum address", + address: common.Address{}, + }, + "arbitrary string": { + hex: "I am a booyan with booyans", + errorMessage: "[I am a booyan with booyans] is not a valid Ethereum address", + address: common.Address{}, + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + address, err := ethutil.AddressFromHex(test.hex) + + message := "" + if err != nil { + message = err.Error() + } + + if message != test.errorMessage { + t.Errorf( + "\nexpected: [%v]\nactual: [%v]", + test.errorMessage, + err, + ) + } + + if address != test.address { + t.Errorf( + "\nexpected: [%v]\nactual: [%v]", + test.address, + address, + ) + } + }) + } +} diff --git a/pkg/chain/ethereumutil/ethutil/logging_wrapper.go b/pkg/chain/ethereumutil/ethutil/logging_wrapper.go new file mode 100644 index 0000000000..213f6be1f5 --- /dev/null +++ b/pkg/chain/ethereumutil/ethutil/logging_wrapper.go @@ -0,0 +1,52 @@ +package ethutil + +import ( + "context" + "github.com/ethereum/go-ethereum" + "github.com/ipfs/go-log" + "math/big" +) + +type loggingWrapper struct { + EthereumClient + + logger log.EventLogger +} + +func (lw *loggingWrapper) SuggestGasPrice( + ctx context.Context, +) (*big.Int, error) { + price, err := lw.EthereumClient.SuggestGasPrice(ctx) + + if err != nil { + lw.logger.Debugf("error requesting gas price suggestion: [%v]", err) + return nil, err + } + + lw.logger.Debugf("received gas price suggestion: [%v]", price) + return price, nil +} + +func (lw *loggingWrapper) EstimateGas( + ctx context.Context, + msg ethereum.CallMsg, +) (uint64, error) { + gas, err := lw.EthereumClient.EstimateGas(ctx, msg) + + if err != nil { + return 0, err + } + + lw.logger.Debugf("received gas estimate: [%v]", gas) + return gas, nil +} + +// WrapCallLogging wraps certain call-related methods on the given `client` +// with debug logging sent to the given `logger`. Actual functionality is +// delegated to the passed client. +func WrapCallLogging( + logger log.EventLogger, + client EthereumClient, +) EthereumClient { + return &loggingWrapper{client, logger} +} diff --git a/pkg/chain/ethereumutil/ethutil/mining_waiter.go b/pkg/chain/ethereumutil/ethutil/mining_waiter.go new file mode 100644 index 0000000000..5383c44470 --- /dev/null +++ b/pkg/chain/ethereumutil/ethutil/mining_waiter.go @@ -0,0 +1,408 @@ +package ethutil + +import ( + "context" + "fmt" + "math/big" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/core/types" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil" +) + +var ( + // DefaultMiningCheckInterval is the default interval in which transaction + // mining status is checked. If the transaction is not mined within this + // time, the gas price is increased and transaction is resubmitted. + // This value can be overwritten in the configuration file. + DefaultMiningCheckInterval = 60 * time.Second + + // DefaultMaxGasFeeCap specifies the default maximum gas fee cap the client + // is willing to pay for the transaction to be mined. The offered + // transaction gas cost can not be higher than the max gas fee cap value. + // If the maximum allowed gas fee cap is reached, no further resubmission + // attempts are performed. This value can be overwritten in the + // configuration file. + DefaultMaxGasFeeCap = *ethereum.WrapWei(big.NewInt(500000000000)) // 500 Gwei +) + +// MiningWaiter allows to block the execution until the given transaction is +// mined as well as monitor the transaction and perform an appropriate action +// in case it is not mined in the given timeout. This action is meant to +// increase the transaction's chance for being picked up by miners. +// +// Specific action depends on transaction type: +// - legacy pre EIP-1559 transaction: bumps up the gas price by 20% +// - dynamic fee post EIP-1559 transaction: bumps up the gas tip cap by 20% +// and adjusts the gas fee cap accordingly +type MiningWaiter struct { + client EthereumClient + checkInterval time.Duration + maxGasFeeCap *big.Int +} + +// NewMiningWaiter creates a new MiningWaiter instance for the provided +// client backend. It accepts two parameters setting up monitoring rules of the +// transaction mining status. +// +// Check interval is the time given for the transaction to be mined. If the +// transaction is not mined within that time, the mining waiter performs +// appropriate actions to increase their chance for being picked up by miners. +// +// Max gas fee cap specifies the maximum price the client is willing to pay +// per gas, for the transaction to be mined. The offered price can not +// be higher than this value. If the maximum allowed price is reached, no +// further resubmission attempts are performed. +func NewMiningWaiter( + client EthereumClient, + config ethereum.Config, +) *MiningWaiter { + checkInterval := DefaultMiningCheckInterval + maxGasFeeCap := DefaultMaxGasFeeCap + if config.MiningCheckInterval != 0 { + checkInterval = config.MiningCheckInterval + } + if config.MaxGasFeeCap.Int != nil { + maxGasFeeCap = config.MaxGasFeeCap + } + + logger.Infof("using [%v] mining check interval", checkInterval) + logger.Infof("using [%v] wei max gas fee cap", maxGasFeeCap) + + return &MiningWaiter{ + client, + checkInterval, + maxGasFeeCap.Int, + } +} + +// waitMined blocks the current execution until the transaction with the given +// hash is mined. Execution is blocked until the transaction is mined or until +// the given timeout passes. +func (mw *MiningWaiter) waitMined( + timeout time.Duration, + transaction *types.Transaction, +) (*types.Receipt, error) { + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + queryTicker := time.NewTicker(time.Second) + defer queryTicker.Stop() + + for { + receipt, _ := mw.client.TransactionReceipt( + context.TODO(), + transaction.Hash(), + ) + if receipt != nil { + return receipt, nil + } + + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-queryTicker.C: + } + } +} + +// ResubmitTransactionFn implements the code for resubmitting the transaction +// after mining waiter performs the action. It should guarantee the same nonce +// is used for transaction resubmission. +type ResubmitTransactionFn func( + newTransactorOptions *bind.TransactOpts, +) (*types.Transaction, error) + +// ForceMining blocks until the transaction is mined and performs an appropriate +// action to increase mining probability in the intervals defined by MiningWaiter +// in case the transaction has not been mined yet. It accepts the original +// transaction reference and the function responsible for executing transaction +// resubmission. +func (mw *MiningWaiter) ForceMining( + originalTransaction *types.Transaction, + originalTransactorOptions *bind.TransactOpts, + resubmitFn ResubmitTransactionFn, +) { + switch originalTransaction.Type() { + case types.LegacyTxType, types.AccessListTxType: + mw.forceMiningLegacyTx( + originalTransaction, + originalTransactorOptions, + resubmitFn, + ) + case types.DynamicFeeTxType: + mw.forceMiningDynamicFeeTx( + originalTransaction, + originalTransactorOptions, + resubmitFn, + ) + default: + logger.Errorf( + "could not start mining waiter; unsupported transaction type [%v]", + originalTransaction.Type, + ) + } +} + +func (mw *MiningWaiter) forceMiningLegacyTx( + originalTransaction *types.Transaction, + originalTransactorOptions *bind.TransactOpts, + resubmitFn ResubmitTransactionFn, +) { + logger.Infof( + "starting mining waiter for legacy transaction: [%v]", + originalTransaction.Hash().TerminalString(), + ) + + // For legacy transactions, the `maxGasFeeCap` is considered to be the same + // as `maxGasPrice`. This is because both parameters means the same: + // the maximum possible price per gas. + maxGasPrice := mw.maxGasFeeCap + + // If the original transaction's gas price was higher or equal the max + // allowed we do nothing; we need to wait for it to be mined. + if originalTransaction.GasPrice().Cmp(maxGasPrice) >= 0 { + logger.Infof( + "original transaction gas price is higher than the max allowed; " + + "skipping resubmissions", + ) + return + } + + transaction := originalTransaction + for { + receipt, err := mw.waitMined(mw.checkInterval, transaction) + if err != nil { + logger.Infof( + "transaction [%v] not yet mined: [%v]", + transaction.Hash().TerminalString(), + err, + ) + } + + // Transaction mined, we are good. + if receipt != nil { + logger.Infof( + "transaction [%v] mined with status [%v] at block [%v]", + transaction.Hash().TerminalString(), + receipt.Status, + receipt.BlockNumber, + ) + return + } + + // Transaction not yet mined, if the previous gas price was the maximum + // one, we no longer resubmit. + gasPrice := transaction.GasPrice() + if gasPrice.Cmp(maxGasPrice) == 0 { + logger.Infof( + "reached the maximum allowed gas price; " + + "stopping resubmissions", + ) + return + } + + // If we still have some margin, add 20% to the previous gas price. + twentyPercent := new(big.Int).Div(gasPrice, big.NewInt(5)) + gasPrice = new(big.Int).Add(gasPrice, twentyPercent) + + // If we reached the maximum allowed gas price, submit one more time + // with the maximum. + if gasPrice.Cmp(maxGasPrice) > 0 { + gasPrice = maxGasPrice + } + + // Transaction not yet mined and we are still under the maximum allowed + // gas price; resubmitting transaction with 20% higher gas price + // evaluated earlier. + logger.Infof( + "resubmitting previous transaction [%v] "+ + "with a higher gas price [%v]", + transaction.Hash().TerminalString(), + gasPrice, + ) + + // Copy transactor options. + newTransactorOptions := new(bind.TransactOpts) + *newTransactorOptions = *originalTransactorOptions + newTransactorOptions.GasPrice = gasPrice + + transaction, err = resubmitFn(newTransactorOptions) + if err != nil { + logger.Warningf( + "could not resubmit TX with a higher gas price: [%v]", + err, + ) + return + } + } +} + +func (mw *MiningWaiter) forceMiningDynamicFeeTx( + originalTransaction *types.Transaction, + originalTransactorOptions *bind.TransactOpts, + resubmitFn ResubmitTransactionFn, +) { + logger.Infof( + "starting mining waiter for dynamic fee transaction: [%v]", + originalTransaction.Hash().TerminalString(), + ) + + // If the original transaction's gas fee cap was higher or equal the max + // allowed we do nothing; we need to wait for it to be mined. + if originalTransaction.GasFeeCap().Cmp(mw.maxGasFeeCap) >= 0 { + logger.Infof( + "original transaction gas fee cap is higher than the max allowed; " + + "skipping resubmissions", + ) + return + } + + transaction := originalTransaction + for { + receipt, err := mw.waitMined(mw.checkInterval, transaction) + if err != nil { + logger.Infof( + "transaction [%v] not yet mined: [%v]", + transaction.Hash().TerminalString(), + err, + ) + } + + // Transaction mined, we are good. + if receipt != nil { + logger.Infof( + "transaction [%v] mined with status [%v] at block [%v]", + transaction.Hash().TerminalString(), + receipt.Status, + receipt.BlockNumber, + ) + return + } + + // Transaction not yet mined, if the previous gas fee cap was the + // maximum one, we no longer resubmit. + oldGasFeeCap := transaction.GasFeeCap() + if oldGasFeeCap.Cmp(mw.maxGasFeeCap) == 0 { + logger.Infof( + "reached the maximum allowed gas fee cap; " + + "stopping resubmissions", + ) + return + } + + // Increase the gas tip cap by 20%. A minimum increase by 10% comparing + // to the previous value is required for transaction replacement to be + // accepted by miners as mentioned in: + // https://github.com/ethereum/go-ethereum/pull/22898/files#r636583352. + // We increase it even more than the required level to greatly increase + // the transaction's chance for being picked up by miners. + oldGasTipCap := transaction.GasTipCap() + newGasTipCap := new(big.Int).Add( + oldGasTipCap, + new(big.Int).Div(oldGasTipCap, big.NewInt(5)), // + 20% + ) + + // Fetch latest base fee from the chain. It's needed to compute the + // new value of gas fee cap. + latestBaseFee, err := mw.latestBaseFee() + if err != nil { + logger.Errorf("could not get latest base fee: [%v]", err) + continue + } + + // Compute new value of gas fee cap using the latest base fee + // and new gas tip cap. The `gasFeeCap = 2 * baseFee + gasTipCap` + // equation originates from `go-ethereum` which estimates this + // parameter in that way. + // See: https://github.com/ethereum/go-ethereum/pull/23038. + // Having the `baseFee` taken twice means the `gasFeeCap` should + // be resilient for six consecutive increases of the `baseFee`. + // This is because `baseFee` can be increased by 12.5% at maximum + // within a single increase. + newGasFeeCap := new(big.Int).Add( + new(big.Int).Mul(latestBaseFee, big.NewInt(2)), + newGasTipCap, + ) + + // The new gas fee cap value needs to be at least 10% bigger + // than the old value. Otherwise, the transaction replacement + // won't be accepted by miners as mentioned in: + // https://github.com/ethereum/go-ethereum/pull/22898/files#r636583352. + // If that's the case (e.g. the `baseFee` dramatically decreased since + // the previous transaction) we need to set the new gas fee cap value + // to the minimum value acceptable by miners. + requiredGasFeeCapThreshold := new(big.Int).Add( + oldGasFeeCap, + new(big.Int).Div(oldGasFeeCap, big.NewInt(10)), + ) + if newGasFeeCap.Cmp(requiredGasFeeCapThreshold) < 0 { + newGasFeeCap = requiredGasFeeCapThreshold + } + + // If we reached the maximum allowed gas fee cap, submit one more time + // with the maximum. + if newGasFeeCap.Cmp(mw.maxGasFeeCap) > 0 { + newGasFeeCap = mw.maxGasFeeCap + + // Check if the threshold condition is fulfilled once again. + // If the maximum allowed gas fee cap is below the threshold, + // there is no sense to submit the transaction as it won't + // be accepted by the miners. + if newGasFeeCap.Cmp(requiredGasFeeCapThreshold) < 0 { + logger.Infof( + "could not fulfill required gas fee cap threshold as " + + "the maximum gas fee cap value defined in config " + + "has been reached; " + + "stopping resubmissions", + ) + return + } + } + + // Transaction not yet mined and we are still under the maximum allowed + // gas fee cap; resubmitting transaction with gas fee and tip parameters + // evaluated earlier. + logger.Infof( + "resubmitting previous transaction [%v] "+ + "with a higher gas fee cap [%v] and tip cap [%v]", + transaction.Hash().TerminalString(), + newGasFeeCap, + newGasTipCap, + ) + + // Copy transactor options. + newTransactorOptions := new(bind.TransactOpts) + *newTransactorOptions = *originalTransactorOptions + newTransactorOptions.GasFeeCap = newGasFeeCap + newTransactorOptions.GasTipCap = newGasTipCap + + transaction, err = resubmitFn(newTransactorOptions) + if err != nil { + logger.Warningf( + "could not resubmit TX with a higher "+ + "gas fee cap and tip cap: [%v]", + err, + ) + return + } + } +} + +func (mw *MiningWaiter) latestBaseFee() (*big.Int, error) { + latestHeader, err := mw.client.HeaderByNumber( + context.Background(), + nil, + ) + if err != nil { + return nil, fmt.Errorf("could not get the latest block header: [%v]", err) + } + + baseFee := latestHeader.BaseFee + if baseFee == nil { + return nil, fmt.Errorf("not an EIP-1559 block") + } + + return baseFee, nil +} diff --git a/pkg/chain/ethereumutil/ethutil/mining_waiter_test.go b/pkg/chain/ethereumutil/ethutil/mining_waiter_test.go new file mode 100644 index 0000000000..d0a09ea93b --- /dev/null +++ b/pkg/chain/ethereumutil/ethutil/mining_waiter_test.go @@ -0,0 +1,794 @@ +package ethutil + +import ( + "context" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil" +) + +var config = ethereum.Config{ + MiningCheckInterval: 1, + MaxGasFeeCap: *ethereum.WrapWei(big.NewInt(45000000000)), // 45 Gwei +} + +var originalTransactorOptions = &bind.TransactOpts{ + Nonce: big.NewInt(100), +} + +func TestForceMining_Legacy_NoResubmission(t *testing.T) { + originalTransaction := createLegacyTransaction(big.NewInt(20000000000)) // 20 Gwei + + chain := &mockAdaptedEthereumClientWithReceipt{} + + var resubmissions []*bind.TransactOpts + + resubmitFn := func( + newTransactorOptions *bind.TransactOpts, + ) (*types.Transaction, error) { + resubmissions = append(resubmissions, newTransactorOptions) + return createLegacyTransaction(newTransactorOptions.GasPrice), nil + } + + // receipt is already there + chain.receipt = &types.Receipt{} + + waiter := NewMiningWaiter(chain, config) + waiter.ForceMining( + originalTransaction, + originalTransactorOptions, + resubmitFn, + ) + + resubmissionCount := len(resubmissions) + if resubmissionCount != 0 { + t.Fatalf("expected no resubmissions; has: [%v]", resubmissionCount) + } +} + +func TestForceMining_Legacy_OneResubmission(t *testing.T) { + originalTransaction := createLegacyTransaction(big.NewInt(20000000000)) // 20 Gwei + + chain := &mockAdaptedEthereumClientWithReceipt{} + + var resubmissions []*bind.TransactOpts + + resubmitFn := func( + newTransactorOptions *bind.TransactOpts, + ) (*types.Transaction, error) { + resubmissions = append(resubmissions, newTransactorOptions) + // first resubmission succeeded + chain.receipt = &types.Receipt{} + return createLegacyTransaction(newTransactorOptions.GasPrice), nil + } + + waiter := NewMiningWaiter(chain, config) + waiter.ForceMining( + originalTransaction, + originalTransactorOptions, + resubmitFn, + ) + + resubmissionCount := len(resubmissions) + if resubmissionCount != 1 { + t.Fatalf("expected one resubmission; has: [%v]", resubmissionCount) + } + + resubmission := resubmissions[0] + + assertNonceUnchanged(t, resubmission) + + if resubmission.GasFeeCap != nil || resubmission.GasTipCap != nil { + t.Fatalf("gas fee and tip cap should be nil") + } + + expectedGasPrice := big.NewInt(24000000000) + if resubmission.GasPrice.Cmp(expectedGasPrice) != 0 { + t.Fatalf( + "unexpected gas price value\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + expectedGasPrice, + resubmission.GasPrice, + ) + } +} + +func TestForceMining_Legacy_MultipleAttempts(t *testing.T) { + originalTransaction := createLegacyTransaction(big.NewInt(20000000000)) // 20 Gwei + + chain := &mockAdaptedEthereumClientWithReceipt{} + + var resubmissions []*bind.TransactOpts + + expectedAttempts := 3 + expectedResubmissionGasPrices := []*big.Int{ + big.NewInt(24000000000), // + 20% + big.NewInt(28800000000), // + 20% + big.NewInt(34560000000), // + 20% + } + + attemptsSoFar := 1 + resubmitFn := func( + newTransactorOptions *bind.TransactOpts, + ) (*types.Transaction, error) { + resubmissions = append(resubmissions, newTransactorOptions) + if attemptsSoFar == expectedAttempts { + chain.receipt = &types.Receipt{} + } else { + attemptsSoFar++ + } + return createLegacyTransaction(newTransactorOptions.GasPrice), nil + } + + waiter := NewMiningWaiter(chain, config) + waiter.ForceMining( + originalTransaction, + originalTransactorOptions, + resubmitFn, + ) + + resubmissionCount := len(resubmissions) + if resubmissionCount != expectedAttempts { + t.Fatalf( + "expected [%v] resubmission; has: [%v]", + expectedAttempts, + resubmissionCount, + ) + } + + for index, resubmission := range resubmissions { + assertNonceUnchanged(t, resubmission) + + if resubmission.GasFeeCap != nil || resubmission.GasTipCap != nil { + t.Fatalf("resubmission [%v] gas fee and tip cap should be nil", index) + } + + price := resubmission.GasPrice + if price.Cmp(expectedResubmissionGasPrices[index]) != 0 { + t.Fatalf( + "unexpected resubmission [%v] gas price\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + index, + expectedResubmissionGasPrices[index], + price, + ) + } + } +} + +func TestForceMining_Legacy_MaxAllowedPriceReached(t *testing.T) { + originalTransaction := createLegacyTransaction(big.NewInt(20000000000)) // 20 Gwei + + chain := &mockAdaptedEthereumClientWithReceipt{} + + var resubmissions []*bind.TransactOpts + + expectedAttempts := 5 + expectedResubmissionGasPrices := []*big.Int{ + big.NewInt(24000000000), // + 20% + big.NewInt(28800000000), // + 20% + big.NewInt(34560000000), // + 20% + big.NewInt(41472000000), // + 20% + big.NewInt(45000000000), // max allowed + } + + resubmitFn := func( + newTransactorOptions *bind.TransactOpts, + ) (*types.Transaction, error) { + resubmissions = append(resubmissions, newTransactorOptions) + // not setting mockBackend.receipt, mining takes a very long time + return createLegacyTransaction(newTransactorOptions.GasPrice), nil + } + + waiter := NewMiningWaiter(chain, config) + waiter.ForceMining( + originalTransaction, + originalTransactorOptions, + resubmitFn, + ) + + resubmissionCount := len(resubmissions) + if resubmissionCount != expectedAttempts { + t.Fatalf( + "expected [%v] resubmission; has: [%v]", + expectedAttempts, + resubmissionCount, + ) + } + + for index, resubmission := range resubmissions { + assertNonceUnchanged(t, resubmission) + + if resubmission.GasFeeCap != nil || resubmission.GasTipCap != nil { + t.Fatalf("resubmission [%v] gas fee and tip cap should be nil", index) + } + + price := resubmission.GasPrice + if price.Cmp(expectedResubmissionGasPrices[index]) != 0 { + t.Fatalf( + "unexpected resubmission [%v] gas price\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + index, + expectedResubmissionGasPrices[index], + price, + ) + } + } +} + +func TestForceMining_Legacy_OriginalPriceHigherThanMaxAllowed(t *testing.T) { + // original transaction was priced at 46 Gwei, the maximum allowed gas price + // is 45 Gwei + originalTransaction := createLegacyTransaction(big.NewInt(46000000000)) + + chain := &mockAdaptedEthereumClientWithReceipt{} + + var resubmissions []*bind.TransactOpts + + resubmitFn := func( + newTransactorOptions *bind.TransactOpts, + ) (*types.Transaction, error) { + resubmissions = append(resubmissions, newTransactorOptions) + // not setting mockBackend.receipt, mining takes a very long time + return createLegacyTransaction(newTransactorOptions.GasPrice), nil + } + + waiter := NewMiningWaiter(chain, config) + waiter.ForceMining( + originalTransaction, + originalTransactorOptions, + resubmitFn, + ) + + resubmissionCount := len(resubmissions) + if resubmissionCount != 0 { + t.Fatalf("expected no resubmissions; has: [%v]", resubmissionCount) + } +} + +func TestForceMining_DynamicFee_NoResubmission(t *testing.T) { + originalBaseFee := big.NewInt(10000000000) // 10 Gwei + originalGasTipCap := big.NewInt(4000000000) // 4 Gwei + originalGasFeeCap := big.NewInt(24000000000) // 24 Gwei (2 * baseFee + gasTipCap) + + originalTransaction := createDynamicFeeTransaction( + originalGasFeeCap, + originalGasTipCap, + ) + + chain := &mockAdaptedEthereumClientWithReceipt{ + mockAdaptedEthereumClient: &mockAdaptedEthereumClient{}, + } + + // Base fee remains unchanged. + chain.blocks = append(chain.blocks, big.NewInt(1)) + chain.blocksBaseFee = append(chain.blocksBaseFee, originalBaseFee) + + var resubmissions []*bind.TransactOpts + + resubmitFn := func( + newTransactorOptions *bind.TransactOpts, + ) (*types.Transaction, error) { + resubmissions = append(resubmissions, newTransactorOptions) + return createDynamicFeeTransaction( + newTransactorOptions.GasFeeCap, + newTransactorOptions.GasTipCap, + ), nil + } + + // Receipt is already there. + chain.receipt = &types.Receipt{} + + waiter := NewMiningWaiter(chain, config) + waiter.ForceMining( + originalTransaction, + originalTransactorOptions, + resubmitFn, + ) + + resubmissionCount := len(resubmissions) + if resubmissionCount != 0 { + t.Fatalf("expected no resubmissions; has: [%v]", resubmissionCount) + } +} + +func TestForceMining_DynamicFee_OneResubmission(t *testing.T) { + originalBaseFee := big.NewInt(10000000000) // 10 Gwei + originalGasTipCap := big.NewInt(4000000000) // 4 Gwei + originalGasFeeCap := big.NewInt(24000000000) // 24 Gwei (2 * baseFee + gasTipCap) + + var tests = map[string]struct { + nextBaseFee *big.Int + expectedGasFeeCap *big.Int + expectedGasTipCap *big.Int + }{ + "base fee decreased": { + // Base fee decreased to 5 Gwei. + nextBaseFee: big.NewInt(5000000000), + // Gas fee cap should be computed as: 2 * 5 Gwei + 4.8 Gwei = 14.8 Gwei. + // However, this value doesn't fulfill the required base fee bump threshold. + // In result, the new gas fee value should be bumped up by 10% to + // satisfy the condition: 24 Gwei * 1.1 = 26.4 Gwei + expectedGasFeeCap: big.NewInt(26400000000), + // Gas tip cap should be bumped up by 20%: 4 Gwei * 1.2 = 4.8 Gwei + expectedGasTipCap: big.NewInt(4800000000), + }, + "base fee unchanged": { + // Base fee remains 10 Gwei. + nextBaseFee: originalBaseFee, + // Gas fee cap should be computed as: 2 * 10 Gwei + 4.8 Gwei = 24.8 Gwei. + // However, this value doesn't fulfill the required base fee bump threshold. + // In result, the new gas fee value should be bumped up by 10% to + // satisfy the condition: 24 Gwei * 1.1 = 26.4 Gwei + expectedGasFeeCap: big.NewInt(26400000000), + // Gas tip cap should be bumped up by 20%: 4 Gwei * 1.2 = 4.8 Gwei + expectedGasTipCap: big.NewInt(4800000000), + }, + "base fee increased": { + // Base fee increased to 20 Gwei. + nextBaseFee: big.NewInt(20000000000), + // Gas fee cap should be computed as: 2 * 20 Gwei + 4.8 Gwei = 44.8 Gwei. + expectedGasFeeCap: big.NewInt(44800000000), + // Gas tip cap should be bumped up by 20%: 4 Gwei * 1.2 = 4.8 Gwei + expectedGasTipCap: big.NewInt(4800000000), + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + originalTransaction := createDynamicFeeTransaction( + originalGasFeeCap, + originalGasTipCap, + ) + + chain := &mockAdaptedEthereumClientWithReceipt{ + mockAdaptedEthereumClient: &mockAdaptedEthereumClient{}, + } + + chain.blocks = append(chain.blocks, big.NewInt(1)) + chain.blocksBaseFee = append(chain.blocksBaseFee, test.nextBaseFee) + + var resubmissions []*bind.TransactOpts + + resubmitFn := func( + newTransactorOptions *bind.TransactOpts, + ) (*types.Transaction, error) { + resubmissions = append(resubmissions, newTransactorOptions) + // First resubmission succeeded. + chain.receipt = &types.Receipt{} + return createDynamicFeeTransaction( + newTransactorOptions.GasFeeCap, + newTransactorOptions.GasTipCap, + ), nil + } + + waiter := NewMiningWaiter(chain, config) + waiter.ForceMining( + originalTransaction, + originalTransactorOptions, + resubmitFn, + ) + + resubmissionCount := len(resubmissions) + if resubmissionCount != 1 { + t.Fatalf( + "expected one resubmission; has: [%v]", + resubmissionCount, + ) + } + + resubmission := resubmissions[0] + + assertNonceUnchanged(t, resubmission) + + if resubmission.GasPrice != nil { + t.Fatalf("gas price should be nil") + } + + if resubmission.GasFeeCap.Cmp(test.expectedGasFeeCap) != 0 { + t.Fatalf( + "unexpected gas fee cap value\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + test.expectedGasFeeCap, + resubmission.GasFeeCap, + ) + } + + if resubmission.GasTipCap.Cmp(test.expectedGasTipCap) != 0 { + t.Fatalf( + "unexpected gas tip cap value\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + test.expectedGasTipCap, + resubmission.GasTipCap, + ) + } + }) + } +} + +func TestForceMining_DynamicFee_MultipleAttemps(t *testing.T) { + originalBaseFee := big.NewInt(10000000000) // 10 Gwei + originalGasTipCap := big.NewInt(4000000000) // 4 Gwei + originalGasFeeCap := big.NewInt(24000000000) // 24 Gwei (2 * baseFee + gasTipCap) + + originalTransaction := createDynamicFeeTransaction( + originalGasFeeCap, + originalGasTipCap, + ) + + chain := &mockAdaptedEthereumClientWithReceipt{ + mockAdaptedEthereumClient: &mockAdaptedEthereumClient{}, + } + + // Base fee remains unchanged. + chain.blocks = append(chain.blocks, big.NewInt(1)) + chain.blocksBaseFee = append(chain.blocksBaseFee, originalBaseFee) + + var resubmissions []*bind.TransactOpts + + type gasPriceTuple struct { + gasFeeCap *big.Int + gasTipCap *big.Int + } + + expectedAttempts := 3 + expectedResubmissionParams := []*gasPriceTuple{ + // gasFeeCap +10%, gasTipCap +20% + {big.NewInt(26400000000), big.NewInt(4800000000)}, + // gasFeeCap +10%, gasTipCap +20% + {big.NewInt(29040000000), big.NewInt(5760000000)}, + // gasFeeCap +10%, gasTipCap +20% + {big.NewInt(31944000000), big.NewInt(6912000000)}, + } + + attemptsSoFar := 1 + resubmitFn := func( + newTransactorOptions *bind.TransactOpts, + ) (*types.Transaction, error) { + resubmissions = append(resubmissions, newTransactorOptions) + if attemptsSoFar == expectedAttempts { + chain.receipt = &types.Receipt{} + } else { + attemptsSoFar++ + } + return createDynamicFeeTransaction( + newTransactorOptions.GasFeeCap, + newTransactorOptions.GasTipCap, + ), nil + } + + waiter := NewMiningWaiter(chain, config) + waiter.ForceMining( + originalTransaction, + originalTransactorOptions, + resubmitFn, + ) + + resubmissionCount := len(resubmissions) + if resubmissionCount != expectedAttempts { + t.Fatalf( + "expected [%v] resubmission; has: [%v]", + expectedAttempts, + resubmissionCount, + ) + } + + for index, resubmission := range resubmissions { + assertNonceUnchanged(t, resubmission) + + if resubmission.GasPrice != nil { + t.Fatalf("resubmission [%v] gas price should be nil", index) + } + + expectedGasFeeCap := expectedResubmissionParams[index].gasFeeCap + if resubmission.GasFeeCap.Cmp(expectedGasFeeCap) != 0 { + t.Fatalf( + "unexpected resubmission [%v] gas fee cap value\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + index, + expectedGasFeeCap, + resubmission.GasFeeCap, + ) + } + + expectedGasTipCap := expectedResubmissionParams[index].gasTipCap + if resubmission.GasTipCap.Cmp(expectedGasTipCap) != 0 { + t.Fatalf( + "unexpected resubmission [%v] gas tip cap value\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + index, + expectedGasTipCap, + resubmission.GasTipCap, + ) + } + } +} + +func TestForceMining_DynamicFee_MaxAllowedPriceReached(t *testing.T) { + originalBaseFee := big.NewInt(10000000000) // 10 Gwei + originalGasTipCap := big.NewInt(4000000000) // 4 Gwei + originalGasFeeCap := big.NewInt(24000000000) // 24 Gwei (2 * baseFee + gasTipCap) + + originalTransaction := createDynamicFeeTransaction( + originalGasFeeCap, + originalGasTipCap, + ) + + chain := &mockAdaptedEthereumClientWithReceipt{ + mockAdaptedEthereumClient: &mockAdaptedEthereumClient{}, + } + + // Massive increase of base fee to 30 Gwei. This is needed + // to exceed the maximum gas fee cap value. + chain.blocks = append(chain.blocks, big.NewInt(1)) + chain.blocksBaseFee = append( + chain.blocksBaseFee, + new(big.Int).Mul(originalBaseFee, big.NewInt(3)), + ) + + var resubmissions []*bind.TransactOpts + + resubmitFn := func( + newTransactorOptions *bind.TransactOpts, + ) (*types.Transaction, error) { + resubmissions = append(resubmissions, newTransactorOptions) + // Not setting mockBackend.receipt, mining takes a very long time. + return createDynamicFeeTransaction( + newTransactorOptions.GasFeeCap, + newTransactorOptions.GasTipCap, + ), nil + } + + waiter := NewMiningWaiter(chain, config) + waiter.ForceMining( + originalTransaction, + originalTransactorOptions, + resubmitFn, + ) + + // The new gas fee value should be computed as usual: + // 2 * 30 Gwei + 4.8 gwei = 64.8 Gwei. However, this value exceeds the + // max gas fee cap value of 45 Gwei. In effect, one resubmission with the + // maximum value should be made. + resubmissionCount := len(resubmissions) + if resubmissionCount != 1 { + t.Fatalf( + "expected one resubmission; has: [%v]", + resubmissionCount, + ) + } + + resubmission := resubmissions[0] + + assertNonceUnchanged(t, resubmission) + + if resubmission.GasPrice != nil { + t.Fatalf("gas price should be nil") + } + + // The new gas fee value should be computed as usual: + // 2 * 30 Gwei + 4.8 gwei = 64.8 Gwei. However, max gas fee cap value + // is 45 Gwei so this value should be used instead. + expectedGasFeeCap := big.NewInt(45000000000) + if resubmission.GasFeeCap.Cmp(expectedGasFeeCap) != 0 { + t.Fatalf( + "unexpected gas fee cap value\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + expectedGasFeeCap, + resubmission.GasFeeCap, + ) + } + + // Gas tip cap should be bumped up by 20%: 4 Gwei * 1.2 = 4.8 Gwei + expectedGasTipCap := big.NewInt(4800000000) + if resubmission.GasTipCap.Cmp(expectedGasTipCap) != 0 { + t.Fatalf( + "unexpected gas tip cap value\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + expectedGasTipCap, + resubmission.GasTipCap, + ) + } +} + +func TestForceMining_DynamicFee_MaxAllowedPriceReachedButBelowThreshold(t *testing.T) { + originalBaseFee := big.NewInt(10000000000) // 10 Gwei + originalGasTipCap := big.NewInt(4000000000) // 4 Gwei + originalGasFeeCap := big.NewInt(24000000000) // 24 Gwei (2 * baseFee + gasTipCap) + + originalTransaction := createDynamicFeeTransaction( + originalGasFeeCap, + originalGasTipCap, + ) + + chain := &mockAdaptedEthereumClientWithReceipt{ + mockAdaptedEthereumClient: &mockAdaptedEthereumClient{}, + } + + // Base fee remains unchanged. + chain.blocks = append(chain.blocks, big.NewInt(1)) + chain.blocksBaseFee = append(chain.blocksBaseFee, originalBaseFee) + + var resubmissions []*bind.TransactOpts + + type gasPriceTuple struct { + gasFeeCap *big.Int + gasTipCap *big.Int + } + + expectedAttempts := 6 + expectedResubmissionParams := []*gasPriceTuple{ + // gasFeeCap +10%, gasTipCap +20% + {big.NewInt(26400000000), big.NewInt(4800000000)}, + // gasFeeCap +10%, gasTipCap +20% + {big.NewInt(29040000000), big.NewInt(5760000000)}, + // gasFeeCap +10%, gasTipCap +20% + {big.NewInt(31944000000), big.NewInt(6912000000)}, + // gasFeeCap +10%, gasTipCap +20% + {big.NewInt(35138400000), big.NewInt(8294400000)}, + // gasFeeCap +10%, gasTipCap +20% + {big.NewInt(38652240000), big.NewInt(9953280000)}, + // gasFeeCap +10%, gasTipCap +20% + {big.NewInt(42517464000), big.NewInt(11943936000)}, + // The last attempt would bump the gas fee cap up to 46769210400. + // However, this value exceeds the max gas fee cap which is 45000000000. + // On the other hand, the max gas fee cap is under the required fee bump + // threshold for this iteration so resubmission should not be performed + // at all. + } + + resubmitFn := func( + newTransactorOptions *bind.TransactOpts, + ) (*types.Transaction, error) { + resubmissions = append(resubmissions, newTransactorOptions) + // Not setting mockBackend.receipt, mining takes a very long time. + return createDynamicFeeTransaction( + newTransactorOptions.GasFeeCap, + newTransactorOptions.GasTipCap, + ), nil + } + + waiter := NewMiningWaiter(chain, config) + waiter.ForceMining( + originalTransaction, + originalTransactorOptions, + resubmitFn, + ) + + resubmissionCount := len(resubmissions) + if resubmissionCount != expectedAttempts { + t.Fatalf( + "expected [%v] resubmission; has: [%v]", + expectedAttempts, + resubmissionCount, + ) + } + + for index, resubmission := range resubmissions { + assertNonceUnchanged(t, resubmission) + + if resubmission.GasPrice != nil { + t.Fatalf("resubmission [%v] gas price should be nil", index) + } + + expectedGasFeeCap := expectedResubmissionParams[index].gasFeeCap + if resubmission.GasFeeCap.Cmp(expectedGasFeeCap) != 0 { + t.Fatalf( + "unexpected resubmission [%v] gas fee cap value\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + index, + expectedGasFeeCap, + resubmission.GasFeeCap, + ) + } + + expectedGasTipCap := expectedResubmissionParams[index].gasTipCap + if resubmission.GasTipCap.Cmp(expectedGasTipCap) != 0 { + t.Fatalf( + "unexpected resubmission [%v] gas tip cap value\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + index, + expectedGasTipCap, + resubmission.GasTipCap, + ) + } + } +} + +func TestForceMining_DynamicFee_OriginalPriceHigherThanMaxAllowed(t *testing.T) { + // Original transaction has gas fee cap set at 46 Gwei, the maximum allowed + // gas fee cap is 45 Gwei. + originalBaseFee := big.NewInt(10000000000) // 10 Gwei + originalGasTipCap := big.NewInt(4000000000) // 4 Gwei + originalGasFeeCap := big.NewInt(46000000000) // 46 Gwei + + originalTransaction := createDynamicFeeTransaction( + originalGasFeeCap, + originalGasTipCap, + ) + + chain := &mockAdaptedEthereumClientWithReceipt{ + mockAdaptedEthereumClient: &mockAdaptedEthereumClient{}, + } + + // Base fee remains unchanged. + chain.blocks = append(chain.blocks, big.NewInt(1)) + chain.blocksBaseFee = append(chain.blocksBaseFee, originalBaseFee) + + var resubmissions []*bind.TransactOpts + + resubmitFn := func( + newTransactorOptions *bind.TransactOpts, + ) (*types.Transaction, error) { + resubmissions = append(resubmissions, newTransactorOptions) + // Not setting mockBackend.receipt, mining takes a very long time. + return createDynamicFeeTransaction( + newTransactorOptions.GasFeeCap, + newTransactorOptions.GasTipCap, + ), nil + } + + waiter := NewMiningWaiter(chain, config) + waiter.ForceMining( + originalTransaction, + originalTransactorOptions, + resubmitFn, + ) + + resubmissionCount := len(resubmissions) + if resubmissionCount != 0 { + t.Fatalf("expected no resubmissions; has: [%v]", resubmissionCount) + } +} + +func assertNonceUnchanged( + t *testing.T, + newTransactionOptions *bind.TransactOpts, +) { + if newTransactionOptions.Nonce.Cmp(originalTransactorOptions.Nonce) != 0 { + t.Fatalf("nonce should remain unchanged") + } +} + +func createLegacyTransaction(gasPrice *big.Int) *types.Transaction { + return types.NewTx(&types.LegacyTx{ + GasPrice: gasPrice, + Gas: 25000, + }) +} + +func createDynamicFeeTransaction(gasFeeCap, gasTipCap *big.Int) *types.Transaction { + return types.NewTx(&types.DynamicFeeTx{ + GasFeeCap: gasFeeCap, + GasTipCap: gasTipCap, + Gas: 35000, + }) +} + +type mockAdaptedEthereumClientWithReceipt struct { + *mockAdaptedEthereumClient + + receipt *types.Receipt +} + +func (maecwr *mockAdaptedEthereumClientWithReceipt) TransactionReceipt( + ctx context.Context, + txHash common.Hash, +) (*types.Receipt, error) { + return maecwr.receipt, nil +} diff --git a/pkg/chain/ethereumutil/ethutil/rate_limiter.go b/pkg/chain/ethereumutil/ethutil/rate_limiter.go new file mode 100644 index 0000000000..d814bbc1e3 --- /dev/null +++ b/pkg/chain/ethereumutil/ethutil/rate_limiter.go @@ -0,0 +1,295 @@ +package ethutil + +import ( + "context" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/keep-network/keep-core/pkg/rate" +) + +type rateLimiter struct { + EthereumClient + + *rate.Limiter +} + +// WrapRateLimiting wraps the given contract backend with rate limiting +// capabilities with respect to the provided configuration. +// All types of requests to the contract are rate-limited, +// including view function calls. +func WrapRateLimiting( + client EthereumClient, + config *rate.LimiterConfig, +) EthereumClient { + return &rateLimiter{ + EthereumClient: client, + Limiter: rate.NewLimiter(config), + } +} + +func (rl *rateLimiter) CodeAt( + ctx context.Context, + contract common.Address, + blockNumber *big.Int, +) ([]byte, error) { + err := rl.Limiter.AcquirePermit() + if err != nil { + return nil, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err) + } + defer rl.Limiter.ReleasePermit() + + return rl.EthereumClient.CodeAt(ctx, contract, blockNumber) +} + +func (rl *rateLimiter) CallContract( + ctx context.Context, + call ethereum.CallMsg, + blockNumber *big.Int, +) ([]byte, error) { + err := rl.Limiter.AcquirePermit() + if err != nil { + return nil, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err) + } + defer rl.Limiter.ReleasePermit() + + return rl.EthereumClient.CallContract(ctx, call, blockNumber) +} + +func (rl *rateLimiter) PendingCodeAt( + ctx context.Context, + account common.Address, +) ([]byte, error) { + err := rl.Limiter.AcquirePermit() + if err != nil { + return nil, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err) + } + defer rl.Limiter.ReleasePermit() + + return rl.EthereumClient.PendingCodeAt(ctx, account) +} + +func (rl *rateLimiter) PendingNonceAt( + ctx context.Context, + account common.Address, +) (uint64, error) { + err := rl.Limiter.AcquirePermit() + if err != nil { + return 0, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err) + } + defer rl.Limiter.ReleasePermit() + + return rl.EthereumClient.PendingNonceAt(ctx, account) +} + +func (rl *rateLimiter) SuggestGasPrice( + ctx context.Context, +) (*big.Int, error) { + err := rl.Limiter.AcquirePermit() + if err != nil { + return nil, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err) + } + defer rl.Limiter.ReleasePermit() + + return rl.EthereumClient.SuggestGasPrice(ctx) +} + +func (rl *rateLimiter) SuggestGasTipCap( + ctx context.Context, +) (*big.Int, error) { + err := rl.Limiter.AcquirePermit() + if err != nil { + return nil, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err) + } + defer rl.Limiter.ReleasePermit() + + return rl.EthereumClient.SuggestGasTipCap(ctx) +} + +func (rl *rateLimiter) EstimateGas( + ctx context.Context, + call ethereum.CallMsg, +) (uint64, error) { + err := rl.Limiter.AcquirePermit() + if err != nil { + return 0, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err) + } + defer rl.Limiter.ReleasePermit() + + return rl.EthereumClient.EstimateGas(ctx, call) +} + +func (rl *rateLimiter) SendTransaction( + ctx context.Context, + tx *types.Transaction, +) error { + err := rl.Limiter.AcquirePermit() + if err != nil { + return fmt.Errorf("cannot acquire rate limiter permit: [%v]", err) + } + defer rl.Limiter.ReleasePermit() + + return rl.EthereumClient.SendTransaction(ctx, tx) +} + +func (rl *rateLimiter) FilterLogs( + ctx context.Context, + query ethereum.FilterQuery, +) ([]types.Log, error) { + err := rl.Limiter.AcquirePermit() + if err != nil { + return nil, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err) + } + defer rl.Limiter.ReleasePermit() + + return rl.EthereumClient.FilterLogs(ctx, query) +} + +func (rl *rateLimiter) SubscribeFilterLogs( + ctx context.Context, + query ethereum.FilterQuery, + ch chan<- types.Log, +) (ethereum.Subscription, error) { + err := rl.Limiter.AcquirePermit() + if err != nil { + return nil, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err) + } + defer rl.Limiter.ReleasePermit() + + return rl.EthereumClient.SubscribeFilterLogs(ctx, query, ch) +} + +func (rl *rateLimiter) BlockByHash( + ctx context.Context, + hash common.Hash, +) (*types.Block, error) { + err := rl.Limiter.AcquirePermit() + if err != nil { + return nil, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err) + } + defer rl.Limiter.ReleasePermit() + + return rl.EthereumClient.BlockByHash(ctx, hash) +} + +func (rl *rateLimiter) BlockByNumber( + ctx context.Context, + number *big.Int, +) (*types.Block, error) { + err := rl.Limiter.AcquirePermit() + if err != nil { + return nil, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err) + } + defer rl.Limiter.ReleasePermit() + + return rl.EthereumClient.BlockByNumber(ctx, number) +} + +func (rl *rateLimiter) HeaderByHash( + ctx context.Context, + hash common.Hash, +) (*types.Header, error) { + err := rl.Limiter.AcquirePermit() + if err != nil { + return nil, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err) + } + defer rl.Limiter.ReleasePermit() + + return rl.EthereumClient.HeaderByHash(ctx, hash) +} + +func (rl *rateLimiter) HeaderByNumber( + ctx context.Context, + number *big.Int, +) (*types.Header, error) { + err := rl.Limiter.AcquirePermit() + if err != nil { + return nil, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err) + } + defer rl.Limiter.ReleasePermit() + + return rl.EthereumClient.HeaderByNumber(ctx, number) +} + +func (rl *rateLimiter) TransactionCount( + ctx context.Context, + blockHash common.Hash, +) (uint, error) { + err := rl.Limiter.AcquirePermit() + if err != nil { + return 0, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err) + } + defer rl.Limiter.ReleasePermit() + + return rl.EthereumClient.TransactionCount(ctx, blockHash) +} + +func (rl *rateLimiter) TransactionInBlock( + ctx context.Context, + blockHash common.Hash, + index uint, +) (*types.Transaction, error) { + err := rl.Limiter.AcquirePermit() + if err != nil { + return nil, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err) + } + defer rl.Limiter.ReleasePermit() + + return rl.EthereumClient.TransactionInBlock(ctx, blockHash, index) +} + +func (rl *rateLimiter) SubscribeNewHead( + ctx context.Context, + ch chan<- *types.Header, +) (ethereum.Subscription, error) { + err := rl.Limiter.AcquirePermit() + if err != nil { + return nil, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err) + } + defer rl.Limiter.ReleasePermit() + + return rl.EthereumClient.SubscribeNewHead(ctx, ch) +} + +func (rl *rateLimiter) TransactionByHash( + ctx context.Context, + txHash common.Hash, +) (*types.Transaction, bool, error) { + err := rl.Limiter.AcquirePermit() + if err != nil { + return nil, false, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err) + } + defer rl.Limiter.ReleasePermit() + + return rl.EthereumClient.TransactionByHash(ctx, txHash) +} + +func (rl *rateLimiter) TransactionReceipt( + ctx context.Context, + txHash common.Hash, +) (*types.Receipt, error) { + err := rl.Limiter.AcquirePermit() + if err != nil { + return nil, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err) + } + defer rl.Limiter.ReleasePermit() + + return rl.EthereumClient.TransactionReceipt(ctx, txHash) +} + +func (rl *rateLimiter) BalanceAt( + ctx context.Context, + account common.Address, + blockNumber *big.Int, +) (*big.Int, error) { + err := rl.Limiter.AcquirePermit() + if err != nil { + return nil, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err) + } + defer rl.Limiter.ReleasePermit() + + return rl.EthereumClient.BalanceAt(ctx, account, blockNumber) +} diff --git a/pkg/chain/ethereumutil/ethutil/rate_limiter_test.go b/pkg/chain/ethereumutil/ethutil/rate_limiter_test.go new file mode 100644 index 0000000000..eafcd92dab --- /dev/null +++ b/pkg/chain/ethereumutil/ethutil/rate_limiter_test.go @@ -0,0 +1,689 @@ +package ethutil + +import ( + "context" + "math/big" + "strings" + "sync" + "testing" + "time" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/keep-network/keep-core/pkg/rate" +) + +func TestRateLimiter(t *testing.T) { + requestsPerSecondLimit := 500 + concurrencyLimit := 5 + acquirePermitTimeout := time.Minute + requests := 500 + requestDuration := 10 * time.Millisecond + + client := &mockEthereumClient{ + requestDuration, + make([]string, 0), + sync.Mutex{}, + } + + rateLimitingClient := WrapRateLimiting( + client, + &rate.LimiterConfig{ + RequestsPerSecondLimit: requestsPerSecondLimit, + ConcurrencyLimit: concurrencyLimit, + AcquirePermitTimeout: acquirePermitTimeout, + }, + ) + + for testName, test := range getTests(rateLimitingClient) { + t.Run(testName, func(t *testing.T) { + wg := sync.WaitGroup{} + wg.Add(requests) + + startSignal := make(chan struct{}) + + for i := 0; i < requests; i++ { + go func() { + <-startSignal + + err := test.function() + if err != nil { + t.Errorf("unexpected error: [%v]", err) + } + + wg.Done() + }() + } + + startTime := time.Now() + close(startSignal) + + wg.Wait() + + duration := time.Now().Sub(startTime) + averageRequestsPerSecond := float64(requests) / duration.Seconds() + + if averageRequestsPerSecond > float64(requestsPerSecondLimit) { + t.Errorf( + "average requests per second exceeded the limit\n"+ + "limit: [%v]\n"+ + "actual: [%v]", + requestsPerSecondLimit, + averageRequestsPerSecond, + ) + } + + maxConcurrency := 0 + temporaryConcurrency := 0 + for _, event := range client.events { + if event == "start" { + temporaryConcurrency++ + } + + if event == "end" { + temporaryConcurrency-- + } + + if temporaryConcurrency > maxConcurrency { + maxConcurrency = temporaryConcurrency + } + } + + if maxConcurrency > concurrencyLimit { + t.Errorf( + "max concurrency exceeded the limit\n"+ + "limit: [%v]\n"+ + "actual: [%v]", + concurrencyLimit, + maxConcurrency, + ) + } + }) + } +} + +func TestRateLimiter_RequestsPerSecondLimitOnly(t *testing.T) { + requestsPerSecondLimit := 500 + concurrencyLimit := 0 // disable the concurrency limit + acquirePermitTimeout := time.Minute + requests := 500 + requestDuration := 10 * time.Millisecond + + client := &mockEthereumClient{ + requestDuration, + make([]string, 0), + sync.Mutex{}, + } + + rateLimitingClient := WrapRateLimiting( + client, + &rate.LimiterConfig{ + RequestsPerSecondLimit: requestsPerSecondLimit, + ConcurrencyLimit: concurrencyLimit, + AcquirePermitTimeout: acquirePermitTimeout, + }, + ) + + for testName, test := range getTests(rateLimitingClient) { + t.Run(testName, func(t *testing.T) { + wg := sync.WaitGroup{} + wg.Add(requests) + + startSignal := make(chan struct{}) + + for i := 0; i < requests; i++ { + go func() { + <-startSignal + + err := test.function() + if err != nil { + t.Errorf("unexpected error: [%v]", err) + } + + wg.Done() + }() + } + + startTime := time.Now() + close(startSignal) + + wg.Wait() + + duration := time.Now().Sub(startTime) + averageRequestsPerSecond := float64(requests) / duration.Seconds() + + // The actual average can exceed the limit a little bit because of + // scheduling jitter and coarse timer resolution. Allow a slightly + // wider deviation to avoid flakes on busy runners. + maxDeviation := 0.15 + + if averageRequestsPerSecond > (1+maxDeviation)*float64(requestsPerSecondLimit) { + t.Errorf( + "average requests per second exceeded the limit\n"+ + "limit: [%v]\n"+ + "actual: [%v]", + requestsPerSecondLimit, + averageRequestsPerSecond, + ) + } + }) + } +} + +func TestRateLimiter_ConcurrencyLimitOnly(t *testing.T) { + requestsPerSecondLimit := 0 // disable the requests per second limit + concurrencyLimit := 50 + acquirePermitTimeout := time.Minute + requests := 500 + requestDuration := 10 * time.Millisecond + + client := &mockEthereumClient{ + requestDuration, + make([]string, 0), + sync.Mutex{}, + } + + rateLimitingClient := WrapRateLimiting( + client, + &rate.LimiterConfig{ + RequestsPerSecondLimit: requestsPerSecondLimit, + ConcurrencyLimit: concurrencyLimit, + AcquirePermitTimeout: acquirePermitTimeout, + }, + ) + + for testName, test := range getTests(rateLimitingClient) { + t.Run(testName, func(t *testing.T) { + wg := sync.WaitGroup{} + wg.Add(requests) + + startSignal := make(chan struct{}) + + for i := 0; i < requests; i++ { + go func() { + <-startSignal + + err := test.function() + if err != nil { + t.Errorf("unexpected error: [%v]", err) + } + + wg.Done() + }() + } + + close(startSignal) + + wg.Wait() + + maxConcurrency := 0 + temporaryConcurrency := 0 + for _, event := range client.events { + if event == "start" { + temporaryConcurrency++ + } + + if event == "end" { + temporaryConcurrency-- + } + + if temporaryConcurrency > maxConcurrency { + maxConcurrency = temporaryConcurrency + } + } + + if maxConcurrency > concurrencyLimit { + t.Errorf( + "max concurrency exceeded the limit\n"+ + "limit: [%v]\n"+ + "actual: [%v]", + concurrencyLimit, + maxConcurrency, + ) + } + }) + } +} + +func TestRateLimiter_AcquirePermitTimout(t *testing.T) { + requestsPerSecondLimit := 1 + concurrencyLimit := 1 + acquirePermitTimeout := 10 * time.Millisecond + requests := 3 + requestDuration := 250 * time.Millisecond + + client := &mockEthereumClient{ + requestDuration, + make([]string, 0), + sync.Mutex{}, + } + + rateLimitingClient := WrapRateLimiting( + client, + &rate.LimiterConfig{ + RequestsPerSecondLimit: requestsPerSecondLimit, + ConcurrencyLimit: concurrencyLimit, + AcquirePermitTimeout: acquirePermitTimeout, + }, + ) + + wg := sync.WaitGroup{} + wg.Add(requests) + + startSignal := make(chan struct{}) + errors := make(chan error, requests) + + for i := 0; i < requests; i++ { + go func() { + <-startSignal + + err := rateLimitingClient.SendTransaction(context.Background(), nil) + if err != nil { + errors <- err + } + + wg.Done() + }() + } + + close(startSignal) + + wg.Wait() + + close(errors) + if len(errors) == 0 { + t.Fatalf("at least one timeout error should be present") + } + + for e := range errors { + if !strings.Contains(e.Error(), "context deadline") { + t.Errorf( + "error should be related with the context deadline\n"+ + "actual error: [%v]", + e, + ) + } + } +} + +type mockEthereumClient struct { + requestDuration time.Duration + + events []string + mutex sync.Mutex +} + +func (mec *mockEthereumClient) mockRequest() { + mec.mutex.Lock() + mec.events = append(mec.events, "start") + mec.mutex.Unlock() + + time.Sleep(mec.requestDuration) + + mec.mutex.Lock() + mec.events = append(mec.events, "end") + mec.mutex.Unlock() +} + +func (mec *mockEthereumClient) CodeAt( + ctx context.Context, + contract common.Address, + blockNumber *big.Int, +) ([]byte, error) { + mec.mockRequest() + return nil, nil +} + +func (mec *mockEthereumClient) CallContract( + ctx context.Context, + call ethereum.CallMsg, + blockNumber *big.Int, +) ([]byte, error) { + mec.mockRequest() + return nil, nil +} + +func (mec *mockEthereumClient) PendingCodeAt( + ctx context.Context, + account common.Address, +) ([]byte, error) { + mec.mockRequest() + return nil, nil +} + +func (mec *mockEthereumClient) PendingNonceAt( + ctx context.Context, + account common.Address, +) (uint64, error) { + mec.mockRequest() + return 0, nil +} + +func (mec *mockEthereumClient) SuggestGasPrice( + ctx context.Context, +) (*big.Int, error) { + mec.mockRequest() + return nil, nil +} + +func (mec *mockEthereumClient) SuggestGasTipCap( + ctx context.Context, +) (*big.Int, error) { + mec.mockRequest() + return nil, nil +} + +func (mec *mockEthereumClient) EstimateGas( + ctx context.Context, + call ethereum.CallMsg, +) (uint64, error) { + mec.mockRequest() + return 0, nil +} + +func (mec *mockEthereumClient) SendTransaction( + ctx context.Context, + tx *types.Transaction, +) error { + mec.mockRequest() + return nil +} + +func (mec *mockEthereumClient) FilterLogs( + ctx context.Context, + query ethereum.FilterQuery, +) ([]types.Log, error) { + mec.mockRequest() + return nil, nil +} + +func (mec *mockEthereumClient) SubscribeFilterLogs( + ctx context.Context, + query ethereum.FilterQuery, + ch chan<- types.Log, +) (ethereum.Subscription, error) { + mec.mockRequest() + return nil, nil +} + +func (mec *mockEthereumClient) BlockByHash( + ctx context.Context, + hash common.Hash, +) (*types.Block, error) { + mec.mockRequest() + return nil, nil +} + +func (mec *mockEthereumClient) BlockByNumber( + ctx context.Context, + number *big.Int, +) (*types.Block, error) { + mec.mockRequest() + return nil, nil +} + +func (mec *mockEthereumClient) HeaderByHash( + ctx context.Context, + hash common.Hash, +) (*types.Header, error) { + mec.mockRequest() + return nil, nil +} + +func (mec *mockEthereumClient) HeaderByNumber( + ctx context.Context, + number *big.Int, +) (*types.Header, error) { + mec.mockRequest() + return nil, nil +} + +func (mec *mockEthereumClient) TransactionCount( + ctx context.Context, + blockHash common.Hash, +) (uint, error) { + mec.mockRequest() + return 0, nil +} + +func (mec *mockEthereumClient) TransactionInBlock( + ctx context.Context, + blockHash common.Hash, + index uint, +) (*types.Transaction, error) { + mec.mockRequest() + return nil, nil +} + +func (mec *mockEthereumClient) SubscribeNewHead( + ctx context.Context, + ch chan<- *types.Header, +) (ethereum.Subscription, error) { + mec.mockRequest() + return nil, nil +} + +func (mec *mockEthereumClient) TransactionByHash( + ctx context.Context, + txHash common.Hash, +) (*types.Transaction, bool, error) { + mec.mockRequest() + return nil, false, nil +} + +func (mec *mockEthereumClient) TransactionReceipt( + ctx context.Context, + txHash common.Hash, +) (*types.Receipt, error) { + mec.mockRequest() + return nil, nil +} + +func (mec *mockEthereumClient) SubscribeTransactionReceipts( + ctx context.Context, + q *ethereum.TransactionReceiptsQuery, + ch chan<- []*types.Receipt, +) (ethereum.Subscription, error) { + mec.mockRequest() + return nil, nil +} + +func (mec *mockEthereumClient) BalanceAt( + ctx context.Context, + account common.Address, + blockNumber *big.Int, +) (*big.Int, error) { + mec.mockRequest() + return nil, nil +} + +func getTests( + client EthereumClient, +) map[string]struct{ function func() error } { + return map[string]struct{ function func() error }{ + "test CodeAt": { + function: func() error { + _, err := client.CodeAt( + context.Background(), + [20]byte{}, + nil, + ) + return err + }, + }, + "test CallContract": { + function: func() error { + _, err := client.CallContract( + context.Background(), + ethereum.CallMsg{}, + nil, + ) + return err + }, + }, + "test PendingCodeAt": { + function: func() error { + _, err := client.PendingCodeAt( + context.Background(), + [20]byte{}, + ) + return err + }, + }, + "test PendingNonceAt": { + function: func() error { + _, err := client.PendingNonceAt( + context.Background(), + [20]byte{}, + ) + return err + }, + }, + "test SuggestGasPrice": { + function: func() error { + _, err := client.SuggestGasPrice( + context.Background(), + ) + return err + }, + }, + "test SuggestGasTipCap": { + function: func() error { + _, err := client.SuggestGasTipCap( + context.Background(), + ) + return err + }, + }, + "test EstimateGas": { + function: func() error { + _, err := client.EstimateGas( + context.Background(), + ethereum.CallMsg{}, + ) + return err + }, + }, + "test SendTransaction": { + function: func() error { + err := client.SendTransaction( + context.Background(), + nil, + ) + return err + }, + }, + "test FilterLogs": { + function: func() error { + _, err := client.FilterLogs( + context.Background(), + ethereum.FilterQuery{}, + ) + return err + }, + }, + "test SubscribeFilterLogs": { + function: func() error { + _, err := client.SubscribeFilterLogs( + context.Background(), + ethereum.FilterQuery{}, + nil, + ) + return err + }, + }, + "test BlockByHash": { + function: func() error { + _, err := client.BlockByHash( + context.Background(), + common.Hash{}, + ) + return err + }, + }, + "test BlockByNumber": { + function: func() error { + _, err := client.BlockByNumber( + context.Background(), + nil, + ) + return err + }, + }, + "test HeaderByHash": { + function: func() error { + _, err := client.HeaderByHash( + context.Background(), + common.Hash{}, + ) + return err + }, + }, + "test HeaderByNumber": { + function: func() error { + _, err := client.HeaderByNumber( + context.Background(), + nil, + ) + return err + }, + }, + "test TransactionCount": { + function: func() error { + _, err := client.TransactionCount( + context.Background(), + common.Hash{}, + ) + return err + }, + }, + "test TransactionInBlock": { + function: func() error { + _, err := client.TransactionInBlock( + context.Background(), + common.Hash{}, + 0, + ) + return err + }, + }, + "test SubscribeNewHead": { + function: func() error { + _, err := client.SubscribeNewHead( + context.Background(), + nil, + ) + return err + }, + }, + "test TransactionByHash": { + function: func() error { + _, _, err := client.TransactionByHash( + context.Background(), + common.Hash{}, + ) + return err + }, + }, + "test TransactionReceipt": { + function: func() error { + _, err := client.TransactionReceipt( + context.Background(), + common.Hash{}, + ) + return err + }, + }, + "test BalanceAt": { + function: func() error { + _, err := client.BalanceAt( + context.Background(), + common.Address{}, + big.NewInt(0), + ) + return err + }, + }, + } +} diff --git a/pkg/chain/ethereumutil/ethutil/resubscribe.go b/pkg/chain/ethereumutil/ethutil/resubscribe.go new file mode 100644 index 0000000000..98a1f62ebf --- /dev/null +++ b/pkg/chain/ethereumutil/ethutil/resubscribe.go @@ -0,0 +1,55 @@ +package ethutil + +import ( + "context" + "time" + + "github.com/ethereum/go-ethereum/event" +) + +// WithResubscription wraps the subscribe function to call it repeatedly +// to keep a subscription alive. When a subscription is established, it is +// monitored and in the case of a failure, resubscribe is attempted by +// calling the subscribe function again. +// +// The mechanism applies backoff between resubscription attempts. +// The time between calls is adapted based on the error rate, but will never +// exceed backoffMax. +// +// The mechanism monitors the time elapsed between resubscription attempts and +// if it is shorter than the specificed alertThreshold, it calls +// thresholdViolatedFn passing the time elapsed between resubscription attempts. +// This function alarms about potential problems with the stability of the +// subscription. +// +// In case of an error returned by the wrapped subscription function, +// subscriptionFailedFn is called with the underlying error. +// +// thresholdViolatedFn and subscriptionFailedFn calls are executed in a separate +// goroutine and thus are non-blocking. +func WithResubscription( + backoffMax time.Duration, + subscribeFn event.ResubscribeFunc, + alertThreshold time.Duration, + thresholdViolatedFn func(time.Duration), + subscriptionFailedFn func(error), +) event.Subscription { + lastAttempt := time.Time{} + wrappedResubscribeFn := func(ctx context.Context) (event.Subscription, error) { + now := time.Now() + elapsed := now.Sub(lastAttempt) + if elapsed < alertThreshold { + go thresholdViolatedFn(elapsed) + } + + lastAttempt = now + + sub, err := subscribeFn(ctx) + if err != nil { + go subscriptionFailedFn(err) + } + return sub, err + } + + return event.Resubscribe(backoffMax, wrappedResubscribeFn) +} diff --git a/pkg/chain/ethereumutil/ethutil/resubscribe_test.go b/pkg/chain/ethereumutil/ethutil/resubscribe_test.go new file mode 100644 index 0000000000..ea33176a38 --- /dev/null +++ b/pkg/chain/ethereumutil/ethutil/resubscribe_test.go @@ -0,0 +1,290 @@ +package ethutil + +import ( + "context" + "errors" + "fmt" + "testing" + "time" + + "github.com/ethereum/go-ethereum/event" +) + +func TestEmitOriginalError(t *testing.T) { + backoffMax := 100 * time.Millisecond + alertThreshold := 100 * time.Millisecond + + failedOnce := false + expectedFailMessage := "wherever I go, he goes" + subscribeFn := func(ctx context.Context) (event.Subscription, error) { + if !failedOnce { + failedOnce = true + return nil, errors.New(expectedFailMessage) + } + delegate := event.NewSubscription(func(unsubscribed <-chan struct{}) error { + return nil + }) + return delegate, nil + } + + // Using buffered channels to do not block writes. + // There should never be a need to write more to those channels if the code + // under the test works as expected. + thresholdViolated := make(chan time.Duration, 10) + subscriptionFailed := make(chan error, 10) + subscription := WithResubscription( + backoffMax, + subscribeFn, + alertThreshold, + func(elapsed time.Duration) { thresholdViolated <- elapsed }, + func(err error) { subscriptionFailed <- err }, + ) + <-subscription.Err() + + // Subscription failed one time so there should be one error in the channel. + subscriptionFailCount := len(subscriptionFailed) + if subscriptionFailCount != 1 { + t.Fatalf( + "subscription failure reported [%v] times, expected [1]", + subscriptionFailCount, + ) + } + + // That failure should refer the original error. + err := <-subscriptionFailed + if err.Error() != expectedFailMessage { + t.Errorf( + "unexpected subscription error message\nexpected: [%v]\nactual: [%v]", + expectedFailMessage, + err.Error(), + ) + } +} + +func TestResubscribeAboveThreshold(t *testing.T) { + backoffMax := 100 * time.Millisecond + alertThreshold := 100 * time.Millisecond + + plannedSubscriptionFailures := 3 + elapsedBetweenFailures := 150 * time.Millisecond + + resubscribeFnCalls := 0 + subscribeFn := func(ctx context.Context) (event.Subscription, error) { + resubscribeFnCalls++ + time.Sleep(elapsedBetweenFailures) // 150ms > 100ms, above alert threshold + if resubscribeFnCalls <= plannedSubscriptionFailures { + return nil, fmt.Errorf("this is the way") + } + delegate := event.NewSubscription(func(unsubscribed <-chan struct{}) error { + return nil + }) + return delegate, nil + } + + // Using buffered channels to do not block writes. + // There should never be a need to write more to those channels if the code + // under the test works as expected. + thresholdViolated := make(chan time.Duration, 10) + subscriptionFailed := make(chan error, 10) + subscription := WithResubscription( + backoffMax, + subscribeFn, + alertThreshold, + func(elapsed time.Duration) { thresholdViolated <- elapsed }, + func(err error) { subscriptionFailed <- err }, + ) + <-subscription.Err() + + // Nothing expected in thresholdViolated channel. + // Alert threshold is set to 100ms and there were no resubscription attempts + // in a time shorter than 150ms one after another. + violationCount := len(thresholdViolated) + if violationCount != 0 { + t.Errorf( + "threshold violation reported [%v] times, expected none", + violationCount, + ) + } + + // Subscription failed plannedSubscriptionFailures times and resubscription + // function should be called plannedSubscriptionFailures + 1 times. One time + // for each failure and one time at the end - that subscription was + // successful and had not to be retried. + expectedResubscriptionCalls := plannedSubscriptionFailures + 1 + if resubscribeFnCalls != expectedResubscriptionCalls { + t.Errorf( + "resubscription called [%v] times, expected [%v]", + resubscribeFnCalls, + expectedResubscriptionCalls, + ) + } + + // Expect all subscription failures to be reported. + subscriptionFailCount := len(subscriptionFailed) + if subscriptionFailCount != plannedSubscriptionFailures { + t.Errorf( + "subscription failure reported [%v] times, expected [%v]", + subscriptionFailCount, + plannedSubscriptionFailures, + ) + } +} + +func TestResubscribeBelowThreshold(t *testing.T) { + backoffMax := 50 * time.Millisecond + alertThreshold := 100 * time.Millisecond + + plannedSubscriptionFailures := 5 + elapsedBetweenFailures := 50 * time.Millisecond + + resubscribeFnCalls := 0 + subscribeFn := func(ctx context.Context) (event.Subscription, error) { + resubscribeFnCalls++ + time.Sleep(elapsedBetweenFailures) // 50ms < 100ms, below alert threshold + if resubscribeFnCalls <= plannedSubscriptionFailures { + return nil, fmt.Errorf("i have spoken") + } + delegate := event.NewSubscription(func(unsubscribed <-chan struct{}) error { + return nil + }) + return delegate, nil + } + + // Using buffered channels to do not block writes. + // There should never be a need to write more to those channels if the code + // under the test works as expected. + thresholdViolated := make(chan time.Duration, 10) + subscriptionFailed := make(chan error, 10) + subscription := WithResubscription( + backoffMax, + subscribeFn, + alertThreshold, + func(elapsed time.Duration) { thresholdViolated <- elapsed }, + func(err error) { subscriptionFailed <- err }, + ) + <-subscription.Err() + + // Threshold violaton should be reported for each subscription failure if + // the time elapsed since the previous resubscription was shorter than the + // threshold. + // In this test, alert threshold is set to 100ms and delays between failures + // are just 50ms. Thus, we expect the same number of threshold violations as + // resubscription attempts. + violationCount := len(thresholdViolated) + if violationCount != plannedSubscriptionFailures { + t.Errorf( + "threshold violation reported [%v] times, expected [%v]", + violationCount, + plannedSubscriptionFailures, + ) + } + + // All violations reported should have correct values - all of them should + // be longer than the time elapsed between failures and shorter than the + // alert threshold. It is not possible to assert on a precise value. + for i := 0; i < violationCount; i++ { + violation := <-thresholdViolated + if violation < elapsedBetweenFailures { + t.Errorf( + "violation reported should be longer than the time elapsed "+ + "between failures; is: [%v] and should be longer than [%v]", + violation, + elapsedBetweenFailures, + ) + } + if violation > alertThreshold { + t.Errorf( + "violation reported should be shorter than the alert threshold; "+ + "; is: [%v] and should be shorter than [%v]", + violation, + alertThreshold, + ) + } + } + + // Subscription failed plannedSubscriptionFailures times and resubscription + // function should be called plannedSubscriptionFailures + 1 times. One time + // for each failure and one time at the end - that subscription was + // successful and had not to be retried. + expectedResubscriptionCalls := plannedSubscriptionFailures + 1 + if resubscribeFnCalls != expectedResubscriptionCalls { + t.Errorf( + "resubscription called [%v] times, expected [%v]", + resubscribeFnCalls, + expectedResubscriptionCalls, + ) + } + + // Expect all subscription failures to be reported. + subscriptionFailCount := len(subscriptionFailed) + if subscriptionFailCount != plannedSubscriptionFailures { + t.Errorf( + "subscription failure reported [%v] times, expected [%v]", + subscriptionFailCount, + plannedSubscriptionFailures, + ) + } +} + +func TestDoNotBlockOnChannelWrites(t *testing.T) { + backoffMax := 50 * time.Millisecond + alertThreshold := 100 * time.Millisecond + + plannedSubscriptionFailures := 5 + elapsedBetweenFailures := 10 * time.Millisecond + + resubscribeFnCalls := 0 + subscribeFn := func(ctx context.Context) (event.Subscription, error) { + resubscribeFnCalls++ + time.Sleep(elapsedBetweenFailures) // 10ms < 100ms, below alert threshold + if resubscribeFnCalls <= plannedSubscriptionFailures { + return nil, fmt.Errorf("Groku?") + } + delegate := event.NewSubscription(func(unsubscribed <-chan struct{}) error { + return nil + }) + return delegate, nil + } + + // Non-buffered channels with no receivers, will block on write + thresholdViolated := make(chan time.Duration) + subscriptionFailed := make(chan error) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + subscription := WithResubscription( + backoffMax, + subscribeFn, + alertThreshold, + func(elapsed time.Duration) { + select { + case thresholdViolated <- elapsed: + case <-ctx.Done(): + return + } + }, + func(err error) { + select { + case subscriptionFailed <- err: + case <-ctx.Done(): + return + } + }, + ) + <-subscription.Err() + + // Subscription failed plannedSubscriptionFailures times and resubscription + // function should be called plannedSubscriptionFailures + 1 times. One time + // for each failure and one time at the end - that subscription was + // successful and had not to be retried. No resubscription attempt should be + // blocked by the lack of channel receivers on non-buffered channels. + expectedResubscriptionCalls := plannedSubscriptionFailures + 1 + if resubscribeFnCalls != expectedResubscriptionCalls { + t.Errorf( + "resubscription called [%v] times, expected [%v]", + resubscribeFnCalls, + expectedResubscriptionCalls, + ) + } +} diff --git a/pkg/chain/ethereumutil/ethutil/signer.go b/pkg/chain/ethereumutil/ethutil/signer.go new file mode 100644 index 0000000000..e5ffcef725 --- /dev/null +++ b/pkg/chain/ethereumutil/ethutil/signer.go @@ -0,0 +1,144 @@ +package ethutil + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "fmt" + + "github.com/ethereum/go-ethereum/crypto" +) + +// SignatureSize is a byte size of a signature calculated by Ethereum with +// recovery-id, V, included. The signature consists of three values (R,S,V) +// in the following order: +// R = [0:31] +// S = [32:63] +// V = [64] +const SignatureSize = 65 + +// EthereumSigner provides functions to sign a message and verify a signature +// using the Ethereum-specific signature format. It also provides functions for +// conversion of a public key to an address. +type EthereumSigner struct { + privateKey *ecdsa.PrivateKey +} + +// NewSigner creates a new EthereumSigner instance for the provided ECDSA +// private key. +func NewSigner(privateKey *ecdsa.PrivateKey) *EthereumSigner { + return &EthereumSigner{privateKey} +} + +// PublicKey returns byte representation of a public key for the private key +// signer was created with. +func (es *EthereumSigner) PublicKey() []byte { + publicKey := es.privateKey.PublicKey + return elliptic.Marshal(publicKey.Curve, publicKey.X, publicKey.Y) +} + +// Sign signs the provided message using Ethereum-specific format. +func (es *EthereumSigner) Sign(message []byte) ([]byte, error) { + signature, err := crypto.Sign(ethereumPrefixedHash(message), es.privateKey) + if err != nil { + return nil, err + } + + if len(signature) == SignatureSize { + // go-ethereum/crypto produces signature with v={0, 1} and we need to add + // 27 to v-part (signature[64]) to conform with the on-chain signature + // validation code that accepts v={27, 28} as specified in the + // Appendix F of the Ethereum Yellow Paper + // https://ethereum.github.io/yellowpaper/paper.pdf + signature[len(signature)-1] = signature[len(signature)-1] + 27 + } + + return signature, nil +} + +// Verify verifies the provided message against a signature using the key +// EthereumSigner was created with. The signature has to be provided in +// Ethereum-specific format. +func (es *EthereumSigner) Verify(message []byte, signature []byte) (bool, error) { + return verifySignature(message, signature, &es.privateKey.PublicKey) +} + +// VerifyWithPublicKey verifies the provided message against a signature and +// public key. The signature has to be provided in Ethereum-specific format. +func (es *EthereumSigner) VerifyWithPublicKey( + message []byte, + signature []byte, + publicKey []byte, +) (bool, error) { + unmarshalledPubKey, err := unmarshalPublicKey( + publicKey, + es.privateKey.Curve, + ) + if err != nil { + return false, fmt.Errorf("failed to unmarshal public key: [%v]", err) + } + + return verifySignature(message, signature, unmarshalledPubKey) +} + +func verifySignature( + message []byte, + signature []byte, + publicKey *ecdsa.PublicKey, +) (bool, error) { + // Convert the operator's static key into an uncompressed public key + // which should be 65 bytes in length. + uncompressedPubKey := crypto.FromECDSAPub(publicKey) + // If our signature is in the [R || S || V] format, ensure we strip out + // the Ethereum-specific recovery-id, V, if it already hasn't been done. + if len(signature) == SignatureSize { + signature = signature[:len(signature)-1] + } + + // The signature should be now 64 bytes long. + if len(signature) != 64 { + return false, fmt.Errorf( + "signature should have 64 bytes; has: [%d]", + len(signature), + ) + } + + return crypto.VerifySignature( + uncompressedPubKey, + ethereumPrefixedHash(message), + signature, + ), nil +} + +func ethereumPrefixedHash(message []byte) []byte { + return crypto.Keccak256( + []byte(fmt.Sprintf("\x19Ethereum Signed Message:\n%v", len(message))), + message, + ) +} + +func unmarshalPublicKey( + bytes []byte, + curve elliptic.Curve, +) (*ecdsa.PublicKey, error) { + x, y := elliptic.Unmarshal(curve, bytes) + if x == nil { + return nil, fmt.Errorf( + "invalid public key bytes", + ) + } + ecdsaPublicKey := &ecdsa.PublicKey{Curve: curve, X: x, Y: y} + return (*ecdsa.PublicKey)(ecdsaPublicKey), nil +} + +// PublicKeyToAddress transforms the provided ECDSA public key into Ethereum +// address represented in bytes. +func (es *EthereumSigner) PublicKeyToAddress(publicKey ecdsa.PublicKey) []byte { + return crypto.PubkeyToAddress(publicKey).Bytes() +} + +// PublicKeyBytesToAddress transforms the provided ECDSA public key in a bytes +// format into Ethereum address represented in bytes. +func (es *EthereumSigner) PublicKeyBytesToAddress(publicKey []byte) []byte { + // Does the same as crypto.PubkeyToAddress but directly on public key bytes. + return crypto.Keccak256(publicKey[1:])[12:] +} diff --git a/pkg/chain/ethereumutil/ethutil/signer_test.go b/pkg/chain/ethereumutil/ethutil/signer_test.go new file mode 100644 index 0000000000..203f2dcca0 --- /dev/null +++ b/pkg/chain/ethereumutil/ethutil/signer_test.go @@ -0,0 +1,165 @@ +package ethutil + +import ( + "testing" + + "github.com/ethereum/go-ethereum/crypto" +) + +func TestSignAndVerify(t *testing.T) { + signer, err := newSigner() + if err != nil { + t.Fatal(err) + } + + message := []byte("He that breaks a thing to find out what it is, has " + + "left the path of wisdom.") + + signature, err := signer.Sign(message) + if err != nil { + t.Fatal(err) + } + + var tests = map[string]struct { + message []byte + signature []byte + validSignatureExpected bool + validationErrorExpected bool + }{ + "valid signature for message": { + message: message, + signature: signature, + validSignatureExpected: true, + validationErrorExpected: false, + }, + "invalid signature for message": { + message: []byte("I am sorry"), + signature: signature, + validSignatureExpected: false, + validationErrorExpected: false, + }, + "corrupted signature": { + message: message, + signature: []byte("I am so sorry"), + validSignatureExpected: false, + validationErrorExpected: true, + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + ok, err := signer.Verify(test.message, test.signature) + + if !ok && test.validSignatureExpected { + t.Errorf("expected valid signature but verification failed") + } + if ok && !test.validSignatureExpected { + t.Errorf("expected invalid signature but verification succeeded") + } + + if err == nil && test.validationErrorExpected { + t.Errorf("expected signature validation error; none happened") + } + if err != nil && !test.validationErrorExpected { + t.Errorf("unexpected signature validation error [%v]", err) + } + }) + } +} + +func TestSignAndVerifyWithProvidedPublicKey(t *testing.T) { + message := []byte("I am looking for someone to share in an adventure") + + signer1, err := newSigner() + if err != nil { + t.Fatal(err) + } + + signer2, err := newSigner() + if err != nil { + t.Fatal(err) + } + + publicKey := signer1.PublicKey() + signature, err := signer1.Sign(message) + if err != nil { + t.Fatal(err) + } + + var tests = map[string]struct { + message []byte + signature []byte + publicKey []byte + validSignatureExpected bool + validationErrorExpected bool + }{ + "valid signature for message": { + message: message, + signature: signature, + publicKey: publicKey, + validSignatureExpected: true, + validationErrorExpected: false, + }, + "invalid signature for message": { + message: []byte("And here..."), + signature: signature, + publicKey: publicKey, + validSignatureExpected: false, + validationErrorExpected: false, + }, + "corrupted signature": { + message: message, + signature: []byte("we..."), + publicKey: publicKey, + validSignatureExpected: false, + validationErrorExpected: true, + }, + "invalid remote public key": { + message: message, + signature: signature, + publicKey: signer2.PublicKey(), + validSignatureExpected: false, + validationErrorExpected: false, + }, + "corrupted remote public key": { + message: message, + signature: signature, + publicKey: []byte("go..."), + validSignatureExpected: false, + validationErrorExpected: true, + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + ok, err := signer2.VerifyWithPublicKey( + test.message, + test.signature, + test.publicKey, + ) + + if !ok && test.validSignatureExpected { + t.Errorf("expected valid signature but verification failed") + } + if ok && !test.validSignatureExpected { + t.Errorf("expected invalid signature but verification succeeded") + } + + if err == nil && test.validationErrorExpected { + t.Errorf("expected signature validation error; none happened") + } + if err != nil && !test.validationErrorExpected { + t.Errorf("unexpected signature validation error [%v]", err) + } + }) + } +} + +func newSigner() (*EthereumSigner, error) { + key, err := crypto.GenerateKey() + if err != nil { + return nil, err + } + + return &EthereumSigner{key}, nil +} diff --git a/pkg/chain/ethereumutil/ethutil/subscribe_opts.go b/pkg/chain/ethereumutil/ethutil/subscribe_opts.go new file mode 100644 index 0000000000..701e8ff651 --- /dev/null +++ b/pkg/chain/ethereumutil/ethutil/subscribe_opts.go @@ -0,0 +1,32 @@ +package ethutil + +import "time" + +const ( + // DefaultSubscribeOptsTick is the default duration with which + // past events are pulled from the chain by the subscription monitoring + // mechanism if no other value is provided in SubscribeOpts when creating + // the subscription. + DefaultSubscribeOptsTick = 15 * time.Minute + + // DefaultSubscribeOptsPastBlocks is the default number of past blocks + // pulled from the chain by the subscription monitoring mechanism if no + // other value is provided in SubscribeOpts when creating the subscription. + DefaultSubscribeOptsPastBlocks = 100 + + // SubscriptionBackoffMax is the maximum backoff time between event + // resubscription attempts. + SubscriptionBackoffMax = 2 * time.Minute + + // SubscriptionAlertThreshold is time threshold below which event + // resubscription emits an error to the logs. + // WS connection can be dropped at any moment and event resubscription will + // follow. However, if WS connection for event subscription is getting + // dropped too often, it may indicate something is wrong with Ethereum + // client. This constant defines the minimum lifetime of an event + // subscription required before the subscription failure happens and + // resubscription follows so that the resubscription does not emit an error + // to the logs alerting about potential problems with Ethereum client + // connection. + SubscriptionAlertThreshold = 15 * time.Minute +) diff --git a/pkg/chain/ethereumutil/ethutil/testdata/UTC--2018-02-15T19-57-35.216297214Z--6ffba2d0f4c8fd7961f516af43c55fe2d56f6044 b/pkg/chain/ethereumutil/ethutil/testdata/UTC--2018-02-15T19-57-35.216297214Z--6ffba2d0f4c8fd7961f516af43c55fe2d56f6044 new file mode 100644 index 0000000000..9b0cdc80e1 --- /dev/null +++ b/pkg/chain/ethereumutil/ethutil/testdata/UTC--2018-02-15T19-57-35.216297214Z--6ffba2d0f4c8fd7961f516af43c55fe2d56f6044 @@ -0,0 +1 @@ +{"address":"6ffba2d0f4c8fd7961f516af43c55fe2d56f6044","crypto":{"cipher":"aes-128-ctr","ciphertext":"9692257e484a1c7c4086b0d3265ac0469766488e36880b1a2d52b5058b9a8705","cipherparams":{"iv":"cac3071fb4b3fd97ab1fd3838514552e"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"59bb28c710bb43fd2c6c67e0482e6198cf396eb4d9a4536901d9a871d19f6c7e"},"mac":"7bd942cb9b37a7ec2932e3dcfc36d248ae3e74b83d5c2aac0e9cec96d853e917"},"id":"f3b200cb-f19b-47dd-86b3-e776aa09ef11","version":3} \ No newline at end of file diff --git a/pkg/chain/ethereumutil/ethutil/transaction_opts.go b/pkg/chain/ethereumutil/ethutil/transaction_opts.go new file mode 100644 index 0000000000..040b0cd139 --- /dev/null +++ b/pkg/chain/ethereumutil/ethutil/transaction_opts.go @@ -0,0 +1,40 @@ +package ethutil + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" +) + +// TransactionOptions represents custom transaction options which can be used +// while invoking contracts methods. +type TransactionOptions struct { + // GasLimit specifies a gas limit to set for a transaction; estimated if + // set to 0. + GasLimit uint64 + + // GasFeeCap specifies gas fee cap for EIP-1559 transaction; estimated if + // set to nil. + GasFeeCap *big.Int + + // GasTipCap specifies gas priority fee cap to use for EIP-1559 transaction; + // estimated if set to nil. + GasTipCap *big.Int +} + +// Apply takes a bind.TransactOpts pointer and applies the options described in +// TransactionOptions to it. Note that GasTipCap, GasFeeCap set to nil and +// GasLimit set to 0 are not applied to the passed bind.TransactOpts; these +// values indicate that the original values in bind.TransactOpts should remain +// unchanged. +func (to TransactionOptions) Apply(transactorOptions *bind.TransactOpts) { + if customGasLimit := to.GasLimit; customGasLimit != 0 { + transactorOptions.GasLimit = customGasLimit + } + if customGasFeeCap := to.GasFeeCap; customGasFeeCap != nil { + transactorOptions.GasFeeCap = customGasFeeCap + } + if customGasTipCap := to.GasTipCap; customGasTipCap != nil { + transactorOptions.GasTipCap = customGasTipCap + } +} diff --git a/pkg/chain/ethereumutil/logger.go b/pkg/chain/ethereumutil/logger.go new file mode 100644 index 0000000000..818162b0a1 --- /dev/null +++ b/pkg/chain/ethereumutil/logger.go @@ -0,0 +1,5 @@ +package ethereum + +import "github.com/ipfs/go-log" + +var logger = log.Logger("keep-ethereum") diff --git a/pkg/chain/ethereumutil/network.go b/pkg/chain/ethereumutil/network.go new file mode 100644 index 0000000000..5a460e8cfd --- /dev/null +++ b/pkg/chain/ethereumutil/network.go @@ -0,0 +1,27 @@ +package ethereum + +// Network is a type used for ethereum networks enumeration. +type Network int + +// Ethereum networks enumeration. +const ( + Unknown Network = iota + Mainnet + Sepolia + Developer +) + +func (n Network) String() string { + return []string{"unknown", "mainnet", "sepolia", "developer"}[n] +} + +// ChainID returns chain id associated with the network. +func (n Network) ChainID() int64 { + switch n { + case Mainnet: + return 1 + case Sepolia: + return 11155111 + } + return 0 +} diff --git a/pkg/chain/ethereumutil/network_test.go b/pkg/chain/ethereumutil/network_test.go new file mode 100644 index 0000000000..1049c82c5a --- /dev/null +++ b/pkg/chain/ethereumutil/network_test.go @@ -0,0 +1,44 @@ +package ethereum + +import ( + "testing" +) + +func TestNetworkString(t *testing.T) { + var tests = map[string]struct { + network Network + expectedString string + }{ + "Unknown": { + network: Unknown, + expectedString: "unknown", + }, + "Mainnet": { + network: Mainnet, + expectedString: "mainnet", + }, + "Sepolia": { + network: Sepolia, + expectedString: "sepolia", + }, + "Developer": { + network: Developer, + expectedString: "developer", + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + + result := test.network.String() + + if result != test.expectedString { + t.Errorf( + "\nexpected: %s\nactual: %s", + test.expectedString, + result, + ) + } + }) + } +} diff --git a/pkg/chain/ethereumutil/nonce_manager.go b/pkg/chain/ethereumutil/nonce_manager.go new file mode 100644 index 0000000000..d95025da88 --- /dev/null +++ b/pkg/chain/ethereumutil/nonce_manager.go @@ -0,0 +1,120 @@ +package ethereum + +import ( + "context" + "time" +) + +// The inactivity time after which the local nonce is refreshed with the value +// from the chain. The local value is invalidated after the certain duration to +// let the nonce recover in case the mempool crashed before propagating the last +// transaction sent. +const localNonceTrustDuration = 30 * time.Second + +// NonceManager tracks the nonce for the account and allows to update it after +// each successfully submitted transaction. Tracking the nonce locally is +// required when transactions are submitted from multiple goroutines or when +// multiple Ethereum clients are deployed behind a load balancer, +// there are no sticky sessions and mempool synchronization between them +// takes some time. +// +// NonceManager provides no synchronization and is NOT safe for concurrent use. +// It is up to the client code to implement the required synchronization. +// +// An example execution might work as follows: +// 1. Obtain transaction lock, +// 2. Calculate CurrentNonce(), +// 3. Submit transaction with the calculated nonce, +// 4. Call IncrementNonce(), +// 5. Release transaction lock. +type NonceManager struct { + account Address + transactor ContractTransactor + localNonce uint64 + expirationDate time.Time +} + +// NewNonceManager creates NonceManager instance for the provided account using +// the provided contract transactor. Contract transactor is used for every +// CurrentNonce execution to check the pending nonce value as seen by the +// Ethereum client. +func NewNonceManager( + transactor ContractTransactor, + account Address, +) *NonceManager { + return &NonceManager{ + account: account, + transactor: transactor, + localNonce: 0, + } +} + +// CurrentNonce returns the nonce value that should be used for the next +// transaction. The nonce is evaluated as the higher value from the local +// nonce and pending nonce fetched from the Ethereum client. The local nonce +// is cached for the specific duration. If the local nonce expired, the pending +// nonce returned from the chain is used. +// +// CurrentNonce is NOT safe for concurrent use. It is up to the code using this +// function to provide the required synchronization, optionally including +// IncrementNonce call as well. +func (nm *NonceManager) CurrentNonce() (uint64, error) { + pendingNonce, err := nm.transactor.PendingNonceAt( + context.TODO(), + nm.account, + ) + if err != nil { + return 0, err + } + + now := time.Now() + + if pendingNonce < nm.localNonce { + if now.Before(nm.expirationDate) { + logger.Infof( + "local nonce [%v] is higher than pending [%v]; using the local one", + nm.localNonce, + pendingNonce, + ) + } else { + logger.Infof( + "local nonce [%v] is higher than pending [%v] but local "+ + "nonce expired; updating local nonce", + nm.localNonce, + pendingNonce, + ) + + nm.localNonce = pendingNonce + } + } + + // After localNonceTrustDuration of inactivity (no CurrentNonce() calls), + // the local copy is considered as no longer up-to-date and it's always + // reset to the pending nonce value as seen by the chain. + // + // We do it to recover from potential mempool crashes. + // + // Keep in mind, the local copy is considered valid as long as transactions + // are submitted one after another. + nm.expirationDate = now.Add(localNonceTrustDuration) + + if pendingNonce > nm.localNonce { + logger.Infof( + "local nonce [%v] is lower than pending [%v]; updating local nonce", + nm.localNonce, + pendingNonce, + ) + + nm.localNonce = pendingNonce + } + + return nm.localNonce, nil +} + +// IncrementNonce increments the value of the nonce kept locally by one. +// This function is NOT safe for concurrent use. It is up to the client code +// using this function to provide the required synchronization. +func (nm *NonceManager) IncrementNonce() uint64 { + nm.localNonce++ + return nm.localNonce +} diff --git a/pkg/chain/ethereumutil/nonce_manager_test.go b/pkg/chain/ethereumutil/nonce_manager_test.go new file mode 100644 index 0000000000..efd5c3eb27 --- /dev/null +++ b/pkg/chain/ethereumutil/nonce_manager_test.go @@ -0,0 +1,91 @@ +package ethereum + +import ( + "context" + "testing" + "time" +) + +func TestResolveAndIncrement(t *testing.T) { + tests := map[string]struct { + pendingNonce uint64 + localNonce uint64 + expirationDate time.Time + expectedNonce uint64 + expectedNextNonce uint64 + }{ + "pending and local the same": { + pendingNonce: 10, + localNonce: 10, + expirationDate: time.Now().Add(time.Second), + expectedNonce: 10, + expectedNextNonce: 11, + }, + "pending nonce higher": { + pendingNonce: 121, + localNonce: 120, + expirationDate: time.Now().Add(time.Second), + expectedNonce: 121, + expectedNextNonce: 122, + }, + "pending nonce lower": { + pendingNonce: 110, + localNonce: 111, + expirationDate: time.Now().Add(time.Second), + expectedNonce: 111, + expectedNextNonce: 112, + }, + "pending nonce lower and local one expired": { + pendingNonce: 110, + localNonce: 111, + expirationDate: time.Now().Add(-1 * time.Second), + expectedNonce: 110, + expectedNextNonce: 111, + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + transactor := &mockContractTransactor{test.pendingNonce} + manager := &NonceManager{ + transactor: transactor, + localNonce: test.localNonce, + expirationDate: test.expirationDate, + } + + nonce, err := manager.CurrentNonce() + if err != nil { + t.Fatal(err) + } + + if nonce != test.expectedNonce { + t.Errorf( + "unexpected nonce\nexpected: [%v]\nactual: [%v]", + test.expectedNonce, + nonce, + ) + } + + nextNonce := manager.IncrementNonce() + + if nextNonce != test.expectedNextNonce { + t.Errorf( + "unexpected nonce\nexpected: [%v]\nactual: [%v]", + test.expectedNextNonce, + nextNonce, + ) + } + }) + } +} + +type mockContractTransactor struct { + nextNonce uint64 +} + +func (mct *mockContractTransactor) PendingNonceAt( + ctx context.Context, + account Address, +) (uint64, error) { + return mct.nextNonce, nil +} diff --git a/pkg/chain/ethereumutil/subscribe_opts.go b/pkg/chain/ethereumutil/subscribe_opts.go new file mode 100644 index 0000000000..5507d800bf --- /dev/null +++ b/pkg/chain/ethereumutil/subscribe_opts.go @@ -0,0 +1,23 @@ +package ethereum + +import "time" + +// SubscribeOpts specifies optional configuration options that can be passed +// when creating Ethereum event subscription. +type SubscribeOpts struct { + + // Tick is the duration with which subscription monitoring mechanism + // pulls events from the chain. This mechanism is an additional process + // next to a regular watchLogs subscription making sure no events are lost + // even in case the regular subscription missed them because of, for + // example, connectivity problems. + Tick time.Duration + + // PastBlocks is the number of past blocks subscription monitoring mechanism + // takes into consideration when pulling past events from the chain. + // This event pull mechanism is an additional process next to a regular + // watchLogs subscription making sure no events are lost even in case the + // regular subscription missed them because of, for example, connectivity + // problems. + PastBlocks uint64 +} diff --git a/pkg/chain/ethereumutil/token.go b/pkg/chain/ethereumutil/token.go new file mode 100644 index 0000000000..f6ed04649e --- /dev/null +++ b/pkg/chain/ethereumutil/token.go @@ -0,0 +1,110 @@ +package ethereum + +import ( + "fmt" + "math/big" + "regexp" + "sort" + "strings" +) + +// Token represents a token. +type Token struct { + *big.Int +} + +// UnmarshalToken is a function used to parse an Ethereum token. +func (t *Token) UnmarshalToken(text []byte, units map[string]int64) error { + re := regexp.MustCompile(`^(\d+[\.]?[\d]*)[ ]?([\w]*)$`) + matched := re.FindSubmatch(text) + + if len(matched) != 3 { + return fmt.Errorf("failed to parse value: [%s]", text) + } + + number, ok := new(big.Float).SetString(string(matched[1])) + if !ok { + return fmt.Errorf( + "failed to set float value from string [%s]", + string(matched[1]), + ) + } + + unit := matched[2] + if len(unit) == 0 { + for unitName, factor := range units { + // set the unit to the default one + if factor == 1 { + unit = []byte(unitName) + break + } + } + + if len(unit) == 0 { + return fmt.Errorf("could not determine default unit") + } + } + + if factor, ok := units[strings.ToLower(string(unit))]; ok { + number.Mul(number, new(big.Float).SetInt64(factor)) + t.Int, _ = number.Int(nil) + return nil + } + + unitNames := make([]string, 0) + for unitName := range units { + unitNames = append(unitNames, unitName) + } + + sort.Strings(unitNames) + + return fmt.Errorf( + "invalid unit: %s; please use one of: %v", + unit, + strings.Join(unitNames, ", "), + ) +} + +// MarshalToken is a function used to marshall an Ethereum token. +func (t *Token) MarshalToken(units map[string]int64) string { + if t.Int == nil { + return "" + } + + sortedUnits := make([]string, 0, len(units)) + for unit := range units { + sortedUnits = append(sortedUnits, unit) + } + + sort.Slice(sortedUnits, func(i, j int) bool { + return units[sortedUnits[i]] > units[sortedUnits[j]] + }) + + result := t.Int.String() + for _, unit := range sortedUnits { + unitInt := big.NewInt(units[unit]) + + if t.Int.Cmp(unitInt) >= 0 { + truncated := big.NewInt(0) + reminder := big.NewInt(0) + + truncated.QuoRem(t.Int, unitInt, reminder) + + if reminder.Cmp(big.NewInt(0)) > 0 { + result = fmt.Sprintf( + "%s.%s %s", + truncated.String(), + strings.TrimRight(reminder.String(), "0"), + unit, + ) + + } else { + result = fmt.Sprintf("%s %s", truncated.String(), unit) + } + + break + } + } + + return result +} diff --git a/pkg/chain/ethereumutil/wei.go b/pkg/chain/ethereumutil/wei.go new file mode 100644 index 0000000000..f7823ac892 --- /dev/null +++ b/pkg/chain/ethereumutil/wei.go @@ -0,0 +1,35 @@ +package ethereum + +import ( + "math/big" +) + +// Units defines denominations of the Ether token. +var Units = map[string]int64{ + "wei": 1, // default unit + "gwei": 1e9, + "ether": 1e18, +} + +// Wei is a custom type to handle Ether value parsing in configuration files +// using BurntSushi/toml package. It supports wei, Gwei and ether units. The +// Ether value is kept as `wei` and `wei` is the default unit. +// The value can be provided in the text file as e.g.: `1 wei`, `200 Gwei` or +// `0.5 ether`. +type Wei struct { + Token +} + +// WrapWei wraps the given integer value in order to represent it as Wei value. +func WrapWei(value *big.Int) *Wei { + return &Wei{Token{value}} +} + +// UnmarshalText is a function used to parse a value of Ethers. +func (w *Wei) UnmarshalText(text []byte) error { + return w.UnmarshalToken(text, Units) +} + +func (w *Wei) String() string { + return w.Token.MarshalToken(Units) +} diff --git a/pkg/chain/ethereumutil/wei_test.go b/pkg/chain/ethereumutil/wei_test.go new file mode 100644 index 0000000000..8078463255 --- /dev/null +++ b/pkg/chain/ethereumutil/wei_test.go @@ -0,0 +1,233 @@ +package ethereum + +import ( + "fmt" + "math/big" + "reflect" + "testing" +) + +var int5000ether, _ = new(big.Int).SetString("5000000000000000000000", 10) + +func TestUnmarshalTextValue(t *testing.T) { + var tests = map[string]struct { + value string + expectedResult *big.Int + expectedError error + }{ + "decimal value": { + value: "0.9", + expectedResult: big.NewInt(0), + }, + "lowest value": { + value: "1", + expectedResult: big.NewInt(1), + }, + "missing unit": { + value: "702", + expectedResult: big.NewInt(702), + }, + "unit: wei": { + value: "4 wei", + expectedResult: big.NewInt(4), + }, + "unit: gwei": { + value: "30 gwei", + expectedResult: big.NewInt(30000000000), + }, + "unit: ether": { + value: "2 ether", + expectedResult: big.NewInt(2000000000000000000), + }, + "unit: mixed case": { + value: "5 GWei", + expectedResult: big.NewInt(5000000000), + }, + "decimal wei": { + value: "2.9 wei", + expectedResult: big.NewInt(2), + }, + "decimal ether": { + value: "0.8 ether", + expectedResult: big.NewInt(800000000000000000), + }, + "multiple decimal digits": { + value: "5.6789 Gwei", + expectedResult: big.NewInt(5678900000), + }, + "missing decimal digit": { + value: "6. Gwei", + expectedResult: big.NewInt(6000000000), + }, + "no space": { + value: "9ether", + expectedResult: big.NewInt(9000000000000000000), + }, + "int overflow amount": { + value: "5000000000000000000000", + expectedResult: int5000ether, + }, + "int overflow amount after conversion": { + value: "5000 ether", + expectedResult: int5000ether, + }, + "double space": { + value: "100 Gwei", + expectedError: fmt.Errorf("failed to parse value: [100 Gwei]"), + }, + "leading space": { + value: " 3 wei", + expectedError: fmt.Errorf("failed to parse value: [ 3 wei]"), + }, + "trailing space": { + value: "3 wei ", + expectedError: fmt.Errorf("failed to parse value: [3 wei ]"), + }, + "invalid comma delimiter": { + value: "3,5 ether", + expectedError: fmt.Errorf("failed to parse value: [3,5 ether]"), + }, + "only decimal number": { + value: ".7 Gwei", + expectedError: fmt.Errorf("failed to parse value: [.7 Gwei]"), + }, + "duplicated delimeters": { + value: "3..4 wei", + expectedError: fmt.Errorf("failed to parse value: [3..4 wei]"), + }, + "multiple decimals": { + value: "3.4.5 wei", + expectedError: fmt.Errorf("failed to parse value: [3.4.5 wei]"), + }, + "invalid thousand separator": { + value: "4 500 gwei", + expectedError: fmt.Errorf("failed to parse value: [4 500 gwei]"), + }, + "two values": { + value: "3 wei2wei", + expectedError: fmt.Errorf("invalid unit: wei2wei; please use one of: ether, gwei, wei"), + }, + "two values separated with space": { + value: "3 wei 2wei", + expectedError: fmt.Errorf("failed to parse value: [3 wei 2wei]"), + }, + "two values separated with break line": { + value: "3 wei\n2wei", + expectedError: fmt.Errorf("failed to parse value: [3 wei\n2wei]"), + }, + "invalid unit: ETH": { + value: "6 ETH", + expectedError: fmt.Errorf("invalid unit: ETH; please use one of: ether, gwei, wei"), + }, + "invalid unit: weinot": { + value: "100 weinot", + expectedError: fmt.Errorf("invalid unit: weinot; please use one of: ether, gwei, wei"), + }, + "invalid unit: notawei": { + value: "100 notawei", + expectedError: fmt.Errorf("invalid unit: notawei; please use one of: ether, gwei, wei"), + }, + "only unit": { + value: "wei", + expectedError: fmt.Errorf("failed to parse value: [wei]"), + }, + "invalid number": { + value: "one wei", + expectedError: fmt.Errorf("failed to parse value: [one wei]"), + }, + } + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + w := Wei{} + err := w.UnmarshalText([]byte(test.value)) + if test.expectedError != nil { + if !reflect.DeepEqual(test.expectedError, err) { + t.Errorf( + "invalid error\nexpected: %v\nactual: %v", + test.expectedError, + err, + ) + } + } else if err != nil { + t.Errorf("unexpected error: %v", err) + } + + if test.expectedResult != nil && test.expectedResult.Cmp(w.Int) != 0 { + t.Errorf( + "invalid value\nexpected: %v\nactual: %v", + test.expectedResult.String(), + w.Int.String(), + ) + } + }) + } +} + +func TestMarshallTextValue(t *testing.T) { + // Test units are defined not in order to verify if the MarshallText function + // sorts them correctly. + var testUnits = map[string]int64{ + "wei": 1, // default unit + "ether": 1e18, + "gwei": 1e9, + } + + var tests = map[string]struct { + value *big.Int + expectedResult string + expectedError error + }{ + "zero": { + value: big.NewInt(0), + expectedResult: "0", + }, + "wei min": { + value: big.NewInt(1), + expectedResult: "1 wei", + }, + "wei max": { + value: big.NewInt(999_999_999), + expectedResult: "999999999 wei", + }, + "gwei min": { + value: big.NewInt(1e9), + expectedResult: "1 gwei", + }, + "gwei max": { + value: big.NewInt(999999999000000000), + expectedResult: "999999999 gwei", + }, + "gwei max with remainder": { + value: big.NewInt(999999999999999999), + expectedResult: "999999999.999999999 gwei", + }, + "ether min": { + value: big.NewInt(1e18), + expectedResult: "1 ether", + }, + "ether with remainder": { + value: big.NewInt(7654300000000000000), + expectedResult: "7.6543 ether", + }, + "ether 5000": { + value: int5000ether, + expectedResult: "5000 ether", + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + w := &Wei{Token: Token{test.value}} + + result := w.MarshalToken(testUnits) + + if test.expectedResult != result { + t.Errorf( + "invalid result\nexpected: %v\nactual: %v", + test.expectedResult, + result, + ) + } + }) + } +} diff --git a/pkg/chain/local/signer.go b/pkg/chain/local/signer.go new file mode 100644 index 0000000000..53f7a78124 --- /dev/null +++ b/pkg/chain/local/signer.go @@ -0,0 +1,112 @@ +package local + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/sha256" + "encoding/asn1" + "fmt" + "math/big" +) + +// Signer provides functions to sign a message and verify a signature +// using the chain-specific signature format. It also provides functions for +// convertion of a public key to address. +type Signer struct { + operatorKey *ecdsa.PrivateKey +} + +type ecdsaSignature struct { + R, S *big.Int +} + +// NewSigner creates a new Signer instance for the provided private key. +func NewSigner(privateKey *ecdsa.PrivateKey) *Signer { + return &Signer{privateKey} +} + +// PublicKey returns byte representation of a public key for the private key +// signer was created with. +func (ls *Signer) PublicKey() []byte { + publicKey := ls.operatorKey.PublicKey + return elliptic.Marshal(publicKey.Curve, publicKey.X, publicKey.Y) +} + +// Sign signs the provided message. +func (ls *Signer) Sign(message []byte) ([]byte, error) { + hash := sha256.Sum256(message) + + r, s, err := ecdsa.Sign(rand.Reader, ls.operatorKey, hash[:]) + if err != nil { + return nil, err + } + + return asn1.Marshal(ecdsaSignature{r, s}) +} + +// Verify verifies the provided message against a signature using the key +// Signer was created with. +func (ls *Signer) Verify(message []byte, signature []byte) (bool, error) { + return verifySignature(message, signature, &ls.operatorKey.PublicKey) +} + +// VerifyWithPublicKey verifies the provided message against a signature and +// public key. +func (ls *Signer) VerifyWithPublicKey( + message []byte, + signature []byte, + publicKey []byte, +) (bool, error) { + unmarshalledPubKey, err := unmarshalPublicKey( + publicKey, + ls.operatorKey.Curve, + ) + if err != nil { + return false, fmt.Errorf("failed to unmarshal public key: [%v]", err) + } + + return verifySignature(message, signature, unmarshalledPubKey) +} + +func verifySignature( + message []byte, + signature []byte, + publicKey *ecdsa.PublicKey, +) (bool, error) { + hash := sha256.Sum256(message) + + sig := &ecdsaSignature{} + _, err := asn1.Unmarshal(signature, sig) + if err != nil { + return false, fmt.Errorf("failed to unmarshal signature: [%v]", err) + } + + return ecdsa.Verify(publicKey, hash[:], sig.R, sig.S), nil +} + +func unmarshalPublicKey( + bytes []byte, + curve elliptic.Curve, +) (*ecdsa.PublicKey, error) { + x, y := elliptic.Unmarshal(curve, bytes) + if x == nil { + return nil, fmt.Errorf( + "invalid public key bytes", + ) + } + ecdsaPublicKey := &ecdsa.PublicKey{Curve: curve, X: x, Y: y} + return (*ecdsa.PublicKey)(ecdsaPublicKey), nil +} + +// PublicKeyToAddress transforms the provided ECDSA public key into chain +// address represented in bytes. +func (ls *Signer) PublicKeyToAddress(publicKey ecdsa.PublicKey) []byte { + return elliptic.Marshal(publicKey.Curve, publicKey.X, publicKey.Y) +} + +// PublicKeyBytesToAddress transforms the provided ECDSA public key in a bytes +// format into chain address represented in bytes. +func (ls *Signer) PublicKeyBytesToAddress(publicKey []byte) []byte { + return publicKey +} diff --git a/pkg/chain/local/signer_test.go b/pkg/chain/local/signer_test.go new file mode 100644 index 0000000000..a92359266f --- /dev/null +++ b/pkg/chain/local/signer_test.go @@ -0,0 +1,166 @@ +package local + +import ( + "crypto/ecdsa" + "crypto/elliptic" + crand "crypto/rand" + "testing" +) + +func TestSignAndVerify(t *testing.T) { + message := []byte("Two things only the greatest fools do: throw " + + "stones at hornets' nests and threaten a witcher.") + + signer, err := newSigner() + if err != nil { + t.Fatal(err) + } + + signature, err := signer.Sign(message) + if err != nil { + t.Fatal(err) + } + + var tests = map[string]struct { + message []byte + signature []byte + validSignatureExpected bool + validationErrorExpected bool + }{ + "valid signature for message": { + message: message, + signature: signature, + validSignatureExpected: true, + validationErrorExpected: false, + }, + "invalid signature for message": { + message: []byte("I am sorry"), + signature: signature, + validSignatureExpected: false, + validationErrorExpected: false, + }, + "corrupted signature": { + message: message, + signature: []byte("I am so sorry"), + validSignatureExpected: false, + validationErrorExpected: true, + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + ok, err := signer.Verify(test.message, test.signature) + + if !ok && test.validSignatureExpected { + t.Errorf("expected valid signature but verification failed") + } + if ok && !test.validSignatureExpected { + t.Errorf("expected invalid signature but verification succeeded") + } + + if err == nil && test.validationErrorExpected { + t.Errorf("expected signature validation error; none happened") + } + if err != nil && !test.validationErrorExpected { + t.Errorf("unexpected signature validation error [%v]", err) + } + }) + } +} + +func TestSignAndVerifyWithProvidedPublicKey(t *testing.T) { + message := []byte("You shall not pass") + + signer1, err := newSigner() + if err != nil { + t.Fatal(err) + } + + signer2, err := newSigner() + if err != nil { + t.Fatal(err) + } + + publicKey := signer1.PublicKey() + signature, err := signer1.Sign(message) + if err != nil { + t.Fatal(err) + } + + var tests = map[string]struct { + message []byte + signature []byte + publicKey []byte + validSignatureExpected bool + validationErrorExpected bool + }{ + "valid signature for message": { + message: message, + signature: signature, + publicKey: publicKey, + validSignatureExpected: true, + validationErrorExpected: false, + }, + "invalid signature for message": { + message: []byte("Fly you fools"), + signature: signature, + publicKey: publicKey, + validSignatureExpected: false, + validationErrorExpected: false, + }, + "corrupted signature": { + message: message, + signature: []byte("My precious"), + publicKey: publicKey, + validSignatureExpected: false, + validationErrorExpected: true, + }, + "invalid remote public key": { + message: message, + signature: signature, + publicKey: signer2.PublicKey(), + validSignatureExpected: false, + validationErrorExpected: false, + }, + "corrupted remote public key": { + message: message, + signature: signature, + publicKey: []byte("A Balrog"), + validSignatureExpected: false, + validationErrorExpected: true, + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + ok, err := signer2.VerifyWithPublicKey( + test.message, + test.signature, + test.publicKey, + ) + + if !ok && test.validSignatureExpected { + t.Errorf("expected valid signature but verification failed") + } + if ok && !test.validSignatureExpected { + t.Errorf("expected invalid signature but verification succeeded") + } + + if err == nil && test.validationErrorExpected { + t.Errorf("expected signature validation error; none happened") + } + if err != nil && !test.validationErrorExpected { + t.Errorf("unexpected signature validation error [%v]", err) + } + }) + } +} + +func newSigner() (*Signer, error) { + key, err := ecdsa.GenerateKey(elliptic.P256(), crand.Reader) + if err != nil { + return nil, err + } + + return &Signer{key}, nil +} diff --git a/pkg/chain/local_v1/local.go b/pkg/chain/local_v1/local.go index 6715634ab2..a0f377f0df 100644 --- a/pkg/chain/local_v1/local.go +++ b/pkg/chain/local_v1/local.go @@ -188,7 +188,8 @@ func ConnectWithKey( GroupSize: groupSize, HonestThreshold: honestThreshold, ResultPublicationBlockStep: resultPublicationBlockStep, - RelayEntryTimeout: resultPublicationBlockStep * uint64(groupSize), + // #nosec G115 -- Local test-chain callers supply a nonnegative protocol group size. + RelayEntryTimeout: resultPublicationBlockStep * uint64(groupSize), }, relayEntryHandlers: make(map[int]func(request *event.RelayEntrySubmitted)), relayRequestHandlers: make(map[int]func(request *event.RelayEntryRequested)), diff --git a/pkg/chain/local_v1/local_test.go b/pkg/chain/local_v1/local_test.go index f061f9a6e8..5dac86840b 100644 --- a/pkg/chain/local_v1/local_test.go +++ b/pkg/chain/local_v1/local_test.go @@ -1,6 +1,7 @@ package local_v1 import ( + "bytes" "context" "fmt" "math/big" @@ -17,10 +18,20 @@ import ( func TestLocalSubmitRelayEntry(t *testing.T) { chainHandle := Connect(10, 4) - err := chainHandle.SubmitRelayEntry(big.NewInt(19).Bytes()) + expectedEntry := big.NewInt(19).Bytes() + err := chainHandle.SubmitRelayEntry(expectedEntry) if err != nil { t.Fatal(err) } + + actualEntry := chainHandle.GetLastRelayEntry() + if !bytes.Equal(expectedEntry, actualEntry) { + t.Fatalf( + "unexpected last relay entry\nexpected: [%x]\nactual: [%x]", + expectedEntry, + actualEntry, + ) + } } func TestLocalOnEntrySubmitted(t *testing.T) { diff --git a/pkg/chain/local_v1/signer.go b/pkg/chain/local_v1/signer.go index 7bf215cc38..6bb238e60a 100644 --- a/pkg/chain/local_v1/signer.go +++ b/pkg/chain/local_v1/signer.go @@ -4,12 +4,12 @@ import ( "encoding/hex" "fmt" - commonlocal "github.com/keep-network/keep-common/pkg/chain/local" "github.com/keep-network/keep-core/pkg/chain" + commonlocal "github.com/keep-network/keep-core/pkg/chain/local" "github.com/keep-network/keep-core/pkg/operator" ) -// TODO: Consider moving the local `Signer` out of `keep-common` to this file. +// TODO: Consider moving the local `Signer` out of `pkg/chain/local` to this file. type signer struct { *commonlocal.Signer } diff --git a/pkg/clientinfo/clientinfo.go b/pkg/clientinfo/clientinfo.go index 7848aa0ec7..bf29882b62 100644 --- a/pkg/clientinfo/clientinfo.go +++ b/pkg/clientinfo/clientinfo.go @@ -1,16 +1,41 @@ +// Package clientinfo provides tools for gathering and exposing system +// metrics and diagnostics for external monitoring tools. +// +// Currently, this package is intended to use with Prometheus but can be +// easily extended if needed. Also, not all Prometheus metric types are +// implemented. +// +// Following specifications were used as reference: +// - https://prometheus.io/docs/instrumenting/writing_clientlibs/ +// - https://prometheus.io/docs/instrumenting/exposition_formats/ +// +// pprof handlers are intentionally served from a private ServeMux built +// per-Registry so the EnablePprof flag fully controls their reachability. +// Importing net/http/pprof also registers those handlers on +// http.DefaultServeMux at init time as a side effect; nothing in this +// package serves DefaultServeMux, so the registration is currently +// dormant. Do not add http.ListenAndServe(":port", nil) (or any other +// nil-handler Listen call) to this package or its consumers: that would +// expose pprof on the new listener regardless of the EnablePprof flag. package clientinfo import ( "context" + "io" + "net/http" + "net/http/pprof" + "sort" + "strconv" + "sync" "time" "github.com/ipfs/go-log" - - "github.com/keep-network/keep-common/pkg/clientinfo" ) var logger = log.Logger("keep-clientinfo") +const readHeaderTimeout = 2 * time.Second + // Config stores configuration for the client info. type Config struct { Port int @@ -18,29 +43,143 @@ type Config struct { EthereumMetricsTick time.Duration BitcoinMetricsTick time.Duration RPCHealthCheckInterval time.Duration + // EnablePprof exposes Go runtime profiling endpoints at /debug/pprof/ on + // the clientinfo port. Requires Port != 0. Never expose to untrusted + // networks; bind behind a firewall or restrict with an SSH tunnel. + EnablePprof bool } -// Registry wraps keep-common clientinfo registry and exposes additional -// functions for registering client-custom metrics and diagnostics +// Registry performs all management of metrics and diagnostics. Specifically, +// it allows registering and exposing them through the HTTP server, and +// exposes additional functions for registering client-custom metrics and +// diagnostics. type Registry struct { - *clientinfo.Registry - ctx context.Context + + metrics map[string]metric + metricsMutex sync.RWMutex + + diagnosticsSources map[string]func() string + diagnosticsMutex sync.RWMutex +} + +// newRegistry creates a new client info registry bound to ctx. +func newRegistry(ctx context.Context) *Registry { + return &Registry{ + ctx: ctx, + metrics: make(map[string]metric), + diagnosticsSources: make(map[string]func() string), + } } // Initialize set up the client info registry and enables metrics and // diagnostics server. func Initialize( ctx context.Context, - port int, + cfg Config, ) (*Registry, bool) { - if port == 0 { + if cfg.Port == 0 { + if cfg.EnablePprof { + // Enabling pprof without a port would be silently ignored because + // no server is started; surface the misconfiguration instead. + logger.Warnf( + "EnablePprof is set but Port is 0; no server is started and " + + "profiling endpoints will not be exposed", + ) + } return nil, false } - registry := &Registry{clientinfo.NewRegistry(), ctx} + registry := newRegistry(ctx) - registry.EnableServer(port) + registry.enableServer(cfg.Port, cfg.EnablePprof) return registry, true } + +// registerPprofHandlers registers the standard net/http/pprof handlers on +// the provided ServeMux when EnablePprof is true. See the package doc for +// the dormant DefaultServeMux side-effect warning. +func registerPprofHandlers(mux *http.ServeMux) { + mux.HandleFunc("/debug/pprof/", pprof.Index) + mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) + mux.HandleFunc("/debug/pprof/profile", pprof.Profile) + mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) + mux.HandleFunc("/debug/pprof/trace", pprof.Trace) +} + +// newServeMux builds the HTTP handler served on the client info port. +// +// The mux is created per call and never shared with http.DefaultServeMux. +// That isolation is load-bearing for two reasons: importing net/http/pprof +// registers /debug/pprof/* on DefaultServeMux from that package's init +// regardless of how it is imported, so serving DefaultServeMux would expose +// profiling endpoints even when disabled; and registering this registry's own +// routes on a process-global mux makes a second registry panic on duplicate +// patterns. +func (r *Registry) newServeMux(enablePprof bool) *http.ServeMux { + mux := http.NewServeMux() + + mux.HandleFunc("/metrics", func(response http.ResponseWriter, _ *http.Request) { + if _, err := io.WriteString(response, r.exposeMetrics()); err != nil { + logger.Errorf("could not write response: [%v]", err) + } + }) + + mux.HandleFunc("/diagnostics", func(response http.ResponseWriter, _ *http.Request) { + if _, err := io.WriteString(response, r.exposeDiagnostics()); err != nil { + logger.Errorf("could not write response: [%v]", err) + } + }) + + if enablePprof { + registerPprofHandlers(mux) + logger.Infof("pprof profiling endpoints enabled at /debug/pprof/") + } + + return mux +} + +func (r *Registry) newServer(port int, enablePprof bool) *http.Server { + return &http.Server{ + Addr: ":" + strconv.Itoa(port), + Handler: r.newServeMux(enablePprof), + ReadHeaderTimeout: readHeaderTimeout, + } +} + +// enableServer starts the client info HTTP server, exposing the profiling +// endpoints only when enablePprof is true. +func (r *Registry) enableServer(port int, enablePprof bool) { + server := r.newServer(port, enablePprof) + + go func() { + if err := server.ListenAndServe(); err != http.ErrServerClosed { + logger.Errorf("client info server error: [%v]", err) + } + }() +} + +// EnableServer enables the client info server on the given port. Data will +// be exposed on `/metrics` and `/diagnostics` paths. pprof profiling +// endpoints are NOT enabled by this method; prefer Initialize, which +// threads the EnablePprof flag from the caller-supplied Config and never +// exposes pprof unless explicitly requested. +// +// Deprecated: prefer Initialize; this method exists for backwards +// compatibility but always disables pprof. The previous behavior of +// implicitly exposing pprof via http.DefaultServeMux is no longer relied on. +func (r *Registry) EnableServer(port int) { + r.enableServer(port, false) +} + +func sortedKeys[V any](m map[string]V) []string { + keys := make([]string, len(m)) + i := 0 + for k := range m { + keys[i] = k + i++ + } + sort.Strings(keys) + return keys +} diff --git a/pkg/clientinfo/gauge.go b/pkg/clientinfo/gauge.go new file mode 100644 index 0000000000..8bfd964f51 --- /dev/null +++ b/pkg/clientinfo/gauge.go @@ -0,0 +1,53 @@ +package clientinfo + +import ( + "fmt" + "strings" + "sync" + "time" +) + +// Gauge is a metric type that represents a single numerical value that can +// arbitrarily go up and down. +type Gauge struct { + name string + labels map[string]string + + value float64 + timestamp int64 // timestamp expressed as milliseconds + mutex sync.RWMutex +} + +// Set allows setting the gauge to an arbitrary value. +func (g *Gauge) Set(value float64) { + g.mutex.Lock() + defer g.mutex.Unlock() + + g.value = value + g.timestamp = time.Now().UnixNano() / 1e6 +} + +// Exposes the gauge in the text-based exposition format. +func (g *Gauge) expose() string { + g.mutex.RLock() + defer g.mutex.RUnlock() + + typeLine := fmt.Sprintf("# TYPE %v %v", g.name, "gauge") + + labelsStrings := make([]string, 0) + for name, value := range g.labels { + labelsStrings = append( + labelsStrings, + fmt.Sprintf("%v=\"%v\"", name, value), + ) + } + labels := strings.Join(labelsStrings, ",") + + if len(labels) > 0 { + labels = "{" + labels + "}" + } + + body := fmt.Sprintf("%v%v %v %v", g.name, labels, g.value, g.timestamp) + + return fmt.Sprintf("%v\n%v", typeLine, body) +} diff --git a/pkg/clientinfo/gauge_test.go b/pkg/clientinfo/gauge_test.go new file mode 100644 index 0000000000..67036a0b74 --- /dev/null +++ b/pkg/clientinfo/gauge_test.go @@ -0,0 +1,84 @@ +package clientinfo + +import ( + "testing" +) + +func TestGaugeSet(t *testing.T) { + gauge := &Gauge{ + name: "test_gauge", + labels: map[string]string{"label": "value"}, + } + + if gauge.value != 0 { + t.Fatal("incorrect gauge initial value") + } + + if gauge.timestamp != 0 { + t.Fatal("incorrect gauge initial timestamp") + } + + newGaugeValue := float64(500) + + gauge.Set(newGaugeValue) + + if gauge.value != newGaugeValue { + t.Fatalf( + "incorrect gauge value:\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + newGaugeValue, + gauge.value, + ) + } + + if gauge.timestamp == 0 { + t.Fatal("timestamp should be set") + } +} + +func TestGaugeExpose(t *testing.T) { + gauge := &Gauge{ + name: "test_gauge", + labels: map[string]string{"label": "value"}, + value: 500, + timestamp: 1000, + } + + actualText := gauge.expose() + + expectedText := "# TYPE test_gauge gauge\ntest_gauge{label=\"value\"} 500 1000" + + if actualText != expectedText { + t.Fatalf( + "incorrect gauge expose text:\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + expectedText, + actualText, + ) + } +} + +func TestGaugeWithoutLabelsExpose(t *testing.T) { + gauge := &Gauge{ + name: "test_gauge", + labels: map[string]string{}, + value: 500, + timestamp: 1000, + } + + actualText := gauge.expose() + + expectedText := "# TYPE test_gauge gauge\ntest_gauge 500 1000" + + if actualText != expectedText { + t.Fatalf( + "incorrect gauge expose text:\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + expectedText, + actualText, + ) + } +} diff --git a/pkg/clientinfo/info.go b/pkg/clientinfo/info.go new file mode 100644 index 0000000000..b46718d40c --- /dev/null +++ b/pkg/clientinfo/info.go @@ -0,0 +1,27 @@ +package clientinfo + +import ( + "fmt" + "strings" +) + +// Info is a metric type that represents a constant information +// that cannot change in the time. +type Info struct { + name string + labels map[string]string +} + +// Exposes the info in the text-based exposition format. +func (i *Info) expose() string { + labelsStrings := make([]string, 0) + for name, value := range i.labels { + labelsStrings = append( + labelsStrings, + fmt.Sprintf("%v=\"%v\"", name, value), + ) + } + labels := strings.Join(labelsStrings, ",") + + return fmt.Sprintf("%v{%v} %v", i.name, labels, "1") +} diff --git a/pkg/clientinfo/info_test.go b/pkg/clientinfo/info_test.go new file mode 100644 index 0000000000..582511d49f --- /dev/null +++ b/pkg/clientinfo/info_test.go @@ -0,0 +1,24 @@ +package clientinfo + +import "testing" + +func TestInfoExpose(t *testing.T) { + info := &Info{ + name: "test_info", + labels: map[string]string{"label": "value"}, + } + + actualText := info.expose() + + expectedText := "test_info{label=\"value\"} 1" + + if actualText != expectedText { + t.Fatalf( + "incorrect gauge expose text:\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + expectedText, + actualText, + ) + } +} diff --git a/pkg/clientinfo/metrics.go b/pkg/clientinfo/metrics.go index 91af36bcd8..f8d8381720 100644 --- a/pkg/clientinfo/metrics.go +++ b/pkg/clientinfo/metrics.go @@ -5,7 +5,6 @@ import ( "strings" "time" - "github.com/keep-network/keep-common/pkg/clientinfo" "github.com/keep-network/keep-core/pkg/bitcoin" "github.com/keep-network/keep-core/pkg/chain" "github.com/keep-network/keep-core/pkg/net" @@ -148,8 +147,8 @@ func (r *Registry) ObserveApplicationSource( func (r *Registry) RegisterMetricClientInfo(version string) { _, err := r.NewMetricInfo( ClientInfoMetricName, - []clientinfo.Label{ - clientinfo.NewLabel("version", version), + []Label{ + NewLabel("version", version), }, ) if err != nil { @@ -162,7 +161,7 @@ func (r *Registry) observe( input Source, tick time.Duration, ) { - observer, err := r.NewMetricGaugeObserver(name, clientinfo.MetricObserverInput(input)) + observer, err := r.NewMetricGaugeObserver(name, MetricObserverInput(input)) if err != nil { // Check if the error is due to metric already existing (expected in some cases) errStr := err.Error() diff --git a/pkg/clientinfo/metrics_test.go b/pkg/clientinfo/metrics_test.go index 18769a8e0d..114ad64715 100644 --- a/pkg/clientinfo/metrics_test.go +++ b/pkg/clientinfo/metrics_test.go @@ -2,10 +2,10 @@ package clientinfo import ( "context" + "strings" "testing" "time" - keepclientinfo "github.com/keep-network/keep-common/pkg/clientinfo" "github.com/keep-network/keep-core/pkg/net" "github.com/keep-network/keep-core/pkg/operator" ) @@ -56,13 +56,15 @@ func (m *mockProvider) CreateTransportIdentifier( } func (m *mockProvider) BroadcastChannelForwarderFor(string) {} -// TestObserveConnectedWellknownPeersCount_Callable verifies that the renamed -// function exists on the Registry type and can be called without panicking. -func TestObserveConnectedWellknownPeersCount_Callable(t *testing.T) { +// TestObserveConnectedWellknownPeersCount verifies that the +// connected_wellknown_peers_count gauge reflects only the wellknown peers that +// are actually connected. Asserting merely that the call does not panic left +// the counting loop - the one piece of logic here - unverified. +func TestObserveConnectedWellknownPeersCount(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - registry := &Registry{keepclientinfo.NewRegistry(), ctx} + registry := newRegistry(ctx) provider := &mockProvider{ connectionManager: &mockConnectionManager{ @@ -72,20 +74,39 @@ func TestObserveConnectedWellknownPeersCount_Callable(t *testing.T) { }, } - // The function should execute without panic. We use a recovered call - // to detect if the method does not exist or panics. - defer func() { - if r := recover(); r != nil { - t.Fatalf( - "ObserveConnectedWellknownPeersCount panicked: %v", - r, - ) - } - }() - registry.ObserveConnectedWellknownPeersCount( provider, - []string{"/ip4/127.0.0.1/tcp/3919"}, + []string{ + "/ip4/127.0.0.1/tcp/3919", // connected + "/ip4/10.0.0.1/tcp/1", // not connected + }, 1*time.Minute, ) + + registry.metricsMutex.RLock() + gauge, ok := registry.metrics[ConnectedWellknownPeersCountMetricName].(*Gauge) + registry.metricsMutex.RUnlock() + if !ok { + t.Fatal("connected_wellknown_peers_count gauge was not registered") + } + + // Observe sets the gauge from the input source on a background goroutine + // as soon as it starts; poll briefly for that first tick. + deadline := time.Now().Add(time.Second) + for { + if strings.Contains( + gauge.expose(), + ConnectedWellknownPeersCountMetricName+" 1 ", + ) { + return + } + if time.Now().After(deadline) { + t.Fatalf( + "expected exactly one of two wellknown peers to be counted, "+ + "got: %s", + gauge.expose(), + ) + } + time.Sleep(time.Millisecond) + } } diff --git a/pkg/clientinfo/observer.go b/pkg/clientinfo/observer.go new file mode 100644 index 0000000000..43165a487e --- /dev/null +++ b/pkg/clientinfo/observer.go @@ -0,0 +1,42 @@ +package clientinfo + +import ( + "context" + "time" +) + +// MetricObserverInput defines a source of metric data. +type MetricObserverInput func() float64 + +// MetricObserverOutput defines a destination of collected metric data. +type MetricObserverOutput interface { + Set(value float64) +} + +// MetricObserver represent a definition of a cyclic metric observation process. +type MetricObserver struct { + input MetricObserverInput + output MetricObserverOutput +} + +// Observe triggers a cyclic metric observation process. +func (o *MetricObserver) Observe( + ctx context.Context, + tick time.Duration, +) { + go func() { + o.output.Set(o.input()) // execute the first check immediately + + ticker := time.NewTicker(tick) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + o.output.Set(o.input()) + case <-ctx.Done(): + return + } + } + }() +} diff --git a/pkg/clientinfo/observer_test.go b/pkg/clientinfo/observer_test.go new file mode 100644 index 0000000000..2f618a3b01 --- /dev/null +++ b/pkg/clientinfo/observer_test.go @@ -0,0 +1,37 @@ +package clientinfo + +import ( + "context" + "testing" + "time" +) + +func TestObserve(t *testing.T) { + input := func() float64 { + return 5000 + } + gauge := &Gauge{} + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Millisecond) + defer cancel() + + observer := &MetricObserver{input, gauge} + + observer.Observe(ctx, 1*time.Millisecond) + + <-ctx.Done() + + expectedGaugeValue := float64(5000) + if gauge.value != expectedGaugeValue { + t.Fatalf( + "incorrect gauge value:\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + expectedGaugeValue, + gauge.value, + ) + } + + if gauge.timestamp == 0 { + t.Fatal("timestamp should be set") + } +} diff --git a/pkg/clientinfo/performance.go b/pkg/clientinfo/performance.go index bcc28137ca..2d3ea0da86 100644 --- a/pkg/clientinfo/performance.go +++ b/pkg/clientinfo/performance.go @@ -37,15 +37,12 @@ type PerformanceMetrics struct { registry *Registry cancel context.CancelFunc - // Counters track cumulative counts of events countersMutex sync.RWMutex counters map[string]*counter - // Histograms track distributions of values (like durations) histogramsMutex sync.RWMutex histograms map[string]*histogram - // Gauges track current values (like queue sizes) gaugesMutex sync.RWMutex gauges map[string]*gauge } @@ -102,29 +99,63 @@ func (pm *PerformanceMetrics) Stop() { // registerAllMetrics registers all performance metrics with 0 values // so they appear in the /metrics endpoint even before operations occur. func (pm *PerformanceMetrics) registerAllMetrics() { - // Register all counter metrics with 0 initial value + pm.registerCounterMetrics() + pm.registerWalletActionMetrics() + pm.registerHistogramMetrics() + pm.registerGaugeMetrics() +} + +// registerCounterMetrics registers all counter metrics with 0 initial values. +// Map entries are populated before observers are registered so that observer +// callbacks never read the map while it is being written concurrently. +func (pm *PerformanceMetrics) registerCounterMetrics() { counters := []string{ + // ----- DKG counters ----- MetricDKGJoinedTotal, MetricDKGFailedTotal, MetricDKGValidationTotal, MetricDKGChallengesSubmittedTotal, MetricDKGApprovalsSubmittedTotal, + + // ----- wallet action counters ----- + MetricWalletActionsTotal, + MetricWalletActionSuccessTotal, + MetricWalletActionFailedTotal, + MetricWalletHeartbeatFailuresTotal, + MetricStuckWalletTransactionsTotal, + MetricUnmonitoredWalletTransactionsTotal, + + // ----- SPV proof-skip counters ----- + + MetricSpvProofSkippedOutsideRelayRangeTotal, + MetricSpvProofSkippedExceededMaxHeadersTotal, + MetricSpvProofTaskFailuresTotal, + MetricRedemptionProofTaskFailuresTotal, + + // ----- on-chain action counters ----- MetricSigningOperationsTotal, MetricSigningSuccessTotal, MetricSigningFailedTotal, MetricSigningTimeoutsTotal, + MetricDepositSweepExecutionsTotal, + MetricDepositSweepExecutionsSuccessTotal, + MetricDepositSweepExecutionsFailedTotal, + MetricDepositSweepFeeBelowFloorTotal, MetricRedemptionExecutionsTotal, MetricRedemptionExecutionsSuccessTotal, MetricRedemptionExecutionsFailedTotal, + MetricRedemptionProposalGenerationTotal, + MetricRedemptionProposalGenerationFailedTotal, + MetricRedemptionProposalGenerationSuccessTotal, + MetricRedemptionProposalBroadcastTotal, + MetricRedemptionProposalBroadcastFailedTotal, MetricRedemptionProofSubmissionsTotal, MetricRedemptionProofSubmissionsSuccessTotal, MetricRedemptionProofSubmissionsFailedTotal, - MetricWalletActionsTotal, - MetricWalletActionSuccessTotal, - MetricWalletActionFailedTotal, - MetricWalletHeartbeatFailuresTotal, - MetricStuckWalletTransactionsTotal, - MetricUnmonitoredWalletTransactionsTotal, + MetricDepositSweepProofSubmissionsTotal, + MetricDepositSweepProofSubmissionsSuccessTotal, + MetricDepositSweepProofSubmissionsFailedTotal, + MetricCoordinationWindowsDetectedTotal, MetricCoordinationProceduresExecutedTotal, MetricCoordinationFailedTotal, @@ -149,14 +180,12 @@ func (pm *PerformanceMetrics) registerAllMetrics() { counters = append(counters, NetworkJoinFailureMetricName(reason)) } - // First, initialize all counters in the map pm.countersMutex.Lock() for _, name := range counters { pm.counters[name] = &counter{value: 0} } pm.countersMutex.Unlock() - // Then, register observers (this prevents concurrent map read/write) for _, name := range counters { metricName := name // Capture for closure pm.registry.ObserveApplicationSource( @@ -177,7 +206,11 @@ func (pm *PerformanceMetrics) registerAllMetrics() { ) } - // Register per-action type wallet metrics +} + +// registerWalletActionMetrics registers per-action-type wallet counters and +// duration histograms with 0 initial values. +func (pm *PerformanceMetrics) registerWalletActionMetrics() { // For each action type, register: total, success_total, failed_total, duration_seconds for _, actionType := range GetAllWalletActionTypes() { actionCounters := []string{ @@ -238,11 +271,17 @@ func (pm *PerformanceMetrics) registerAllMetrics() { ) } - // Register all duration/histogram metrics with 0 initial values - // Note: These use the actual metric names as used in the codebase +} + +// registerHistogramMetrics registers standalone duration/histogram metrics with +// 0 initial values. +func (pm *PerformanceMetrics) registerHistogramMetrics() { + // These use the actual metric names as used in the codebase. durationMetrics := []string{ MetricDKGDurationSeconds, MetricSigningDurationSeconds, + MetricDepositSweepExecutionDurationSeconds, + MetricDepositSweepTxSigningDurationSeconds, MetricRedemptionActionDurationSeconds, MetricWalletActionDurationSeconds, MetricCoordinationDurationSeconds, @@ -251,7 +290,6 @@ func (pm *PerformanceMetrics) registerAllMetrics() { MetricNetworkHandshakeDurationSeconds, } - // First, initialize all histograms in the map pm.histogramsMutex.Lock() for _, name := range durationMetrics { pm.histograms[name] = &histogram{ @@ -260,7 +298,6 @@ func (pm *PerformanceMetrics) registerAllMetrics() { } pm.histogramsMutex.Unlock() - // Then, register observers (this prevents concurrent map read/write) for _, name := range durationMetrics { metricName := name sources := map[string]Source{ @@ -297,13 +334,20 @@ func (pm *PerformanceMetrics) registerAllMetrics() { pm.registry.ObserveApplicationSource("performance", sources) } - // Register all gauge metrics with 0 initial value +} + +// registerGaugeMetrics registers all gauge metrics with 0 initial values. +func (pm *PerformanceMetrics) registerGaugeMetrics() { gauges := []string{ + MetricSpvMaintainerActive, + MetricSpvMaintainerLastActivityTimestamp, + MetricSpvMaintainerLastSuccessTimestamp, + MetricSpvMaintainerLastFailureTimestamp, + MetricSpvMaintainerMaxBackoffSeconds, MetricWalletDispatcherActiveActions, MetricIncomingMessageQueueSize, MetricMessageHandlerQueueSize, MetricSigningAttemptsPerOperation, - MetricCPUUtilization, MetricMemoryUsageMB, MetricGoroutineCount, MetricCPULoadPercent, @@ -311,14 +355,12 @@ func (pm *PerformanceMetrics) registerAllMetrics() { MetricSwapUtilizationPercent, } - // First, initialize all gauges in the map pm.gaugesMutex.Lock() for _, name := range gauges { pm.gauges[name] = &gauge{value: 0} } pm.gaugesMutex.Unlock() - // Then, register observers (this prevents concurrent map read/write) for _, name := range gauges { metricName := name // Capture for closure pm.registry.ObserveApplicationSource( @@ -338,7 +380,6 @@ func (pm *PerformanceMetrics) registerAllMetrics() { }, ) } - } // IncrementCounter increments a counter metric by the given value. @@ -346,33 +387,24 @@ func (pm *PerformanceMetrics) registerAllMetrics() { // only updates the counter value without re-registering observers. func (pm *PerformanceMetrics) IncrementCounter(name string, value float64) { pm.countersMutex.RLock() - c, exists := pm.counters[name] - pm.countersMutex.RUnlock() - - // Fast path: if counter exists, just increment it - if exists { - c.mutex.Lock() - c.value += value - c.mutex.Unlock() + defer pm.countersMutex.RUnlock() + + c, ok := pm.counters[name] + if !ok { + // Counter not pre-registered. Pre-registration is enforced by + // registerAllMetrics() and tested by the *_CountersRegistered + // tests. The original slow path lazily added the counter to + // pm.counters on first increment but never called + // ObserveApplicationSource, so the value lived in memory but + // never reached /metrics; the current code silently ignores + // the increment. Review the registration list if a counter + // appears here unexpectedly. return } - // Slow path: counter doesn't exist, need to create it - // Upgrade to write lock and check/create - pm.countersMutex.Lock() - c, exists = pm.counters[name] - if !exists { - c = &counter{value: value} - pm.counters[name] = c - pm.countersMutex.Unlock() - return - } - pm.countersMutex.Unlock() - - // Counter was created by another goroutine after our first check c.mutex.Lock() + defer c.mutex.Unlock() c.value += value - c.mutex.Unlock() } // RecordDuration records a duration value in a histogram. @@ -380,18 +412,22 @@ func (pm *PerformanceMetrics) IncrementCounter(name string, value float64) { // Observers are already registered in registerAllMetrics, so this method // only updates the histogram without re-registering observers. func (pm *PerformanceMetrics) RecordDuration(name string, duration time.Duration) { - pm.histogramsMutex.Lock() - h, exists := pm.histograms[name] - if !exists { - h = &histogram{ - buckets: make(map[float64]float64), - } - pm.histograms[name] = h + pm.histogramsMutex.RLock() + h, ok := pm.histograms[name] + pm.histogramsMutex.RUnlock() + + if !ok { + // Histogram not pre-registered. Pre-registration is enforced by + // registerAllMetrics() and tested by the *_CountersRegistered + // tests. Silently ignoring the duration is the original behavior + // of this slow path; review the registration list if a histogram + // appears here unexpectedly. + return } - pm.histogramsMutex.Unlock() seconds := duration.Seconds() h.mutex.Lock() + defer h.mutex.Unlock() // Simple histogram: increment bucket counts // Buckets: 0.001, 0.01, 0.1, 1, 10, 60, 300, 600, +Inf (overflow) buckets := []float64{0.001, 0.01, 0.1, 1, 10, 60, 300, 600} @@ -410,39 +446,36 @@ func (pm *PerformanceMetrics) RecordDuration(name string, duration time.Duration // Also track total count and sum for average calculation h.buckets[histogramCountKey]++ // count h.buckets[histogramSumKey] += seconds - h.mutex.Unlock() } // SetGauge sets a gauge metric to the given value. // Observers are already registered in registerAllMetrics, so this method // only updates the gauge value without re-registering observers. func (pm *PerformanceMetrics) SetGauge(name string, value float64) { - pm.gaugesMutex.Lock() - g, exists := pm.gauges[name] - if !exists { - g = &gauge{value: value} - pm.gauges[name] = g - pm.gaugesMutex.Unlock() + pm.gaugesMutex.RLock() + g, ok := pm.gauges[name] + pm.gaugesMutex.RUnlock() + + if !ok { + // Gauge not pre-registered. Pre-registration is enforced by + // registerAllMetrics() and tested by the *_CountersRegistered + // tests. Silently ignoring the value is the original behavior + // of this slow path; review the registration list if a gauge + // appears here unexpectedly. return } - pm.gaugesMutex.Unlock() g.mutex.Lock() + defer g.mutex.Unlock() g.value = value - g.mutex.Unlock() } // observeSystemMetrics periodically collects and updates system metrics // including CPU utilization, memory usage, and goroutine count. func (pm *PerformanceMetrics) observeSystemMetrics(ctx context.Context) { - ticker := time.NewTicker(60 * time.Second) // Update every 10 seconds + ticker := time.NewTicker(60 * time.Second) // Update every 60 seconds defer ticker.Stop() - var lastMemStats runtime.MemStats - var lastUpdateTime time.Time - runtime.ReadMemStats(&lastMemStats) - lastUpdateTime = time.Now() - for { select { case <-ticker.C: @@ -459,17 +492,6 @@ func (pm *PerformanceMetrics) observeSystemMetrics(ctx context.Context) { memoryUsageMB := float64(memStats.Sys) / (1024 * 1024) // Total memory in megabytes pm.SetGauge(MetricMemoryUsageMB, memoryUsageMB) - // Calculate CPU utilization using a more realistic heuristic - now := time.Now() - elapsed := now.Sub(lastUpdateTime) - if elapsed > 0 { - cpuUtilization := pm.calculateCPUUtilizationHeuristic(memStats, lastMemStats, elapsed) - pm.SetGauge(MetricCPUUtilization, cpuUtilization) - - lastMemStats = memStats - lastUpdateTime = now - } - // Update OS-level machine stats pm.updateMachineStats() case <-ctx.Done(): @@ -478,55 +500,6 @@ func (pm *PerformanceMetrics) observeSystemMetrics(ctx context.Context) { } } -// calculateCPUUtilizationHeuristic calculates CPU utilization using a heuristic -// based on goroutine count and GC activity. This provides a reasonable approximation. -// Note: For accurate CPU metrics, consider using OS-level process CPU time. -func (pm *PerformanceMetrics) calculateCPUUtilizationHeuristic( - currentMemStats runtime.MemStats, - lastMemStats runtime.MemStats, - elapsed time.Duration, -) float64 { - numCPU := float64(runtime.NumCPU()) - activeGoroutines := float64(runtime.NumGoroutine()) - - // Calculate GC rate (GCs per second) - gcDelta := float64(currentMemStats.NumGC - lastMemStats.NumGC) - gcRate := gcDelta / elapsed.Seconds() - - // Normalize goroutines: if we have more goroutines than CPU cores, - // we're likely using more CPU, but use a conservative multiplier - // Formula: (goroutines / CPU cores) * 10%, capped at 40% - goroutineContribution := (activeGoroutines / numCPU) * 10.0 - if goroutineContribution > 40.0 { - goroutineContribution = 40.0 - } - - // GC contribution: frequent GCs indicate CPU work, but use conservative multiplier - // Formula: GC rate * 1%, capped at 20% - gcContribution := gcRate * 1.0 - if gcContribution > 20.0 { - gcContribution = 20.0 - } - - // Total CPU utilization estimate - cpuUtilization := goroutineContribution + gcContribution - - // Add a small base load if there are active goroutines - if cpuUtilization < 1.0 && activeGoroutines > 0 { - cpuUtilization = 1.0 // Minimum 1% if there are active goroutines - } - - // Cap CPU utilization at 100% - if cpuUtilization > 100.0 { - cpuUtilization = 100.0 - } - if cpuUtilization < 0.0 { - cpuUtilization = 0.0 - } - - return cpuUtilization -} - // updateMachineStats collects and updates OS-level machine statistics // including CPU load, RAM utilization, and swapfile utilization. func (pm *PerformanceMetrics) updateMachineStats() { @@ -558,25 +531,6 @@ func (pm *PerformanceMetrics) updateMachineStats() { } } -// NoOpPerformanceMetrics is a no-op implementation of PerformanceMetricsRecorder -// that can be used when metrics are disabled. -type NoOpPerformanceMetrics struct{} - -// IncrementCounter is a no-op. -func (n *NoOpPerformanceMetrics) IncrementCounter(name string, value float64) {} - -// RecordDuration is a no-op. -func (n *NoOpPerformanceMetrics) RecordDuration(name string, duration time.Duration) {} - -// SetGauge is a no-op. -func (n *NoOpPerformanceMetrics) SetGauge(name string, value float64) {} - -// GetCounterValue always returns 0. -func (n *NoOpPerformanceMetrics) GetCounterValue(name string) float64 { return 0 } - -// GetGaugeValue always returns 0. -func (n *NoOpPerformanceMetrics) GetGaugeValue(name string) float64 { return 0 } - // GetCounterValue returns the current value of a counter. func (pm *PerformanceMetrics) GetCounterValue(name string) float64 { pm.countersMutex.RLock() @@ -625,17 +579,62 @@ const ( MetricSigningAttemptsPerOperation = "signing_attempts_per_operation" MetricSigningTimeoutsTotal = "signing_timeouts_total" + // Deposit Sweep Metrics + MetricDepositSweepExecutionsTotal = "deposit_sweep_executions_total" + MetricDepositSweepExecutionsSuccessTotal = "deposit_sweep_executions_success_total" + MetricDepositSweepExecutionsFailedTotal = "deposit_sweep_executions_failed_total" + MetricDepositSweepExecutionDurationSeconds = "deposit_sweep_execution_duration_seconds" + MetricDepositSweepTxSigningDurationSeconds = "deposit_sweep_tx_signing_duration_seconds" + // MetricDepositSweepFeeBelowFloorTotal backs the follower-side soft check + // that the leader's proposed sweep fee is not below the safe minimum (see + // threshold-network/keep-core#4171). + MetricDepositSweepFeeBelowFloorTotal = "deposit_sweep_fee_below_floor_total" + // Redemption Metrics MetricRedemptionExecutionsTotal = "redemption_executions_total" MetricRedemptionExecutionsSuccessTotal = "redemption_executions_success_total" MetricRedemptionExecutionsFailedTotal = "redemption_executions_failed_total" MetricRedemptionActionDurationSeconds = "redemption_action_duration_seconds" + // Redemption proposal counters distinguish task generation from P2P broadcast. + // Recorded only when the node is acting as coordination leader for the wallet/window. + MetricRedemptionProposalGenerationTotal = "redemption_proposal_generation_total" + MetricRedemptionProposalGenerationFailedTotal = "redemption_proposal_generation_failed_total" + MetricRedemptionProposalGenerationSuccessTotal = "redemption_proposal_generation_success_total" + MetricRedemptionProposalBroadcastTotal = "redemption_proposal_broadcast_total" + MetricRedemptionProposalBroadcastFailedTotal = "redemption_proposal_broadcast_failed_total" // Redemption Proof Submission Metrics (SPV maintainer) MetricRedemptionProofSubmissionsTotal = "redemption_proof_submissions_total" MetricRedemptionProofSubmissionsSuccessTotal = "redemption_proof_submissions_success_total" MetricRedemptionProofSubmissionsFailedTotal = "redemption_proof_submissions_failed_total" + // Deposit Sweep Proof Submission Metrics (SPV maintainer) + MetricDepositSweepProofSubmissionsTotal = "deposit_sweep_proof_submissions_total" + MetricDepositSweepProofSubmissionsSuccessTotal = "deposit_sweep_proof_submissions_success_total" + MetricDepositSweepProofSubmissionsFailedTotal = "deposit_sweep_proof_submissions_failed_total" + + // SPV Maintainer Health Metrics (proof-task failures and control-loop + // lifecycle gauges) + // MetricSpvProofTaskFailuresTotal and MetricRedemptionProofTaskFailuresTotal + // cover discovery and proof-info errors, not just submission failures. + MetricSpvProofTaskFailuresTotal = "spv_proof_task_failures_total" + MetricRedemptionProofTaskFailuresTotal = "redemption_proof_task_failures_total" + MetricSpvMaintainerLastFailureTimestamp = "spv_maintainer_last_failure_timestamp_seconds" + MetricSpvMaintainerActive = "spv_maintainer_active" + MetricSpvMaintainerLastActivityTimestamp = "spv_maintainer_last_activity_timestamp_seconds" + MetricSpvMaintainerLastSuccessTimestamp = "spv_maintainer_last_success_timestamp_seconds" + MetricSpvMaintainerMaxBackoffSeconds = "spv_maintainer_max_backoff_seconds" + + // SPV Proof Skip Metrics (SPV maintainer) + // MetricSpvProofSkippedOutsideRelayRangeTotal counts the number of + // transactions whose SPV proofs were skipped because no relay range + // contained the transaction. + MetricSpvProofSkippedOutsideRelayRangeTotal = "spv_proof_skipped_outside_relay_range_total" + // MetricSpvProofSkippedExceededMaxHeadersTotal counts the number of + // transactions whose SPV proofs were skipped because the chain header + // count exceeded the configured maximum. + MetricSpvProofSkippedExceededMaxHeadersTotal = "spv_proof_skipped_exceeded_max_headers_total" + // Wallet Action Metrics (aggregate) MetricWalletActionsTotal = "wallet_actions_total" MetricWalletActionSuccessTotal = "wallet_action_success_total" @@ -690,7 +689,6 @@ const ( MetricWalletDispatcherRejectedTotal = "wallet_dispatcher_rejected_total" // System Metrics - MetricCPUUtilization = "cpu_utilization_percent" MetricMemoryUsageMB = "memory_usage_mb" MetricGoroutineCount = "goroutine_count" MetricCPULoadPercent = "cpu_load_percent" diff --git a/pkg/clientinfo/performance_test.go b/pkg/clientinfo/performance_test.go index 5ebf253288..ec254c7a25 100644 --- a/pkg/clientinfo/performance_test.go +++ b/pkg/clientinfo/performance_test.go @@ -2,12 +2,12 @@ package clientinfo import ( "context" + "fmt" "math" + "strings" "sync" "testing" "time" - - keepclientinfo "github.com/keep-network/keep-common/pkg/clientinfo" ) // TestConcurrentCounterIncrement tests that concurrent counter increments @@ -16,7 +16,7 @@ func TestConcurrentCounterIncrement(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - registry := &Registry{keepclientinfo.NewRegistry(), ctx} + registry := newRegistry(ctx) pm := NewPerformanceMetrics(ctx, registry) const ( @@ -50,7 +50,7 @@ func TestConcurrentCounterDifferentMetrics(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - registry := &Registry{keepclientinfo.NewRegistry(), ctx} + registry := newRegistry(ctx) pm := NewPerformanceMetrics(ctx, registry) const ( @@ -114,7 +114,7 @@ func TestConcurrentDurationRecording(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - registry := &Registry{keepclientinfo.NewRegistry(), ctx} + registry := newRegistry(ctx) pm := NewPerformanceMetrics(ctx, registry) const ( @@ -168,7 +168,7 @@ func TestConcurrentGaugeSet(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - registry := &Registry{keepclientinfo.NewRegistry(), ctx} + registry := newRegistry(ctx) pm := NewPerformanceMetrics(ctx, registry) const ( @@ -204,7 +204,7 @@ func TestConcurrentDifferentOperations(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - registry := &Registry{keepclientinfo.NewRegistry(), ctx} + registry := newRegistry(ctx) pm := NewPerformanceMetrics(ctx, registry) const ( @@ -263,7 +263,7 @@ func TestHistogramBucketPlacement(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - registry := &Registry{keepclientinfo.NewRegistry(), ctx} + registry := newRegistry(ctx) pm := NewPerformanceMetrics(ctx, registry) metricName := "test_duration_seconds" @@ -284,6 +284,10 @@ func TestHistogramBucketPlacement(t *testing.T) { {1000 * time.Second, 0, false}, // > 600s (overflow) } + pm.histogramsMutex.Lock() + pm.histograms[metricName] = &histogram{buckets: make(map[float64]float64)} + pm.histogramsMutex.Unlock() + for _, tc := range testCases { pm.RecordDuration(metricName, tc.duration) } @@ -319,7 +323,7 @@ func TestMetricsInitialization(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - registry := &Registry{keepclientinfo.NewRegistry(), ctx} + registry := newRegistry(ctx) pm := NewPerformanceMetrics(ctx, registry) // Test counters @@ -338,7 +342,6 @@ func TestMetricsInitialization(t *testing.T) { // Test gauges gauges := []string{ - MetricCPUUtilization, MetricMemoryUsageMB, MetricGoroutineCount, MetricCPULoadPercent, @@ -354,20 +357,32 @@ func TestMetricsInitialization(t *testing.T) { } } -// TestContextCancelation tests that goroutines stop when context is cancelled. +// TestContextCancelation tests that observeSystemMetrics terminates when its +// context is cancelled, and that subsequent metric operations do not panic +// after shutdown. func TestContextCancelation(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) - registry := &Registry{keepclientinfo.NewRegistry(), ctx} + registry := newRegistry(ctx) pm := NewPerformanceMetrics(ctx, registry) - // Cancel context immediately + done := make(chan struct{}) + go func() { + defer close(done) + pm.observeSystemMetrics(ctx) + }() + + // Cancel context to signal the observation loop to stop. cancel() - // Give goroutines time to stop - time.Sleep(100 * time.Millisecond) + select { + case <-done: + // observeSystemMetrics observed context cancellation and returned. + case <-time.After(2 * time.Second): + t.Fatal("observeSystemMetrics did not return after context cancellation") + } - // This should not panic or cause issues + // Operations after shutdown must not panic or cause issues. pm.IncrementCounter(MetricSigningOperationsTotal, 1) pm.SetGauge(MetricIncomingMessageQueueSize, 5) pm.RecordDuration("signing_duration_seconds", 100*time.Millisecond) @@ -396,6 +411,29 @@ func TestNetworkJoinFailureMetricName(t *testing.T) { } } +// assertCounterExportedInRegistry verifies that counterName is actually +// exposed through the metrics registry (not just tracked in pm's internal +// counters map) by attempting to register the same gauge name again: a +// registration that was silently skipped (e.g. because +// ObserveApplicationSource was never called, or was called with the wrong +// metric name) would succeed here instead of failing with "already exists". +func assertCounterExportedInRegistry( + t *testing.T, + registry *Registry, + counterName string, +) { + t.Helper() + + metricName := fmt.Sprintf("performance_%s", counterName) + if _, err := registry.NewMetricGauge(metricName); err == nil || + !strings.Contains(err.Error(), "already exists") { + t.Errorf( + "counter %s should be exported in the metrics registry as %s", + counterName, metricName, + ) + } +} + // TestJoinFailureAndOnChainCountersRegistered tests that the per-reason join // failure counters and the firewall on-chain checks counter are registered // upfront so they appear in the metrics endpoint before any increment. @@ -403,7 +441,7 @@ func TestJoinFailureAndOnChainCountersRegistered(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - registry := &Registry{keepclientinfo.NewRegistry(), ctx} + registry := newRegistry(ctx) pm := NewPerformanceMetrics(ctx, registry) expectedCounters := []string{MetricFirewallOnChainChecksTotal} @@ -420,6 +458,86 @@ func TestJoinFailureAndOnChainCountersRegistered(t *testing.T) { continue } + assertCounterExportedInRegistry(t, registry, counterName) + + if value := pm.GetCounterValue(counterName); value != 0 { + t.Errorf("counter %s should start at 0, got %v", counterName, value) + } + + pm.IncrementCounter(counterName, 1) + if value := pm.GetCounterValue(counterName); value != 1 { + t.Errorf("counter %s should increment to 1, got %v", counterName, value) + } + } +} + +// TestDepositSweepProofSubmissionCountersRegistered tests that the +// deposit-sweep proof-submission counters are registered upfront so they +// appear in the metrics endpoint before any increment. +func TestDepositSweepProofSubmissionCountersRegistered(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + registry := newRegistry(ctx) + pm := NewPerformanceMetrics(ctx, registry) + + expectedCounters := []string{ + MetricDepositSweepProofSubmissionsTotal, + MetricDepositSweepProofSubmissionsSuccessTotal, + MetricDepositSweepProofSubmissionsFailedTotal, + } + + for _, counterName := range expectedCounters { + pm.countersMutex.RLock() + _, exists := pm.counters[counterName] + pm.countersMutex.RUnlock() + if !exists { + t.Errorf("counter %s should be registered upfront", counterName) + continue + } + + assertCounterExportedInRegistry(t, registry, counterName) + + if value := pm.GetCounterValue(counterName); value != 0 { + t.Errorf("counter %s should start at 0, got %v", counterName, value) + } + + pm.IncrementCounter(counterName, 1) + if value := pm.GetCounterValue(counterName); value != 1 { + t.Errorf("counter %s should increment to 1, got %v", counterName, value) + } + } +} + +// TestSpvProofSkipCountersRegistered tests that the SPV proof-skip counters +// are registered upfront so they appear in the metrics endpoint before any +// increment. The spv.go maintainer emits IncrementCounter calls for these +// counters from the relay-range and exceeded-max-headers skip branches; a +// missing upfront registration would cause the values to be silently dropped +// from /metrics because the lazy-create-without-register path in +// IncrementCounter never calls ObserveApplicationSource. +func TestSpvProofSkipCountersRegistered(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + registry := newRegistry(ctx) + pm := NewPerformanceMetrics(ctx, registry) + + expectedCounters := []string{ + MetricSpvProofSkippedOutsideRelayRangeTotal, + MetricSpvProofSkippedExceededMaxHeadersTotal, + } + + for _, counterName := range expectedCounters { + pm.countersMutex.RLock() + _, exists := pm.counters[counterName] + pm.countersMutex.RUnlock() + if !exists { + t.Errorf("counter %s should be registered upfront", counterName) + continue + } + + assertCounterExportedInRegistry(t, registry, counterName) if value := pm.GetCounterValue(counterName); value != 0 { t.Errorf("counter %s should start at 0, got %v", counterName, value) } @@ -430,3 +548,58 @@ func TestJoinFailureAndOnChainCountersRegistered(t *testing.T) { } } } + +// TestDepositSweepMetricsRegistered tests that all deposit sweep counters and +// duration metrics are registered upfront so they appear on the /metrics +// endpoint before a deposit sweep action ever executes. Counters and +// histograms recorded via IncrementCounter/RecordDuration are otherwise +// created lazily on first use, which would leave them invisible to +// Prometheus scraping until the metric first occurs - defeating their +// purpose as an alerting signal. +func TestDepositSweepMetricsRegistered(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + registry := newRegistry(ctx) + pm := NewPerformanceMetrics(ctx, registry) + + counters := []string{ + MetricDepositSweepExecutionsTotal, + MetricDepositSweepExecutionsSuccessTotal, + MetricDepositSweepExecutionsFailedTotal, + MetricDepositSweepFeeBelowFloorTotal, + } + + for _, counterName := range counters { + pm.countersMutex.RLock() + _, exists := pm.counters[counterName] + pm.countersMutex.RUnlock() + if !exists { + t.Errorf("counter %s should be registered upfront", counterName) + continue + } + + if value := pm.GetCounterValue(counterName); value != 0 { + t.Errorf("counter %s should start at 0, got %v", counterName, value) + } + + pm.IncrementCounter(counterName, 1) + if value := pm.GetCounterValue(counterName); value != 1 { + t.Errorf("counter %s should increment to 1, got %v", counterName, value) + } + } + + histograms := []string{ + MetricDepositSweepExecutionDurationSeconds, + MetricDepositSweepTxSigningDurationSeconds, + } + + for _, histogramName := range histograms { + pm.histogramsMutex.RLock() + _, exists := pm.histograms[histogramName] + pm.histogramsMutex.RUnlock() + if !exists { + t.Errorf("histogram %s should be registered upfront", histogramName) + } + } +} diff --git a/pkg/clientinfo/pprof_exposure_test.go b/pkg/clientinfo/pprof_exposure_test.go new file mode 100644 index 0000000000..a8053646db --- /dev/null +++ b/pkg/clientinfo/pprof_exposure_test.go @@ -0,0 +1,135 @@ +package clientinfo + +import ( + "context" + "fmt" + "net/http" + "net/http/httptest" + "testing" +) + +// TestClientInfoServerDoesNotExposePprofWhenDisabled asserts that the Go +// profiling endpoints are NOT reachable on the client info port when profiling +// was not enabled. +// +// This is a security regression guard, not a coverage exercise. Importing +// net/http/pprof registers /debug/pprof/* on http.DefaultServeMux from that +// package's init function, whether the import is blank or named. If the client +// info server serves DefaultServeMux, those endpoints are exposed on the client +// info port regardless of Config.EnablePprof, silently defeating an operator +// who explicitly disabled profiling and handing any caller that can reach the +// port goroutine/runtime introspection plus the expensive profile and trace +// endpoints. +// +// The server under test is started by TestMain with profiling disabled. +func TestClientInfoServerDoesNotExposePprofWhenDisabled(t *testing.T) { + for _, path := range []string{ + "/debug/pprof/", + "/debug/pprof/cmdline", + "/debug/pprof/profile?seconds=1", + "/debug/pprof/symbol", + "/debug/pprof/trace?seconds=1", + } { + t.Run(path, func(t *testing.T) { + response, err := http.Get( + fmt.Sprintf("http://localhost:%d%s", port, path), + ) + if err != nil { + t.Fatal(err) + } + defer response.Body.Close() + + if response.StatusCode != http.StatusNotFound { + t.Errorf( + "profiling endpoint [%s] is reachable while profiling is disabled\n"+ + "expected status: %d\nactual status: %d", + path, + http.StatusNotFound, + response.StatusCode, + ) + } + }) + } +} + +// TestClientInfoServerServesMetricsWhenPprofDisabled asserts the endpoints the +// server exists to serve stay reachable, so the pprof fix cannot regress them. +func TestClientInfoServerServesMetricsWhenPprofDisabled(t *testing.T) { + for _, path := range []string{"/metrics", "/diagnostics"} { + t.Run(path, func(t *testing.T) { + response, err := http.Get( + fmt.Sprintf("http://localhost:%d%s", port, path), + ) + if err != nil { + t.Fatal(err) + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + t.Errorf( + "expected [%s] to be reachable\nexpected status: %d\nactual status: %d", + path, + http.StatusOK, + response.StatusCode, + ) + } + }) + } +} + +// TestNewServeMux_PprofEnabled asserts the flag remains functional in the +// other direction: opting into profiling must actually serve the endpoints. +// Without this, the disabled-path test above could be satisfied by never +// registering the handlers at all. +func TestNewServeMux_PprofEnabled(t *testing.T) { + handler := newRegistry(context.Background()).newServeMux(true) + + for _, path := range []string{ + "/debug/pprof/", + "/debug/pprof/cmdline", + "/debug/pprof/profile?seconds=1", + "/debug/pprof/symbol", + "/debug/pprof/trace?seconds=1", + } { + t.Run(path, func(t *testing.T) { + recorder := httptest.NewRecorder() + handler.ServeHTTP( + recorder, + httptest.NewRequest(http.MethodGet, path, nil), + ) + + if recorder.Code != http.StatusOK { + t.Errorf( + "expected [%s] to be served when profiling is enabled\n"+ + "expected status: %d\nactual status: %d", + path, + http.StatusOK, + recorder.Code, + ) + } + }) + } +} + +// TestNewServeMux_PprofDisabledIsIsolatedFromDefaultServeMux asserts the +// mux is isolated from http.DefaultServeMux, which is where importing +// net/http/pprof installs its handlers. This is the root cause the live-server +// test above observes, asserted directly against the constructed mux. +func TestNewServeMux_PprofDisabledIsIsolatedFromDefaultServeMux(t *testing.T) { + handler := newRegistry(context.Background()).newServeMux(false) + + recorder := httptest.NewRecorder() + handler.ServeHTTP( + recorder, + httptest.NewRequest(http.MethodGet, "/debug/pprof/", nil), + ) + + if recorder.Code != http.StatusNotFound { + t.Errorf( + "handler is serving http.DefaultServeMux, exposing profiling "+ + "endpoints while disabled\nexpected status: %d\nactual status: %d", + http.StatusNotFound, + recorder.Code, + ) + } +} diff --git a/pkg/clientinfo/proposal_metrics_test.go b/pkg/clientinfo/proposal_metrics_test.go new file mode 100644 index 0000000000..d51e530fd3 --- /dev/null +++ b/pkg/clientinfo/proposal_metrics_test.go @@ -0,0 +1,47 @@ +package clientinfo + +import ( + "context" + "testing" +) + +// TestRedemptionProposalCountersRegistered tests that the redemption +// proposal counters are registered upfront so they appear in the metrics +// endpoint before any increment. +func TestRedemptionProposalCountersRegistered(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + registry := newRegistry(ctx) + pm := NewPerformanceMetrics(ctx, registry) + defer pm.Stop() + + expectedCounters := []string{ + MetricRedemptionProposalGenerationTotal, + MetricRedemptionProposalGenerationFailedTotal, + MetricRedemptionProposalGenerationSuccessTotal, + MetricRedemptionProposalBroadcastTotal, + MetricRedemptionProposalBroadcastFailedTotal, + } + + for _, counterName := range expectedCounters { + pm.countersMutex.RLock() + _, exists := pm.counters[counterName] + pm.countersMutex.RUnlock() + if !exists { + t.Errorf("counter %s should be registered upfront", counterName) + continue + } + + assertCounterExportedInRegistry(t, registry, counterName) + + if value := pm.GetCounterValue(counterName); value != 0 { + t.Errorf("counter %s should start at 0, got %v", counterName, value) + } + + pm.IncrementCounter(counterName, 1) + if value := pm.GetCounterValue(counterName); value != 1 { + t.Errorf("counter %s should increment to 1, got %v", counterName, value) + } + } +} diff --git a/pkg/clientinfo/registry_diagnostics.go b/pkg/clientinfo/registry_diagnostics.go new file mode 100644 index 0000000000..bc33c89d84 --- /dev/null +++ b/pkg/clientinfo/registry_diagnostics.go @@ -0,0 +1,41 @@ +package clientinfo + +import ( + "encoding/json" +) + +// RegisterDiagnosticSource registers diagnostics source callback with a given name. +// Name will be used as a key and callback result as a value in JSON object +// during composing diagnostics JSON. +// Note: function will override existing diagnostics source on attempt +// to register another one with the same name. +func (r *Registry) RegisterDiagnosticSource(name string, source func() string) { + r.diagnosticsMutex.Lock() + defer r.diagnosticsMutex.Unlock() + + r.diagnosticsSources[name] = source +} + +// Exposes all registered diagnostics sources in a single JSON document. +func (r *Registry) exposeDiagnostics() string { + r.diagnosticsMutex.RLock() + defer r.diagnosticsMutex.RUnlock() + + diagnostics := make(map[string]interface{}) + for _, sourceName := range sortedKeys(r.diagnosticsSources) { + var jsonString = r.diagnosticsSources[sourceName]() + var jsonObject interface{} + err := json.Unmarshal([]byte(jsonString), &jsonObject) + if err == nil { + diagnostics[sourceName] = jsonObject + } + } + + bytes, err := json.MarshalIndent(diagnostics, "", " ") + if err != nil { + logger.Errorf("diagnostics JSON serialization error: [%v]", err) + return "" + } + + return string(bytes) +} diff --git a/pkg/clientinfo/registry_metrics.go b/pkg/clientinfo/registry_metrics.go new file mode 100644 index 0000000000..0bd595141e --- /dev/null +++ b/pkg/clientinfo/registry_metrics.go @@ -0,0 +1,119 @@ +package clientinfo + +import ( + "fmt" + "strings" +) + +type metric interface { + expose() string +} + +// Label represents an arbitrary information attached to the metrics. +type Label struct { + name string + value string +} + +// NewLabel creates a new label using the given name and value. +func NewLabel(name, value string) Label { + return Label{name, value} +} + +// Exposes all registered metrics in their text format. +func (r *Registry) exposeMetrics() string { + r.metricsMutex.RLock() + defer r.metricsMutex.RUnlock() + + metrics := make([]string, 0) + for _, metric := range sortedKeys(r.metrics) { + metrics = append(metrics, r.metrics[metric].expose()) + } + + return fmt.Sprintf("%s\n", strings.Join(metrics, "\n\n")) +} + +// NewMetricGauge creates and registers a new gauge metric which will be exposed +// through the metrics server. In case a metric already exists, an error +// will be returned. +func (r *Registry) NewMetricGauge( + name string, + labels ...Label, +) (*Gauge, error) { + r.metricsMutex.Lock() + defer r.metricsMutex.Unlock() + + if _, exists := r.metrics[name]; exists { + return nil, fmt.Errorf("metric [%v] already exists", name) + } + + gauge := &Gauge{ + name: name, + labels: processLabels(labels), + } + + r.metrics[name] = gauge + return gauge, nil +} + +// NewMetricGaugeObserver creates and registers a gauge just like `NewMetricGauge` +// method and wraps it with a ready to use observer of the provided input. This +// allows to easily create self-refreshing metrics. +func (r *Registry) NewMetricGaugeObserver( + name string, + input MetricObserverInput, + labels ...Label, +) (*MetricObserver, error) { + gauge, err := r.NewMetricGauge(name, labels...) + if err != nil { + return nil, err + } + + return &MetricObserver{ + input: input, + output: gauge, + }, nil +} + +// NewMetricInfo creates and registers a new info metric which will be exposed +// through the metrics server. In case a metric already exists, an error +// will be returned. +func (r *Registry) NewMetricInfo( + name string, + labels []Label, +) (*Info, error) { + r.metricsMutex.Lock() + defer r.metricsMutex.Unlock() + + if _, exists := r.metrics[name]; exists { + return nil, fmt.Errorf("metric [%v] already exists", name) + } + + if len(labels) == 0 { + return nil, fmt.Errorf("at least one label should be set") + } + + info := &Info{ + name: name, + labels: processLabels(labels), + } + + r.metrics[name] = info + return info, nil +} + +func processLabels( + labels []Label, +) map[string]string { + result := make(map[string]string) + + for _, label := range labels { + if label.name == "" || label.value == "" { + continue + } + + result[label.name] = label.value + } + + return result +} diff --git a/pkg/clientinfo/registry_metrics_test.go b/pkg/clientinfo/registry_metrics_test.go new file mode 100644 index 0000000000..a40a48ce8b --- /dev/null +++ b/pkg/clientinfo/registry_metrics_test.go @@ -0,0 +1,79 @@ +package clientinfo + +import ( + "context" + "testing" +) + +func TestRegistryNewMetricGauge(t *testing.T) { + registry := newRegistry(context.Background()) + + gauge, err := registry.NewMetricGauge("test-gauge") + if err != nil { + t.Fatal(err) + } + + if _, err = registry.NewMetricGauge("test-gauge"); err == nil { + t.Fatalf("should fail when creating gauge with the same name") + } + + if _, exists := registry.metrics[gauge.name]; !exists { + t.Fatalf("metric with name [%v] should exist in the registry", gauge.name) + } +} + +func TestRegistryNewMetricGaugeObserver(t *testing.T) { + registry := newRegistry(context.Background()) + + input := func() float64 { + return 1 + } + + _, err := registry.NewMetricGaugeObserver("test-gauge", input) + if err != nil { + t.Fatal(err) + } + + if _, err = registry.NewMetricGaugeObserver("test-gauge", input); err == nil { + t.Fatalf("should fail when creating gauge with the same name") + } + + if _, exists := registry.metrics["test-gauge"]; !exists { + t.Fatalf("metric with name [%v] should exist in the registry", "test-gauge") + } +} + +func TestRegistryNewMetricInfo(t *testing.T) { + registry := newRegistry(context.Background()) + + if _, err := registry.NewMetricInfo("test-info", []Label{}); err == nil { + t.Fatalf("should fail when creating info without labels") + } + + label := NewLabel("label", "value") + info, err := registry.NewMetricInfo("test-info", []Label{label}) + if err != nil { + t.Fatal(err) + } + + if _, err = registry.NewMetricInfo("test-info", []Label{label}); err == nil { + t.Fatalf("should fail when creating info with the same name") + } + + if _, exists := registry.metrics[info.name]; !exists { + t.Fatalf("metric with name [%v] should exist in the registry", info.name) + } + + expectedLabelValue, exists := info.labels[label.name] + if !exists { + t.Fatalf("label with name [%v] should exist", label.name) + } + + if expectedLabelValue != label.value { + t.Fatalf( + "label with name [%v] should have value [%v]", + label.name, + label.value, + ) + } +} diff --git a/pkg/clientinfo/registry_test.go b/pkg/clientinfo/registry_test.go new file mode 100644 index 0000000000..f4d6be33c9 --- /dev/null +++ b/pkg/clientinfo/registry_test.go @@ -0,0 +1,226 @@ +package clientinfo + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net" + "net/http" + "net/http/httptest" + "os" + "reflect" + "strings" + "testing" +) + +var registry *Registry + +// port is an OS-reserved ephemeral port the package's live server listens on. +// Reserving it in TestMain avoids the flakiness of a hardcoded port: another +// process or a parallel test run could bind 9799 while this suite runs. The +// brief gap between closing the listener and the server's ListenAndServe is +// acceptable for a test server (same pattern as cmd/maintainer_test.go). +var port int + +func TestMain(m *testing.M) { + listener, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + panic(fmt.Sprintf("could not reserve a test port: [%v]", err)) + } + port = listener.Addr().(*net.TCPAddr).Port + if err := listener.Close(); err != nil { + panic(fmt.Sprintf("could not release the reserved test port: [%v]", err)) + } + + registry = newRegistry(context.Background()) + registry.EnableServer(port) + + os.Exit(m.Run()) +} + +func TestClientInfoServerMetrics(t *testing.T) { + // Register gauge metric + gauge, err := registry.NewMetricGauge( + "test_gauge", + NewLabel("gaugeLabelName", "gauge-label-value"), + ) + if err != nil { + t.Fatal(err) + } + gauge.value = float64(12) + gauge.timestamp = int64(51241) + + // Register info metric + if _, err := registry.NewMetricInfo( + "test_info", + []Label{ + NewLabel("infoLabelName", "info-label-value"), + }, + ); err != nil { + t.Fatal(err) + } + + // Assemble the expected endpoint response + expected := new(strings.Builder) + expected.WriteString("# TYPE test_gauge gauge\n") + expected.WriteString("test_gauge{gaugeLabelName=\"gauge-label-value\"} 12 51241\n\n") + expected.WriteString("test_info{infoLabelName=\"info-label-value\"} 1\n") + + // Execute Test + resp, err := http.Get(fmt.Sprintf("http://localhost:%d/metrics", port)) + if err != nil { + t.Fatalf("failed to get metrics: %v", err) + } + + actual := new(strings.Builder) + _, err = io.Copy(actual, resp.Body) + if err != nil { + t.Fatal(err) + } + + if actual.String() != expected.String() { + t.Fatalf( + "unexpected server response\n"+ + "expected:\n[%s]\n"+ + "actual:\n[%v]\n", + expected.String(), + actual.String(), + ) + } +} + +func TestClientInfoServerDiagnostics(t *testing.T) { + + // Register Diagnostics Sources + nodeChainAddress := "0x1234567890" + registry.RegisterDiagnosticSource("chain_address", func() string { + result, err := json.Marshal(nodeChainAddress) + if err != nil { + t.Fatal(err) + } + return string(result) + }) + + peers := []testDiagnosticsPeerInfo{ + { + ChainAddress: "0xABCdef", + NetworkMultiAddresses: []string{"/dns4/address1/3919/ipfs/AaBbCc"}, + }, + { + ChainAddress: "0x98765A", + NetworkMultiAddresses: []string{"/ip4/127.0.0.1/3919/ipfs/963"}, + }, + } + registry.RegisterDiagnosticSource("connected_peers", func() string { + result, err := json.Marshal(peers) + if err != nil { + t.Fatal(err) + } + return string(result) + }) + + expectedDiagnostics := &testDiagnosticsInfo{nodeChainAddress, peers} + + resp, err := http.Get(fmt.Sprintf("http://localhost:%d/diagnostics", port)) + if err != nil { + t.Fatalf("failed to get diagnostics: %v", err) + } + + actualDiagnostics := &testDiagnosticsInfo{} + if err = json.NewDecoder(resp.Body).Decode(actualDiagnostics); err != nil { + t.Fatalf("failed to decode diagnostics: %v", err) + } + + if !reflect.DeepEqual(expectedDiagnostics, actualDiagnostics) { + t.Errorf( + "incorrect diagnostics\n"+ + "expected: %+v\n"+ + "actual: %+v", + expectedDiagnostics, + actualDiagnostics, + ) + } +} + +type testDiagnosticsInfo struct { + ChainAddress string `json:"chain_address"` + ConnectedPeers []testDiagnosticsPeerInfo `json:"connected_peers"` +} + +type testDiagnosticsPeerInfo struct { + ChainAddress string `json:"chain_address"` + NetworkMultiAddresses []string `json:"multiaddrs"` +} + +func TestPprofEndpoints(t *testing.T) { + ctx := context.Background() + + t.Run("pprof disabled", func(t *testing.T) { + reg := newRegistry(ctx) + srv := reg.newServer(0, false) + ts := httptest.NewServer(srv.Handler) + defer ts.Close() + + pprofPaths := []string{ + "/debug/pprof/", + "/debug/pprof/cmdline", + "/debug/pprof/profile", + "/debug/pprof/symbol", + "/debug/pprof/trace", + } + + for _, path := range pprofPaths { + resp, err := ts.Client().Get(ts.URL + path) + if err != nil { + t.Fatalf("failed to GET %s: %v", path, err) + } + resp.Body.Close() + + if resp.StatusCode != http.StatusNotFound { + t.Errorf("expected 404 for path %s when pprof is disabled, got %d", path, resp.StatusCode) + } + } + + for _, path := range []string{"/metrics", "/diagnostics"} { + resp, err := ts.Client().Get(ts.URL + path) + if err != nil { + t.Fatalf("failed to GET %s: %v", path, err) + } + resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + t.Errorf("expected 200 for path %s, got %d", path, resp.StatusCode) + } + } + }) + + t.Run("pprof enabled", func(t *testing.T) { + reg := newRegistry(ctx) + srv := reg.newServer(0, true) + ts := httptest.NewServer(srv.Handler) + defer ts.Close() + + resp, err := ts.Client().Get(ts.URL + "/debug/pprof/") + if err != nil { + t.Fatalf("failed to GET /debug/pprof/: %v", err) + } + resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + t.Errorf("expected 200 for /debug/pprof/ when pprof is enabled, got %d", resp.StatusCode) + } + + for _, path := range []string{"/metrics", "/diagnostics"} { + resp, err := ts.Client().Get(ts.URL + path) + if err != nil { + t.Fatalf("failed to GET %s: %v", path, err) + } + resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + t.Errorf("expected 200 for path %s, got %d", path, resp.StatusCode) + } + } + }) +} diff --git a/pkg/clientinfo/rpc_health.go b/pkg/clientinfo/rpc_health.go index 5c97cedd51..8aaeed4301 100644 --- a/pkg/clientinfo/rpc_health.go +++ b/pkg/clientinfo/rpc_health.go @@ -10,11 +10,19 @@ import ( "github.com/ipfs/go-log" "github.com/keep-network/keep-core/pkg/bitcoin" - "github.com/keep-network/keep-core/pkg/chain" ) var rpcHealthLogger = log.Logger("keep-rpc-health") +const ethereumRPCProbeTimeout = 30 * time.Second + +// EthereumRPC provides an uncached Ethereum endpoint probe. Implementations must +// contact the endpoint on every call and forward ctx to the underlying RPC. +// A subscription-backed BlockCounter.CurrentBlock() is not a health probe. +type EthereumRPC interface { + LatestBlockNumber(ctx context.Context) (uint64, error) +} + // benignBtcHeaderErrorPattern matches the JSON-RPC error code -32602 // ("invalid params") returned by some Electrum servers that reject the // `cp_height` parameter of `blockchain.block.header`. The condition is @@ -43,7 +51,7 @@ type RPCHealthChecker struct { registry *Registry // Ethereum health check - ethBlockCounter chain.BlockCounter + ethRPC EthereumRPC ethLastCheck time.Time ethLastSuccess time.Time ethLastError error @@ -72,19 +80,22 @@ type RPCHealthChecker struct { // NewRPCHealthChecker creates a new RPC health checker instance. func NewRPCHealthChecker( registry *Registry, - ethBlockCounter chain.BlockCounter, + ethRPC EthereumRPC, btcChain bitcoin.Chain, checkInterval time.Duration, ) *RPCHealthChecker { if checkInterval == 0 { - checkInterval = 30 * time.Second // Default: check every 30 seconds + // Default kept comfortably above ethereumRPCProbeTimeout so a probe + // that consumes the full deadline during an outage still leaves an + // idle gap before the next tick, instead of re-probing back-to-back. + checkInterval = 60 * time.Second } return &RPCHealthChecker{ - registry: registry, - ethBlockCounter: ethBlockCounter, - btcChain: btcChain, - checkInterval: checkInterval, + registry: registry, + ethRPC: ethRPC, + btcChain: btcChain, + checkInterval: checkInterval, } } @@ -98,6 +109,9 @@ func (r *RPCHealthChecker) Start(ctx context.Context) { // start is the internal implementation of Start. Use Start() for public API. func (r *RPCHealthChecker) start(ctx context.Context) { + // Export unknown health before making calls, including when an RPC hangs. + r.registerMetrics() + // Perform initial health checks immediately r.checkEthereumHealth(ctx) r.checkBitcoinHealth(ctx) @@ -106,8 +120,6 @@ func (r *RPCHealthChecker) start(ctx context.Context) { go r.runEthereumHealthChecks(ctx) go r.runBitcoinHealthChecks(ctx) - // Register metrics observers - r.registerMetrics() } // runEthereumHealthChecks runs periodic Ethereum RPC health checks. @@ -140,59 +152,48 @@ func (r *RPCHealthChecker) runBitcoinHealthChecks(ctx context.Context) { } } -// checkEthereumHealth performs a comprehensive health check on the Ethereum RPC endpoint -// by making actual RPC calls to verify the service is working properly. -// It checks: -// 1. Current block number retrieval -// 2. Block number is reasonable (not stuck at 0 or extremely old) +// checkEthereumHealth probes the Ethereum endpoint for a nonzero latest block. +// The caller's cancellation and a probe deadline are forwarded to the RPC. +// A successful response confirms connectivity, not chain synchronization. func (r *RPCHealthChecker) checkEthereumHealth(ctx context.Context) { - if r.ethBlockCounter == nil { + if r.ethRPC == nil { return } startTime := time.Now() + probeCtx, cancel := context.WithTimeout(ctx, ethereumRPCProbeTimeout) + defer cancel() - // First check: Get current block number - currentBlock, err := r.ethBlockCounter.CurrentBlock() - if err != nil { - r.ethMutex.Lock() - r.ethLastCheck = startTime - r.ethLastError = err - r.ethMutex.Unlock() - rpcHealthLogger.Warnf( - "Ethereum RPC health check failed (CurrentBlock): [%v] (duration: %v)", - err, - time.Since(startTime), - ) - return + currentBlock, err := r.ethRPC.LatestBlockNumber(probeCtx) + if err == nil { + // Never count a response received after cancellation/deadline as healthy. + err = probeCtx.Err() } - - // Second check: Verify block number is reasonable - // Block number should be > 0 (unless on a very new testnet) - // For mainnet/testnet, block numbers should be in thousands/millions - if currentBlock == 0 { - blockErr := fmt.Errorf("block number is 0, node may not be synced") - r.ethMutex.Lock() - r.ethLastCheck = startTime - r.ethLastError = blockErr - r.ethMutex.Unlock() - rpcHealthLogger.Warnf( - "Ethereum RPC health check failed (block number is 0): [%v] (duration: %v)", - blockErr, - time.Since(startTime), - ) - return + if err == nil && currentBlock == 0 { + err = fmt.Errorf("block number is 0, node may not be synced") } - duration := time.Since(startTime) + completedAt := time.Now() + duration := completedAt.Sub(startTime) r.ethMutex.Lock() - r.ethLastCheck = startTime - r.ethLastSuccess = time.Now() - r.ethLastError = nil - r.ethLastDuration = duration + r.ethLastCheck = completedAt + r.ethLastError = err + if err == nil { + r.ethLastSuccess = completedAt + r.ethLastDuration = duration + } r.ethMutex.Unlock() + if err != nil { + rpcHealthLogger.Warnf( + "Ethereum RPC health check failed (LatestBlockNumber): [%v] (duration: %v)", + err, + duration, + ) + return + } + rpcHealthLogger.Debugf( "Ethereum RPC health check succeeded (block: %d, duration: %v)", currentBlock, @@ -204,8 +205,8 @@ func (r *RPCHealthChecker) checkEthereumHealth(ctx context.Context) { // by making actual RPC calls to verify the service is working properly. // It checks: // 1. Latest block height retrieval -// 2. Block header retrieval for the latest block (verifies RPC can retrieve block data) -// 3. Block height is reasonable (not 0) +// 2. Block height is reasonable (not 0) +// 3. Block header retrieval for the latest block (verifies RPC can retrieve block data) func (r *RPCHealthChecker) checkBitcoinHealth(ctx context.Context) { if r.btcChain == nil { return @@ -216,8 +217,9 @@ func (r *RPCHealthChecker) checkBitcoinHealth(ctx context.Context) { // First check: Get latest block height latestHeight, err := r.btcChain.GetLatestBlockHeight() if err != nil { + completedAt := time.Now() r.btcMutex.Lock() - r.btcLastCheck = startTime + r.btcLastCheck = completedAt r.btcLastError = err r.btcMutex.Unlock() rpcHealthLogger.Warnf( @@ -231,8 +233,9 @@ func (r *RPCHealthChecker) checkBitcoinHealth(ctx context.Context) { // Second check: Verify block height is reasonable if latestHeight == 0 { heightErr := fmt.Errorf("block height is 0, node may not be synced") + completedAt := time.Now() r.btcMutex.Lock() - r.btcLastCheck = startTime + r.btcLastCheck = completedAt r.btcLastError = heightErr r.btcMutex.Unlock() rpcHealthLogger.Warnf( @@ -249,8 +252,9 @@ func (r *RPCHealthChecker) checkBitcoinHealth(ctx context.Context) { if err != nil { headerErr := fmt.Errorf("failed to get block header for height %d: %w", latestHeight, err) benign := isKnownBenignBtcHeaderError(err) + completedAt := time.Now() r.btcMutex.Lock() - r.btcLastCheck = startTime + r.btcLastCheck = completedAt r.btcLastError = headerErr if benign { r.btcBenignHeaderErrors++ @@ -274,11 +278,12 @@ func (r *RPCHealthChecker) checkBitcoinHealth(ctx context.Context) { return } - duration := time.Since(startTime) + completedAt := time.Now() + duration := completedAt.Sub(startTime) r.btcMutex.Lock() - r.btcLastCheck = startTime - r.btcLastSuccess = time.Now() + r.btcLastCheck = completedAt + r.btcLastSuccess = completedAt r.btcLastError = nil r.btcLastDuration = duration r.btcMutex.Unlock() @@ -319,6 +324,7 @@ func (r *RPCHealthChecker) GetBitcoinBenignHeaderErrorCount() float64 { // registerMetrics registers metrics observers for RPC health status. func (r *RPCHealthChecker) registerMetrics() { + r.registry.ObserveApplicationSource("performance", r.healthSources()) // Ethereum RPC response time r.registry.ObserveApplicationSource( "performance", @@ -352,3 +358,32 @@ func (r *RPCHealthChecker) registerMetrics() { }, ) } + +// healthSources distinguishes a failed RPC from a probe that stopped completing. +func (r *RPCHealthChecker) healthSources() map[string]Source { + health := func(getStatus func() (bool, time.Time, time.Time, error, time.Duration)) Source { + return func() float64 { + ok, _, _, _, _ := getStatus() + if ok { + return 1 + } + return 0 + } + } + lastCheck := func(getStatus func() (bool, time.Time, time.Time, error, time.Duration)) Source { + return func() float64 { + _, checked, _, _, _ := getStatus() + if checked.IsZero() { + return 0 + } + return float64(checked.Unix()) + } + } + return map[string]Source{ + "rpc_eth_healthy": health(r.GetEthereumHealthStatus), + "rpc_btc_healthy": health(r.GetBitcoinHealthStatus), + "rpc_eth_last_check_timestamp_seconds": lastCheck(r.GetEthereumHealthStatus), + "rpc_btc_last_check_timestamp_seconds": lastCheck(r.GetBitcoinHealthStatus), + "rpc_health_check_interval_seconds": func() float64 { return r.checkInterval.Seconds() }, + } +} diff --git a/pkg/clientinfo/rpc_health_metrics_test.go b/pkg/clientinfo/rpc_health_metrics_test.go new file mode 100644 index 0000000000..b8d1242359 --- /dev/null +++ b/pkg/clientinfo/rpc_health_metrics_test.go @@ -0,0 +1,133 @@ +package clientinfo + +import ( + "context" + "errors" + "testing" + "time" +) + +func TestRPCHealthMetricTransitions(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + eth := &fakeEthereumRPC{currentBlock: 100} + btc := &fakeBitcoinChain{latestHeight: 100} + checker := newTestChecker(eth, btc) + checker.registry = newRegistry(ctx) + checker.registerMetrics() + sources := checker.healthSources() + for name := range sources { + assertCounterExportedInRegistry(t, checker.registry, name) + } + for _, network := range []string{"eth", "btc"} { + if sources["rpc_"+network+"_healthy"]() != 0 || sources["rpc_"+network+"_last_check_timestamp_seconds"]() != 0 { + t.Fatal("unprobed RPC was reported healthy or recently checked") + } + } + before := float64(time.Now().Unix()) + checker.checkEthereumHealth(ctx) + checker.checkBitcoinHealth(ctx) + for _, network := range []string{"eth", "btc"} { + if sources["rpc_"+network+"_healthy"]() != 1 || sources["rpc_"+network+"_last_check_timestamp_seconds"]() < before { + t.Fatalf("%s healthy check was not reflected in metrics", network) + } + } + eth.err = errors.New("Ethereum unavailable") + btc.latestErr = errors.New("Bitcoin unavailable") + _, _, lastSuccess, _, _ := checker.GetEthereumHealthStatus() + failedAt := time.Now() + checker.checkEthereumHealth(ctx) + checker.checkBitcoinHealth(ctx) + if sources["rpc_eth_healthy"]() != 0 || sources["rpc_btc_healthy"]() != 0 { + t.Fatal("RPC failures were not reflected in health metrics") + } + _, lastCheck, retainedSuccess, lastError, _ := checker.GetEthereumHealthStatus() + if lastCheck.Before(failedAt) || !retainedSuccess.Equal(lastSuccess) || lastError == nil { + t.Fatal("failed RPC must complete the check without advancing last success") + } +} + +type ethereumRPCFunc func(context.Context) (uint64, error) + +func (probe ethereumRPCFunc) LatestBlockNumber(ctx context.Context) (uint64, error) { + return probe(ctx) +} + +func TestEthereumProbeDoesNotRefreshMetricsWhilePending(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + started := make(chan struct{}) + checker := NewRPCHealthChecker(nil, ethereumRPCFunc(func(probeCtx context.Context) (uint64, error) { + close(started) + <-probeCtx.Done() + return 0, probeCtx.Err() + }), nil, time.Minute) + previousCheck := time.Now().Add(-time.Hour) + checker.ethLastCheck = previousCheck + checker.ethLastSuccess = previousCheck + sources := checker.healthSources() + done := make(chan struct{}) + go func() { + defer close(done) + checker.checkEthereumHealth(ctx) + }() + <-started + if got := sources["rpc_eth_last_check_timestamp_seconds"](); got != float64(previousCheck.Unix()) { + t.Errorf("pending RPC refreshed the completed-probe timestamp: %v", got) + } + cancel() + <-done + if sources["rpc_eth_healthy"]() != 0 { + t.Fatal("cancelled RPC was reported healthy") + } + _, lastCheck, lastSuccess, lastError, _ := checker.GetEthereumHealthStatus() + if !lastCheck.After(previousCheck) || !lastSuccess.Equal(previousCheck) || !errors.Is(lastError, context.Canceled) { + t.Fatalf("unexpected cancellation state: %v, %v, %v", lastCheck, lastSuccess, lastError) + } +} + +func TestEthereumProbeDeadline(t *testing.T) { + for _, expired := range []bool{false, true} { + t.Run(map[bool]string{false: "bounded RPC context", true: "expired caller context"}[expired], func(t *testing.T) { + ctx := context.Background() + if expired { + var cancel context.CancelFunc + ctx, cancel = context.WithDeadline(ctx, time.Now().Add(-time.Second)) + defer cancel() + } + checker := NewRPCHealthChecker(nil, ethereumRPCFunc(func(probeCtx context.Context) (uint64, error) { + deadline, ok := probeCtx.Deadline() + if !ok || time.Until(deadline) > 30*time.Second { + t.Fatal("Ethereum RPC did not receive the probe deadline") + } + // Even a client that returns a cached/late success after cancellation + // must not turn the health metric green. + return 100, nil + }), nil, time.Minute) + checker.checkEthereumHealth(ctx) + healthy, _, _, lastError, _ := checker.GetEthereumHealthStatus() + if healthy == expired { + t.Fatalf("unexpected health for expired=%v: %v", expired, healthy) + } + if expired && !errors.Is(lastError, context.DeadlineExceeded) { + t.Fatalf("expected deadline failure, got %v", lastError) + } + }) + } +} + +func TestMaintainerMetricsRegistered(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + registry := newRegistry(ctx) + metrics := NewPerformanceMetrics(ctx, registry) + defer metrics.Stop() + for _, name := range []string{ + MetricSpvMaintainerActive, MetricSpvMaintainerLastActivityTimestamp, + MetricSpvMaintainerLastSuccessTimestamp, MetricSpvMaintainerMaxBackoffSeconds, + MetricSpvMaintainerLastFailureTimestamp, + MetricSpvProofTaskFailuresTotal, MetricRedemptionProofTaskFailuresTotal, + } { + assertCounterExportedInRegistry(t, registry, name) + } +} diff --git a/pkg/clientinfo/rpc_health_test.go b/pkg/clientinfo/rpc_health_test.go index 3aa680ce91..e16b4ac554 100644 --- a/pkg/clientinfo/rpc_health_test.go +++ b/pkg/clientinfo/rpc_health_test.go @@ -7,38 +7,26 @@ import ( "fmt" "strings" "sync" + "sync/atomic" "testing" "time" log2 "github.com/ipfs/go-log/v2" - keepclientinfo "github.com/keep-network/keep-common/pkg/clientinfo" "github.com/keep-network/keep-core/pkg/bitcoin" ) // --- fakes --- -type fakeBlockCounter struct { +type fakeEthereumRPC struct { currentBlock uint64 err error } -func (f *fakeBlockCounter) CurrentBlock() (uint64, error) { +func (f *fakeEthereumRPC) LatestBlockNumber(context.Context) (uint64, error) { return f.currentBlock, f.err } -func (f *fakeBlockCounter) WaitForBlockHeight(blockNumber uint64) error { return nil } -func (f *fakeBlockCounter) BlockHeightWaiter(blockNumber uint64) (<-chan uint64, error) { - ch := make(chan uint64) - close(ch) - return ch, nil -} -func (f *fakeBlockCounter) WatchBlocks(ctx context.Context) <-chan uint64 { - ch := make(chan uint64) - go func() { <-ctx.Done(); close(ch) }() - return ch -} - type fakeBitcoinChain struct { latestHeight uint latestErr error @@ -92,18 +80,18 @@ func (f *fakeBitcoinChain) GetCoinbaseTxHash(blockHeight uint) (bitcoin.Hash, er // --- helpers --- -func newTestChecker(eth *fakeBlockCounter, btc *fakeBitcoinChain) *RPCHealthChecker { +func newTestChecker(eth *fakeEthereumRPC, btc *fakeBitcoinChain) *RPCHealthChecker { return &RPCHealthChecker{ - ethBlockCounter: eth, - btcChain: btc, - checkInterval: time.Minute, // not used in direct call tests + ethRPC: eth, + btcChain: btc, + checkInterval: time.Minute, // not used in direct call tests } } // --- Ethereum health tests --- func TestRPCHealthChecker_EthereumHealthy(t *testing.T) { - checker := newTestChecker(&fakeBlockCounter{currentBlock: 12345678}, nil) + checker := newTestChecker(&fakeEthereumRPC{currentBlock: 12345678}, nil) checker.checkEthereumHealth(context.Background()) @@ -125,7 +113,7 @@ func TestRPCHealthChecker_EthereumHealthy(t *testing.T) { func TestRPCHealthChecker_EthereumUnhealthy_RPCError(t *testing.T) { rpcErr := fmt.Errorf("connection refused") - checker := newTestChecker(&fakeBlockCounter{err: rpcErr}, nil) + checker := newTestChecker(&fakeEthereumRPC{err: rpcErr}, nil) checker.checkEthereumHealth(context.Background()) @@ -143,7 +131,7 @@ func TestRPCHealthChecker_EthereumUnhealthy_RPCError(t *testing.T) { } func TestRPCHealthChecker_EthereumUnhealthy_ZeroBlock(t *testing.T) { - checker := newTestChecker(&fakeBlockCounter{currentBlock: 0}, nil) + checker := newTestChecker(&fakeEthereumRPC{currentBlock: 0}, nil) checker.checkEthereumHealth(context.Background()) @@ -157,28 +145,28 @@ func TestRPCHealthChecker_EthereumUnhealthy_ZeroBlock(t *testing.T) { } } -func TestRPCHealthChecker_EthereumNilBlockCounter(t *testing.T) { - // Use a nil interface directly -- not a nil *fakeBlockCounter, which would +func TestRPCHealthChecker_EthereumNilRPC(t *testing.T) { + // Use a nil interface directly -- not a nil *fakeEthereumRPC, which would // create a non-nil interface wrapping a nil pointer and bypass the guard. checker := &RPCHealthChecker{ - ethBlockCounter: nil, // true nil interface - checkInterval: time.Minute, + ethRPC: nil, // true nil interface + checkInterval: time.Minute, } - // Should not panic when ethBlockCounter is nil. + // Should not panic when ethRPC is nil. checker.checkEthereumHealth(context.Background()) healthy, lastCheck, _, _, _ := checker.GetEthereumHealthStatus() if healthy { - t.Error("expected not healthy with nil block counter") + t.Error("expected not healthy with nil Ethereum RPC") } if !lastCheck.IsZero() { - t.Error("lastCheck should not be set when block counter is nil") + t.Error("lastCheck should not be set when Ethereum RPC is nil") } } func TestRPCHealthChecker_EthereumHealthTransition(t *testing.T) { - eth := &fakeBlockCounter{currentBlock: 100} + eth := &fakeEthereumRPC{currentBlock: 100} checker := newTestChecker(eth, nil) // First check: healthy. @@ -531,8 +519,8 @@ func TestRPCHealthChecker_StartIdempotent(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - registry := &Registry{keepclientinfo.NewRegistry(), ctx} - eth := &fakeBlockCounter{currentBlock: 12345} + registry := newRegistry(ctx) + eth := &fakeEthereumRPC{currentBlock: 12345} btc := &fakeBitcoinChain{latestHeight: 800000} checker := NewRPCHealthChecker(registry, eth, btc, time.Hour) @@ -548,3 +536,69 @@ func TestRPCHealthChecker_StartIdempotent(t *testing.T) { t.Error("expected healthy after Start") } } + +// countingEthereumRPC wraps fakeEthereumRPC to count LatestBlockNumber calls, +// used to detect whether the periodic health-check goroutine keeps running. +type countingEthereumRPC struct { + fakeEthereumRPC + calls *int32 +} + +func (f *countingEthereumRPC) LatestBlockNumber(ctx context.Context) (uint64, error) { + atomic.AddInt32(f.calls, 1) + return f.fakeEthereumRPC.LatestBlockNumber(ctx) +} + +// countingBitcoinChain wraps fakeBitcoinChain to count GetLatestBlockHeight +// calls, used to detect whether the periodic health-check goroutine keeps +// running. +type countingBitcoinChain struct { + fakeBitcoinChain + calls *int32 +} + +func (f *countingBitcoinChain) GetLatestBlockHeight() (uint, error) { + atomic.AddInt32(f.calls, 1) + return f.fakeBitcoinChain.GetLatestBlockHeight() +} + +// TestRPCHealthChecker_GoroutinesStopOnCancel verifies that +// runEthereumHealthChecks and runBitcoinHealthChecks actually exit on +// ctx.Done() instead of leaking: it lets several ticks elapse to confirm the +// periodic goroutines are running, cancels the context, then asserts no +// further probes occur even though the check interval would otherwise have +// fired several more times. +func TestRPCHealthChecker_GoroutinesStopOnCancel(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + + var ethCalls, btcCalls int32 + eth := &countingEthereumRPC{fakeEthereumRPC: fakeEthereumRPC{currentBlock: 100}, calls: ðCalls} + btc := &countingBitcoinChain{fakeBitcoinChain: fakeBitcoinChain{latestHeight: 100}, calls: &btcCalls} + + registry := newRegistry(ctx) + checker := NewRPCHealthChecker(registry, eth, btc, 5*time.Millisecond) + checker.Start(ctx) + + // Let several ticks elapse so both periodic goroutines are confirmed + // running before cancellation. + time.Sleep(50 * time.Millisecond) + if atomic.LoadInt32(ðCalls) < 2 || atomic.LoadInt32(&btcCalls) < 2 { + t.Fatal("expected multiple periodic health checks before cancellation") + } + + cancel() + // Allow any tick already in flight at cancellation time to complete. + time.Sleep(20 * time.Millisecond) + ethAtCancel := atomic.LoadInt32(ðCalls) + btcAtCancel := atomic.LoadInt32(&btcCalls) + + // Wait long enough that several more ticks would have fired had the + // goroutines not exited on ctx.Done(). + time.Sleep(50 * time.Millisecond) + if got := atomic.LoadInt32(ðCalls); got != ethAtCancel { + t.Fatalf("runEthereumHealthChecks kept probing after cancellation: %d -> %d", ethAtCancel, got) + } + if got := atomic.LoadInt32(&btcCalls); got != btcAtCancel { + t.Fatalf("runBitcoinHealthChecks kept probing after cancellation: %d -> %d", btcAtCancel, got) + } +} diff --git a/pkg/cmd/cmd.go b/pkg/cmd/cmd.go new file mode 100644 index 0000000000..e6abc92058 --- /dev/null +++ b/pkg/cmd/cmd.go @@ -0,0 +1,178 @@ +// Package cmd contains useful utilities for commands that interact with the +// Ethereum blockchain. +package cmd + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil" + "github.com/keep-network/keep-core/pkg/cmd/flag" + "github.com/spf13/cobra" +) + +const ( + blockFlag string = "block" + blockShort string = "b" + // SubmitFlag allows for definition and lookup of a boolean `--submit` + // command-line flag indicating that a given contract interaction should be + // submitted as a paid, mutating interaction to the configured Ethereum chain. + SubmitFlag string = "submit" + submitShort string = "s" + valueFlag string = "value" + valueShort string = "v" +) + +var ( + // BlockFlagValue allows for reading the block flag included in ConstFlags, + // which represents the block at which to execute a contract interaction. + // The value, if that flag is passed on the command line, is stored in this + // variable. + BlockFlagValue flag.BigIntFlagValue + // ValueFlagValue allows for reading the value flag included in + // PayableFlags, which represents an amount of ETH to send with a contract + // interaction. The value, if that flag is passed on the command line, is + // stored in this variable. + ValueFlagValue ethereum.Wei +) + +// InitConstFlags initializes flags useful for constant contract interactions, +// meaning contract interactions that do not require transaction submission and +// are used for inspecting chain state. These flags include: +// +// --block flag to check an interaction's result value at a specific block. +func InitConstFlags(cmd *cobra.Command) { + flag.BigIntVarPFlag( + cmd.Flags(), + &BlockFlagValue, + blockFlag, + blockShort, + nil, + "Retrieve the result of calling this method on `BLOCK`.", + ) +} + +// InitNonConstFlags initializes flags useful for non-constant contract interactions, +// meaning contract interactions that can be submitted as transactions and are +// used for modifying chain state. These flags include: +// +// --submit flag to submit an interaction as a transaction, +// +// as well as all flags in ConstFlags. +func InitNonConstFlags(cmd *cobra.Command) { + InitConstFlags(cmd) + + cmd.Flags().BoolP( + SubmitFlag, + submitShort, + false, + "Submit this call as a gas-spending network transaction.", + ) +} + +// InitPayableFlags initializes flags useful for payable contract interactions, +// meaning contract interactions that can be submitted as transactions and are +// used for modifying chain state with a payload that includes ETH. These flags +// include: +// +// --value flag to specify the ETH amount to send with the interaction, +// +// as well as all flags in NonConstFlags. +func InitPayableFlags(cmd *cobra.Command) { + InitNonConstFlags(cmd) + + flag.WeiVarPFlag( + cmd.Flags(), + &ValueFlagValue, + valueFlag, + valueShort, + *ethereum.WrapWei(big.NewInt(0)), + "Send `VALUE` ether with this call.", + ) +} + +// ComposableArgChecker is a type that allows multiple spf13/cobra Before functions +// to be chained. See AndThen for more. +type ComposableArgChecker func(*cobra.Command, []string) error + +// AndThen on a ComposableArgChecker allows composing a ComposableArgChecker +// with another one, such that this ComposableArgChecker runs and, if it +// succeeds, the nextChecker runs. +// +// As an example, this allows for two BeforeFuncs to be composed as: +// +// ComposableArgChecker(checkFlagAValue).AndThen(ComposableArgChecker(checkFlagBValue)) +// +// The resulting ComposableArgChecker will run checkFlagAValue and, if it +// passes, checkFlagBValue. +func (cac ComposableArgChecker) AndThen(nextChecker ComposableArgChecker) ComposableArgChecker { + return func(c *cobra.Command, args []string) error { + cacErr := cac(c, args) + if cacErr != nil { + return cacErr + } + + return nextChecker(c, args) + } +} + +var ( + valueArgChecker ComposableArgChecker = func(c *cobra.Command, args []string) error { + if err := c.MarkFlagRequired(valueFlag); err != nil { + return fmt.Errorf("failed to mark %s flag required: %w", valueFlag, err) + } + + return nil + } + + submittedArgChecker ComposableArgChecker = func(c *cobra.Command, args []string) error { + c.MarkFlagsMutuallyExclusive(SubmitFlag, blockFlag) + + return nil + } +) + +var ( + // NonConstArgsChecker runs any validation of parameters needed for a + // command that will submit a mutating transaction to an Ethereum node. In + // particular, it will disallow const arguments like --block and + // --transaction if --submit is specified. + NonConstArgsChecker = submittedArgChecker + // PayableArgsChecker runs any validation of parameters needed for a + // command that will submit a payable transaction to an Ethereum node. In + // particular, it will disallow const arguments like --block and + // --transaction if --submit is specified, and will also ensure that the + // call includes specifies a --value. + PayableArgsChecker = NonConstArgsChecker.AndThen(valueArgChecker) +) + +// ArgCountChecker provides a consistent error in case the number of arguments +// passed on the command-line is incorrect. +func ArgCountChecker(expectedArgCount int) func(*cobra.Command, []string) error { + return func(c *cobra.Command, args []string) error { + if len(args) != expectedArgCount { + return fmt.Errorf( + "expected [%d] arguments but got [%d]", + expectedArgCount, + len(args), + ) + } + + return nil + } +} + +// PrintOutput provides for custom command-line-friendly ways of printing +// addresses (as hex) and transaction and related hashes (also as hex). It falls +// back on a standard Println for other types. +func PrintOutput(output interface{}) { + switch out := output.(type) { + case common.Address: + fmt.Println(out.Hex()) + case common.Hash: + fmt.Println(out.Hex()) + default: + fmt.Printf("%+v\n", out) + } +} diff --git a/pkg/cmd/cmd_test.go b/pkg/cmd/cmd_test.go new file mode 100644 index 0000000000..91fcb8264d --- /dev/null +++ b/pkg/cmd/cmd_test.go @@ -0,0 +1,147 @@ +package cmd + +import ( + "fmt" + "reflect" + "testing" + + "github.com/spf13/cobra" +) + +func TestComposableArgCheckerComposesOnSuccess(t *testing.T) { + var seenFunctions []int + + firstComposer := ComposableArgChecker(func(*cobra.Command, []string) error { + seenFunctions = append(seenFunctions, 1) + return nil + }) + secondComposer := ComposableArgChecker(func(*cobra.Command, []string) error { + seenFunctions = append(seenFunctions, 2) + return nil + }) + thirdComposer := ComposableArgChecker(func(*cobra.Command, []string) error { + seenFunctions = append(seenFunctions, 3) + return nil + }) + + tests := map[string]struct { + composed ComposableArgChecker + sequence []int + }{ + "1-2-3": { + composed: firstComposer.AndThen(secondComposer).AndThen(thirdComposer), + sequence: []int{1, 2, 3}, + }, + "3-2-1": { + composed: thirdComposer.AndThen(secondComposer).AndThen(firstComposer), + sequence: []int{3, 2, 1}, + }, + "2-1-3": { + composed: secondComposer.AndThen(firstComposer).AndThen(thirdComposer), + sequence: []int{2, 1, 3}, + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + seenFunctions = []int{} + result := test.composed(nil, []string{}) + + if !reflect.DeepEqual(seenFunctions, test.sequence) { + t.Errorf( + "\nexpected: [%v]\nactual: [%v]", + test.sequence, + seenFunctions, + ) + } + + if result != nil { + t.Errorf( + "\nexpected: [%v]\nactual: [%v]", + nil, + result, + ) + } + }) + } +} + +func TestComposableArgCheckerShortCircuitsOnFailure(t *testing.T) { + var seenFunctions []int + + firstComposer := ComposableArgChecker(func(*cobra.Command, []string) error { + seenFunctions = append(seenFunctions, 1) + return nil + }) + secondComposer := ComposableArgChecker(func(*cobra.Command, []string) error { + seenFunctions = append(seenFunctions, 2) + return nil + }) + thirdComposer := ComposableArgChecker(func(*cobra.Command, []string) error { + seenFunctions = append(seenFunctions, 3) + return nil + }) + errorComposer := ComposableArgChecker(func(*cobra.Command, []string) error { + return fmt.Errorf("ohai") + }) + + tests := map[string]struct { + composed ComposableArgChecker + sequence []int + errorMessage string + }{ + "1-2-error-3": { + composed: firstComposer.AndThen(secondComposer).AndThen(errorComposer).AndThen(thirdComposer), + sequence: []int{1, 2}, + errorMessage: "ohai", + }, + "3-error-2-1": { + composed: thirdComposer.AndThen(errorComposer).AndThen(secondComposer).AndThen(firstComposer), + sequence: []int{3}, + errorMessage: "ohai", + }, + "2-1-error-3": { + composed: secondComposer.AndThen(firstComposer).AndThen(errorComposer).AndThen(thirdComposer), + sequence: []int{2, 1}, + errorMessage: "ohai", + }, + "3-1-2-error": { + composed: thirdComposer.AndThen(firstComposer).AndThen(secondComposer).AndThen(errorComposer), + sequence: []int{3, 1, 2}, + errorMessage: "ohai", + }, + "3-1-2": { + composed: thirdComposer.AndThen(firstComposer).AndThen(secondComposer), + sequence: []int{3, 1, 2}, + errorMessage: "", + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + seenFunctions = []int{} + err := test.composed(nil, []string{}) + + if !reflect.DeepEqual(seenFunctions, test.sequence) { + t.Errorf( + "\nexpected: [%v]\nactual: [%v]", + test.sequence, + seenFunctions, + ) + } + + message := "" + if err != nil { + message = err.Error() + } + + if message != test.errorMessage { + t.Errorf( + "\nexpected: [%v]\nactual: [%v]", + test.errorMessage, + message, + ) + } + }) + } +} diff --git a/pkg/cmd/flag/flag_big_int.go b/pkg/cmd/flag/flag_big_int.go new file mode 100644 index 0000000000..41d256409a --- /dev/null +++ b/pkg/cmd/flag/flag_big_int.go @@ -0,0 +1,60 @@ +package flag + +import ( + "fmt" + "math/big" + + "github.com/spf13/pflag" +) + +// BigIntVarFlag is a custom flag to handle `big.Int` type, that is not supported +// by `pflag.FlagSet`. +func BigIntVarFlag(f *pflag.FlagSet, p *BigIntFlagValue, name string, defaultValue *big.Int, usage string) { + BigIntVarPFlag(f, p, name, "", defaultValue, usage) +} + +// BigIntVarPFlag is a custom flag to handle `big.Int` type, that is not supported +// by `pflag.FlagSet`. +func BigIntVarPFlag(f *pflag.FlagSet, p *BigIntFlagValue, name string, short string, defaultValue *big.Int, usage string) { + f.VarP(newBigIntValue(defaultValue, p), name, short, usage) +} + +// BigIntFlagValue is a wrapper for big.Int to use as a flag value. The flag value +// supports setting `nil` as a default value. +type BigIntFlagValue struct { + *big.Int +} + +func newBigIntValue(val *big.Int, p *BigIntFlagValue) *BigIntFlagValue { + if p == nil { + p = &BigIntFlagValue{} + } + *p = BigIntFlagValue{val} + return p +} + +// Set sets the flag value from a string. +func (b *BigIntFlagValue) Set(s string) error { + v := &big.Int{} + v, ok := v.SetString(s, 0) + if !ok { + return fmt.Errorf("failed to parse as big.Int: %s", s) + } + b.Int = v + + return nil +} + +// Type returns the type name handled by the flag. +func (b *BigIntFlagValue) Type() string { + return "big.Int" +} + +// String outputs the flag value as a string. If the value is `nil` it returns +// an empty string. +func (b *BigIntFlagValue) String() string { + if b.Int == nil { + return "" + } + return b.Int.String() +} diff --git a/pkg/cmd/flag/flag_big_int_test.go b/pkg/cmd/flag/flag_big_int_test.go new file mode 100644 index 0000000000..0bd2df6103 --- /dev/null +++ b/pkg/cmd/flag/flag_big_int_test.go @@ -0,0 +1,89 @@ +package flag + +import ( + "errors" + "math/big" + "testing" + + pflag "github.com/spf13/pflag" +) + +const bigIntFlagName = "amount" + +func TestBigIntVarFlag_Set(t *testing.T) { + defaultValue := big.NewInt(11) + + tests := map[string]struct { + value string + expectedError error + expectedValue *big.Int + }{ + "valid value": { + value: "8569412", + expectedValue: big.NewInt(8569412), + }, + "invalid value": { + value: "100k", + expectedError: errors.New( + "invalid argument \"100k\" for \"--" + bigIntFlagName + + "\" flag: failed to parse as big.Int: 100k", + ), + expectedValue: defaultValue, + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + flags := pflag.NewFlagSet("flag-set-"+testName, pflag.PanicOnError) + + var valueDest BigIntFlagValue + + BigIntVarFlag(flags, &valueDest, bigIntFlagName, defaultValue, "") + + err := flags.Set(bigIntFlagName, test.value) + + if errorMessage(err) != errorMessage(test.expectedError) { + t.Errorf( + "unexpected error\nexpected: %v\nactual: %v\n", + test.expectedError, + err, + ) + } + + if valueDest.Cmp(test.expectedValue) != 0 { + t.Errorf( + "\nexpected: %s\nactual: %s", + test.expectedValue, + valueDest, + ) + } + }) + } +} + +func TestBigIntVarFlag_DefaultValueNil(t *testing.T) { + var defaultValue *big.Int = nil + + flags := pflag.NewFlagSet("flag-set", pflag.PanicOnError) + + var valueDest BigIntFlagValue + + BigIntVarFlag(flags, &valueDest, bigIntFlagName, defaultValue, "") + + if &valueDest == nil { + t.Errorf( + "invalid valueDest\nexpected: %+v\nactual: %+v", + &BigIntFlagValue{}, + valueDest, + ) + } + + if valueDest.Int != nil { + t.Errorf( + "invalid valueDest.Int\nexpected: %+v\nactual: %+v", + nil, + valueDest.Int, + ) + } + +} diff --git a/pkg/cmd/flag/flag_helpers_test.go b/pkg/cmd/flag/flag_helpers_test.go new file mode 100644 index 0000000000..53c0fc8558 --- /dev/null +++ b/pkg/cmd/flag/flag_helpers_test.go @@ -0,0 +1,12 @@ +package flag + +// errorMessage returns err.Error() or "" if err is nil. Used to compare error +// equality by message string rather than by concrete type, since pflag wraps +// underlying errors with fmt.Errorf("...: %w", inner) — the rendered message +// stays stable across pflag versions but the concrete type does not. +func errorMessage(err error) string { + if err == nil { + return "" + } + return err.Error() +} diff --git a/pkg/cmd/flag/flag_wei.go b/pkg/cmd/flag/flag_wei.go new file mode 100644 index 0000000000..14750b3b39 --- /dev/null +++ b/pkg/cmd/flag/flag_wei.go @@ -0,0 +1,38 @@ +package flag + +import ( + "github.com/keep-network/keep-core/pkg/chain/ethereumutil" + "github.com/spf13/pflag" +) + +// WeiVarFlag is a custom flag to handle `ethereum.Wei` type, that is not supported +// by `pflag.FlagSet`. +func WeiVarFlag(f *pflag.FlagSet, p *ethereum.Wei, name string, value ethereum.Wei, usage string) { + WeiVarPFlag(f, p, name, "", value, usage) +} + +// WeiVarPFlag is a custom flag to handle `ethereum.Wei` type, that is not supported +// by `pflag.FlagSet`. +func WeiVarPFlag(f *pflag.FlagSet, p *ethereum.Wei, name string, short string, value ethereum.Wei, usage string) { + f.VarP(newWeiValue(value, p), name, short, usage) +} + +type weiValue ethereum.Wei + +func newWeiValue(val ethereum.Wei, p *ethereum.Wei) *weiValue { + *p = val + return (*weiValue)(p) +} + +func (w *weiValue) Set(s string) error { + v := ethereum.Wei{} + err := v.UnmarshalText([]byte(s)) + *w = weiValue(v) + return err +} + +func (w *weiValue) Type() string { + return "wei" +} + +func (w *weiValue) String() string { return (*ethereum.Wei)(w).String() } diff --git a/pkg/cmd/flag/flag_wei_test.go b/pkg/cmd/flag/flag_wei_test.go new file mode 100644 index 0000000000..f3d6e62df1 --- /dev/null +++ b/pkg/cmd/flag/flag_wei_test.go @@ -0,0 +1,100 @@ +package flag + +import ( + "errors" + "math/big" + "testing" + + "github.com/keep-network/keep-core/pkg/chain/ethereumutil" + pflag "github.com/spf13/pflag" +) + +func TestWeiVarFlag_Set(t *testing.T) { + defaultValue := *ethereum.WrapWei(big.NewInt(0)) + flagName := "amount" + + tests := map[string]struct { + value string + expectedError error + expectedValue *big.Int + }{ + "value without unit": { + value: "101", + expectedValue: big.NewInt(101), + }, + "value with wei unit": { + value: "202 wei", + expectedValue: big.NewInt(202), + }, + "value with gwei unit": { + value: "303 gwei", + expectedValue: big.NewInt(303000000000), + }, + "value with ether unit": { + value: "0.9 ether", + expectedValue: big.NewInt(900000000000000000), + }, + "value with invalid comma delimiter": { + value: "3,5 ether", + expectedError: errors.New( + "invalid argument \"3,5 ether\" for \"--" + flagName + + "\" flag: failed to parse value: [3,5 ether]", + ), + }, + "value with invalid unit": { + value: "10 bei", + expectedError: errors.New( + "invalid argument \"10 bei\" for \"--" + flagName + + "\" flag: invalid unit: bei; please use one of: ether, gwei, wei", + ), + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + flags := pflag.NewFlagSet("flag-set-"+testName, pflag.PanicOnError) + + var valueDest ethereum.Wei + + WeiVarFlag(flags, &valueDest, flagName, defaultValue, "") + + err := flags.Set(flagName, test.value) + + if errorMessage(err) != errorMessage(test.expectedError) { + t.Errorf( + "unexpected error\nexpected: %v\nactual: %v\n", + test.expectedError, + err, + ) + } + + if valueDest.Cmp(test.expectedValue) != 0 { + t.Errorf( + "\nexpected: %s\nactual: %s", + test.expectedValue, + valueDest, + ) + } + }) + } +} + +func TestWeiVarFlag_DefaultValue(t *testing.T) { + defaultValue := *ethereum.WrapWei(big.NewInt(859756)) + flagName := "amount" + + flags := pflag.NewFlagSet("flag-set", pflag.PanicOnError) + + var valueDest ethereum.Wei + + WeiVarFlag(flags, &valueDest, flagName, defaultValue, "") + + if valueDest.Cmp(defaultValue.Int) != 0 { + t.Errorf( + "\nexpected: %s\nactual: %s", + defaultValue, + valueDest, + ) + } + +} diff --git a/pkg/crypto/ephemeral/private_key.go b/pkg/crypto/ephemeral/private_key.go index e75376cc45..2373e42388 100644 --- a/pkg/crypto/ephemeral/private_key.go +++ b/pkg/crypto/ephemeral/private_key.go @@ -1,11 +1,19 @@ package ephemeral import ( + "errors" "fmt" "github.com/btcsuite/btcd/btcec" ) +// ErrInvalidPublicKey is returned by UnmarshalPublicKey when the given bytes +// do not decode to a valid point on the curve. Wrapped into the returned +// error via %w so callers up the stack (including retry-policy code) can +// classify the failure with errors.Is regardless of the underlying decoder's +// error type. +var ErrInvalidPublicKey = errors.New("invalid ephemeral public key") + // PrivateKey is an ephemeral private elliptic curve key. type PrivateKey btcec.PrivateKey @@ -58,7 +66,7 @@ func UnmarshalPrivateKey(bytes []byte) *PrivateKey { func UnmarshalPublicKey(bytes []byte) (*PublicKey, error) { pubKey, err := btcec.ParsePubKey(bytes, curve()) if err != nil { - return nil, fmt.Errorf("could not parse ephemeral public key: [%v]", err) + return nil, fmt.Errorf("%w: [%w]", ErrInvalidPublicKey, err) } return (*PublicKey)(pubKey), nil diff --git a/pkg/crypto/ephemeral/symmetric_key.go b/pkg/crypto/ephemeral/symmetric_key.go index 75fba04baf..abe2fac24f 100644 --- a/pkg/crypto/ephemeral/symmetric_key.go +++ b/pkg/crypto/ephemeral/symmetric_key.go @@ -4,7 +4,7 @@ import ( "crypto/sha256" "github.com/btcsuite/btcd/btcec" - "github.com/keep-network/keep-common/pkg/encryption" + "github.com/keep-network/keep-core/pkg/encryption" ) // SymmetricEcdhKey is an ephemeral Elliptic Curve key created with diff --git a/pkg/decode/bytes.go b/pkg/decode/bytes.go new file mode 100644 index 0000000000..4f92530446 --- /dev/null +++ b/pkg/decode/bytes.go @@ -0,0 +1,39 @@ +package decode + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common/hexutil" +) + +// ParseBytes20 parses `string` into `[20]byte` type. The input string must have +// 20 bytes hex-encoded. +func ParseBytes20(str string) ([20]byte, error) { + bytesArray := [20]byte{} + slice, err := hexutil.Decode(str) + if err != nil { + return bytesArray, err + } + if len(slice) != 20 { + return bytesArray, fmt.Errorf("expected 20 bytes array; has: [%v]", len(slice)) + } + + copy(bytesArray[:], slice) + return bytesArray, nil +} + +// ParseBytes32 parses `string` into `[32]byte` type. The input string must have +// 32 bytes hex-encoded. +func ParseBytes32(str string) ([32]byte, error) { + bytesArray := [32]byte{} + slice, err := hexutil.Decode(str) + if err != nil { + return bytesArray, err + } + if len(slice) != 32 { + return bytesArray, fmt.Errorf("expected 32 bytes array; has: [%v]", len(slice)) + } + + copy(bytesArray[:], slice) + return bytesArray, nil +} diff --git a/pkg/decode/bytes_test.go b/pkg/decode/bytes_test.go new file mode 100644 index 0000000000..96b774b828 --- /dev/null +++ b/pkg/decode/bytes_test.go @@ -0,0 +1,126 @@ +package decode + +import ( + "fmt" + "testing" +) + +func TestParseBytes20(t *testing.T) { + hexEncoded := "0x3805eed0bb0792eff8815addedb36add2c7257e5" + bytes, err := ParseBytes20(hexEncoded) + if err != nil { + t.Fatal(err) + } + + roundtrip := fmt.Sprintf("0x%x", bytes) + + if roundtrip != hexEncoded { + t.Errorf( + "unexpected parsed bytes\nexpected: %v\nactual: %v\n", + hexEncoded, + roundtrip, + ) + } +} + +func TestParseBytes20_Fail(t *testing.T) { + + var tests = map[string]struct { + input string + expectedError string + }{ + "too short": { + input: "0xFFFF", + expectedError: "expected 20 bytes array; has: [2]", + }, + "empty": { + input: "", + expectedError: "empty hex string", + }, + "just 0x prefix": { + input: "0x", + expectedError: "expected 20 bytes array; has: [0]", + }, + "no prefix": { + input: "FF", + expectedError: "hex string without 0x prefix", + }, + "invalid hex": { + input: "0xLMA0", + expectedError: "invalid hex string", + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + _, actualError := ParseBytes20(test.input) + if actualError.Error() != test.expectedError { + t.Errorf( + "unexpected error\nexpected: %v\nactual: %v\n", + test.expectedError, + actualError, + ) + } + }) + } +} + +func TestParseBytes32(t *testing.T) { + hexEncoded := "0xad63a8286ea7fa22d75e167216171417a96c4753946fd45e3a8dff4e4f29a830" + bytes, err := ParseBytes32(hexEncoded) + if err != nil { + t.Fatal(err) + } + + roundtrip := fmt.Sprintf("0x%x", bytes) + + if roundtrip != hexEncoded { + t.Errorf( + "unexpected parsed bytes\nexpected: %v\nactual: %v\n", + hexEncoded, + roundtrip, + ) + } +} + +func TestParseBytes32_Fail(t *testing.T) { + + var tests = map[string]struct { + input string + expectedError string + }{ + "too short": { + input: "0xFFFF", + expectedError: "expected 32 bytes array; has: [2]", + }, + "empty": { + input: "", + expectedError: "empty hex string", + }, + "just 0x prefix": { + input: "0x", + expectedError: "expected 32 bytes array; has: [0]", + }, + "no prefix": { + input: "FF", + expectedError: "hex string without 0x prefix", + }, + "invalid hex": { + input: "0xLMA0", + expectedError: "invalid hex string", + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + _, actualError := ParseBytes32(test.input) + if actualError.Error() != test.expectedError { + t.Errorf( + "unexpected error\nexpected: %v\nactual: %v\n", + test.expectedError, + actualError, + ) + } + }) + } +} diff --git a/pkg/decode/uint.go b/pkg/decode/uint.go new file mode 100644 index 0000000000..336cee4af6 --- /dev/null +++ b/pkg/decode/uint.go @@ -0,0 +1,33 @@ +package decode + +import ( + "strconv" +) + +type number interface { + int8 | int16 | int32 | int64 +} + +type unumber interface { + uint8 | uint16 | uint32 | uint64 +} + +// ParseInt parses string to int of the given bit size. +func ParseInt[K number](str string, bitSize int) (K, error) { + val64, err := strconv.ParseInt(str, 10, bitSize) + if err != nil { + return K(0), err + } + + return K(val64), nil +} + +// ParseUint parses string to uint of the given bit size. +func ParseUint[K unumber](str string, bitSize int) (K, error) { + val64, err := strconv.ParseUint(str, 10, bitSize) + if err != nil { + return K(0), err + } + + return K(val64), nil +} diff --git a/pkg/decode/uint_test.go b/pkg/decode/uint_test.go new file mode 100644 index 0000000000..6b1adcbe54 --- /dev/null +++ b/pkg/decode/uint_test.go @@ -0,0 +1,104 @@ +package decode + +import ( + "fmt" + "testing" +) + +func TestParseInt(t *testing.T) { + assertParseInt(t, "min int8", "-128", 8, int8(-128)) + assertParseInt(t, "max int8", "127", 8, int8(127)) + + assertParseInt(t, "min int16", "-32768", 16, int16(-32768)) + assertParseInt(t, "max int16", "32767", 16, int16(32767)) + + assertParseInt(t, "min int32", "-2147483648", 32, int32(-2147483648)) + assertParseInt(t, "max int32", "2147483647", 32, int32(2147483647)) + + assertParseInt(t, "min int64", "-9223372036854775808", 64, int64(-9223372036854775808)) + assertParseInt(t, "max int64", "9223372036854775807", 64, int64(9223372036854775807)) +} + +func TestParseInt_Fail(t *testing.T) { + assertParseIntFail[int8](t, "int8 out of range", "129", 8, fmt.Errorf(`strconv.ParseInt: parsing "129": value out of range`)) +} + +func TestParseUint(t *testing.T) { + assertParseUint(t, "min uint8", "0", 8, uint8(0)) + assertParseUint(t, "max uint8", "255", 8, uint8(255)) + + assertParseUint(t, "min uint16", "0", 16, uint16(0)) + assertParseUint(t, "max uint16", "65535", 16, uint16(65535)) + + assertParseUint(t, "min uint32", "0", 32, uint32(0)) + assertParseUint(t, "max uint32", "4294967295", 32, uint32(4294967295)) + + assertParseUint(t, "min uint64", "0", 64, uint64(0)) + assertParseUint(t, "max uint64", "18446744073709551615", 64, uint64(18446744073709551615)) +} + +func TestParseUint_Fail(t *testing.T) { + assertParseUintFail[uint8](t, "int8 out of range", "256", 8, fmt.Errorf(`strconv.ParseUint: parsing "256": value out of range`)) +} + +func assertParseInt[K number](t *testing.T, testName string, str string, bitSize int, expectedResult K) { + t.Run(testName, func(t *testing.T) { + actualResult, err := ParseInt[K](str, bitSize) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if actualResult != expectedResult { + t.Errorf( + "unexpected result\nexpected: %d\nactual: %d", + expectedResult, + actualResult, + ) + } + }) +} + +func assertParseIntFail[K number](t *testing.T, testName string, str string, bitSize int, expectedError error) { + t.Run(testName, func(t *testing.T) { + _, actualError := ParseInt[K](str, bitSize) + if actualError.Error() != expectedError.Error() { + t.Errorf( + "unexpected error\nexpected: %s\nactual: %s", + expectedError, + actualError, + ) + } + + }) +} + +func assertParseUint[K unumber](t *testing.T, testName string, str string, bitSize int, expectedResult K) { + t.Run(testName, func(t *testing.T) { + actualResult, err := ParseUint[K](str, bitSize) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if actualResult != expectedResult { + t.Errorf( + "unexpected result\nexpected: %d\nactual: %d", + expectedResult, + actualResult, + ) + } + }) +} + +func assertParseUintFail[K unumber](t *testing.T, testName string, str string, bitSize int, expectedError error) { + t.Run(testName, func(t *testing.T) { + _, actualError := ParseUint[K](str, bitSize) + if actualError.Error() != expectedError.Error() { + t.Errorf( + "unexpected error\nexpected: %s\nactual: %s", + expectedError, + actualError, + ) + } + + }) +} diff --git a/pkg/encryption/box.go b/pkg/encryption/box.go new file mode 100644 index 0000000000..a4a535b7f7 --- /dev/null +++ b/pkg/encryption/box.go @@ -0,0 +1,65 @@ +package encryption + +import ( + "crypto/rand" + "errors" + "fmt" + "io" + + "golang.org/x/crypto/nacl/secretbox" +) + +const ( + // KeyLength represents the byte size of the key. + KeyLength = 32 + + // NonceSize represents the byte size of nonce for XSalsa20 cipher used for + // encryption. + NonceSize = 24 +) + +// box is used to encrypt and decrypt a plaintext. +type box struct { + key [KeyLength]byte +} + +// NewBox uses XSalsa20 and Poly1305 to encrypt and decrypt the plaintext +// with the key. +func NewBox(key [KeyLength]byte) Box { + return &box{ + key: key, + } +} + +// Encrypt takes the input plaintext and uses XSalsa20 and Poly1305 to encrypt +// the plaintext with the key. +func (b *box) Encrypt(plaintext []byte) ([]byte, error) { + // The nonce needs to be unique, but not secure. Therefore we include it + // at the beginning of the ciphertext. + var nonce [NonceSize]byte + if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil { + return nil, fmt.Errorf("key encryption failed [%v]", err) + } + + return secretbox.Seal(nonce[:], plaintext, &nonce, &b.key), nil +} + +// Decrypt takes the input ciphertext and decrypts it. +func (b *box) Decrypt(ciphertext []byte) (plaintext []byte, err error) { + defer func() { + // secretbox Open panics for invalid input + if recover() != nil { + err = errors.New("symmetric key decryption failed") + } + }() + + var nonce [NonceSize]byte + copy(nonce[:], ciphertext[:NonceSize]) + + plaintext, ok := secretbox.Open(nil, ciphertext[NonceSize:], &nonce, &b.key) + if !ok { + err = fmt.Errorf("symmetric key decryption failed") + } + + return +} diff --git a/pkg/encryption/box_test.go b/pkg/encryption/box_test.go new file mode 100644 index 0000000000..0b78ef3f47 --- /dev/null +++ b/pkg/encryption/box_test.go @@ -0,0 +1,81 @@ +package encryption + +import ( + "crypto/sha256" + "fmt" + "reflect" + "testing" +) + +var accountPassword = []byte("passW0rd") + +func TestEncryptDecrypt(t *testing.T) { + msg := "Keep Calm and Carry On" + + box := NewBox(sha256.Sum256(accountPassword)) + + encrypted, err := box.Encrypt([]byte(msg)) + if err != nil { + t.Fatal(err) + } + + decrypted, err := box.Decrypt(encrypted) + if err != nil { + t.Fatal(err) + } + + decryptedString := string(decrypted) + if decryptedString != msg { + t.Fatalf( + "unexpected message\nexpected: %v\nactual: %v", + msg, + decryptedString, + ) + } +} + +func TestCiphertextRandomized(t *testing.T) { + msg := `Why do we tell actors to 'break a leg?' + Because every play has a cast.` + + box := NewBox(sha256.Sum256(accountPassword)) + + encrypted1, err := box.Encrypt([]byte(msg)) + if err != nil { + t.Fatal(err) + } + + encrypted2, err := box.Encrypt([]byte(msg)) + if err != nil { + t.Fatal(err) + } + + if len(encrypted1) != len(encrypted2) { + t.Fatalf( + "expected the same length of ciphertexts (%v vs %v)", + len(encrypted1), + len(encrypted2), + ) + } + + if reflect.DeepEqual(encrypted1, encrypted2) { + t.Fatalf("expected two different ciphertexts") + } +} + +func TestGracefullyHandleBrokenCipher(t *testing.T) { + box := NewBox(sha256.Sum256(accountPassword)) + + brokenCipher := []byte{0x01, 0x02, 0x03} + + _, err := box.Decrypt(brokenCipher) + + expectedError := fmt.Errorf("symmetric key decryption failed") + if !reflect.DeepEqual(expectedError, err) { + t.Fatalf( + "unexpected error\nexpected: %v\nactual: %v", + expectedError, + err, + ) + } +} diff --git a/pkg/encryption/encryption.go b/pkg/encryption/encryption.go new file mode 100644 index 0000000000..51e9daa5d2 --- /dev/null +++ b/pkg/encryption/encryption.go @@ -0,0 +1,12 @@ +// Package encryption adds a layer to store data on disk encrypted in case +// a filesystem is compromised. +// Under the hood we use "golang.org/x/crypto/nacl/secretbox" for encryption. +// Secretbox uses XSalsa20 and Poly1305 to encrypt an array of bytes with +// secret-key cryptography. +package encryption + +// Box is a general interface to encrypt and decrypt an array of bytes. +type Box interface { + Encrypt([]byte) ([]byte, error) + Decrypt([]byte) ([]byte, error) +} diff --git a/pkg/firewall/firewall.go b/pkg/firewall/firewall.go index bbe2eeb9f3..6c3286e919 100644 --- a/pkg/firewall/firewall.go +++ b/pkg/firewall/firewall.go @@ -5,7 +5,7 @@ import ( "sync" "time" - "github.com/keep-network/keep-common/pkg/cache" + "github.com/keep-network/keep-core/pkg/cache" "github.com/keep-network/keep-core/pkg/clientinfo" "github.com/keep-network/keep-core/pkg/net" "github.com/keep-network/keep-core/pkg/operator" diff --git a/pkg/firewall/firewall_test.go b/pkg/firewall/firewall_test.go index 70e7e4deeb..9b4738d7a7 100644 --- a/pkg/firewall/firewall_test.go +++ b/pkg/firewall/firewall_test.go @@ -6,8 +6,8 @@ import ( "testing" "time" - "github.com/keep-network/keep-common/pkg/cache" "github.com/keep-network/keep-core/internal/testutils" + "github.com/keep-network/keep-core/pkg/cache" "github.com/keep-network/keep-core/pkg/chain/local_v1" "github.com/keep-network/keep-core/pkg/clientinfo" "github.com/keep-network/keep-core/pkg/operator" diff --git a/pkg/generate/generate.go b/pkg/generate/generate.go new file mode 100644 index 0000000000..622835dbd9 --- /dev/null +++ b/pkg/generate/generate.go @@ -0,0 +1,58 @@ +// Package generate contains helper functions for code generators. +package generate + +import ( + "bytes" + "fmt" + "os" + "path/filepath" + + "golang.org/x/tools/imports" +) + +// OrganizeImports takes a buffer containing Go code and a file path where that +// code will live, resolves the imports and formats the code, and writes the +// resulting formatted code into the buffer. +// +// Returns nil if the code was processed and the buffer is now updated with the +// organized, formatted code, or an error if something went wrong during the +// import+format process. +func OrganizeImports(codeBuffer *bytes.Buffer, filePath string) error { + // Resolve imports + code, err := imports.Process(filePath, codeBuffer.Bytes(), nil) + if err != nil { + return fmt.Errorf("failed to find/resolve imports [%v]", err) + } + + // Write organized code to the buffer. + codeBuffer.Reset() + if _, err := codeBuffer.Write(code); err != nil { + return fmt.Errorf("cannot write code to buffer [%v]", err) + } + + return nil +} + +// SaveBufferToFile stores the given buffer's contents to a file at `filePath`. +// +// Returns nil if the file was written successfully, or an error if there was an +// error writing the file. +func SaveBufferToFile(buffer *bytes.Buffer, filePath string) error { + file, err := os.Create(filepath.Clean(filePath)) + + // #nosec G104 G307 (audit errors not checked & deferring unsafe method) + // This line is placed in the auxiliary generator code, + // not in the core application. Also, the Close function returns only + // the error. It doesn't return any other values which can be a security + // threat when used without checking the error. + defer file.Close() + if err != nil { + return fmt.Errorf("output file %s creation failed [%v]", filePath, err) + } + + if _, err := buffer.WriteTo(file); err != nil { + return fmt.Errorf("writing to output file %s failed [%v]", filePath, err) + } + + return nil +} diff --git a/pkg/generator/scheduler_test.go b/pkg/generator/scheduler_test.go index 178cfc5dd9..d6198c1540 100644 --- a/pkg/generator/scheduler_test.go +++ b/pkg/generator/scheduler_test.go @@ -3,6 +3,7 @@ package generator import ( "context" "math/big" + "sync" "testing" "time" @@ -11,6 +12,143 @@ import ( var one = big.NewInt(1) +type testWorker struct { + mu sync.Mutex + number *big.Int + iterated chan struct{} + lastCtx context.Context +} + +func newTestWorker() *testWorker { + return &testWorker{ + number: big.NewInt(0), + iterated: make(chan struct{}, 1), + } +} + +func (tw *testWorker) workerFunc() func(context.Context) { + return func(ctx context.Context) { + tw.mu.Lock() + tw.lastCtx = ctx + if ctx.Err() != nil { + tw.mu.Unlock() + return + } + + tw.number.Add(tw.number, one) + tw.mu.Unlock() + + select { + case tw.iterated <- struct{}{}: + default: + } + } +} + +func (tw *testWorker) value() *big.Int { + tw.mu.Lock() + defer tw.mu.Unlock() + return new(big.Int).Set(tw.number) +} + +func (tw *testWorker) waitForStop(t *testing.T, timeout time.Duration) { + t.Helper() + tw.mu.Lock() + ctx := tw.lastCtx + tw.mu.Unlock() + + if ctx == nil { + t.Fatal("worker has not started yet") + } + + select { + case <-ctx.Done(): + case <-time.After(timeout): + t.Fatal("timed out waiting for worker to stop") + } + + // Take the lock so no in-flight execution of workerFunc is inside its + // increment critical section when the value is read next; its channel + // send may still be pending. + tw.mu.Lock() + tw.mu.Unlock() +} + +func (tw *testWorker) waitForValueChange(t *testing.T, initial *big.Int, timeout time.Duration) *big.Int { + t.Helper() + deadline := time.Now().Add(timeout) + for time.Now().Before(deadline) { + current := tw.value() + if current.Cmp(initial) != 0 { + return current + } + select { + case <-tw.iterated: + case <-time.After(10 * time.Millisecond): + } + } + current := tw.value() + if current.Cmp(initial) != 0 { + return current + } + t.Fatalf("timed out waiting for worker value to change from %v", initial) + return nil +} + +func (tw *testWorker) waitForNonZero(t *testing.T, timeout time.Duration) *big.Int { + t.Helper() + return tw.waitForValueChange(t, big.NewInt(0), timeout) +} + +// assertNoValueChange fails if the worker performs any further computation +// within the given window. +// +// Proving that nothing happens needs an observation window; there is no event to +// wait for. The window is short because a running worker increments on every +// scheduler iteration, so it is caught almost immediately. +// +// The value, not the tw.iterated signal, is the source of truth: workerFunc +// increments the counter and sends on the channel as two separate steps, so a +// worker that incremented before the stop can still deliver its signal after +// it. The signal is only used to re-check early; a late delivery from a +// completed increment must not count as execution. +func (tw *testWorker) assertNoValueChange(t *testing.T, window time.Duration) { + t.Helper() + + initial := tw.value() + deadline := time.After(window) + + for { + select { + case <-tw.iterated: + if current := tw.value(); current.Cmp(initial) != 0 { + t.Fatalf( + "worker executed after stop: initial value %v, current value %v", + initial, + current, + ) + } + case <-deadline: + testutils.AssertBigIntsEqual( + t, + "computation result after stop signal", + initial, + tw.value(), + ) + return + } + } +} + +func waitForSignal(t *testing.T, ch <-chan struct{}, timeout time.Duration, msg string) { + t.Helper() + select { + case <-ch: + case <-time.After(timeout): + t.Fatalf("timed out waiting for %s", msg) + } +} + // TestComputeStop tests the situation when two new worker functions are added // to a scheduler in a working state. The test ensures the worker functions // starts doing their work. Then, the scheduler is stopped and the test ensures @@ -18,46 +156,26 @@ var one = big.NewInt(1) func TestComputeStop(t *testing.T) { scheduler := new(Scheduler) - number1 := big.NewInt(0) - number2 := big.NewInt(0) + tw1 := newTestWorker() + tw2 := newTestWorker() - scheduler.compute(func(context.Context) { - number1.Add(number1, one) - }) - scheduler.compute(func(context.Context) { - number2.Add(number2, one) - }) - - // give some time to perform computations - time.Sleep(10 * time.Millisecond) + scheduler.compute(tw1.workerFunc()) + scheduler.compute(tw2.workerFunc()) // ensure computations started - testutils.AssertBigIntNonZero(t, "computation result", number1) - testutils.AssertBigIntNonZero(t, "computation result", number2) + val1 := tw1.waitForNonZero(t, 1*time.Second) + val2 := tw2.waitForNonZero(t, 1*time.Second) + testutils.AssertBigIntNonZero(t, "computation result", val1) + testutils.AssertBigIntNonZero(t, "computation result", val2) - // send the stop signal and give some time to stop computations + // send the stop signal and wait for computations to stop scheduler.stop() - time.Sleep(100 * time.Millisecond) - - // at this point, all computations should be stopped, capture the current - // result - result1 := new(big.Int).Set(number1) - result2 := new(big.Int).Set(number2) + tw1.waitForStop(t, 1*time.Second) + tw2.waitForStop(t, 1*time.Second) - // wait some time and ensure computations stopped - time.Sleep(20 * time.Millisecond) - testutils.AssertBigIntsEqual( - t, - "computation result after stop signal", - result1, - number1, - ) - testutils.AssertBigIntsEqual( - t, - "computation result after stop signal", - result2, - number2, - ) + // ensure computations stopped + tw1.assertNoValueChange(t, 100*time.Millisecond) + tw2.assertNoValueChange(t, 100*time.Millisecond) } // TestComputeStopContext covers the same situation as TestComputeStop except @@ -66,34 +184,45 @@ func TestComputeStop(t *testing.T) { func TestComputeStopContext(t *testing.T) { scheduler := new(Scheduler) - cancelled1 := false - cancelled2 := false + started1 := make(chan struct{}) + started2 := make(chan struct{}) + cancelled1 := make(chan struct{}) + cancelled2 := make(chan struct{}) + + var onceStarted1, onceStarted2 sync.Once + var onceCancelled1, onceCancelled2 sync.Once scheduler.compute(func(ctx context.Context) { // this simulates a long-running task + onceStarted1.Do(func() { + close(started1) + }) <-ctx.Done() - cancelled1 = true + onceCancelled1.Do(func() { + close(cancelled1) + }) }) scheduler.compute(func(ctx context.Context) { // this simulates a long-running task + onceStarted2.Do(func() { + close(started2) + }) <-ctx.Done() - cancelled2 = true + onceCancelled2.Do(func() { + close(cancelled2) + }) }) - // give some time to perform computations - time.Sleep(10 * time.Millisecond) + // wait for workers to start and reach the long-running task + waitForSignal(t, started1, 1*time.Second, "worker 1 start") + waitForSignal(t, started2, 1*time.Second, "worker 2 start") - // send the stop signal and give some time to stop computations + // send the stop signal scheduler.stop() - time.Sleep(100 * time.Millisecond) // ensure context got cancelled - if !cancelled1 { - t.Errorf("expected context to be cancelled") - } - if !cancelled2 { - t.Errorf("expected context to be cancelled") - } + waitForSignal(t, cancelled1, 1*time.Second, "worker 1 context cancellation") + waitForSignal(t, cancelled2, 1*time.Second, "worker 2 context cancellation") } // TestComputeStopResume tests the situation when two new worker functions are @@ -104,41 +233,42 @@ func TestComputeStopResume(t *testing.T) { scheduler := new(Scheduler) defer scheduler.stop() - number1 := big.NewInt(0) - number2 := big.NewInt(0) + tw1 := newTestWorker() + tw2 := newTestWorker() - scheduler.compute(func(context.Context) { - number1.Add(number1, one) - }) - scheduler.compute(func(context.Context) { - number2.Add(number2, one) - }) + scheduler.compute(tw1.workerFunc()) + scheduler.compute(tw2.workerFunc()) - // send the stop signal and give some time to stop computations + // ensure computations started + tw1.waitForNonZero(t, 1*time.Second) + tw2.waitForNonZero(t, 1*time.Second) + + // send the stop signal and wait for computations to stop scheduler.stop() - time.Sleep(100 * time.Millisecond) + tw1.waitForStop(t, 1*time.Second) + tw2.waitForStop(t, 1*time.Second) // at this point, all computations should be stopped, capture the current // result - intermediateResult1 := new(big.Int).Set(number1) - intermediateResult2 := new(big.Int).Set(number2) + intermediateResult1 := tw1.value() + intermediateResult2 := tw2.value() - // send the resume signal and give some time to resume computations + // send the resume signal and ensure computations have been resumed scheduler.resume() - time.Sleep(100 * time.Millisecond) + tw1.waitForValueChange(t, intermediateResult1, 1*time.Second) + tw2.waitForValueChange(t, intermediateResult2, 1*time.Second) - // ensure computations have been resumed testutils.AssertBigIntsNotEqual( t, "computation results after resume signal", intermediateResult1, - number1, + tw1.value(), ) testutils.AssertBigIntsNotEqual( t, "computation results after resume signal", intermediateResult2, - number2, + tw2.value(), ) } @@ -149,39 +279,31 @@ func TestComputeStopResume(t *testing.T) { func TestComputeStopResumeStop(t *testing.T) { scheduler := new(Scheduler) - number1 := big.NewInt(0) - number2 := big.NewInt(0) + tw1 := newTestWorker() + tw2 := newTestWorker() - scheduler.compute(func(context.Context) { - number1.Add(number1, one) - }) - scheduler.compute(func(context.Context) { - number2.Add(number2, one) - }) + scheduler.compute(tw1.workerFunc()) + scheduler.compute(tw2.workerFunc()) + + // ensure computations started + tw1.waitForNonZero(t, 1*time.Second) + tw2.waitForNonZero(t, 1*time.Second) scheduler.stop() + tw1.waitForStop(t, 1*time.Second) + tw2.waitForStop(t, 1*time.Second) + scheduler.resume() - scheduler.stop() + tw1.waitForValueChange(t, tw1.value(), 1*time.Second) + tw2.waitForValueChange(t, tw2.value(), 1*time.Second) - // at this point, all computations should be stopped, capture the current - // result - result1 := new(big.Int).Set(number1) - result2 := new(big.Int).Set(number2) + scheduler.stop() + tw1.waitForStop(t, 1*time.Second) + tw2.waitForStop(t, 1*time.Second) - // wait some time and ensure computations stopped - time.Sleep(20 * time.Millisecond) - testutils.AssertBigIntsEqual( - t, - "computation result after stop signal", - result1, - number1, - ) - testutils.AssertBigIntsEqual( - t, - "computation result after stop signal", - result2, - number2, - ) + // ensure computations stopped + tw1.assertNoValueChange(t, 100*time.Millisecond) + tw2.assertNoValueChange(t, 100*time.Millisecond) } // TestStopComputeResume tests the situation when two new worker functions are @@ -194,29 +316,23 @@ func TestStopComputeResume(t *testing.T) { scheduler.stop() - number1 := big.NewInt(0) - number2 := big.NewInt(0) + tw1 := newTestWorker() + tw2 := newTestWorker() - scheduler.compute(func(context.Context) { - number1.Add(number1, one) - }) - scheduler.compute(func(context.Context) { - number2.Add(number2, one) - }) + scheduler.compute(tw1.workerFunc()) + scheduler.compute(tw2.workerFunc()) // assert computations have not started - the scheduler is stopped - testutils.AssertBigIntsEqual(t, "computation result", big.NewInt(0), number1) - testutils.AssertBigIntsEqual(t, "computation result", big.NewInt(0), number2) + testutils.AssertBigIntsEqual(t, "computation result", big.NewInt(0), tw1.value()) + testutils.AssertBigIntsEqual(t, "computation result", big.NewInt(0), tw2.value()) scheduler.resume() - // give some time to perform computations; - // given the goroutines are started after Resume call, we are giving this - // test a bit more time than others - time.Sleep(250 * time.Millisecond) // ensure computations started - testutils.AssertBigIntNonZero(t, "computation result", number1) - testutils.AssertBigIntNonZero(t, "computation result", number2) + val1 := tw1.waitForNonZero(t, 1*time.Second) + val2 := tw2.waitForNonZero(t, 1*time.Second) + testutils.AssertBigIntNonZero(t, "computation result", val1) + testutils.AssertBigIntNonZero(t, "computation result", val2) } // TestCheckProtocols_NoProtocols ensures the execution of checkProtocols @@ -225,41 +341,37 @@ func TestCheckProtocols_NoProtocols(t *testing.T) { scheduler := new(Scheduler) defer scheduler.stop() - number1 := big.NewInt(0) - number2 := big.NewInt(0) + tw1 := newTestWorker() + tw2 := newTestWorker() - scheduler.compute(func(context.Context) { - number1.Add(number1, one) - }) - scheduler.compute(func(context.Context) { - number2.Add(number2, one) - }) + scheduler.compute(tw1.workerFunc()) + scheduler.compute(tw2.workerFunc()) - // give some time to perform computations - time.Sleep(10 * time.Millisecond) + // ensure computations started + tw1.waitForNonZero(t, 1*time.Second) + tw2.waitForNonZero(t, 1*time.Second) scheduler.checkProtocols() - // give some time to potentially stop computations (shouldn't happen) - time.Sleep(100 * time.Millisecond) - // there are no protocols executed, nothing can stop the scheduler; // ensure the computations are performed - intermediateResult1 := new(big.Int).Set(number1) - intermediateResult2 := new(big.Int).Set(number2) + intermediateResult1 := tw1.value() + intermediateResult2 := tw2.value() + + tw1.waitForValueChange(t, intermediateResult1, 1*time.Second) + tw2.waitForValueChange(t, intermediateResult2, 1*time.Second) - time.Sleep(20 * time.Millisecond) testutils.AssertBigIntsNotEqual( t, "computation result after stop signal", intermediateResult1, - number1, + tw1.value(), ) testutils.AssertBigIntsNotEqual( t, "computation result after stop signal", intermediateResult2, - number2, + tw2.value(), ) } @@ -270,46 +382,42 @@ func TestCheckProtocols_ProtocolNotExecuting(t *testing.T) { scheduler := new(Scheduler) defer scheduler.stop() - number1 := big.NewInt(0) - number2 := big.NewInt(0) + tw1 := newTestWorker() + tw2 := newTestWorker() - scheduler.compute(func(context.Context) { - number1.Add(number1, one) - }) - scheduler.compute(func(context.Context) { - number2.Add(number2, one) - }) + scheduler.compute(tw1.workerFunc()) + scheduler.compute(tw2.workerFunc()) protocol1 := &mockProtocol{} protocol2 := &mockProtocol{} scheduler.RegisterProtocol(protocol1) scheduler.RegisterProtocol(protocol2) - // give some time to perform computations - time.Sleep(10 * time.Millisecond) + // ensure computations started + tw1.waitForNonZero(t, 1*time.Second) + tw2.waitForNonZero(t, 1*time.Second) scheduler.checkProtocols() - // give some time to potentially stop computations (shouldn't happen) - time.Sleep(100 * time.Millisecond) - // there are two protocols but they are not executing; // ensure the computations are performed - intermediateResult1 := new(big.Int).Set(number1) - intermediateResult2 := new(big.Int).Set(number2) + intermediateResult1 := tw1.value() + intermediateResult2 := tw2.value() + + tw1.waitForValueChange(t, intermediateResult1, 1*time.Second) + tw2.waitForValueChange(t, intermediateResult2, 1*time.Second) - time.Sleep(20 * time.Millisecond) testutils.AssertBigIntsNotEqual( t, "computation result after stop signal", intermediateResult1, - number1, + tw1.value(), ) testutils.AssertBigIntsNotEqual( t, "computation result after stop signal", intermediateResult2, - number2, + tw2.value(), ) } @@ -319,48 +427,32 @@ func TestCheckProtocols_ProtocolExecuting(t *testing.T) { scheduler := new(Scheduler) defer scheduler.stop() - number1 := big.NewInt(0) - number2 := big.NewInt(0) + tw1 := newTestWorker() + tw2 := newTestWorker() - scheduler.compute(func(context.Context) { - number1.Add(number1, one) - }) - scheduler.compute(func(context.Context) { - number2.Add(number2, one) - }) + scheduler.compute(tw1.workerFunc()) + scheduler.compute(tw2.workerFunc()) protocol1 := &mockProtocol{} protocol2 := &mockProtocol{} scheduler.RegisterProtocol(protocol1) scheduler.RegisterProtocol(protocol2) - // give some time to perform computations - time.Sleep(10 * time.Millisecond) + // ensure computations started + tw1.waitForNonZero(t, 1*time.Second) + tw2.waitForNonZero(t, 1*time.Second) protocol2.isExecuting = true scheduler.checkProtocols() - // give some time to stop computations - time.Sleep(100 * time.Millisecond) + // wait for computations to stop + tw1.waitForStop(t, 1*time.Second) + tw2.waitForStop(t, 1*time.Second) - // there are two protocols and the second one is executing + // there are two protocols and the second one is executing; // ensure the computations are stopped - intermediateResult1 := new(big.Int).Set(number1) - intermediateResult2 := new(big.Int).Set(number2) - - time.Sleep(20 * time.Millisecond) - testutils.AssertBigIntsEqual( - t, - "computation result after stop signal", - intermediateResult1, - number1, - ) - testutils.AssertBigIntsEqual( - t, - "computation result after stop signal", - intermediateResult2, - number2, - ) + tw1.assertNoValueChange(t, 100*time.Millisecond) + tw2.assertNoValueChange(t, 100*time.Millisecond) } // TestCheckProtocols_ProtocolFinishedExecution ensures the execution of @@ -370,53 +462,50 @@ func TestCheckProtocols_ProtocolFinishedExecution(t *testing.T) { scheduler := new(Scheduler) defer scheduler.stop() - number1 := big.NewInt(0) - number2 := big.NewInt(0) + tw1 := newTestWorker() + tw2 := newTestWorker() - scheduler.compute(func(context.Context) { - number1.Add(number1, one) - }) - scheduler.compute(func(context.Context) { - number2.Add(number2, one) - }) + scheduler.compute(tw1.workerFunc()) + scheduler.compute(tw2.workerFunc()) protocol1 := &mockProtocol{} protocol2 := &mockProtocol{} scheduler.RegisterProtocol(protocol1) scheduler.RegisterProtocol(protocol2) - // give some time to perform computations - time.Sleep(10 * time.Millisecond) + // ensure computations started + tw1.waitForNonZero(t, 1*time.Second) + tw2.waitForNonZero(t, 1*time.Second) protocol2.isExecuting = true scheduler.checkProtocols() - // give some time to stop computations - time.Sleep(100 * time.Millisecond) + // wait for computations to stop + tw1.waitForStop(t, 1*time.Second) + tw2.waitForStop(t, 1*time.Second) protocol2.isExecuting = false scheduler.checkProtocols() - // give some time to resume computations - time.Sleep(100 * time.Millisecond) - // there are two protocols, the second one was executing, but it has // finished; ensure the computations are resumed - intermediateResult1 := new(big.Int).Set(number1) - intermediateResult2 := new(big.Int).Set(number2) + intermediateResult1 := tw1.value() + intermediateResult2 := tw2.value() + + tw1.waitForValueChange(t, intermediateResult1, 1*time.Second) + tw2.waitForValueChange(t, intermediateResult2, 1*time.Second) - time.Sleep(20 * time.Millisecond) testutils.AssertBigIntsNotEqual( t, "computation result after stop signal", intermediateResult1, - number1, + tw1.value(), ) testutils.AssertBigIntsNotEqual( t, "computation result after stop signal", intermediateResult2, - number2, + tw2.value(), ) } diff --git a/pkg/internal/pbutils/fuzz_test.go b/pkg/internal/pbutils/fuzz_test.go new file mode 100644 index 0000000000..cb61c35231 --- /dev/null +++ b/pkg/internal/pbutils/fuzz_test.go @@ -0,0 +1,127 @@ +package pbutils + +import ( + "math/big" + "testing" + + "github.com/btcsuite/btcd/btcec" + + "github.com/keep-network/keep-core/pkg/crypto/ephemeral" +) + +// FuzzEphemeralKeyRoundTrip exercises marshal and unmarshal of ephemeral public +// and private keys across the whole scalar domain, including the boundaries at 1 +// and N-1 that a fixed-count generator loop is unlikely to reach. +// +// Scope, stated precisely because it is easy to overstate: this target builds its +// keys directly from a scalar, so it does NOT exercise fuzzEphemeralPublicKey or +// fuzzEphemeralPrivateKey, and it would NOT fail if either were regressed to +// fuzzing coordinates independently again. The guards against that are +// TestFuzzedEphemeralPublicKeyIsSerializable and +// TestFuzzedEphemeralPrivateKeyIsConsistent, which do call FuzzFuncs. +// +// What this target does guard is the shared normalizeScalar helper, which the +// production generators also use, and the marshaling itself against any scalar +// the engine can reach. +func FuzzEphemeralKeyRoundTrip(f *testing.F) { + curve := btcec.S256() + + // Seed 1: Empty and all-zero byte slices (normalize to scalar 1). + f.Add([]byte{}) + f.Add([]byte{0x00}) + f.Add(make([]byte, 32)) + + // Seed 2: Small inputs producing small in-range scalars. + f.Add([]byte{0x01}) + f.Add([]byte{0x02}) + f.Add(big.NewInt(42).Bytes()) + + // Seed 3: Large inputs near the top of the accepted domain [1, N-1]. + // N - 2 and N - 1 test boundaries near the curve order. + topMinus2 := new(big.Int).Sub(curve.N, big.NewInt(2)) + topMinus1 := new(big.Int).Sub(curve.N, big.NewInt(1)) + f.Add(topMinus2.Bytes()) + f.Add(topMinus1.Bytes()) + + f.Fuzz(func(t *testing.T, data []byte) { + scalar := normalizeScalar(new(big.Int).SetBytes(data)) + + // 1. Ephemeral Public Key Round Trip + x, y := curve.ScalarBaseMult(scalar.Bytes()) + originalPubKey := &ephemeral.PublicKey{ + Curve: curve, + X: x, + Y: y, + } + + marshaledPubKey := originalPubKey.Marshal() + if len(marshaledPubKey) != 33 { + t.Fatalf( + "unexpected marshaled public key length: expected 33, got %d", + len(marshaledPubKey), + ) + } + + unmarshaledPubKey, err := ephemeral.UnmarshalPublicKey(marshaledPubKey) + if err != nil { + t.Fatalf( + "failed to unmarshal valid ephemeral public key: %v", + err, + ) + } + + // Explicit field comparison on (X, Y) coordinates using big.Int.Cmp + // to verify mathematical equality and format clear mismatch diagnostics. + if originalPubKey.X.Cmp(unmarshaledPubKey.X) != 0 || + originalPubKey.Y.Cmp(unmarshaledPubKey.Y) != 0 { + t.Fatalf( + "public key round-trip inequality\n"+ + "original: (X: %s, Y: %s)\n"+ + "unmarshaled: (X: %s, Y: %s)", + originalPubKey.X.String(), + originalPubKey.Y.String(), + unmarshaledPubKey.X.String(), + unmarshaledPubKey.Y.String(), + ) + } + + // 2. Ephemeral Private Key Consistency and Round Trip + priv, _ := btcec.PrivKeyFromBytes(curve, scalar.Bytes()) + originalPrivKey := (*ephemeral.PrivateKey)(priv) + + pubFromPriv := (*ephemeral.PublicKey)(&originalPrivKey.PublicKey) + if !pubFromPriv.IsKeyMatching(originalPrivKey) { + t.Fatalf( + "private key D does not match its public key\n"+ + "D: (D: %s)\n"+ + "pub: (X: %s, Y: %s)", + originalPrivKey.D.String(), + pubFromPriv.X.String(), + pubFromPriv.Y.String(), + ) + } + + marshaledPrivKey := originalPrivKey.Marshal() + unmarshaledPrivKey := ephemeral.UnmarshalPrivateKey(marshaledPrivKey) + if unmarshaledPrivKey == nil { + t.Fatalf("failed to unmarshal valid ephemeral private key") + } + + // Explicit field comparison on scalar D and public coordinates (X, Y). + if originalPrivKey.D.Cmp(unmarshaledPrivKey.D) != 0 || + originalPrivKey.X.Cmp(unmarshaledPrivKey.X) != 0 || + originalPrivKey.Y.Cmp(unmarshaledPrivKey.Y) != 0 { + t.Fatalf( + "private key round-trip inequality\n"+ + "original: (D: %s, X: %s, Y: %s)\n"+ + "unmarshaled: (D: %s, X: %s, Y: %s)", + originalPrivKey.D.String(), + originalPrivKey.X.String(), + originalPrivKey.Y.String(), + unmarshaledPrivKey.D.String(), + unmarshaledPrivKey.X.String(), + unmarshaledPrivKey.Y.String(), + ) + } + }) +} diff --git a/pkg/internal/pbutils/pbutils.go b/pkg/internal/pbutils/pbutils.go index 8149572de3..00182fed61 100644 --- a/pkg/internal/pbutils/pbutils.go +++ b/pkg/internal/pbutils/pbutils.go @@ -3,7 +3,6 @@ package pbutils import ( - "crypto/ecdsa" "math/big" "github.com/btcsuite/btcd/btcec" @@ -38,8 +37,15 @@ func RoundTrip( return nil } -// FuzzUnmarshaler tests given unmarshaler with random bytes. -func FuzzUnmarshaler(unmarshaler pb.Unmarshaler) { +// AssertUnmarshalDoesNotPanic feeds the given unmarshaler 100 random byte +// slices and fails the test only if one of them panics. +// +// It deliberately discards the unmarshal error: random bytes are almost never a +// valid message, so requiring a nil error would fail constantly. That makes +// this a crash check, not a correctness check. It cannot detect an unmarshaler +// that silently accepts a malformed message, so a caller needing that guarantee +// must assert it separately. +func AssertUnmarshalDoesNotPanic(unmarshaler pb.Unmarshaler) { for i := 0; i < 100; i++ { var messageBytes []byte @@ -73,32 +79,51 @@ func fuzzBigInt() func(*big.Int, fuzz.Continue) { func fuzzEphemeralPublicKey() func(*ephemeral.PublicKey, fuzz.Continue) { return func(key *ephemeral.PublicKey, c fuzz.Continue) { - var x, y big.Int + var scalar big.Int + + c.Fuzz(&scalar) - c.Fuzz(&x) - c.Fuzz(&y) + // Derive the point from a scalar instead of fuzzing X and Y directly. + // Arbitrary X and Y are almost never a point on the curve, and their + // compressed form is not 33 bytes, so ParsePubKey rejects it and no + // round-trip through Marshal/Unmarshal can succeed. + curve := btcec.S256() + x, y := curve.ScalarBaseMult(normalizeScalar(&scalar).Bytes()) - key.Curve = btcec.S256() - key.X = &x - key.Y = &y + key.Curve = curve + key.X = x + key.Y = y } } func fuzzEphemeralPrivateKey() func(*ephemeral.PrivateKey, fuzz.Continue) { return func(key *ephemeral.PrivateKey, c fuzz.Continue) { - var ( - publicKey ephemeral.PublicKey - d big.Int - ) + var scalar big.Int - c.Fuzz(&publicKey) - c.Fuzz(&d) + c.Fuzz(&scalar) - key.PublicKey = ecdsa.PublicKey(publicKey) - key.D = &d + // Derive both halves from one scalar so the key pair is internally + // consistent. Fuzzing the public key and D independently produces a + // private key whose D does not generate its own public point, which + // IsKeyMatching rejects and which makes any ECDH round trip meaningless. + curve := btcec.S256() + priv, _ := btcec.PrivKeyFromBytes(curve, normalizeScalar(&scalar).Bytes()) + + *key = ephemeral.PrivateKey(*priv) } } +// normalizeScalar reduces a fuzzed value into [1, N-1], the range of valid +// secp256k1 private scalars, excluding zero so the derived point is never the +// point at infinity. +func normalizeScalar(scalar *big.Int) *big.Int { + curve := btcec.S256() + + normalized := new(big.Int).Mod(scalar, new(big.Int).Sub(curve.N, big.NewInt(1))) + + return normalized.Add(normalized, big.NewInt(1)) +} + func fuzzG1() func(*bn256.G1, fuzz.Continue) { return func(g1 *bn256.G1, c fuzz.Continue) { var k big.Int diff --git a/pkg/internal/pbutils/pbutils_test.go b/pkg/internal/pbutils/pbutils_test.go new file mode 100644 index 0000000000..d5a53fc302 --- /dev/null +++ b/pkg/internal/pbutils/pbutils_test.go @@ -0,0 +1,82 @@ +package pbutils + +import ( + "testing" + + fuzz "github.com/google/gofuzz" + + "github.com/keep-network/keep-core/pkg/crypto/ephemeral" +) + +// TestFuzzedEphemeralPublicKeyIsSerializable checks that every public key the +// fuzzer produces survives a Marshal/Unmarshal round trip. +// +// This is the contract the round-trip marshaling tests across pkg/beacon and +// pkg/tecdsa rely on: they fuzz a message, round-trip it, and assert no error. +// A generator that emits points which are not on the curve makes those tests +// unable to pass, which is how this was previously masked by a discarded error. +func TestFuzzedEphemeralPublicKeyIsSerializable(t *testing.T) { + f := fuzz.New().NilChance(0).Funcs(FuzzFuncs()...) + + for i := 0; i < 100; i++ { + var key ephemeral.PublicKey + + f.Fuzz(&key) + + marshaled := key.Marshal() + if len(marshaled) != 33 { + t.Fatalf( + "unexpected compressed public key length\n"+ + "expected: [33]\n"+ + "actual: [%d]", + len(marshaled), + ) + } + + unmarshaled, err := ephemeral.UnmarshalPublicKey(marshaled) + if err != nil { + t.Fatal(err) + } + + if key.X.Cmp(unmarshaled.X) != 0 || key.Y.Cmp(unmarshaled.Y) != 0 { + t.Fatalf( + "public key does not round-trip\n"+ + "expected: [%v, %v]\n"+ + "actual: [%v, %v]", + key.X, + key.Y, + unmarshaled.X, + unmarshaled.Y, + ) + } + } +} + +// TestFuzzedEphemeralPrivateKeyIsConsistent checks that the fuzzer produces +// private keys whose D actually generates their own public point. +// +// The generator used to fuzz the public key and D independently, so the two +// halves disagreed. Nothing round-trips an ephemeral private key today, which +// is why that never surfaced - but IsKeyMatching would reject such a key and +// any ECDH derived from it is meaningless, so the next test to touch one would +// have inherited the same silent-garbage problem the round-trip repairs exposed +// elsewhere. +func TestFuzzedEphemeralPrivateKeyIsConsistent(t *testing.T) { + f := fuzz.New().NilChance(0).Funcs(FuzzFuncs()...) + + for i := 0; i < 100; i++ { + var key ephemeral.PrivateKey + + f.Fuzz(&key) + + publicKey := (*ephemeral.PublicKey)(&key.PublicKey) + if !publicKey.IsKeyMatching(&key) { + t.Fatal("fuzzed private key does not match its own public key") + } + + marshaled := publicKey.Marshal() + if _, err := ephemeral.UnmarshalPublicKey(marshaled); err != nil { + t.Fatal(err) + } + } +} diff --git a/pkg/internal/tecdsatest/manifest_test.go b/pkg/internal/tecdsatest/manifest_test.go new file mode 100644 index 0000000000..d974fa0ea8 --- /dev/null +++ b/pkg/internal/tecdsatest/manifest_test.go @@ -0,0 +1,78 @@ +package tecdsatest + +import ( + "os" + "path/filepath" + "runtime" + "testing" +) + +// Required fixture files in pkg/internal/tecdsatest/testdata. +// These slices explicitly enumerate all fixture files required by the test +// suite. Directory globbing is avoided because a glob that matches nothing +// would pass silently. +var ( + requiredPrivateKeyShareFixtures = []string{ + "private_key_share_data_0.json", + "private_key_share_data_1.json", + "private_key_share_data_2.json", + "private_key_share_data_3.json", + "private_key_share_data_4.json", + } +) + +// TestRequiredFixturesPresent guards the test fixtures in testdata against +// accidental deletion or corruption. +func TestRequiredFixturesPresent(t *testing.T) { + _, callerFileName, _, _ := runtime.Caller(0) + testDataDir := filepath.Join(filepath.Dir(callerFileName), "testdata") + + tests := []struct { + name string + required []string + load func() (int, error) + }{ + { + name: "PrivateKeyShare", + required: requiredPrivateKeyShareFixtures, + load: func() (int, error) { + shares, err := LoadPrivateKeyShareTestFixtures( + len(requiredPrivateKeyShareFixtures), + ) + return len(shares), err + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + if len(tc.required) == 0 { + t.Fatal("manifest is empty") + } + + for _, fileName := range tc.required { + filePath := filepath.Join(testDataDir, fileName) + if _, err := os.Stat(filePath); err != nil { + t.Errorf("missing required fixture file [%s]: %v", fileName, err) + } + } + + count, err := tc.load() + if err != nil { + t.Fatalf("loader failed: %v", err) + } + + if count == 0 { + t.Fatal("loader returned 0 fixtures") + } + + if count != len(tc.required) { + t.Errorf( + "unexpected fixture count: got %d, want %d", + count, + len(tc.required), + ) + } + }) + } +} diff --git a/pkg/logging/logging.go b/pkg/logging/logging.go new file mode 100644 index 0000000000..4f2ac8deb0 --- /dev/null +++ b/pkg/logging/logging.go @@ -0,0 +1,91 @@ +package logging + +import ( + "fmt" + "strings" + + logging "github.com/ipfs/go-log" +) + +// Configure sets up logging configuration from the given string. This string is +// expected to have a space-delimited set of level directives, which are each +// evaluated in order by the evaluateLevelDirective function. +// +// If the level directive string is empty, a default level of info for all keep* +// subsystems is imposed. +func Configure(levelDirectiveString string) error { + // Default to info logs for keep. + if len(levelDirectiveString) == 0 { + levelDirectiveString = "keep*=info" + } + + levelDirectives := strings.Split(levelDirectiveString, " ") + for _, directive := range levelDirectives { + err := evaluateLevelDirective(directive) + if err != nil { + return fmt.Errorf( + "Failed to parse log level directive [%s]: [%v]\n"+ + "Directives can be any of:\n"+ + " - a global log level, e.g. 'debug'\n"+ + " - a subsystem=level pair, e.g. 'keep-relay=info'\n"+ + " - a subsystem*=level prefix pair, e.g. 'keep*=warn'\n", + directive, + err, + ) + } + } + + return nil +} + +// Takes a levelDirective that can have one of three formats: +// +// | +// = | +// *= +// +// In the first form, the given log-level is set on all subsystems. +// +// In the second form, the given log-level is set on the given subsystem. +// +// In the third form, the given log-level is set on any subsystem that starts +// with the given subsystem-prefix. +// +// Supported log levels are as per the ipfs/go-logging library. +func evaluateLevelDirective(levelDirective string) error { + splitLevel := strings.Split(levelDirective, "=") + + switch len(splitLevel) { + case 1: + level := splitLevel[0] + + err := logging.SetLogLevel("*", level) + if err != nil { + return err + } + + case 2: + levelSubsystem := splitLevel[0] + level := splitLevel[1] + + if strings.HasSuffix(levelSubsystem, "*") { + subsystemPrefix := strings.TrimSuffix(levelSubsystem, "*") + // Wildcard suffix, check for matching subsystems. + for _, subsystem := range logging.GetSubsystems() { + if strings.HasPrefix(subsystem, subsystemPrefix) { + err := logging.SetLogLevel(subsystem, level) + if err != nil { + return err + } + } + } + } else { + return logging.SetLogLevel(levelSubsystem, level) + } + + default: + return fmt.Errorf("more than two =-delimited components in directive") + } + + return nil +} diff --git a/pkg/maintainer/btcdiff/bitcoin_difficulty.go b/pkg/maintainer/btcdiff/bitcoin_difficulty.go index b33e391182..1a8c2257dd 100644 --- a/pkg/maintainer/btcdiff/bitcoin_difficulty.go +++ b/pkg/maintainer/btcdiff/bitcoin_difficulty.go @@ -42,9 +42,11 @@ var ( ) ) -// lightRelayMinDifficultyTarget matches LightRelay.MIN_DIFFICULTY_TARGET / -// BTCUtils.DIFF1_TARGET (compact bits 0x1d00ffff). -var lightRelayMinDifficultyTarget = blockchain.CompactToBig(0x1d00ffff) +// LightRelayMinDifficultyTarget matches LightRelay.MIN_DIFFICULTY_TARGET / +// BTCUtils.DIFF1_TARGET (compact bits 0x1d00ffff). Exported so other packages +// (e.g. pkg/maintainer/spv) can share the same decoded value rather than +// duplicating the compact-bits decode. +var LightRelayMinDifficultyTarget = blockchain.CompactToBig(0x1d00ffff) func Initialize( ctx context.Context, @@ -397,7 +399,7 @@ func relayAllowsPreRetargetHeaderTarget(oldEpochTarget, headerTarget *big.Int) b if oldEpochTarget.Cmp(headerTarget) == 0 { return true } - return lightRelayMinDifficultyTarget.Cmp(headerTarget) == 0 + return LightRelayMinDifficultyTarget.Cmp(headerTarget) == 0 } // getBlockHeaders returns block headers from the given range. diff --git a/pkg/maintainer/config.go b/pkg/maintainer/config.go index 52175cf350..5cce52a57a 100644 --- a/pkg/maintainer/config.go +++ b/pkg/maintainer/config.go @@ -1,6 +1,8 @@ package maintainer import ( + "fmt" + "github.com/keep-network/keep-core/pkg/maintainer/btcdiff" "github.com/keep-network/keep-core/pkg/maintainer/spv" ) @@ -10,3 +12,19 @@ type Config struct { BitcoinDifficulty btcdiff.Config Spv spv.Config } + +// Validate checks whether the maintainer configuration is valid for the +// modules that will be launched. Currently only Spv requires pre-launch +// validation; BitcoinDifficulty does not. +func (c Config) Validate() error { + launchAll := !c.BitcoinDifficulty.Enabled && + !c.Spv.Enabled + + if c.Spv.Enabled || launchAll { + if err := c.Spv.Validate(); err != nil { + return fmt.Errorf("cannot validate spv maintainer config: [%w]", err) + } + } + + return nil +} diff --git a/pkg/maintainer/config_test.go b/pkg/maintainer/config_test.go new file mode 100644 index 0000000000..d56b795014 --- /dev/null +++ b/pkg/maintainer/config_test.go @@ -0,0 +1,155 @@ +package maintainer + +import ( + "testing" + + "github.com/keep-network/keep-core/pkg/maintainer/btcdiff" + "github.com/keep-network/keep-core/pkg/maintainer/spv" +) + +func TestConfig_Validate(t *testing.T) { + validSpv := spv.Config{ + HistoryDepth: spv.DefaultHistoryDepth, + TransactionLimit: spv.DefaultTransactionLimit, + RestartBackoffTime: spv.DefaultRestartBackoffTime, + IdleBackoffTime: spv.DefaultIdleBackOffTime, + MaxProofHeaders: spv.DefaultMaxProofHeaders, + } + + tests := map[string]struct { + config Config + expectErr bool + }{ + "launch-all with zero SPV maxProofHeaders fails": { + config: Config{ + BitcoinDifficulty: btcdiff.Config{Enabled: false}, + Spv: spv.Config{ + Enabled: false, + HistoryDepth: spv.DefaultHistoryDepth, + TransactionLimit: spv.DefaultTransactionLimit, + RestartBackoffTime: spv.DefaultRestartBackoffTime, + IdleBackoffTime: spv.DefaultIdleBackOffTime, + MaxProofHeaders: 0, + }, + }, + expectErr: true, + }, + "enabled SPV with zero maxProofHeaders fails": { + config: Config{ + BitcoinDifficulty: btcdiff.Config{Enabled: false}, + Spv: spv.Config{ + Enabled: true, + HistoryDepth: spv.DefaultHistoryDepth, + TransactionLimit: spv.DefaultTransactionLimit, + RestartBackoffTime: spv.DefaultRestartBackoffTime, + IdleBackoffTime: spv.DefaultIdleBackOffTime, + MaxProofHeaders: 0, + }, + }, + expectErr: true, + }, + "difficulty-only with zero SPV maxProofHeaders passes": { + config: Config{ + BitcoinDifficulty: btcdiff.Config{Enabled: true}, + Spv: spv.Config{ + Enabled: false, + MaxProofHeaders: 0, + }, + }, + expectErr: false, + }, + "launch-all with positive SPV maxProofHeaders passes": { + config: Config{ + BitcoinDifficulty: btcdiff.Config{Enabled: false}, + Spv: validSpv, + }, + expectErr: false, + }, + "enabled SPV with positive maxProofHeaders passes": { + config: Config{ + BitcoinDifficulty: btcdiff.Config{Enabled: false}, + Spv: spv.Config{ + Enabled: true, + HistoryDepth: spv.DefaultHistoryDepth, + TransactionLimit: spv.DefaultTransactionLimit, + RestartBackoffTime: spv.DefaultRestartBackoffTime, + IdleBackoffTime: spv.DefaultIdleBackOffTime, + MaxProofHeaders: spv.DefaultMaxProofHeaders, + }, + }, + expectErr: false, + }, + "enabled SPV with zero historyDepth fails": { + config: Config{ + BitcoinDifficulty: btcdiff.Config{Enabled: false}, + Spv: spv.Config{ + Enabled: true, + HistoryDepth: 0, + TransactionLimit: spv.DefaultTransactionLimit, + RestartBackoffTime: spv.DefaultRestartBackoffTime, + IdleBackoffTime: spv.DefaultIdleBackOffTime, + MaxProofHeaders: spv.DefaultMaxProofHeaders, + }, + }, + expectErr: true, + }, + "enabled SPV with non-positive transactionLimit fails": { + config: Config{ + BitcoinDifficulty: btcdiff.Config{Enabled: false}, + Spv: spv.Config{ + Enabled: true, + HistoryDepth: spv.DefaultHistoryDepth, + TransactionLimit: 0, + RestartBackoffTime: spv.DefaultRestartBackoffTime, + IdleBackoffTime: spv.DefaultIdleBackOffTime, + MaxProofHeaders: spv.DefaultMaxProofHeaders, + }, + }, + expectErr: true, + }, + "enabled SPV with zero restartBackoffTime fails": { + config: Config{ + BitcoinDifficulty: btcdiff.Config{Enabled: false}, + Spv: spv.Config{ + Enabled: true, + HistoryDepth: spv.DefaultHistoryDepth, + TransactionLimit: spv.DefaultTransactionLimit, + RestartBackoffTime: 0, + IdleBackoffTime: spv.DefaultIdleBackOffTime, + MaxProofHeaders: spv.DefaultMaxProofHeaders, + }, + }, + expectErr: true, + }, + "enabled SPV with zero idleBackoffTime fails": { + config: Config{ + BitcoinDifficulty: btcdiff.Config{Enabled: false}, + Spv: spv.Config{ + Enabled: true, + HistoryDepth: spv.DefaultHistoryDepth, + TransactionLimit: spv.DefaultTransactionLimit, + RestartBackoffTime: spv.DefaultRestartBackoffTime, + IdleBackoffTime: 0, + MaxProofHeaders: spv.DefaultMaxProofHeaders, + }, + }, + expectErr: true, + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + err := test.config.Validate() + + if test.expectErr { + if err == nil { + t.Fatal("expected error, got nil") + } + } else { + if err != nil { + t.Fatalf("expected no error, got: %v", err) + } + } + }) + } +} diff --git a/pkg/maintainer/maintainer.go b/pkg/maintainer/maintainer.go index ea2fbfabcf..cf785f5de9 100644 --- a/pkg/maintainer/maintainer.go +++ b/pkg/maintainer/maintainer.go @@ -2,6 +2,7 @@ package maintainer import ( "context" + "github.com/ipfs/go-log/v2" "github.com/keep-network/keep-core/pkg/bitcoin" @@ -17,9 +18,11 @@ func Initialize( btcChain bitcoin.Chain, btcDiffChain btcdiff.Chain, spvChain spv.Chain, -) { - // If none of the maintainers was specified in the config (i.e. no option was - // provided to the `maintainer` command), all maintainers should be launched. + metricsRecorder spv.MetricsRecorder, +) error { + // Configuration is validated at config-load time and again inside + // spv.Initialize (the only module that requires pre-launch validation), + // so we don't re-validate here to avoid a redundant pass. launchAll := !config.BitcoinDifficulty.Enabled && !config.Spv.Enabled @@ -37,18 +40,18 @@ func Initialize( } if config.Spv.Enabled || launchAll { - spv.Initialize( + err := spv.Initialize( ctx, config.Spv, spvChain, btcDiffChain, btcChain, + metricsRecorder, ) + if err != nil { + return err + } } - // TODO: Allow for launching multiple maintainers here. Every flag - // indicating a maintainer task should launch a separate maintainer. - // Notice that panic on one maintainer goroutine will crush the whole - // program. Consider cancelling all maintainers if one maintainer - // cannot ba launched due to a configuration error. + return nil } diff --git a/pkg/maintainer/spv/chain_test.go b/pkg/maintainer/spv/chain_test.go index 2a0bcc0a89..6972693574 100644 --- a/pkg/maintainer/spv/chain_test.go +++ b/pkg/maintainer/spv/chain_test.go @@ -63,6 +63,10 @@ type localChain struct { currentEpoch uint64 currentEpochDifficulty *big.Int previousEpochDifficulty *big.Int + + // Error fields for testing on-chain submit failure metrics + submitDepositSweepProofErr error + submitRedemptionProofErr error } func newLocalChain() *localChain { @@ -89,6 +93,11 @@ func (lc *localChain) SubmitDepositSweepProofWithReimbursement( lc.mutex.Lock() defer lc.mutex.Unlock() + // Allow tests to force an error from this method + if lc.submitDepositSweepProofErr != nil { + return lc.submitDepositSweepProofErr + } + lc.submittedDepositSweepProofs = append( lc.submittedDepositSweepProofs, &submittedDepositSweepProof{ @@ -264,6 +273,11 @@ func (lc *localChain) SubmitRedemptionProofWithReimbursement( lc.mutex.Lock() defer lc.mutex.Unlock() + // Allow tests to force an error from this method + if lc.submitRedemptionProofErr != nil { + return lc.submitRedemptionProofErr + } + lc.submittedRedemptionProofs = append( lc.submittedRedemptionProofs, &submittedRedemptionProof{ @@ -684,8 +698,9 @@ func (lc *localChain) GetMovedFundsSweepRequest( } type mockBlockCounter struct { - mutex sync.Mutex - currentBlock uint64 + mutex sync.Mutex + currentBlock uint64 + currentBlockErr error } func newMockBlockCounter() *mockBlockCounter { @@ -707,6 +722,10 @@ func (mbc *mockBlockCounter) CurrentBlock() (uint64, error) { mbc.mutex.Lock() defer mbc.mutex.Unlock() + if mbc.currentBlockErr != nil { + return 0, mbc.currentBlockErr + } + return mbc.currentBlock, nil } @@ -717,6 +736,25 @@ func (mbc *mockBlockCounter) SetCurrentBlock(block uint64) { mbc.currentBlock = block } +func (mbc *mockBlockCounter) SetCurrentBlockErr(err error) { + mbc.mutex.Lock() + defer mbc.mutex.Unlock() + + mbc.currentBlockErr = err +} + func (mbc *mockBlockCounter) WatchBlocks(ctx context.Context) <-chan uint64 { panic("unsupported") } + +// errorBlockCounterChain overrides BlockCounter on the local chain so that +// unprovenSearchStartBlock can be exercised against a spvChain.BlockCounter() +// failure, independently of the chain's normal blockCounter plumbing. +type errorBlockCounterChain struct { + *localChain + err error +} + +func (c *errorBlockCounterChain) BlockCounter() (chain.BlockCounter, error) { + return nil, c.err +} diff --git a/pkg/maintainer/spv/config.go b/pkg/maintainer/spv/config.go index 49cdfe40d9..b966d9b317 100644 --- a/pkg/maintainer/spv/config.go +++ b/pkg/maintainer/spv/config.go @@ -1,6 +1,7 @@ package spv import ( + "fmt" "time" ) @@ -29,6 +30,12 @@ const ( DefaultIdleBackOffTime = 10 * time.Minute ) +// DefaultMaxProofHeaders is the default value for the maximum number of +// block headers allowed in a single SPV proof. It caps the forward walk +// over headers when assembling a proof; see the documentation on the +// MaxProofHeaders config field and on getProofInfo in spv.go. +const DefaultMaxProofHeaders = 144 + // Config holds configurable properties. type Config struct { // Enabled indicates whether the SPV maintainer should be started. @@ -65,4 +72,63 @@ type Config struct { // IdleBackoffTime is a wait time which should be applied when there are no // more transaction proofs to submit. IdleBackoffTime time.Duration + + // MaxProofHeaders caps the forward walk over headers when assembling an + // SPV proof. The proof window is anchored at a fixed start block, so a + // run of leading minimum-difficulty (DIFF1) headers longer than this + // bound makes the transaction permanently unprovable rather than merely + // delayed. Raise the value on networks (e.g. testnet4 with extended + // BIP94 minimum-difficulty runs) where the default 144 headers is + // insufficient. + MaxProofHeaders uint +} + +// Validate checks that the configuration is usable, returning an error +// describing the first problem found. +// +// A zero or negative value is rejected rather than normalized to the +// default: the default only protects against omission, and each of these +// values silently degrades the maintainer at runtime when set to zero - +// for example a zero MaxProofHeaders makes getProofInfo skip every +// transaction on the first iteration. Silently substituting the default +// would hide an operator's explicit, if mistaken, instruction; failing at +// startup surfaces it. +func (c Config) Validate() error { + if c.MaxProofHeaders == 0 { + return fmt.Errorf( + "spv.maxProofHeaders must be greater than 0; " + + "a zero bound skips every transaction and disables SPV proving", + ) + } + + if c.HistoryDepth == 0 { + return fmt.Errorf( + "spv.historyDepth must be greater than 0; " + + "a zero depth makes the event search start at the " + + "current tip, so no past transactions are ever found", + ) + } + + if c.TransactionLimit <= 0 { + return fmt.Errorf( + "spv.transactionLimit must be greater than 0; " + + "the maintainer would find no candidate transactions", + ) + } + + if c.RestartBackoffTime <= 0 { + return fmt.Errorf( + "spv.restartBackoffTime must be greater than 0; " + + "a non-positive backoff tight-loops the restart of the maintainer", + ) + } + + if c.IdleBackoffTime <= 0 { + return fmt.Errorf( + "spv.idleBackoffTime must be greater than 0; " + + "a non-positive backoff tight-loops the proof task rounds", + ) + } + + return nil } diff --git a/pkg/maintainer/spv/config_test.go b/pkg/maintainer/spv/config_test.go new file mode 100644 index 0000000000..29dacd6928 --- /dev/null +++ b/pkg/maintainer/spv/config_test.go @@ -0,0 +1,116 @@ +package spv + +import ( + "context" + "testing" +) + +// TestConfig_Validate guards against silently-degrading zero settings +// reaching the maintainer's runtime. Each field is checked for the +// misconfiguration that looks like a valid value but renders the maintainer +// inert: a zero MaxProofHeaders makes getProofInfo skip every transaction on +// the first loop iteration; a zero HistoryDepth anchors the event search at +// the current chain tip; a non-positive TransactionLimit returns no +// transactions to prove; zero backoff times remove the pauses between +// control-loop iterations. The flag/file defaults only cover omission, so an +// operator's explicit zero has to be rejected at startup. +func TestConfig_Validate(t *testing.T) { + validConfig := Config{ + HistoryDepth: DefaultHistoryDepth, + TransactionLimit: DefaultTransactionLimit, + RestartBackoffTime: DefaultRestartBackoffTime, + IdleBackoffTime: DefaultIdleBackOffTime, + MaxProofHeaders: DefaultMaxProofHeaders, + } + + tests := map[string]struct { + config Config + expectErr bool + }{ + "valid config is accepted": { + config: validConfig, + expectErr: false, + }, + "zero maxProofHeaders is rejected": { + config: withZeroField(validConfig, func(c *Config) { c.MaxProofHeaders = 0 }), + expectErr: true, + }, + "custom positive maxProofHeaders is accepted": { + config: withCustomMaxProofHeaders(validConfig, 288), + expectErr: false, + }, + "zero historyDepth is rejected": { + config: withZeroField(validConfig, func(c *Config) { c.HistoryDepth = 0 }), + expectErr: true, + }, + "zero transactionLimit is rejected": { + config: withZeroField(validConfig, func(c *Config) { c.TransactionLimit = 0 }), + expectErr: true, + }, + "negative transactionLimit is rejected": { + config: withZeroField(validConfig, func(c *Config) { c.TransactionLimit = -1 }), + expectErr: true, + }, + "zero restartBackoffTime is rejected": { + config: withZeroField(validConfig, func(c *Config) { c.RestartBackoffTime = 0 }), + expectErr: true, + }, + "zero idleBackoffTime is rejected": { + config: withZeroField(validConfig, func(c *Config) { c.IdleBackoffTime = 0 }), + expectErr: true, + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + err := test.config.Validate() + + if test.expectErr { + if err == nil { + t.Fatal("expected error, got nil") + } + } else { + if err != nil { + t.Fatalf("expected no error, got: %v", err) + } + } + }) + } +} + +// withZeroField returns a copy of base with one field mutated to its invalid +// value; used to build single-field-invalid configs for the table test. +func withZeroField(base Config, mutate func(*Config)) Config { + c := base + mutate(&c) + return c +} + +func withCustomMaxProofHeaders(base Config, value uint) Config { + c := base + c.MaxProofHeaders = value + return c +} + +// TestInitialize_InvalidConfig guards the public entry point: Initialize must +// reject a misconfigured config before touching any chain interface. +func TestInitialize_InvalidConfig(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + config := Config{ + MaxProofHeaders: 0, + } + + err := Initialize( + ctx, + config, + nil, + nil, + nil, + nil, + ) + if err == nil { + t.Fatal("expected Initialize to fail on invalid config, got nil") + } +} diff --git a/pkg/maintainer/spv/deposit_sweep.go b/pkg/maintainer/spv/deposit_sweep.go index f8405e1576..5608ccc949 100644 --- a/pkg/maintainer/spv/deposit_sweep.go +++ b/pkg/maintainer/spv/deposit_sweep.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/keep-network/keep-core/pkg/bitcoin" "github.com/keep-network/keep-core/pkg/chain" + "github.com/keep-network/keep-core/pkg/clientinfo" ) // SubmitDepositSweepProof prepares deposit sweep proof for the given @@ -19,6 +20,7 @@ func SubmitDepositSweepProof( requiredConfirmations uint, btcChain bitcoin.Chain, spvChain Chain, + metricsRecorder MetricsRecorder, ) error { return submitDepositSweepProof( transactionHash, @@ -26,7 +28,7 @@ func SubmitDepositSweepProof( btcChain, spvChain, bitcoin.AssembleSpvProof, - getGlobalMetricsRecorder(), + metricsRecorder, ) } @@ -36,18 +38,16 @@ func submitDepositSweepProof( btcChain bitcoin.Chain, spvChain Chain, spvProofAssembler spvProofAssembler, - metricsRecorder interface { - IncrementCounter(name string, value float64) - }, + metricsRecorder MetricsRecorder, ) error { // Record proof submission attempt if metricsRecorder != nil { - metricsRecorder.IncrementCounter("deposit_sweep_proof_submissions_total", 1) + metricsRecorder.IncrementCounter(clientinfo.MetricDepositSweepProofSubmissionsTotal, 1) } if requiredConfirmations == 0 { if metricsRecorder != nil { - metricsRecorder.IncrementCounter("deposit_sweep_proof_submissions_failed_total", 1) + metricsRecorder.IncrementCounter(clientinfo.MetricDepositSweepProofSubmissionsFailedTotal, 1) } return fmt.Errorf( "provided required confirmations count must be greater than 0", @@ -61,7 +61,7 @@ func submitDepositSweepProof( ) if err != nil { if metricsRecorder != nil { - metricsRecorder.IncrementCounter("deposit_sweep_proof_submissions_failed_total", 1) + metricsRecorder.IncrementCounter(clientinfo.MetricDepositSweepProofSubmissionsFailedTotal, 1) } return fmt.Errorf( "failed to assemble transaction spv proof: [%v]", @@ -76,7 +76,7 @@ func submitDepositSweepProof( ) if err != nil { if metricsRecorder != nil { - metricsRecorder.IncrementCounter("deposit_sweep_proof_submissions_failed_total", 1) + metricsRecorder.IncrementCounter(clientinfo.MetricDepositSweepProofSubmissionsFailedTotal, 1) } return fmt.Errorf( "error while parsing transaction inputs: [%v]", @@ -91,7 +91,7 @@ func submitDepositSweepProof( vault, ); err != nil { if metricsRecorder != nil { - metricsRecorder.IncrementCounter("deposit_sweep_proof_submissions_failed_total", 1) + metricsRecorder.IncrementCounter(clientinfo.MetricDepositSweepProofSubmissionsFailedTotal, 1) } return fmt.Errorf( "failed to submit deposit sweep proof with reimbursement: [%v]", @@ -101,7 +101,7 @@ func submitDepositSweepProof( // Record successful proof submission if metricsRecorder != nil { - metricsRecorder.IncrementCounter("deposit_sweep_proof_submissions_success_total", 1) + metricsRecorder.IncrementCounter(clientinfo.MetricDepositSweepProofSubmissionsSuccessTotal, 1) } return nil @@ -118,17 +118,12 @@ func parseDepositSweepTransactionInputs( common.Address, error, ) { - // Represents the main UTXO of the deposit sweep transaction. Nil if there - // was no main UTXO. var mainUTXO *bitcoin.UnspentTransactionOutput = nil - // Stores the vault address of the deposits. Each deposit should have the - // same value of vault. The zero-filled value indicates there was no vault - // value set for the deposits. + // Each deposit must have the same vault value. The zero-filled value + // indicates there was no vault set for the deposits. var vault = common.Address{} - // This flag checks if at least one deposit input has been found during - // deposit processing. var depositAlreadyProcessed = false // Perform a sanity check: a deposit sweep transaction must have exactly one @@ -256,20 +251,11 @@ func getUnprovenDepositSweepTransactions( []*bitcoin.Transaction, error, ) { - blockCounter, err := spvChain.BlockCounter() + startBlock, err := unprovenSearchStartBlock(historyDepth, spvChain) if err != nil { - return nil, fmt.Errorf("failed to get block counter: [%v]", err) + return nil, err } - currentBlock, err := blockCounter.CurrentBlock() - if err != nil { - return nil, fmt.Errorf("failed to get current block: [%v]", err) - } - - // Calculate the starting block of the range in which the events will be - // searched for. - startBlock := currentBlock - historyDepth - events, err := spvChain.PastDepositRevealedEvents( &tbtc.DepositRevealedEventFilter{ @@ -310,40 +296,28 @@ func getUnprovenDepositSweepTransactions( continue } - walletTransactions, err := btcChain.GetTransactionsForPublicKeyHash( + unproven, err := collectUnprovenWalletTransactions( walletPublicKeyHash, transactionLimit, - ) - if err != nil { - return nil, fmt.Errorf( - "failed to get transactions for wallet: [%v]", - err, - ) - } - - for _, transaction := range walletTransactions { - isUnproven, err := - isUnprovenDepositSweepTransaction( + btcChain, + func(transaction *bitcoin.Transaction) (bool, error) { + return isUnprovenDepositSweepTransaction( transaction, walletPublicKeyHash, btcChain, spvChain, ) - if err != nil { - return nil, fmt.Errorf( - "failed to check if transaction is an unproven deposit sweep "+ - "transaction: [%v]", - err, - ) - } - - if isUnproven { - unprovenDepositSweepTransactions = append( - unprovenDepositSweepTransactions, - transaction, - ) - } + }, + false, + ) + if err != nil { + return nil, err } + + unprovenDepositSweepTransactions = append( + unprovenDepositSweepTransactions, + unproven..., + ) } return unprovenDepositSweepTransactions, nil diff --git a/pkg/maintainer/spv/deposit_sweep_test.go b/pkg/maintainer/spv/deposit_sweep_test.go index dc61256ccf..0556edc1c9 100644 --- a/pkg/maintainer/spv/deposit_sweep_test.go +++ b/pkg/maintainer/spv/deposit_sweep_test.go @@ -10,9 +10,24 @@ import ( "github.com/keep-network/keep-core/internal/testutils" "github.com/keep-network/keep-core/pkg/bitcoin" + "github.com/keep-network/keep-core/pkg/clientinfo" "github.com/keep-network/keep-core/pkg/tbtc" ) +// fakeMetricsRecorder is a test double for MetricsRecorder that accumulates the +// counter increments it receives, so tests can assert on them. +type fakeMetricsRecorder struct { + counters map[string]float64 +} + +func newFakeMetricsRecorder() *fakeMetricsRecorder { + return &fakeMetricsRecorder{counters: make(map[string]float64)} +} + +func (f *fakeMetricsRecorder) IncrementCounter(name string, value float64) { + f.counters[name] += value +} + func TestSubmitDepositSweepProof(t *testing.T) { bytesFromHex := func(str string) []byte { value, err := hex.DecodeString(str) @@ -90,13 +105,15 @@ func TestSubmitDepositSweepProof(t *testing.T) { return nil, nil, fmt.Errorf("error while assembling spv proof") } + recorder := newFakeMetricsRecorder() + err := submitDepositSweepProof( depositSweepTransaction.Hash(), requiredConfirmations, btcChain, spvChain, mockSpvProofAssembler, - getGlobalMetricsRecorder(), + recorder, ) if err != nil { t.Fatal(err) @@ -132,6 +149,298 @@ func TestSubmitDepositSweepProof(t *testing.T) { expectedVault[:], submittedProof.vault[:], ) + + // A successful submission must record one attempt and one success, and + // must not record a failure. + testutils.AssertIntsEqual( + t, + "total submissions counter", + 1, + int(recorder.counters[clientinfo.MetricDepositSweepProofSubmissionsTotal]), + ) + testutils.AssertIntsEqual( + t, + "success counter", + 1, + int(recorder.counters[clientinfo.MetricDepositSweepProofSubmissionsSuccessTotal]), + ) + testutils.AssertIntsEqual( + t, + "failed counter", + 0, + int(recorder.counters[clientinfo.MetricDepositSweepProofSubmissionsFailedTotal]), + ) +} + +// TestSubmitDepositSweepProofRecordsFailureMetrics verifies that a rejected +// submission (here, zero required confirmations) records both an attempt and a +// failure, but no success. This is the metrics seam that the maintainer boot +// path activates in production by passing a real recorder. +func TestSubmitDepositSweepProofRecordsFailureMetrics(t *testing.T) { + recorder := newFakeMetricsRecorder() + + err := submitDepositSweepProof( + bitcoin.Hash{}, + 0, // zero required confirmations forces an early failure + nil, + nil, + nil, + recorder, + ) + if err == nil { + t.Fatal("expected an error for zero required confirmations") + } + + testutils.AssertIntsEqual( + t, + "total submissions counter", + 1, + int(recorder.counters[clientinfo.MetricDepositSweepProofSubmissionsTotal]), + ) + testutils.AssertIntsEqual( + t, + "failed counter", + 1, + int(recorder.counters[clientinfo.MetricDepositSweepProofSubmissionsFailedTotal]), + ) + testutils.AssertIntsEqual( + t, + "success counter", + 0, + int(recorder.counters[clientinfo.MetricDepositSweepProofSubmissionsSuccessTotal]), + ) +} + +// TestSubmitDepositSweepProofRecordsAssembleFailureMetrics verifies that a +// failure occurring after the initial attempt is counted as a failure and not a +// success. Here the SPV proof assembler errors out, exercising a deeper +// failed-counter branch than the early zero-confirmations reject. The +// parse-inputs and on-chain-submit branches share this same guard idiom; the +// local chain double cannot be forced to fail the on-chain submit, so that +// branch is left to the shared pattern. +func TestSubmitDepositSweepProofRecordsAssembleFailureMetrics(t *testing.T) { + recorder := newFakeMetricsRecorder() + + failingAssembler := func( + bitcoin.Hash, + uint, + bitcoin.Chain, + ) (*bitcoin.Transaction, *bitcoin.SpvProof, error) { + return nil, nil, fmt.Errorf("error while assembling spv proof") + } + + err := submitDepositSweepProof( + bitcoin.Hash{}, + 6, // non-zero, so the failure comes from proof assembly + nil, + nil, + failingAssembler, + recorder, + ) + if err == nil { + t.Fatal("expected an error from the failing proof assembler") + } + + testutils.AssertIntsEqual( + t, + "total submissions counter", + 1, + int(recorder.counters[clientinfo.MetricDepositSweepProofSubmissionsTotal]), + ) + testutils.AssertIntsEqual( + t, + "failed counter", + 1, + int(recorder.counters[clientinfo.MetricDepositSweepProofSubmissionsFailedTotal]), + ) + testutils.AssertIntsEqual( + t, + "success counter", + 0, + int(recorder.counters[clientinfo.MetricDepositSweepProofSubmissionsSuccessTotal]), + ) +} + +// TestSubmitDepositSweepProofRecordsParseFailureMetrics verifies that a +// failure during transaction input parsing (here, a transaction with more than +// one output) records both an attempt and a failure, but no success. This +// covers the parse-input-error branch specifically, distinct from the already- +// tested zero-confirmations and assembly-failure branches. +func TestSubmitDepositSweepProofRecordsParseFailureMetrics(t *testing.T) { + recorder := newFakeMetricsRecorder() + + // Create a transaction with 2 outputs (parseDepositSweepTransactionInputs + // requires exactly 1 output) + parseFailingTransaction := &bitcoin.Transaction{ + Outputs: []*bitcoin.TransactionOutput{ + {}, + {}, + }, + } + + mockSpvProofAssembler := func( + hash bitcoin.Hash, + confirmations uint, + btcChain bitcoin.Chain, + ) (*bitcoin.Transaction, *bitcoin.SpvProof, error) { + // Return a transaction with wrong output count to trigger parse failure + return parseFailingTransaction, &bitcoin.SpvProof{}, nil + } + + err := submitDepositSweepProof( + bitcoin.Hash{}, + 6, // non-zero, so the failure comes from parsing, not zero confirmations + nil, + nil, + mockSpvProofAssembler, + recorder, + ) + if err == nil { + t.Fatal("expected an error from the parse failure") + } + + testutils.AssertIntsEqual( + t, + "total submissions counter", + 1, + int(recorder.counters[clientinfo.MetricDepositSweepProofSubmissionsTotal]), + ) + testutils.AssertIntsEqual( + t, + "failed counter", + 1, + int(recorder.counters[clientinfo.MetricDepositSweepProofSubmissionsFailedTotal]), + ) + testutils.AssertIntsEqual( + t, + "success counter", + 0, + int(recorder.counters[clientinfo.MetricDepositSweepProofSubmissionsSuccessTotal]), + ) +} + +// TestSubmitDepositSweepProofRecordsSubmitFailureMetrics verifies that a +// failure occurring during on-chain submission records both an attempt and a +// failure, but no success. This test was previously untestable because the +// local chain's SubmitDepositSweepProofWithReimbursement method always +// returned nil. This is now made testable via the injected error field. +func TestSubmitDepositSweepProofRecordsSubmitFailureMetrics(t *testing.T) { + bytesFromHex := func(str string) []byte { + value, err := hex.DecodeString(str) + if err != nil { + t.Fatal(err) + } + + return value + } + + txFromHex := func(str string) *bitcoin.Transaction { + transaction := new(bitcoin.Transaction) + err := transaction.Deserialize(bytesFromHex(str)) + if err != nil { + t.Fatal(err) + } + + return transaction + } + + requiredConfirmations := uint(6) + + btcChain := newLocalBitcoinChain() + // Use the local chain with error injection capability + spvChain := newLocalChain() + + // Take an arbitrary deposit sweep transaction: + // https://live.blockcypher.com/btc-testnet/tx/435d4aff6d4bc34134877bd3213c17970142fdd04d4113d534120033b9eecb2e/ + depositSweepTransaction := txFromHex("010000000001036896f9abcac13ce6bd2b80d125bedf997ff6330e999f2f605ea15ea542f2eaf80000000000ffffffffed0ae94da996c6f3b89dfe967675d4808251db93e81022ae9e038d06f92efed400000000c948304502210092327ddff69a2b8c7ae787c5d590a2f14586089e6339e942d56e82aa42052cd902204c0d1700ba1ac617da27fee032a57937c9607f0187199ed3c46954df845643d7012103989d253b17a6a0f41838b84ff0d20e8898f9d7b1a98f2564da4cc29dcf8581d94c5c14934b98637ca318a4d6e7ca6ffd1690b8e77df6377508f9f0c90d000395237576a9148db50eb52063ea9d98b3eac91489a90f738986f68763ac6776a914e257eccafbc07c381642ce6e7e55120fb077fbed8804e0250162b175ac68ffffffffe37f552fc23fa0032bfd00c8eef5f5c22bf85fe4c6e735857719ff8a4ff66eb80000000000ffffffff0180ed0000000000001600148db50eb52063ea9d98b3eac91489a90f738986f602483045022100baf754252d0d6a49aceba7eb0ec40b4cc568e8c659e168b96598a11cf56dc078022051117466ee998a3fc72221006817e8cfe9c2e71ad622ff811a0bf100d888d49c012103989d253b17a6a0f41838b84ff0d20e8898f9d7b1a98f2564da4cc29dcf8581d90003473044022014a535eb334656665ac69a678dbf7c019c4f13262e9ea4d195c61a00cd5f698d022023c0062913c4614bdff07f94475ceb4c585df53f71611776c3521ed8f8785913012103989d253b17a6a0f41838b84ff0d20e8898f9d7b1a98f2564da4cc29dcf8581d95c14934b98637ca318a4d6e7ca6ffd1690b8e77df6377508f9f0c90d000395237576a9148db50eb52063ea9d98b3eac91489a90f738986f68763ac6776a914e257eccafbc07c381642ce6e7e55120fb077fbed8804e0250162b175ac6800000000") + + // Set the transactions that created the inputs of the deposit sweep + // transaction. It is necessary as the tested function logic fetches its + // data to determine the wallet's main UTXO and the deposit vault. + inputTransactions := []*bitcoin.Transaction{ + // main UTXO input: https://live.blockcypher.com/btc-testnet/tx/f8eaf242a55ea15e602f9f990e33f67f99dfbe25d1802bbde63cc1caabf99668/ + txFromHex("01000000000102bc187be612bc3db8cfcdec56b75e9bc0262ab6eacfe27cc1a699bacd53e3d07400000000c948304502210089a89aaf3fec97ac9ffa91cdff59829f0cb3ef852a468153e2c0e2b473466d2e022072902bb923ef016ac52e941ced78f816bf27991c2b73211e227db27ec200bc0a012103989d253b17a6a0f41838b84ff0d20e8898f9d7b1a98f2564da4cc29dcf8581d94c5c14934b98637ca318a4d6e7ca6ffd1690b8e77df6377508f9f0c90d000395237576a9148db50eb52063ea9d98b3eac91489a90f738986f68763ac6776a914e257eccafbc07c381642ce6e7e55120fb077fbed8804e0250162b175ac68ffffffffdc557e737b6688c5712649b86f7757a722dc3d42786f23b2fa826394dfec545c0000000000ffffffff01488a0000000000001600148db50eb52063ea9d98b3eac91489a90f738986f6000347304402203747f5ee31334b11ebac6a2a156b1584605de8d91a654cd703f9c8438634997402202059d680211776f93c25636266b02e059ed9fcc6209f7d3d9926c49a0d8750ed012103989d253b17a6a0f41838b84ff0d20e8898f9d7b1a98f2564da4cc29dcf8581d95c14934b98637ca318a4d6e7ca6ffd1690b8e77df6377508f9f0c90d000395237576a9148db50eb52063ea9d98b3eac91489a90f738986f68763ac6776a914e257eccafbc07c381642ce6e7e55120fb077fbed8804e0250162b175ac6800000000"), + // deposit input: https://live.blockcypher.com/btc-testnet/tx/d4fe2ef9068d039eae2210e893db518280d4757696fe9db8f3c696a94de90aed/ + txFromHex("01000000000101e37f552fc23fa0032bfd00c8eef5f5c22bf85fe4c6e735857719ff8a4ff66eb80100000000ffffffff02684200000000000017a9143ec459d0f3c29286ae5df5fcc421e2786024277e8742b7100000000000160014e257eccafbc07c381642ce6e7e55120fb077fbed0248304502210084eb60347b9aa48d9a53c6ab0fc2c2357a0df430d193507facfb2238e46f034502202a29d11e128dba3ff3a8ad9a1e820a3b58e89e37fa90d1cc2b3f05207599fef00121039d61d62dcd048d3f8550d22eb90b4af908db60231d117aeede04e7bc11907bfa00000000"), + // deposit input: https://live.blockcypher.com/btc-testnet/tx/b86ef64f8aff19778535e7c6e45ff82bc2f5f5eec800fd2b03a03fc22f557fe3/ + txFromHex("01000000000101dc557e737b6688c5712649b86f7757a722dc3d42786f23b2fa826394dfec545c0100000000ffffffff02102700000000000022002086a303cdd2e2eab1d1679f1a813835dc5a1b65321077cdccaf08f98cbf04ca962cff100000000000160014e257eccafbc07c381642ce6e7e55120fb077fbed02473044022050759dde2c84bccf3c1502b0e33a6acb570117fd27a982c0c2991c9f9737508e02201fcba5d6f6c0ab780042138a9110418b3f589d8d09a900f20ee28cfcdb14d2970121039d61d62dcd048d3f8550d22eb90b4af908db60231d117aeede04e7bc11907bfa00000000"), + } + for _, transaction := range inputTransactions { + err := btcChain.BroadcastTransaction(transaction) + if err != nil { + t.Fatal(err) + } + } + + // Set deposit request information for the transaction's deposit inputs. + for i := 1; i < len(depositSweepTransaction.Inputs); i++ { + spvChain.setDepositRequest( + depositSweepTransaction.Inputs[i].Outpoint.TransactionHash, + depositSweepTransaction.Inputs[i].Outpoint.OutputIndex, + &tbtc.DepositChainRequest{ + RevealedAt: time.Unix(1000, 0), + SweptAt: time.Unix(0, 0), + }, + ) + } + + // Just a mock proof. + proof := &bitcoin.SpvProof{ + MerkleProof: []byte{0x01}, + TxIndexInBlock: 2, + BitcoinHeaders: []byte{0x03}, + } + + mockSpvProofAssembler := func( + hash bitcoin.Hash, + confirmations uint, + btcChain bitcoin.Chain, + ) (*bitcoin.Transaction, *bitcoin.SpvProof, error) { + if hash == depositSweepTransaction.Hash() && confirmations == requiredConfirmations { + return depositSweepTransaction, proof, nil + } + + return nil, nil, fmt.Errorf("error while assembling spv proof") + } + + recorder := newFakeMetricsRecorder() + + // Force an error from the on-chain submit method + spvChain.submitDepositSweepProofErr = fmt.Errorf("forced on-chain submit error") + + err := submitDepositSweepProof( + depositSweepTransaction.Hash(), + requiredConfirmations, + btcChain, + spvChain, + mockSpvProofAssembler, + recorder, + ) + if err == nil { + t.Fatal("expected an error from the forced on-chain submit failure") + } + + submittedProofs := spvChain.getSubmittedDepositSweepProofs() + testutils.AssertIntsEqual(t, "proofs count", 0, len(submittedProofs)) + + testutils.AssertIntsEqual( + t, + "total submissions counter", + 1, + int(recorder.counters[clientinfo.MetricDepositSweepProofSubmissionsTotal]), + ) + testutils.AssertIntsEqual( + t, + "failed counter", + 1, + int(recorder.counters[clientinfo.MetricDepositSweepProofSubmissionsFailedTotal]), + ) + testutils.AssertIntsEqual( + t, + "success counter", + 0, + int(recorder.counters[clientinfo.MetricDepositSweepProofSubmissionsSuccessTotal]), + ) } func TestGetUnprovenDepositSweepTransactions(t *testing.T) { diff --git a/pkg/maintainer/spv/health.go b/pkg/maintainer/spv/health.go new file mode 100644 index 0000000000..99b46dec9c --- /dev/null +++ b/pkg/maintainer/spv/health.go @@ -0,0 +1,39 @@ +package spv + +import ( + "time" + + "github.com/keep-network/keep-core/pkg/clientinfo" + "github.com/keep-network/keep-core/pkg/tbtc" +) + +func (sm *spvMaintainer) setHealthGauge(name string, value float64) { + if sm.metricsRecorder != nil { + sm.metricsRecorder.SetGauge(name, value) + } +} + +func (sm *spvMaintainer) recordActivity() { + sm.setHealthGauge(clientinfo.MetricSpvMaintainerLastActivityTimestamp, float64(time.Now().Unix())) +} + +// runProofTask includes discovery and proof-info failures that occur before a +// proof submitter can increment its submission counters. Skipped proofs are +// counted separately by proveTransactions and are not task failures. +func (sm *spvMaintainer) runProofTask( + action tbtc.WalletActionType, + getter unprovenTransactionsGetter, + submitter transactionProofSubmitter, +) error { + sm.recordActivity() + err := sm.proveTransactions(getter, submitter) + sm.recordActivity() + if err != nil && sm.metricsRecorder != nil { + sm.setHealthGauge(clientinfo.MetricSpvMaintainerLastFailureTimestamp, float64(time.Now().Unix())) + sm.metricsRecorder.IncrementCounter(clientinfo.MetricSpvProofTaskFailuresTotal, 1) + if action == tbtc.ActionRedemption { + sm.metricsRecorder.IncrementCounter(clientinfo.MetricRedemptionProofTaskFailuresTotal, 1) + } + } + return err +} diff --git a/pkg/maintainer/spv/health_test.go b/pkg/maintainer/spv/health_test.go new file mode 100644 index 0000000000..9fdea6640e --- /dev/null +++ b/pkg/maintainer/spv/health_test.go @@ -0,0 +1,145 @@ +package spv + +import ( + "context" + "errors" + "sync/atomic" + "testing" + "time" + + "github.com/keep-network/keep-core/pkg/bitcoin" + "github.com/keep-network/keep-core/pkg/clientinfo" + "github.com/keep-network/keep-core/pkg/tbtc" +) + +func TestProofTaskFailuresBeforeSubmission(t *testing.T) { + for _, discoveryFails := range []bool{true, false} { + for _, enabled := range []bool{true, false} { + recorder := &recordingMetricsRecorder{counters: make(map[string]float64)} + sm := &spvMaintainer{btcChain: newLocalBitcoinChain(), spvChain: newLocalChain(), btcDiffChain: newLocalChain()} + if enabled { + sm.metricsRecorder = recorder + } + getter := func(uint64, int, bitcoin.Chain, Chain) ([]*bitcoin.Transaction, error) { + if discoveryFails { + return nil, errors.New("cannot fetch redemption requests") + } + // Proof-info lookup fails because this transaction is unknown to + // the Bitcoin backend. The submitter must never be called. + return []*bitcoin.Transaction{{Version: 1}}, nil + } + submitter := func(bitcoin.Hash, uint, bitcoin.Chain, Chain, MetricsRecorder) error { + t.Fatal("submission attempted after an earlier failure") + return nil + } + if err := sm.runProofTask(tbtc.ActionRedemption, getter, submitter); err == nil { + t.Fatal("expected a task error") + } + if enabled { + if recorder.gauges[clientinfo.MetricSpvMaintainerLastFailureTimestamp] == 0 { + t.Fatal("first task failure timestamp was not recorded") + } + for _, name := range []string{clientinfo.MetricSpvProofTaskFailuresTotal, clientinfo.MetricRedemptionProofTaskFailuresTotal} { + if recorder.counters[name] != 1 { + t.Errorf("expected one %s failure, got %v", name, recorder.counters[name]) + } + } + if recorder.gauges[clientinfo.MetricSpvMaintainerLastActivityTimestamp] == 0 { + t.Fatal("task completion did not update activity") + } + } + } + } +} + +func TestMaintainerHealthLifecycle(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + recorder := &recordingMetricsRecorder{counters: make(map[string]float64)} + sm := &spvMaintainer{ + config: Config{RestartBackoffTime: time.Hour, IdleBackoffTime: 10 * time.Minute}, + metricsRecorder: recorder, + } + sm.startControlLoop(ctx) + // Read with comma-ok: a gauge that was never exported reads back as zero, + // so asserting "== 0" alone passes just as happily when the maintainer + // stops publishing the metric altogether. + active, ok := recorder.gauges[clientinfo.MetricSpvMaintainerActive] + if !ok { + t.Fatal("active gauge was not exported at all") + } + if active != 0 { + t.Fatal("stopped maintainer remains active") + } + if recorder.gauges[clientinfo.MetricSpvMaintainerMaxBackoffSeconds] != 3600 { + t.Fatal("configured restart backoff was not exported") + } + // A last-success timestamp is only exported from inside a completed cycle + // (setHealthGauge in spv.go). A canceled context never completes one, so + // the gauge must be absent, not merely zero - asserting "== 0" would pass + // just as happily if the timestamp were published outside the success + // branch and happened to be zero. + if _, ok := recorder.gauges[clientinfo.MetricSpvMaintainerLastSuccessTimestamp]; ok { + t.Fatal("canceled cycle exported a last-success timestamp") + } +} + +func TestMaintainerHealthLifecycle_MaxBackoffIdleLarger(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + recorder := &recordingMetricsRecorder{counters: make(map[string]float64)} + sm := &spvMaintainer{ + config: Config{RestartBackoffTime: 10 * time.Minute, IdleBackoffTime: time.Hour}, + metricsRecorder: recorder, + } + sm.startControlLoop(ctx) + if recorder.gauges[clientinfo.MetricSpvMaintainerMaxBackoffSeconds] != 3600 { + t.Fatal("expected max backoff to use the larger configured idle backoff") + } +} + +// TestMaintainSpv_CancelsBetweenProofTasks verifies the per-action ctx.Err() +// check inside maintainSpv's loop actually stops the cycle: once the context +// is canceled while processing one proof type, no other proof type's getter +// is invoked afterward. proofTypes iteration order is randomized by Go's map +// semantics, so the fake getter shared by every action treats "first call" +// as whichever action the runtime visits first, and fails the test if a +// second call ever happens after cancellation. +func TestMaintainSpv_CancelsBetweenProofTasks(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + + var callCount int32 + sharedGetter := func(uint64, int, bitcoin.Chain, Chain) ([]*bitcoin.Transaction, error) { + if atomic.AddInt32(&callCount, 1) > 1 { + t.Fatal("a proof task's getter ran after the SPV loop's context was canceled") + } + cancel() + return nil, nil + } + sharedSubmitter := func(bitcoin.Hash, uint, bitcoin.Chain, Chain, MetricsRecorder) error { + t.Fatal("submitter must not run when the getter reports no transactions") + return nil + } + + original := proofTypes + defer func() { proofTypes = original }() + proofTypes = map[tbtc.WalletActionType]struct { + unprovenTransactionsGetter unprovenTransactionsGetter + transactionProofSubmitter transactionProofSubmitter + }{ + tbtc.ActionDepositSweep: {unprovenTransactionsGetter: sharedGetter, transactionProofSubmitter: sharedSubmitter}, + tbtc.ActionRedemption: {unprovenTransactionsGetter: sharedGetter, transactionProofSubmitter: sharedSubmitter}, + } + + sm := &spvMaintainer{btcChain: newLocalBitcoinChain(), spvChain: newLocalChain(), btcDiffChain: newLocalChain()} + err := sm.maintainSpv(ctx) + if !errors.Is(err, context.Canceled) { + t.Fatalf("expected context.Canceled from the canceled loop, got %v", err) + } + if got := atomic.LoadInt32(&callCount); got != 1 { + t.Fatalf("expected exactly one proof task invocation before cancellation, got %d", got) + } +} + +// Proof submission test recorders do not observe lifecycle gauges. +func (*fakeMetricsRecorder) SetGauge(string, float64) {} diff --git a/pkg/maintainer/spv/moved_funds_sweep.go b/pkg/maintainer/spv/moved_funds_sweep.go index 417a1f5347..e070710abb 100644 --- a/pkg/maintainer/spv/moved_funds_sweep.go +++ b/pkg/maintainer/spv/moved_funds_sweep.go @@ -11,11 +11,15 @@ import ( // SubmitMovedFundsSweepProof prepares moved funds sweep proof for the given // transaction and submits it to the on-chain contract. If the number of // required confirmations is `0`, an error is returned. +// The metricsRecorder parameter is accepted to satisfy transactionProofSubmitter +// but is currently unused: moved funds sweep proof submissions are not yet +// instrumented with metrics. func SubmitMovedFundsSweepProof( transactionHash bitcoin.Hash, requiredConfirmations uint, btcChain bitcoin.Chain, spvChain Chain, + _ MetricsRecorder, ) error { return submitMovedFundsSweepProof( transactionHash, @@ -137,20 +141,11 @@ func getUnprovenMovedFundsSweepTransactions( []*bitcoin.Transaction, error, ) { - blockCounter, err := spvChain.BlockCounter() + startBlock, err := unprovenSearchStartBlock(historyDepth, spvChain) if err != nil { - return nil, fmt.Errorf("failed to get block counter: [%v]", err) + return nil, err } - currentBlock, err := blockCounter.CurrentBlock() - if err != nil { - return nil, fmt.Errorf("failed to get current block: [%v]", err) - } - - // Calculate the starting block of the range in which the events will be - // searched for. - startBlock := currentBlock - historyDepth - events, err := spvChain.PastMovingFundsCommitmentSubmittedEvents( &tbtc.MovingFundsCommitmentSubmittedEventFilter{ @@ -211,45 +206,31 @@ func getUnprovenMovedFundsSweepTransactions( // When wallet makes a moved funds sweep transaction, it transfers // funds to itself. Therefore we can search all the transactions that // pay to the wallet's public key hash. - walletTransactions, err := btcChain.GetTransactionsForPublicKeyHash( + // + // A wallet can have only one unproven moved funds sweep transaction at + // a time, so we stop at the first match. + unproven, err := collectUnprovenWalletTransactions( walletPublicKeyHash, transactionLimit, - ) - if err != nil { - return nil, fmt.Errorf( - "failed to get transactions for wallet: [%v]", - err, - ) - } - - for _, transaction := range walletTransactions { - isUnproven, err := - isUnprovenMovedFundsSweepTransaction( + btcChain, + func(transaction *bitcoin.Transaction) (bool, error) { + return isUnprovenMovedFundsSweepTransaction( transaction, walletPublicKeyHash, btcChain, spvChain, ) - if err != nil { - return nil, fmt.Errorf( - "failed to check if transaction is an unproven moved "+ - "funds sweep transaction: [%v]", - err, - ) - } - - if isUnproven { - unprovenMovedFundsSweepTransactions = append( - unprovenMovedFundsSweepTransactions, - transaction, - ) - - // A wallet can have only one unproven moved funds sweep - // transaction at a time. If we found such transaction, we don't - // have to look at this wallet's transactions anymore. - break - } + }, + true, + ) + if err != nil { + return nil, err } + + unprovenMovedFundsSweepTransactions = append( + unprovenMovedFundsSweepTransactions, + unproven..., + ) } return unprovenMovedFundsSweepTransactions, nil diff --git a/pkg/maintainer/spv/moving_funds.go b/pkg/maintainer/spv/moving_funds.go index 81d1e13e51..011e17e80c 100644 --- a/pkg/maintainer/spv/moving_funds.go +++ b/pkg/maintainer/spv/moving_funds.go @@ -11,11 +11,15 @@ import ( // SubmitMovingFundsProof prepares moving funds proof for the given // transaction and submits it to the on-chain contract. If the number of // required confirmations is `0`, an error is returned. +// The metricsRecorder parameter is accepted to satisfy transactionProofSubmitter +// but is currently unused: moving funds proof submissions are not yet +// instrumented with metrics. func SubmitMovingFundsProof( transactionHash bitcoin.Hash, requiredConfirmations uint, btcChain bitcoin.Chain, spvChain Chain, + _ MetricsRecorder, ) error { return submitMovingFundsProof( transactionHash, @@ -133,20 +137,11 @@ func getUnprovenMovingFundsTransactions( []*bitcoin.Transaction, error, ) { - blockCounter, err := spvChain.BlockCounter() + startBlock, err := unprovenSearchStartBlock(historyDepth, spvChain) if err != nil { - return nil, fmt.Errorf("failed to get block counter: [%v]", err) + return nil, err } - currentBlock, err := blockCounter.CurrentBlock() - if err != nil { - return nil, fmt.Errorf("failed to get current block: [%v]", err) - } - - // Calculate the starting block of the range in which the events will be - // searched for. - startBlock := currentBlock - historyDepth - // The `MovingFundsCommitmentSubmitted` event can only be emitted once for // a given wallet. Therefore there will always be only one event for a wallet. // We do not have to worry about duplicate events for the same wallet. @@ -197,41 +192,29 @@ func getUnprovenMovingFundsTransactions( // source wallet. targetWalletPublicKeyHash := targetWallets[0] - walletTransactions, err := btcChain.GetTransactionsForPublicKeyHash( + unproven, err := collectUnprovenWalletTransactions( targetWalletPublicKeyHash, transactionLimit, - ) - if err != nil { - return nil, fmt.Errorf( - "failed to get transactions for wallet: [%v]", - err, - ) - } - - for _, transaction := range walletTransactions { - isUnproven, err := - isUnprovenMovingFundsTransaction( + btcChain, + func(transaction *bitcoin.Transaction) (bool, error) { + return isUnprovenMovingFundsTransaction( transaction, walletPublicKeyHash, targetWallets, btcChain, spvChain, ) - if err != nil { - return nil, fmt.Errorf( - "failed to check if transaction is an unproven moving funds "+ - "transaction: [%v]", - err, - ) - } - - if isUnproven { - unprovenMovingFundsTransactions = append( - unprovenMovingFundsTransactions, - transaction, - ) - } + }, + false, + ) + if err != nil { + return nil, err } + + unprovenMovingFundsTransactions = append( + unprovenMovingFundsTransactions, + unproven..., + ) } return unprovenMovingFundsTransactions, nil diff --git a/pkg/maintainer/spv/moving_funds_test.go b/pkg/maintainer/spv/moving_funds_test.go index c5f1332b95..c4aa3ee8d3 100644 --- a/pkg/maintainer/spv/moving_funds_test.go +++ b/pkg/maintainer/spv/moving_funds_test.go @@ -289,3 +289,176 @@ func TestGetUnprovenMovingFundsTransactions(t *testing.T) { t.Errorf("invalid unproven transaction hashes: %v", diff) } } + +// TestGetUnprovenMovingFundsTransactions_MultipleMatchesForSameWallet proves +// that getUnprovenMovingFundsTransactions collects ALL unproven moving funds +// transactions for a wallet, not just the first one found. It calls +// collectUnprovenWalletTransactions with stopAtFirstMatch set to false, and +// this test guards against that argument accidentally being flipped to true, +// which none of the other action-level tests in this package would catch +// since they never give a single wallet more than one genuinely-qualifying +// transaction. +func TestGetUnprovenMovingFundsTransactions_MultipleMatchesForSameWallet(t *testing.T) { + bytesFromHex := func(str string) []byte { + value, err := hex.DecodeString(str) + if err != nil { + t.Fatal(err) + } + + return value + } + + bytes20FromHex := func(str string) [20]byte { + var value [20]byte + copy(value[:], bytesFromHex(str)) + return value + } + + txFromHex := func(str string) *bitcoin.Transaction { + transaction := new(bitcoin.Transaction) + err := transaction.Deserialize(bytesFromHex(str)) + if err != nil { + t.Fatal(err) + } + + return transaction + } + + // Set an arbitrary history depth and transaction limit. + historyDepth := uint64(5) + transactionLimit := 10 + + btcChain := newLocalBitcoinChain() + spvChain := newLocalChain() + + // Set a predictable current block. + currentBlock := uint64(1000) + blockCounter := newMockBlockCounter() + blockCounter.SetCurrentBlock(currentBlock) + spvChain.setBlockCounter(blockCounter) + + walletPublicKeyHash := bytes20FromHex("8db50eb52063ea9d98b3eac91489a90f738986f6") + + targetWalletsPublicKeyHashes := [][20]byte{ + bytes20FromHex("3091d288521caec06ea912eacfd733edc5a36d6e"), + bytes20FromHex("92a6ec889a8fa34f731e639edede4c75e184307c"), + bytes20FromHex("c7302d75072d78be94eb8d36c4b77583c7abb06e"), + } + + // Transaction that creates the wallet's main UTXO: + // https://live.blockcypher.com/btc-testnet/tx/11d27b4af5598bd0e5cea22c40f0ed8623278ad18f7fb2afc139ce99087aae44/ + mainUtxoCreationTransaction := txFromHex("02000000000101cf063c32da06ff5044f38220c61ee57ac5f3c31368a665bddb109d225d8b4d1a0100000000fdffffff02409c0000000000001600148db50eb52063ea9d98b3eac91489a90f738986f6df66000000000000160014be8347707d02375d1bd0c8f21a59f44c62990d8f024730440220166fbabc5d144d639e350826a04f1d2d148702312ce532da962076eb3859b81c02203d640f23f84a3792451539616432ffb07dc8ddac72047da56a22ecb842165bb4012103399de99c1d409735b7d20f46f616cd485f6b0442db13dfe4cd1b3772ae675fe024572700") + + err := btcChain.BroadcastTransaction(mainUtxoCreationTransaction) + if err != nil { + t.Fatal(err) + } + + // buildMovingFundsTransaction constructs a transaction whose single input + // spends the wallet's main UTXO and whose outputs pay the target wallets + // from the commitment, in order. Such a transaction independently + // satisfies isUnprovenMovingFundsTransaction. Varying outputValues across + // calls yields distinct transaction hashes, mimicking a wallet operator + // broadcasting more than one moving funds attempt (e.g. a fee bump) + // against the same main UTXO before either gets proven. + buildMovingFundsTransaction := func(outputValues [3]int64) *bitcoin.Transaction { + outputs := make([]*bitcoin.TransactionOutput, len(targetWalletsPublicKeyHashes)) + for i, targetWalletPublicKeyHash := range targetWalletsPublicKeyHashes { + script, err := bitcoin.PayToWitnessPublicKeyHash(targetWalletPublicKeyHash) + if err != nil { + t.Fatal(err) + } + + outputs[i] = &bitcoin.TransactionOutput{ + Value: outputValues[i], + PublicKeyScript: script, + } + } + + return &bitcoin.Transaction{ + Version: 1, + Inputs: []*bitcoin.TransactionInput{ + { + Outpoint: &bitcoin.TransactionOutpoint{ + TransactionHash: mainUtxoCreationTransaction.Hash(), + OutputIndex: 0, + }, + Sequence: 0xffffffff, + }, + }, + Outputs: outputs, + Locktime: 0, + } + } + + movingFundsTransaction1 := buildMovingFundsTransaction([3]int64{30000, 30000, 30000}) + movingFundsTransaction2 := buildMovingFundsTransaction([3]int64{29000, 29500, 30500}) + + err = btcChain.BroadcastTransaction(movingFundsTransaction1) + if err != nil { + t.Fatal(err) + } + + err = btcChain.BroadcastTransaction(movingFundsTransaction2) + if err != nil { + t.Fatal(err) + } + + walletData := &tbtc.WalletChainData{ + MainUtxoHash: spvChain.ComputeMainUtxoHash( + &bitcoin.UnspentTransactionOutput{ + Outpoint: &bitcoin.TransactionOutpoint{ + TransactionHash: mainUtxoCreationTransaction.Hash(), + OutputIndex: 0, + }, + Value: mainUtxoCreationTransaction.Outputs[0].Value, + }, + ), + State: tbtc.StateMovingFunds, + } + + spvChain.setWallet(walletPublicKeyHash, walletData) + + event := &tbtc.MovingFundsCommitmentSubmittedEvent{ + WalletPublicKeyHash: walletPublicKeyHash, + TargetWallets: targetWalletsPublicKeyHashes, + BlockNumber: 100, + } + + err = spvChain.addPastMovingFundsCommitmentSubmittedEvent( + &tbtc.MovingFundsCommitmentSubmittedEventFilter{ + StartBlock: currentBlock - historyDepth, + }, + event, + ) + if err != nil { + t.Fatal(err) + } + + transactions, err := getUnprovenMovingFundsTransactions( + historyDepth, + transactionLimit, + btcChain, + spvChain, + ) + if err != nil { + t.Fatal(err) + } + + transactionsHashes := make([]bitcoin.Hash, len(transactions)) + for i, transaction := range transactions { + transactionsHashes[i] = transaction.Hash() + } + + // Both transactions were broadcast in this order and + // localBitcoinChain.GetTransactionsForPublicKeyHash preserves broadcast + // (insertion) order, so asserting this exact order is not incidental. + expectedTransactionsHashes := []bitcoin.Hash{ + movingFundsTransaction1.Hash(), + movingFundsTransaction2.Hash(), + } + + if diff := deep.Equal(expectedTransactionsHashes, transactionsHashes); diff != nil { + t.Errorf("invalid unproven transaction hashes: %v", diff) + } +} diff --git a/pkg/maintainer/spv/redemptions.go b/pkg/maintainer/spv/redemptions.go index e504860f81..6665cf1f4a 100644 --- a/pkg/maintainer/spv/redemptions.go +++ b/pkg/maintainer/spv/redemptions.go @@ -9,13 +9,6 @@ import ( "github.com/keep-network/keep-core/pkg/tbtc" ) -// getGlobalMetricsRecorder returns the global metrics recorder if set. -func getGlobalMetricsRecorder() interface { - IncrementCounter(name string, value float64) -} { - return getMetricsRecorder() -} - // SubmitRedemptionProof prepares redemption proof for the given transaction // and submits it to the on-chain contract. If the number of required // confirmations is `0`, an error is returned. @@ -24,6 +17,7 @@ func SubmitRedemptionProof( requiredConfirmations uint, btcChain bitcoin.Chain, spvChain Chain, + metricsRecorder MetricsRecorder, ) error { return submitRedemptionProof( transactionHash, @@ -31,7 +25,7 @@ func SubmitRedemptionProof( btcChain, spvChain, bitcoin.AssembleSpvProof, - getGlobalMetricsRecorder(), + metricsRecorder, ) } @@ -41,9 +35,7 @@ func submitRedemptionProof( btcChain bitcoin.Chain, spvChain Chain, spvProofAssembler spvProofAssembler, - metricsRecorder interface { - IncrementCounter(name string, value float64) - }, + metricsRecorder MetricsRecorder, ) error { // Record proof submission attempt if metricsRecorder != nil { @@ -167,20 +159,11 @@ func getUnprovenRedemptionTransactions( []*bitcoin.Transaction, error, ) { - blockCounter, err := spvChain.BlockCounter() + startBlock, err := unprovenSearchStartBlock(historyDepth, spvChain) if err != nil { - return nil, fmt.Errorf("failed to get block counter: [%v]", err) + return nil, err } - currentBlock, err := blockCounter.CurrentBlock() - if err != nil { - return nil, fmt.Errorf("failed to get current block: [%v]", err) - } - - // Calculate the starting block of the range in which the events will be - // searched for. - startBlock := currentBlock - historyDepth - events, err := spvChain.PastRedemptionRequestedEvents( &tbtc.RedemptionRequestedEventFilter{ @@ -221,40 +204,28 @@ func getUnprovenRedemptionTransactions( continue } - walletTransactions, err := btcChain.GetTransactionsForPublicKeyHash( + unproven, err := collectUnprovenWalletTransactions( walletPublicKeyHash, transactionLimit, - ) - if err != nil { - return nil, fmt.Errorf( - "failed to get transactions for wallet: [%v]", - err, - ) - } - - for _, transaction := range walletTransactions { - isUnproven, err := - isUnprovenRedemptionTransaction( + btcChain, + func(transaction *bitcoin.Transaction) (bool, error) { + return isUnprovenRedemptionTransaction( transaction, walletPublicKeyHash, btcChain, spvChain, ) - if err != nil { - return nil, fmt.Errorf( - "failed to check if transaction is an unproven redemption "+ - "transaction: [%v]", - err, - ) - } - - if isUnproven { - unprovenRedemptionTransactions = append( - unprovenRedemptionTransactions, - transaction, - ) - } + }, + false, + ) + if err != nil { + return nil, err } + + unprovenRedemptionTransactions = append( + unprovenRedemptionTransactions, + unproven..., + ) } return unprovenRedemptionTransactions, nil diff --git a/pkg/maintainer/spv/redemptions_test.go b/pkg/maintainer/spv/redemptions_test.go index 4f10a3a208..bbab7b5271 100644 --- a/pkg/maintainer/spv/redemptions_test.go +++ b/pkg/maintainer/spv/redemptions_test.go @@ -6,10 +6,157 @@ import ( "github.com/go-test/deep" "github.com/keep-network/keep-core/internal/testutils" "github.com/keep-network/keep-core/pkg/bitcoin" + "github.com/keep-network/keep-core/pkg/clientinfo" "github.com/keep-network/keep-core/pkg/tbtc" "testing" ) +// TestSubmitRedemptionProofRecordsFailureMetrics verifies that a rejected +// submission (here, zero required confirmations) records both an attempt and a +// failure, but no success. This is the metrics seam that the maintainer boot +// path activates in production by passing a real recorder. +func TestSubmitRedemptionProofRecordsFailureMetrics(t *testing.T) { + recorder := newFakeMetricsRecorder() + + err := submitRedemptionProof( + bitcoin.Hash{}, + 0, // zero required confirmations forces an early failure + nil, + nil, + nil, + recorder, + ) + if err == nil { + t.Fatal("expected an error for zero required confirmations") + } + + testutils.AssertIntsEqual( + t, + "total submissions counter", + 1, + int(recorder.counters[clientinfo.MetricRedemptionProofSubmissionsTotal]), + ) + testutils.AssertIntsEqual( + t, + "failed counter", + 1, + int(recorder.counters[clientinfo.MetricRedemptionProofSubmissionsFailedTotal]), + ) + testutils.AssertIntsEqual( + t, + "success counter", + 0, + int(recorder.counters[clientinfo.MetricRedemptionProofSubmissionsSuccessTotal]), + ) +} + +// TestSubmitRedemptionProofRecordsAssembleFailureMetrics verifies that a +// failure occurring after the initial attempt is counted as a failure and not a +// success. Here the SPV proof assembler errors out, exercising a deeper +// failed-counter branch than the early zero-confirmations reject. The +// parse-inputs and on-chain-submit branches share this same guard idiom; the +// local chain double cannot be forced to fail the on-chain submit, so that +// branch is left to the shared pattern. +func TestSubmitRedemptionProofRecordsAssembleFailureMetrics(t *testing.T) { + recorder := newFakeMetricsRecorder() + + failingAssembler := func( + bitcoin.Hash, + uint, + bitcoin.Chain, + ) (*bitcoin.Transaction, *bitcoin.SpvProof, error) { + return nil, nil, fmt.Errorf("error while assembling spv proof") + } + + err := submitRedemptionProof( + bitcoin.Hash{}, + 6, // non-zero, so the failure comes from proof assembly + nil, + nil, + failingAssembler, + recorder, + ) + if err == nil { + t.Fatal("expected an error from the failing proof assembler") + } + + testutils.AssertIntsEqual( + t, + "total submissions counter", + 1, + int(recorder.counters[clientinfo.MetricRedemptionProofSubmissionsTotal]), + ) + testutils.AssertIntsEqual( + t, + "failed counter", + 1, + int(recorder.counters[clientinfo.MetricRedemptionProofSubmissionsFailedTotal]), + ) + testutils.AssertIntsEqual( + t, + "success counter", + 0, + int(recorder.counters[clientinfo.MetricRedemptionProofSubmissionsSuccessTotal]), + ) +} + +// TestSubmitRedemptionProofRecordsParseFailureMetrics verifies that a +// failure during transaction input parsing (here, a transaction with more than +// one input) records both an attempt and a failure, but no success. This +// covers the parse-input-error branch specifically, distinct from the already- +// tested zero-confirmations and assembly-failure branches. +func TestSubmitRedemptionProofRecordsParseFailureMetrics(t *testing.T) { + recorder := newFakeMetricsRecorder() + + // Create a transaction with 2 inputs (parseRedemptionTransactionInput + // requires exactly 1 input) + parseFailingTransaction := &bitcoin.Transaction{ + Inputs: []*bitcoin.TransactionInput{ + {}, + {}, + }, + } + + mockSpvProofAssembler := func( + hash bitcoin.Hash, + confirmations uint, + btcChain bitcoin.Chain, + ) (*bitcoin.Transaction, *bitcoin.SpvProof, error) { + // Return a transaction with wrong input count to trigger parse failure + return parseFailingTransaction, &bitcoin.SpvProof{}, nil + } + + err := submitRedemptionProof( + bitcoin.Hash{}, + 6, // non-zero, so the failure comes from parsing, not zero confirmations + nil, + nil, + mockSpvProofAssembler, + recorder, + ) + if err == nil { + t.Fatal("expected an error from the parse failure") + } + + testutils.AssertIntsEqual( + t, + "total submissions counter", + 1, + int(recorder.counters[clientinfo.MetricRedemptionProofSubmissionsTotal]), + ) + testutils.AssertIntsEqual( + t, + "failed counter", + 1, + int(recorder.counters[clientinfo.MetricRedemptionProofSubmissionsFailedTotal]), + ) + testutils.AssertIntsEqual( + t, + "success counter", + 0, + int(recorder.counters[clientinfo.MetricRedemptionProofSubmissionsSuccessTotal]), + ) +} func TestSubmitRedemptionProof(t *testing.T) { bytesFromHex := func(str string) []byte { value, err := hex.DecodeString(str) @@ -72,13 +219,15 @@ func TestSubmitRedemptionProof(t *testing.T) { return nil, nil, fmt.Errorf("error while assembling spv proof") } + recorder := newFakeMetricsRecorder() + err = submitRedemptionProof( redemptionTransaction.Hash(), requiredConfirmations, btcChain, spvChain, mockSpvProofAssembler, - getGlobalMetricsRecorder(), + recorder, ) if err != nil { t.Fatal(err) @@ -110,6 +259,135 @@ func TestSubmitRedemptionProof(t *testing.T) { } testutils.AssertBytesEqual(t, bytesFromHex("03b74d6893ad46dfdd01b9e0e3b3385f4fce2d1e"), submittedProof.walletPublicKeyHash[:]) + + // A successful submission must record one attempt and one success, and + // must not record a failure. + testutils.AssertIntsEqual( + t, + "total submissions counter", + 1, + int(recorder.counters[clientinfo.MetricRedemptionProofSubmissionsTotal]), + ) + testutils.AssertIntsEqual( + t, + "success counter", + 1, + int(recorder.counters[clientinfo.MetricRedemptionProofSubmissionsSuccessTotal]), + ) + testutils.AssertIntsEqual( + t, + "failed counter", + 0, + int(recorder.counters[clientinfo.MetricRedemptionProofSubmissionsFailedTotal]), + ) +} + +// TestSubmitRedemptionProofRecordsSubmitFailureMetrics verifies that a +// failure occurring during on-chain submission records both an attempt and a +// failure, but no success. This test was previously untestable because the +// local chain's SubmitRedemptionProofWithReimbursement method always +// returned nil. This is now made testable via the injected error field. +func TestSubmitRedemptionProofRecordsSubmitFailureMetrics(t *testing.T) { + bytesFromHex := func(str string) []byte { + value, err := hex.DecodeString(str) + if err != nil { + t.Fatal(err) + } + + return value + } + + txFromHex := func(str string) *bitcoin.Transaction { + transaction := new(bitcoin.Transaction) + err := transaction.Deserialize(bytesFromHex(str)) + if err != nil { + t.Fatal(err) + } + + return transaction + } + + requiredConfirmations := uint(6) + + btcChain := newLocalBitcoinChain() + // Use the local chain with error injection capability + spvChain := newLocalChain() + + // Take an arbitrary redemption transaction: + // https://live.blockcypher.com/btc-testnet/tx/15c9b4dd136f1c102cd45a92f6d6f41accc610a68566029de9af3524d53f1d82/ + redemptionTransaction := txFromHex("0100000000010189a128bbd1fd4626f752aa9036a118b2f4b2363ef409f5b527c69d048214d3130000000000ffffffff039ef9e92e0000000016001403b74d6893ad46dfdd01b9e0e3b3385f4fce2d1e6eed10000000000017a91486884e6be1525dab5ae0b451bd2c72cee67dcf4187791411000000000017a914538e4cc700d6510c8cae5e8b688d65276771e6088702483045022100b2e7fc655e0ddadbfef49201fb5f7046a40b36848c08f17ef2e4483bffb7a29e022024616909a96f8c901572d6a9e19d29d6aee6a835b409d4383a463fe1b338a2940121028ed84936be6a9f594a2dcc636d4bebf132713da3ce4dac5c61afbf8bbb47d6f700000000") + // Take the transaction that is the redemption transaction input. It is + // necessary as the tested function logic fetches its data to determine + // the wallet public key hash. + // https://live.blockcypher.com/btc-testnet/tx/13d31482049dc627b5f509f43e36b2f4b218a13690aa52f72646fdd1bb28a189 + redemptionInputTransaction := txFromHex("01000000000101db7aad9f51cffa7cebf5a3b41dc3552e1151d2550d8919a8e13d6bb00e046d5b0000000000ffffffff0333fc0b2f0000000016001403b74d6893ad46dfdd01b9e0e3b3385f4fce2d1e182612000000000017a914538e4cc700d6510c8cae5e8b688d65276771e60887aa9f10000000000017a91486884e6be1525dab5ae0b451bd2c72cee67dcf418702483045022100dded6eeacf49830de6f6b590a56f9b8ba3c2fda0b24e7f51884226a5ee78b5c2022024b1fbf3406716c9f9c5bfe241cfc0766af8209ecf8eb5f3318b407fd41c59ec0121028ed84936be6a9f594a2dcc636d4bebf132713da3ce4dac5c61afbf8bbb47d6f700000000") + // Then, record both transactions on the local BTC chain. + err := btcChain.BroadcastTransaction(redemptionTransaction) + if err != nil { + t.Fatal(err) + } + err = btcChain.BroadcastTransaction(redemptionInputTransaction) + if err != nil { + t.Fatal(err) + } + + // Just a mock proof. + proof := &bitcoin.SpvProof{ + MerkleProof: []byte{0x01}, + TxIndexInBlock: 2, + BitcoinHeaders: []byte{0x03}, + } + + mockSpvProofAssembler := func( + hash bitcoin.Hash, + confirmations uint, + btcChain bitcoin.Chain, + ) (*bitcoin.Transaction, *bitcoin.SpvProof, error) { + if hash == redemptionTransaction.Hash() && confirmations == requiredConfirmations { + return redemptionTransaction, proof, nil + } + + return nil, nil, fmt.Errorf("error while assembling spv proof") + } + + recorder := newFakeMetricsRecorder() + + // Force an error from the on-chain submit method + spvChain.submitRedemptionProofErr = fmt.Errorf("forced on-chain submit error") + + err = submitRedemptionProof( + redemptionTransaction.Hash(), + requiredConfirmations, + btcChain, + spvChain, + mockSpvProofAssembler, + recorder, + ) + if err == nil { + t.Fatal("expected an error from the forced on-chain submit failure") + } + + submittedProofs := spvChain.getSubmittedRedemptionProofs() + testutils.AssertIntsEqual(t, "proofs count", 0, len(submittedProofs)) + + testutils.AssertIntsEqual( + t, + "total submissions counter", + 1, + int(recorder.counters[clientinfo.MetricRedemptionProofSubmissionsTotal]), + ) + testutils.AssertIntsEqual( + t, + "failed counter", + 1, + int(recorder.counters[clientinfo.MetricRedemptionProofSubmissionsFailedTotal]), + ) + testutils.AssertIntsEqual( + t, + "success counter", + 0, + int(recorder.counters[clientinfo.MetricRedemptionProofSubmissionsSuccessTotal]), + ) } func TestGetUnprovenRedemptionTransactions(t *testing.T) { diff --git a/pkg/maintainer/spv/spv.go b/pkg/maintainer/spv/spv.go index 6191a2144d..af143377a7 100644 --- a/pkg/maintainer/spv/spv.go +++ b/pkg/maintainer/spv/spv.go @@ -16,7 +16,6 @@ import ( "encoding/hex" "fmt" "math/big" - "sync" "time" "github.com/keep-network/keep-core/pkg/tbtc" @@ -24,18 +23,45 @@ import ( "github.com/ipfs/go-log/v2" "github.com/keep-network/keep-core/pkg/bitcoin" + "github.com/keep-network/keep-core/pkg/clientinfo" "github.com/keep-network/keep-core/pkg/maintainer/btcdiff" ) var logger = log.Logger("keep-maintainer-spv") -// The length of the Bitcoin difficulty epoch in blocks. -const difficultyEpochLength = 2016 +// proofSkipReason explains why an SPV proof cannot be assembled for a +// transaction in the current cycle. It lets callers log and record metrics +// with the specific cause instead of collapsing every skip into one generic +// message. +type proofSkipReason int + +const ( + // proofSkipNone means the proof is within the relay's difficulty range and + // should be assembled once enough confirmations accumulate. + proofSkipNone proofSkipReason = iota + // proofSkipOutsideRelayRange means the decisive header matched neither the + // current nor the previous relay epoch difficulty. The Bridge would revert + // with "Not at current or previous difficulty". This is usually transient - + // the transaction's epoch is not yet proven in the relay - and resolves as + // the relay advances. + proofSkipOutsideRelayRange + // proofSkipExceededMaxHeaders means no decisive header was found and not + // enough difficulty accumulated within the configured MaxProofHeaders + // bound. Because the proof window is anchored at a fixed start block, a + // run of leading minimum-difficulty (DIFF1) headers longer than the bound + // is permanently unprovable rather than merely delayed, hence it is + // signalled separately. + proofSkipExceededMaxHeaders +) -// The maximum number of block headers allowed in a single SPV proof. Bounds -// the forward walk over headers when computing required confirmations -// (relevant on testnet4 where long runs of minimum-difficulty blocks occur). -const maxProofHeaders = 144 +// MetricsRecorder records proof counters and maintainer health gauges. It is +// satisfied by *clientinfo.PerformanceMetrics. A nil MetricsRecorder is a valid +// argument that disables metrics recording: callers must treat nil as "metrics +// off" and guard every invocation against it. +type MetricsRecorder interface { + IncrementCounter(name string, value float64) + SetGauge(name string, value float64) +} func Initialize( ctx context.Context, @@ -43,43 +69,23 @@ func Initialize( spvChain Chain, btcDiffChain btcdiff.Chain, btcChain bitcoin.Chain, -) { - spvMaintainer := &spvMaintainer{ - config: config, - spvChain: spvChain, - btcDiffChain: btcDiffChain, - btcChain: btcChain, + metricsRecorder MetricsRecorder, +) error { + if err := config.Validate(); err != nil { + return fmt.Errorf("cannot validate spv maintainer config: [%w]", err) } - go spvMaintainer.startControlLoop(ctx) -} - -// globalMetricsRecorder is a package-level variable to access metrics recorder -// from proof submission functions. -var ( - globalMetricsRecorderMu sync.RWMutex - globalMetricsRecorder interface { - IncrementCounter(name string, value float64) + spvMaintainer := &spvMaintainer{ + config: config, + spvChain: spvChain, + btcDiffChain: btcDiffChain, + btcChain: btcChain, + metricsRecorder: metricsRecorder, } -) -// SetMetricsRecorder sets the metrics recorder for the SPV maintainer. -// This allows recording metrics for proof submissions. -func SetMetricsRecorder(recorder interface { - IncrementCounter(name string, value float64) -}) { - globalMetricsRecorderMu.Lock() - defer globalMetricsRecorderMu.Unlock() - globalMetricsRecorder = recorder -} + go spvMaintainer.startControlLoop(ctx) -// getMetricsRecorder safely retrieves the metrics recorder. -func getMetricsRecorder() interface { - IncrementCounter(name string, value float64) -} { - globalMetricsRecorderMu.RLock() - defer globalMetricsRecorderMu.RUnlock() - return globalMetricsRecorder + return nil } // proofTypes holds the information about proof types supported by the @@ -107,21 +113,33 @@ var proofTypes = map[tbtc.WalletActionType]struct { } type spvMaintainer struct { - config Config - spvChain Chain - btcDiffChain btcdiff.Chain - btcChain bitcoin.Chain + config Config + spvChain Chain + btcDiffChain btcdiff.Chain + btcChain bitcoin.Chain + metricsRecorder MetricsRecorder } func (sm *spvMaintainer) startControlLoop(ctx context.Context) { logger.Info("starting SPV maintainer") + sm.setHealthGauge(clientinfo.MetricSpvMaintainerActive, 1) + sm.recordActivity() + maxBackoff := sm.config.RestartBackoffTime + if sm.config.IdleBackoffTime > maxBackoff { + maxBackoff = sm.config.IdleBackoffTime + } + sm.setHealthGauge(clientinfo.MetricSpvMaintainerMaxBackoffSeconds, maxBackoff.Seconds()) defer func() { + sm.setHealthGauge(clientinfo.MetricSpvMaintainerActive, 0) logger.Info("stopping SPV maintainer") }() for { err := sm.maintainSpv(ctx) + if ctx.Err() != nil { + return + } if err != nil { logger.Errorf( "error while maintaining SPV: [%v]; restarting maintainer", @@ -140,9 +158,13 @@ func (sm *spvMaintainer) startControlLoop(ctx context.Context) { func (sm *spvMaintainer) maintainSpv(ctx context.Context) error { for { for action, v := range proofTypes { + if err := ctx.Err(); err != nil { + return err + } logger.Infof("starting [%s] proof task execution...", action) - if err := sm.proveTransactions( + if err := sm.runProofTask( + action, v.unprovenTransactionsGetter, v.transactionProofSubmitter, ); err != nil { @@ -156,6 +178,8 @@ func (sm *spvMaintainer) maintainSpv(ctx context.Context) error { logger.Infof("[%s] proof task completed", action) } + sm.setHealthGauge(clientinfo.MetricSpvMaintainerLastSuccessTimestamp, float64(time.Now().Unix())) + logger.Infof( "proof tasks completed; next run in [%s]", sm.config.IdleBackoffTime, @@ -188,6 +212,7 @@ type transactionProofSubmitter func( requiredConfirmations uint, btcChain bitcoin.Chain, spvChain Chain, + metricsRecorder MetricsRecorder, ) error // proveTransactions gets unproven Bitcoin transactions using the provided @@ -218,27 +243,66 @@ func (sm *spvMaintainer) proveTransactions( transactionHashStr, ) - isProofWithinRelayRange, accumulatedConfirmations, requiredConfirmations, err := getProofInfo( + accumulatedConfirmations, requiredConfirmations, skipReason, err := getProofInfo( transaction.Hash(), sm.btcChain, sm.spvChain, sm.btcDiffChain, + sm.config.MaxProofHeaders, ) if err != nil { return fmt.Errorf("failed to get proof info: [%v]", err) } - if !isProofWithinRelayRange { + switch skipReason { + case proofSkipOutsideRelayRange: // The required proof goes outside the previous and current // difficulty epochs as seen by the relay. Skip the transaction. It - // will most likely be proven later. + // will most likely be proven later, once the relay advances. logger.Warnf( "skipped proving transaction [%s]; the range "+ "of the required proof goes outside the previous and "+ "current difficulty epochs as seen by the relay", transactionHashStr, ) + if recorder := sm.metricsRecorder; recorder != nil { + recorder.IncrementCounter( + clientinfo.MetricSpvProofSkippedOutsideRelayRangeTotal, + 1, + ) + } + continue + case proofSkipExceededMaxHeaders: + // No decisive header was found and not enough difficulty + // accumulated within the configured MaxProofHeaders bound. Unlike + // the range skip above, this transaction may be permanently + // unprovable if it is buried under a run of minimum-difficulty + // blocks longer than the bound. + logger.Errorf( + "skipped proving transaction [%s]; could not find a decisive "+ + "header or accumulate enough difficulty within [%d] "+ + "headers; the transaction may be permanently unprovable", + transactionHashStr, + sm.config.MaxProofHeaders, + ) + if recorder := sm.metricsRecorder; recorder != nil { + recorder.IncrementCounter( + clientinfo.MetricSpvProofSkippedExceededMaxHeadersTotal, + 1, + ) + } continue + case proofSkipNone: + // The proof is within range and assemblable; proceed to the + // confirmation check and submission below. + default: + // Defensive: a skip reason getProofInfo does not currently emit + // must never silently fall through to proof submission. + return fmt.Errorf( + "unexpected proof skip reason [%d] for transaction [%s]", + skipReason, + transactionHashStr, + ) } if accumulatedConfirmations < requiredConfirmations { @@ -259,6 +323,7 @@ func (sm *spvMaintainer) proveTransactions( requiredConfirmations, sm.btcChain, sm.spvChain, + sm.metricsRecorder, ) if err != nil { return err @@ -287,7 +352,7 @@ func isInputCurrentWalletsMainUTXO( if err != nil { return false, fmt.Errorf("failed to get previous transaction: [%v]", err) } - if fundingOutputIndex >= uint32(len(previousTransaction.Outputs)) { + if uint64(fundingOutputIndex) >= uint64(len(previousTransaction.Outputs)) { return false, fmt.Errorf( "funding output index [%d] out of range for transaction [%s] "+ "with [%d] outputs", @@ -316,21 +381,23 @@ func isInputCurrentWalletsMainUTXO( return bytes.Equal(mainUtxoHash[:], wallet.MainUtxoHash[:]), nil } -// getProofInfo returns information about the SPV proof. It includes the -// information whether the transaction proof range is within the previous and -// current difficulty epochs as seen by the relay, the accumulated number of -// confirmations and the required number of confirmations. +// getProofInfo returns information about the SPV proof: the accumulated number +// of confirmations, the required number of confirmations, and a proofSkipReason +// indicating whether the proof can be assembled (proofSkipNone) or why it must +// be skipped this cycle. The confirmation counts are meaningful only when the +// reason is proofSkipNone. func getProofInfo( transactionHash bitcoin.Hash, btcChain bitcoin.Chain, spvChain Chain, btcDiffChain btcdiff.Chain, + maxProofHeaders uint, ) ( - bool, uint, uint, error, + uint, uint, proofSkipReason, error, ) { latestBlockHeight, err := btcChain.GetLatestBlockHeight() if err != nil { - return false, 0, 0, fmt.Errorf( + return 0, 0, proofSkipNone, fmt.Errorf( "failed to get latest block height: [%v]", err, ) @@ -341,7 +408,7 @@ func getProofInfo( transactionHash, ) if err != nil { - return false, 0, 0, fmt.Errorf( + return 0, 0, proofSkipNone, fmt.Errorf( "failed to get transaction confirmations: [%v]", err, ) @@ -349,7 +416,7 @@ func getProofInfo( txProofDifficultyFactor, err := spvChain.TxProofDifficultyFactor() if err != nil { - return false, 0, 0, fmt.Errorf( + return 0, 0, proofSkipNone, fmt.Errorf( "failed to get transaction proof difficulty factor: [%v]", err, ) @@ -358,7 +425,7 @@ func getProofInfo( currentEpochDifficulty, previousEpochDifficulty, err := btcDiffChain.GetCurrentAndPrevEpochDifficulty() if err != nil { - return false, 0, 0, fmt.Errorf( + return 0, 0, proofSkipNone, fmt.Errorf( "failed to get Bitcoin epoch difficulties: [%v]", err, ) @@ -382,15 +449,17 @@ func getProofInfo( previousEpochDifficulty.Cmp(one) > 0 var requestedDiff *big.Int + var totalDifficultyRequired *big.Int observedDiff := big.NewInt(0) headerCount := uint(0) for { if headerCount >= maxProofHeaders { // Could not find a decisive header or accumulate enough - // difficulty within a sane number of headers. Skip the - // transaction; it may become provable later. - return false, 0, 0, nil + // difficulty within the header bound. Signal the distinct cause; + // with a fixed proof window this may be permanent rather than + // merely delayed. + return 0, 0, proofSkipExceededMaxHeaders, nil } blockHeight := proofStartBlock + uint64(headerCount) @@ -398,12 +467,12 @@ func getProofInfo( // Not enough mined blocks yet to assemble the proof. Report the // number of headers needed so far plus one more; the caller will // see accumulated < required and skip the transaction for now. - return true, accumulatedConfirmations, headerCount + 1, nil + return accumulatedConfirmations, headerCount + 1, proofSkipNone, nil } header, err := btcChain.GetBlockHeader(uint(blockHeight)) if err != nil { - return false, 0, 0, fmt.Errorf( + return 0, 0, proofSkipNone, fmt.Errorf( "failed to get block header at height [%v]: [%v]", blockHeight, err, @@ -415,8 +484,12 @@ func getProofInfo( observedDiff.Add(observedDiff, headerDiff) if requestedDiff == nil { - // Still looking for the decisive header. - if skipMinDifficulty && headerDiff.Cmp(one) == 0 { + // Still looking for the decisive header. Skip minimum-difficulty + // (DIFF1) headers by exact target equality, mirroring the Bridge's + // target == MIN_DIFFICULTY_TARGET predicate. Their work is still + // added to observedDiff above. + if skipMinDifficulty && + header.Target().Cmp(btcdiff.LightRelayMinDifficultyTarget) == 0 { continue } @@ -429,16 +502,17 @@ func getProofInfo( // difficulty". The transaction is either too fresh (its epoch // is not yet proven in the relay) or too old. Skip it; it may // be proven in the future. - return false, 0, 0, nil + return 0, 0, proofSkipOutsideRelayRange, nil } + + totalDifficultyRequired = new(big.Int).Mul( + requestedDiff, + txProofDifficultyFactor, + ) } - totalDifficultyRequired := new(big.Int).Mul( - requestedDiff, - txProofDifficultyFactor, - ) if observedDiff.Cmp(totalDifficultyRequired) >= 0 { - return true, accumulatedConfirmations, headerCount, nil + return accumulatedConfirmations, headerCount, proofSkipNone, nil } } } @@ -468,6 +542,79 @@ func uniqueWalletPublicKeyHashes[T walletEvent](events []T) [][20]byte { return publicKeyHashes } +// unprovenSearchStartBlock returns the starting block of the range in which +// the events used to find unproven transactions are searched for. It is +// derived from the current chain tip and the configured history depth. +func unprovenSearchStartBlock( + historyDepth uint64, + spvChain Chain, +) (uint64, error) { + blockCounter, err := spvChain.BlockCounter() + if err != nil { + return 0, fmt.Errorf("failed to get block counter: [%v]", err) + } + + currentBlock, err := blockCounter.CurrentBlock() + if err != nil { + return 0, fmt.Errorf("failed to get current block: [%v]", err) + } + + // Guard against unsigned underflow on short chains (e.g. early test + // networks) where the configured history depth can exceed the current + // tip; clamp the search start to the genesis block instead of wrapping + // around to a near-maximum block number. + if historyDepth > currentBlock { + return 0, nil + } + + return currentBlock - historyDepth, nil +} + +// collectUnprovenWalletTransactions returns the recent transactions of the +// wallet identified by lookupPublicKeyHash that satisfy the isUnproven +// predicate. When stopAtFirstMatch is true it returns as soon as the first +// matching transaction is found, which is sufficient for wallet operations +// that can have at most one unproven transaction at a time. +func collectUnprovenWalletTransactions( + lookupPublicKeyHash [20]byte, + transactionLimit int, + btcChain bitcoin.Chain, + isUnproven func(transaction *bitcoin.Transaction) (bool, error), + stopAtFirstMatch bool, +) ([]*bitcoin.Transaction, error) { + walletTransactions, err := btcChain.GetTransactionsForPublicKeyHash( + lookupPublicKeyHash, + transactionLimit, + ) + if err != nil { + return nil, fmt.Errorf( + "failed to get transactions for wallet: [%v]", + err, + ) + } + + var unprovenTransactions []*bitcoin.Transaction + + for _, transaction := range walletTransactions { + matched, err := isUnproven(transaction) + if err != nil { + return nil, fmt.Errorf( + "failed to check if transaction is unproven: [%v]", + err, + ) + } + + if matched { + unprovenTransactions = append(unprovenTransactions, transaction) + if stopAtFirstMatch { + break + } + } + } + + return unprovenTransactions, nil +} + // spvProofAssembler is a type representing a function that is used // to assemble an SPV proof for the given transaction hash and confirmations // count. diff --git a/pkg/maintainer/spv/spv_test.go b/pkg/maintainer/spv/spv_test.go index 088c619883..dee0502fdf 100644 --- a/pkg/maintainer/spv/spv_test.go +++ b/pkg/maintainer/spv/spv_test.go @@ -2,13 +2,16 @@ package spv import ( "encoding/hex" + "fmt" "math/big" "reflect" "strings" "testing" + "github.com/btcsuite/btcd/blockchain" "github.com/keep-network/keep-core/internal/testutils" "github.com/keep-network/keep-core/pkg/bitcoin" + "github.com/keep-network/keep-core/pkg/maintainer/btcdiff" "github.com/keep-network/keep-core/pkg/tbtc" ) @@ -28,7 +31,7 @@ func TestGetProofInfo(t *testing.T) { previousEpochDifficulty *big.Int headerDifficultyAt func(uint) *big.Int headersFrom, headersTo uint - expectedIsProofWithinRelayRange bool + expectedSkipReason proofSkipReason expectedAccumulatedConfirmations uint expectedRequiredConfirmations uint }{ @@ -42,7 +45,7 @@ func TestGetProofInfo(t *testing.T) { headersFrom: proofStart, headersTo: proofStart + 19, - expectedIsProofWithinRelayRange: true, + expectedSkipReason: proofSkipNone, expectedAccumulatedConfirmations: 20, expectedRequiredConfirmations: 6, }, @@ -55,7 +58,7 @@ func TestGetProofInfo(t *testing.T) { headersFrom: proofStart, headersTo: proofStart + 19, - expectedIsProofWithinRelayRange: true, + expectedSkipReason: proofSkipNone, expectedAccumulatedConfirmations: 20, expectedRequiredConfirmations: 6, }, @@ -75,7 +78,7 @@ func TestGetProofInfo(t *testing.T) { headersFrom: proofStart, headersTo: proofStart + 30, - expectedIsProofWithinRelayRange: true, + expectedSkipReason: proofSkipNone, expectedAccumulatedConfirmations: 31, expectedRequiredConfirmations: 10, }, @@ -93,7 +96,7 @@ func TestGetProofInfo(t *testing.T) { headersFrom: proofStart, headersTo: proofStart + 30, - expectedIsProofWithinRelayRange: true, + expectedSkipReason: proofSkipNone, expectedAccumulatedConfirmations: 31, expectedRequiredConfirmations: 4, }, @@ -114,7 +117,7 @@ func TestGetProofInfo(t *testing.T) { headersFrom: proofStart, headersTo: proofStart + 30, - expectedIsProofWithinRelayRange: true, + expectedSkipReason: proofSkipNone, expectedAccumulatedConfirmations: 31, expectedRequiredConfirmations: 8, }, @@ -128,7 +131,7 @@ func TestGetProofInfo(t *testing.T) { headersFrom: proofStart, headersTo: proofStart + 19, - expectedIsProofWithinRelayRange: true, + expectedSkipReason: proofSkipNone, expectedAccumulatedConfirmations: 20, expectedRequiredConfirmations: 6, }, @@ -143,12 +146,13 @@ func TestGetProofInfo(t *testing.T) { headersFrom: proofStart, headersTo: proofStart + 19, - expectedIsProofWithinRelayRange: false, + expectedSkipReason: proofSkipOutsideRelayRange, expectedAccumulatedConfirmations: 0, expectedRequiredConfirmations: 0, }, - // A run of minimum-difficulty headers longer than maxProofHeaders + // A run of minimum-difficulty headers longer than DefaultMaxProofHeaders // never reaches a decisive header. + "minimum difficulty run exceeds header bound": { transactionConfirmations: 150, currentEpochDifficulty: diff(32), @@ -157,7 +161,7 @@ func TestGetProofInfo(t *testing.T) { headersFrom: proofStart, headersTo: proofStart + 149, - expectedIsProofWithinRelayRange: false, + expectedSkipReason: proofSkipExceededMaxHeaders, expectedAccumulatedConfirmations: 0, expectedRequiredConfirmations: 0, }, @@ -172,7 +176,112 @@ func TestGetProofInfo(t *testing.T) { headersFrom: proofStart, headersTo: proofStart + 2, - expectedIsProofWithinRelayRange: true, + expectedSkipReason: proofSkipNone, + expectedAccumulatedConfirmations: 3, + expectedRequiredConfirmations: 4, + }, + // The decisive header matches the current (not previous) epoch on an + // epoch-spanning proof. Complements the "difficulty drops/raises" cases + // (which bind to the previous epoch) by exercising the current-epoch + // binding branch on asymmetric difficulties. Proof starts in the current + // epoch (32) for two blocks, then drops to the previous epoch's value + // (16). Required total is 6*32=192; 2*32 + 8*16 = 192 -> 10 headers. + "decisive header binds current epoch": { + transactionConfirmations: 31, + currentEpochDifficulty: diff(32), + previousEpochDifficulty: diff(16), + headerDifficultyAt: func(h uint) *big.Int { + if h < proofStart+2 { + return diff(32) + } + return diff(16) + }, + headersFrom: proofStart, + headersTo: proofStart + 30, + + expectedSkipReason: proofSkipNone, + expectedAccumulatedConfirmations: 31, + expectedRequiredConfirmations: 10, + }, + // A minimum-difficulty (DIFF1) header appearing after the decisive + // header is accumulated like any other header and does not re-enter the + // skip/binding logic (that runs only until the decisive header is + // found). Decisive header 32 binds requestedDiff; the interior DIFF1 + // contributes its work to the observed difficulty. Required total is + // 6*32=192; 32 + 1 + 5*32 = 193 >= 192 -> 7 headers. + "minimum difficulty header after decisive header is counted": { + transactionConfirmations: 20, + currentEpochDifficulty: diff(32), + previousEpochDifficulty: diff(16), + headerDifficultyAt: func(h uint) *big.Int { + if h == proofStart+1 { + return diff(1) + } + return diff(32) + }, + headersFrom: proofStart, + headersTo: proofStart + 19, + + expectedSkipReason: proofSkipNone, + expectedAccumulatedConfirmations: 20, + expectedRequiredConfirmations: 7, + }, + // The decisive header sits exactly at the header bound: 143 leading + // DIFF1 headers (skipped for binding but contributing 1 each) followed + // by the decisive header at position DefaultMaxProofHeaders. Required + // total is 6*16=96; 143*1 + 16 = 159 >= 96 -> exactly 144 headers, at + // the bound. + "decisive header exactly at header bound is proven": { + transactionConfirmations: DefaultMaxProofHeaders, + currentEpochDifficulty: diff(16), + previousEpochDifficulty: diff(32), + headerDifficultyAt: func(h uint) *big.Int { + if h < proofStart+DefaultMaxProofHeaders-1 { + return diff(1) + } + return diff(16) + }, + headersFrom: proofStart, + headersTo: proofStart + DefaultMaxProofHeaders - 1, + + expectedSkipReason: proofSkipNone, + expectedAccumulatedConfirmations: DefaultMaxProofHeaders, + expectedRequiredConfirmations: DefaultMaxProofHeaders, + }, + // The decisive header sits one past the header bound: DefaultMaxProofHeaders + // leading DIFF1 headers exhaust the walk before the decisive header at + // position DefaultMaxProofHeaders+1 is ever examined. This is the off-by-one + // companion to the case above and must be signalled as exceeded. + "decisive header just past header bound is skipped": { + transactionConfirmations: DefaultMaxProofHeaders + 1, + currentEpochDifficulty: diff(16), + previousEpochDifficulty: diff(32), + headerDifficultyAt: func(h uint) *big.Int { + if h < proofStart+DefaultMaxProofHeaders { + return diff(1) + } + return diff(16) + }, + headersFrom: proofStart, + headersTo: proofStart + DefaultMaxProofHeaders, + + expectedSkipReason: proofSkipExceededMaxHeaders, + expectedAccumulatedConfirmations: 0, + expectedRequiredConfirmations: 0, + }, + // The chain tip is reached while still skipping leading DIFF1 headers, + // before any decisive header is bound (requestedDiff is still nil). The + // proof is within range and the caller is told to wait for one more + // header than currently exists. + "chain tip reached before decisive header": { + transactionConfirmations: 3, + currentEpochDifficulty: diff(32), + previousEpochDifficulty: diff(16), + headerDifficultyAt: func(uint) *big.Int { return diff(1) }, + headersFrom: proofStart, + headersTo: proofStart + 2, + + expectedSkipReason: proofSkipNone, expectedAccumulatedConfirmations: 3, expectedRequiredConfirmations: 4, }, @@ -206,30 +315,32 @@ func TestGetProofInfo(t *testing.T) { localChain.setTxProofDifficultyFactor(big.NewInt(6)) localChain.setCurrentEpoch(392) + // Note the setter's parameter order is (previous, current). localChain.setCurrentAndPrevEpochDifficulty( - test.currentEpochDifficulty, test.previousEpochDifficulty, + test.currentEpochDifficulty, ) - isProofWithinRelayRange, - accumulatedConfirmations, + accumulatedConfirmations, requiredConfirmations, + skipReason, err := getProofInfo( transactionHash, btcChain, localChain, localChain, + DefaultMaxProofHeaders, ) if err != nil { t.Fatal(err) } - testutils.AssertBoolsEqual( + testutils.AssertIntsEqual( t, - "is proof within range", - test.expectedIsProofWithinRelayRange, - isProofWithinRelayRange, + "skip reason", + int(test.expectedSkipReason), + int(skipReason), ) testutils.AssertUintsEqual( @@ -249,6 +360,284 @@ func TestGetProofInfo(t *testing.T) { } } +// TestGetProofInfo_MinDifficultyDetectedByExactTarget pins the DIFF1 skip +// predicate to exact target equality. The Bridge skips headers whose target +// equals MIN_DIFFICULTY_TARGET, not headers whose computed difficulty rounds +// to 1. These differ: any target in (maxTarget/2, maxTarget] yields +// Difficulty()==1, but only the exact maxTarget is the canonical +// minimum-difficulty target. A header with Difficulty()==1 yet a target below +// maxTarget must NOT be skipped - it is a decisive header. +// +// Here that decisive header matches neither relay epoch, so the Bridge would +// revert and getProofInfo must report proofSkipOutsideRelayRange. If the +// predicate regressed to Difficulty()==1, the header would be skipped as DIFF1 +// and the following current-epoch headers would prove the transaction +// (proofSkipNone) - so this case fails loudly on that regression. +func TestGetProofInfo_MinDifficultyDetectedByExactTarget(t *testing.T) { + const proofStart = 790270 + + // A target of 3/4 * maxTarget: Difficulty() floors to 1, but the target is + // strictly below the minimum-difficulty target. BigToCompact truncates + // toward zero, so the encoded target can never round up to maxTarget. + nonMinTarget := new(big.Int).Mul(btcdiff.LightRelayMinDifficultyTarget, big.NewInt(3)) + nonMinTarget.Div(nonMinTarget, big.NewInt(4)) + decisiveHeader := &bitcoin.BlockHeader{ + Bits: blockchain.BigToCompact(nonMinTarget), + } + + // Guard the construction; without both properties the test proves nothing. + if decisiveHeader.Difficulty().Cmp(big.NewInt(1)) != 0 { + t.Fatalf( + "test header must have difficulty 1, got [%v]", + decisiveHeader.Difficulty(), + ) + } + if decisiveHeader.Target().Cmp(btcdiff.LightRelayMinDifficultyTarget) == 0 { + t.Fatal( + "test header target must differ from the minimum-difficulty target", + ) + } + + transactionHash, err := bitcoin.NewHashFromString( + "44c568bc0eac07a2a9c2b46829be5b5d46e7d00e17bfb613f506a75ccf86a473", + bitcoin.InternalByteOrder, + ) + if err != nil { + t.Fatal(err) + } + + btcChain := newLocalBitcoinChain() + // The first (decisive) header carries Difficulty()==1 with a non-minimum + // target; the remaining headers carry the current epoch difficulty. + if err := btcChain.addBlockHeader(proofStart, decisiveHeader); err != nil { + t.Fatal(err) + } + if err := populateBlockHeaders( + btcChain, + proofStart+1, + proofStart+19, + func(uint) *big.Int { return big.NewInt(32) }, + ); err != nil { + t.Fatal(err) + } + btcChain.addTransactionConfirmations(transactionHash, 20) + + localChain := newLocalChain() + localChain.setTxProofDifficultyFactor(big.NewInt(6)) + localChain.setCurrentEpoch(392) + // Note the setter's parameter order is (previous, current). + localChain.setCurrentAndPrevEpochDifficulty(big.NewInt(16), big.NewInt(32)) + + _, _, skipReason, err := getProofInfo( + transactionHash, + btcChain, + localChain, + localChain, + DefaultMaxProofHeaders, + ) + if err != nil { + t.Fatal(err) + } + + testutils.AssertIntsEqual( + t, + "skip reason", + int(proofSkipOutsideRelayRange), + int(skipReason), + ) +} + +// recordingMetricsRecorder captures IncrementCounter and SetGauge calls for +// assertions. proveTransactions and the maintainer control loop invoke it +// synchronously, so no locking is needed. +type recordingMetricsRecorder struct { + counters map[string]float64 + gauges map[string]float64 +} + +func (r *recordingMetricsRecorder) IncrementCounter(name string, value float64) { + r.counters[name] += value +} + +func (r *recordingMetricsRecorder) SetGauge(name string, value float64) { + if r.gauges == nil { + r.gauges = make(map[string]float64) + } + r.gauges[name] = value +} + +// TestProveTransactions covers the caller-side handling of each proofSkipReason +// in proveTransactions. The safety property under test is that a skip reason +// never results in a proof submission, and that an assemblable proof is +// submitted; the per-reason metric counter is asserted as a secondary check. +func TestProveTransactions(t *testing.T) { + const proofStart = 790270 + + // A concrete transaction so proveTransactions can derive a real hash. + rawTransaction, err := hex.DecodeString( + "0100000000010110a15e879b7e8b07df62772579a64bf2b409409bbcc8bc2c7f6e39" + + "31dc615e920100000000ffffffff02042900000000000017a9143ec459d0f3c29286" + + "ae5df5fcc421e2786024277e87b4121600000000001600148db50eb52063ea9d98b3" + + "eac91489a90f738986f6024830450221009740ad12d2e74c00ccb4741d533d2ecd69" + + "02289144c4626508afb61eed790c97022006e67179e8e2a63dc4f1ab758867d8bbfe" + + "0a2b67682be6dadfa8e07d3b7ba04d012103989d253b17a6a0f41838b84ff0d20e88" + + "98f9d7b1a98f2564da4cc29dcf8581d900000000", + ) + if err != nil { + t.Fatal(err) + } + transaction := new(bitcoin.Transaction) + if err := transaction.Deserialize(rawTransaction); err != nil { + t.Fatal(err) + } + transactionHash := transaction.Hash() + + tests := map[string]struct { + headerDifficultyAt func(uint) *big.Int + headersTo uint + transactionConfirmations uint + expectSubmitted bool + expectedCounter string + submissionError bool + }{ + // Decisive header (difficulty 8) matches neither epoch -> skipped. + "outside relay range is skipped and metered": { + headerDifficultyAt: func(uint) *big.Int { return big.NewInt(8) }, + headersTo: proofStart + 19, + transactionConfirmations: 20, + expectSubmitted: false, + expectedCounter: "spv_proof_skipped_outside_relay_range_total", + }, + // A run of DIFF1 headers longer than the bound never binds -> skipped. + "exceeded max headers is skipped and metered": { + headerDifficultyAt: func(uint) *big.Int { return big.NewInt(1) }, + headersTo: proofStart + 149, + transactionConfirmations: 150, + expectSubmitted: false, + expectedCounter: "spv_proof_skipped_exceeded_max_headers_total", + }, + "submission failure is counted": { + headerDifficultyAt: func(uint) *big.Int { return big.NewInt(32) }, + headersTo: proofStart + 19, + transactionConfirmations: 20, + expectSubmitted: true, + submissionError: true, + }, + // All headers at the current epoch difficulty -> proof is submitted. + "assemblable proof is submitted": { + headerDifficultyAt: func(uint) *big.Int { return big.NewInt(32) }, + headersTo: proofStart + 19, + transactionConfirmations: 20, + expectSubmitted: true, + expectedCounter: "", + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + btcChain := newLocalBitcoinChain() + if err := populateBlockHeaders( + btcChain, + proofStart, + test.headersTo, + test.headerDifficultyAt, + ); err != nil { + t.Fatal(err) + } + btcChain.addTransactionConfirmations( + transactionHash, + test.transactionConfirmations, + ) + + localChain := newLocalChain() + localChain.setTxProofDifficultyFactor(big.NewInt(6)) + localChain.setCurrentEpoch(392) + // Note the setter's parameter order is (previous, current). + localChain.setCurrentAndPrevEpochDifficulty( + big.NewInt(16), + big.NewInt(32), + ) + + recorder := &recordingMetricsRecorder{ + counters: make(map[string]float64), + } + + sm := &spvMaintainer{ + metricsRecorder: recorder, + config: Config{MaxProofHeaders: DefaultMaxProofHeaders}, + spvChain: localChain, + btcDiffChain: localChain, + btcChain: btcChain, + } + + var submitted []bitcoin.Hash + getter := func( + uint64, + int, + bitcoin.Chain, + Chain, + ) ([]*bitcoin.Transaction, error) { + return []*bitcoin.Transaction{transaction}, nil + } + submitter := func( + hash bitcoin.Hash, + _ uint, + _ bitcoin.Chain, + _ Chain, + metrics MetricsRecorder, + ) error { + if metrics != recorder { + t.Fatal("proof submitter did not receive the maintainer recorder") + } + submitted = append(submitted, hash) + if test.submissionError { + return fmt.Errorf("submission failed") + } + return nil + } + + err := sm.runProofTask(tbtc.ActionRedemption, getter, submitter) + if (err != nil) != test.submissionError { + t.Fatalf("unexpected task error: %v", err) + } + wantFailures := float64(0) + if test.submissionError { + wantFailures = 1 + } + for _, name := range []string{"spv_proof_task_failures_total", "redemption_proof_task_failures_total"} { + if got := recorder.counters[name]; got != wantFailures { + t.Errorf("%s: want %v, got %v", name, wantFailures, got) + } + } + + if test.expectSubmitted { + if len(submitted) != 1 || submitted[0] != transactionHash { + t.Errorf( + "expected the transaction to be submitted, "+ + "got submissions [%v]", + submitted, + ) + } + } else if len(submitted) != 0 { + t.Errorf( + "expected no submission on skip, got [%d]", + len(submitted), + ) + } + + if test.expectedCounter != "" { + if got := recorder.counters[test.expectedCounter]; got != 1 { + t.Errorf( + "expected counter [%s] to be 1, got [%v]", + test.expectedCounter, + got, + ) + } + } + }) + } +} + func TestUniqueWalletPublicKeyHashes(t *testing.T) { bytesFromHex := func(str string) []byte { value, err := hex.DecodeString(str) @@ -471,3 +860,260 @@ func TestIsInputCurrentWalletsMainUTXO(t *testing.T) { }) } } + +// TestUnprovenSearchStartBlock exercises the clamp guard and error paths of +// unprovenSearchStartBlock directly. The action-level integration tests only +// ever exercise it with a historyDepth well below the current block, so the +// error branches and the clamp boundary are otherwise untested. +func TestUnprovenSearchStartBlock(t *testing.T) { + blockCounterErr := fmt.Errorf("block counter unavailable") + currentBlockErr := fmt.Errorf("current block unavailable") + + tests := map[string]struct { + historyDepth uint64 + currentBlock uint64 + blockCounterErr error + currentBlockErr error + expectedStart uint64 + expectedErr string + }{ + "history depth below current block": { + historyDepth: 100, + currentBlock: 1000, + expectedStart: 900, + }, + "history depth equal to current block": { + // The clamp guard is strictly historyDepth > currentBlock, so + // equal values must fall through to the plain subtraction, not + // the clamp branch. Both yield 0 here, pinning the off-by-one. + historyDepth: 1000, + currentBlock: 1000, + expectedStart: 0, + }, + "history depth one above current block": { + // The first value that DOES trigger the clamp guard; paired with + // the equal case above, this pins the exact boundary. + historyDepth: 1001, + currentBlock: 1000, + expectedStart: 0, + }, + "history depth far exceeds current block": { + historyDepth: 1_000_000, + currentBlock: 5, + expectedStart: 0, + }, + "zero current block and zero history depth": { + historyDepth: 0, + currentBlock: 0, + expectedStart: 0, + }, + "block counter unavailable": { + historyDepth: 100, + blockCounterErr: blockCounterErr, + expectedErr: "failed to get block counter", + }, + "current block unavailable": { + historyDepth: 100, + currentBlock: 1000, + currentBlockErr: currentBlockErr, + expectedErr: "failed to get current block", + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + var spvChain Chain + + if test.blockCounterErr != nil { + spvChain = &errorBlockCounterChain{ + localChain: newLocalChain(), + err: test.blockCounterErr, + } + } else { + localChain := newLocalChain() + blockCounter := newMockBlockCounter() + blockCounter.SetCurrentBlock(test.currentBlock) + if test.currentBlockErr != nil { + blockCounter.SetCurrentBlockErr(test.currentBlockErr) + } + localChain.setBlockCounter(blockCounter) + spvChain = localChain + } + + start, err := unprovenSearchStartBlock(test.historyDepth, spvChain) + + if test.expectedErr != "" { + if err == nil { + t.Fatalf( + "expected error containing [%s], got nil", + test.expectedErr, + ) + } + if !strings.Contains(err.Error(), test.expectedErr) { + t.Errorf( + "unexpected error\nexpected to contain: [%s]\nactual: [%v]", + test.expectedErr, + err, + ) + } + return + } + + if err != nil { + t.Fatalf("unexpected error: [%v]", err) + } + + testutils.AssertUintsEqual( + t, + "search start block", + test.expectedStart, + start, + ) + }) + } +} + +// stubTransactionChain overrides GetTransactionsForPublicKeyHash on the local +// Bitcoin chain so that collectUnprovenWalletTransactions can be exercised with +// a controlled set of transactions and error, independently of how the local +// chain filters by public key hash. +type stubTransactionChain struct { + *localBitcoinChain + transactions []*bitcoin.Transaction + err error +} + +func (s *stubTransactionChain) GetTransactionsForPublicKeyHash( + _ [20]byte, + _ int, +) ([]*bitcoin.Transaction, error) { + return s.transactions, s.err +} + +func TestCollectUnprovenWalletTransactions(t *testing.T) { + // Distinct transactions identified by pointer. Empty Transaction values + // compare equal under reflect.DeepEqual, so assertions below rely on + // pointer identity, not value equality. + tx1 := &bitcoin.Transaction{} + tx2 := &bitcoin.Transaction{} + tx3 := &bitcoin.Transaction{} + + // matches returns a predicate reporting a transaction as unproven when it + // is one of the given transactions (compared by pointer). + matches := func(unproven ...*bitcoin.Transaction) func(*bitcoin.Transaction) (bool, error) { + return func(transaction *bitcoin.Transaction) (bool, error) { + for _, u := range unproven { + if transaction == u { + return true, nil + } + } + return false, nil + } + } + + predicateErr := fmt.Errorf("predicate failure") + chainErr := fmt.Errorf("chain failure") + + tests := map[string]struct { + transactions []*bitcoin.Transaction + isUnproven func(*bitcoin.Transaction) (bool, error) + stopAtFirstMatch bool + chainErr error + expectedResult []*bitcoin.Transaction + expectedErr string + }{ + "returns all matches when not stopping at first match": { + transactions: []*bitcoin.Transaction{tx1, tx2, tx3}, + isUnproven: matches(tx1, tx3), + stopAtFirstMatch: false, + expectedResult: []*bitcoin.Transaction{tx1, tx3}, + }, + "returns only the first match when stopping at first match": { + transactions: []*bitcoin.Transaction{tx1, tx2, tx3}, + isUnproven: matches(tx2, tx3), + stopAtFirstMatch: true, + expectedResult: []*bitcoin.Transaction{tx2}, + }, + "returns nothing when no transaction matches": { + transactions: []*bitcoin.Transaction{tx1, tx2, tx3}, + isUnproven: matches(), + stopAtFirstMatch: false, + expectedResult: nil, + }, + "propagates the chain error": { + transactions: []*bitcoin.Transaction{tx1}, + isUnproven: matches(tx1), + chainErr: chainErr, + expectedErr: "failed to get transactions for wallet", + }, + "propagates the predicate error": { + transactions: []*bitcoin.Transaction{tx1}, + isUnproven: func(*bitcoin.Transaction) (bool, error) { + return false, predicateErr + }, + expectedErr: "failed to check if transaction is unproven", + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + btcChain := &stubTransactionChain{ + localBitcoinChain: newLocalBitcoinChain(), + transactions: test.transactions, + err: test.chainErr, + } + + result, err := collectUnprovenWalletTransactions( + [20]byte{}, + len(test.transactions), + btcChain, + test.isUnproven, + test.stopAtFirstMatch, + ) + + if test.expectedErr != "" { + if result != nil { + t.Errorf( + "expected nil result on error, got [%v]", + result, + ) + } + if err == nil { + t.Fatalf( + "expected error containing [%s], got nil", + test.expectedErr, + ) + } + if !strings.Contains(err.Error(), test.expectedErr) { + t.Errorf( + "unexpected error\nexpected to contain: [%s]\nactual: [%v]", + test.expectedErr, + err, + ) + } + return + } + + if err != nil { + t.Fatalf("unexpected error: [%v]", err) + } + + testutils.AssertIntsEqual( + t, + "number of unproven transactions", + len(test.expectedResult), + len(result), + ) + + for i, expected := range test.expectedResult { + if result[i] != expected { + t.Errorf( + "unexpected transaction at index [%d]; "+ + "pointer identity mismatch", + i, + ) + } + } + }) + } +} diff --git a/pkg/net/libp2p/channel.go b/pkg/net/libp2p/channel.go index 87f0094d48..184042d46f 100644 --- a/pkg/net/libp2p/channel.go +++ b/pkg/net/libp2p/channel.go @@ -84,11 +84,7 @@ type channel struct { retransmissionTicker *retransmission.Ticker // metricsRecorder is optional and used for recording performance metrics - metricsRecorder interface { - IncrementCounter(name string, value float64) - SetGauge(name string, value float64) - RecordDuration(name string, duration time.Duration) - } + metricsRecorder fullMetricsRecorder // monitorQueueSizesOnce ensures the monitoring goroutine is started only once monitorQueueSizesOnce sync.Once @@ -453,11 +449,7 @@ func extractPublicKey(peer peer.ID) (*operator.PublicKey, error) { // setMetricsRecorder sets the metrics recorder for the channel and starts // periodic queue size monitoring. -func (c *channel) setMetricsRecorder(recorder interface { - IncrementCounter(name string, value float64) - SetGauge(name string, value float64) - RecordDuration(name string, duration time.Duration) -}) { +func (c *channel) setMetricsRecorder(recorder fullMetricsRecorder) { c.metricsRecorder = recorder // Start periodic queue size monitoring (only once) if recorder != nil { diff --git a/pkg/net/libp2p/channel_manager.go b/pkg/net/libp2p/channel_manager.go index bcb10f7ffb..42ae17818e 100644 --- a/pkg/net/libp2p/channel_manager.go +++ b/pkg/net/libp2p/channel_manager.go @@ -50,11 +50,7 @@ type channelManager struct { topics map[string]*pubsub.Topic // metricsRecorder is optional and used for recording performance metrics - metricsRecorder interface { - IncrementCounter(name string, value float64) - SetGauge(name string, value float64) - RecordDuration(name string, duration time.Duration) - } + metricsRecorder fullMetricsRecorder } func newChannelManager( @@ -126,11 +122,7 @@ func (cm *channelManager) getChannel(name string) (*channel, error) { // setMetricsRecorder sets the metrics recorder for the channel manager // and wires it into existing channels. -func (cm *channelManager) setMetricsRecorder(recorder interface { - IncrementCounter(name string, value float64) - SetGauge(name string, value float64) - RecordDuration(name string, duration time.Duration) -}) { +func (cm *channelManager) setMetricsRecorder(recorder fullMetricsRecorder) { // Wire metrics into existing channels cm.channelsMutex.Lock() defer cm.channelsMutex.Unlock() diff --git a/pkg/net/libp2p/channel_test.go b/pkg/net/libp2p/channel_test.go index 116c5da73d..916a337595 100644 --- a/pkg/net/libp2p/channel_test.go +++ b/pkg/net/libp2p/channel_test.go @@ -610,3 +610,62 @@ func (ms *mockSubscription) Next(ctx context.Context) (*pubsub.Message, error) { } func (ms *mockSubscription) Cancel() {} + +// --- Benchmarks --- + +// BenchmarkChannelDeliver_SingleHandler measures deliver() latency with a +// single registered handler. The handler's buffer fills after messageHandlerThrottle +// calls; subsequent iterations take the non-blocking default branch. Both paths +// exercise the same mutex lock and snapshot copy overhead. +func BenchmarkChannelDeliver_SingleHandler(b *testing.B) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + ch := &channel{} + ch.messageHandlers = []*messageHandler{ + {ctx: ctx, channel: make(chan net.Message, messageHandlerThrottle)}, + } + msg := &mockNetMessage{} + b.ResetTimer() + for range b.N { + ch.deliver(msg) + } +} + +// BenchmarkChannelDeliver_10Handlers measures deliver() fan-out cost across 10 +// concurrent handlers -- representative of a node with multiple active protocol +// subscriptions on the same channel. +func BenchmarkChannelDeliver_10Handlers(b *testing.B) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + ch := &channel{} + handlers := make([]*messageHandler, 10) + for i := range handlers { + handlers[i] = &messageHandler{ + ctx: ctx, + channel: make(chan net.Message, messageHandlerThrottle), + } + } + ch.messageHandlers = handlers + msg := &mockNetMessage{} + b.ResetTimer() + for range b.N { + ch.deliver(msg) + } +} + +// BenchmarkProcessPubsubMessage measures the raw throughput of +// processPubsubMessage with an empty message. proto.Unmarshal succeeds on empty +// input; the call returns early with "couldn't find unmarshaler", giving a +// baseline for the per-message overhead before any application logic runs. +func BenchmarkProcessPubsubMessage(b *testing.B) { + ch := &channel{ + unmarshalersByType: make(map[string]func() net.TaggedUnmarshaler), + } + msg := &pubsub.Message{Message: &pubsubpb.Message{}} + b.ResetTimer() + for range b.N { + _ = ch.processPubsubMessage(msg) + } +} diff --git a/pkg/net/libp2p/libp2p.go b/pkg/net/libp2p/libp2p.go index 0d8339df86..1a9f5ca860 100644 --- a/pkg/net/libp2p/libp2p.go +++ b/pkg/net/libp2p/libp2p.go @@ -394,6 +394,12 @@ func Connect( // SetMetricsRecorder sets the metrics recorder for the provider and wires it // into network components. +// +// The parameter is an anonymous interface rather than the named +// fullMetricsRecorder on purpose: callers (e.g. cmd.start) wire metrics via a +// structural type assertion against this exact signature to avoid importing the +// unexported provider type. Changing it to a named type would silently break +// that assertion. func (p *provider) SetMetricsRecorder(recorder interface { IncrementCounter(name string, value float64) SetGauge(name string, value float64) @@ -583,18 +589,10 @@ func buildNotifiee(libp2pHost host.Host, p *provider) libp2pnet.Notifiee { logger.Infof("established connection to [%v]", peerMultiaddress) - var recorder interface { - IncrementCounter(name string, value float64) - SetGauge(name string, value float64) - RecordDuration(name string, duration time.Duration) - } + var recorder fullMetricsRecorder if p.metricsRecorder != nil { if metricsRecorderValue := p.metricsRecorder.Load(); metricsRecorderValue != nil { - recorder = metricsRecorderValue.(interface { - IncrementCounter(name string, value float64) - SetGauge(name string, value float64) - RecordDuration(name string, duration time.Duration) - }) + recorder = metricsRecorderValue.(fullMetricsRecorder) recorder.IncrementCounter(clientinfo.MetricPeerConnectionsTotal, 1) } } @@ -625,11 +623,7 @@ func buildNotifiee(libp2pHost host.Host, p *provider) libp2pnet.Notifiee { if p.metricsRecorder != nil { if metricsRecorderValue := p.metricsRecorder.Load(); metricsRecorderValue != nil { - recorder := metricsRecorderValue.(interface { - IncrementCounter(name string, value float64) - SetGauge(name string, value float64) - RecordDuration(name string, duration time.Duration) - }) + recorder := metricsRecorderValue.(fullMetricsRecorder) recorder.IncrementCounter(clientinfo.MetricPeerDisconnectionsTotal, 1) } } @@ -650,11 +644,7 @@ func executePingTest( libp2pHost host.Host, peerID peer.ID, peerMultiaddress string, - metricsRecorder interface { - IncrementCounter(name string, value float64) - SetGauge(name string, value float64) - RecordDuration(name string, duration time.Duration) - }, + metricsRecorder fullMetricsRecorder, ) { logger.Infof("starting ping test for [%v]", peerMultiaddress) diff --git a/pkg/net/libp2p/libp2p_test.go b/pkg/net/libp2p/libp2p_test.go index 0564a65cfe..b5cbc939e9 100644 --- a/pkg/net/libp2p/libp2p_test.go +++ b/pkg/net/libp2p/libp2p_test.go @@ -16,35 +16,6 @@ import ( "github.com/keep-network/keep-core/pkg/net/retransmission" ) -func TestProviderReturnsType(t *testing.T) { - ctx, cancel := newTestContext() - defer cancel() - - operatorPrivateKey, _, err := operator.GenerateKeyPair(DefaultCurve) - if err != nil { - t.Fatal(err) - } - - expectedType := "libp2p" - provider, err := Connect( - ctx, - generateDeterministicNetworkConfig(), - operatorPrivateKey, - firewall.Disabled, - idleTicker(), - ) - if err != nil { - t.Fatal(err) - } - - if provider.Type() != expectedType { - t.Fatalf("expected: provider type [%s]\nactual: provider type [%s]", - provider.Type(), - expectedType, - ) - } -} - func TestProviderReturnsChannel(t *testing.T) { ctx, cancel := newTestContext() defer cancel() diff --git a/pkg/net/libp2p/metrics_wiring_test.go b/pkg/net/libp2p/metrics_wiring_test.go new file mode 100644 index 0000000000..e7df04c602 --- /dev/null +++ b/pkg/net/libp2p/metrics_wiring_test.go @@ -0,0 +1,29 @@ +package libp2p + +import ( + "testing" + "time" +) + +// TestProviderSatisfiesMetricsSetterAssertion pins the wiring contract used by +// cmd.start to inject the performance metrics recorder into the provider. That +// wiring is a structural type assertion against an anonymous interface, so the +// provider's SetMetricsRecorder parameter must remain that exact anonymous +// interface. If it is changed to a named type, the assertion silently fails at +// runtime (ok == false) and provider metrics stop being recorded, which no +// build error or other test would catch. +func TestProviderSatisfiesMetricsSetterAssertion(t *testing.T) { + var np interface{} = &provider{} + if _, ok := np.(interface { + SetMetricsRecorder(recorder interface { + IncrementCounter(name string, value float64) + SetGauge(name string, value float64) + RecordDuration(name string, duration time.Duration) + }) + }); !ok { + t.Fatal( + "provider no longer satisfies the metrics-setter assertion used " + + "by cmd.start; provider metrics wiring is broken", + ) + } +} diff --git a/pkg/net/libp2p/transport.go b/pkg/net/libp2p/transport.go index ccaa51f523..e0b761a7b1 100644 --- a/pkg/net/libp2p/transport.go +++ b/pkg/net/libp2p/transport.go @@ -46,6 +46,15 @@ type MetricsRecorder interface { RecordDuration(name string, duration time.Duration) } +// fullMetricsRecorder is a MetricsRecorder that also supports gauge metrics. +// It is the contract for components that record counters, durations, and +// gauges (e.g. message queue sizes), unlike the transport which records only +// counters and durations. +type fullMetricsRecorder interface { + MetricsRecorder + SetGauge(name string, value float64) +} + // transport constructs an encrypted and authenticated connection for a peer. type transport struct { protocolID protocol.ID diff --git a/pkg/net/retransmission/strategy_test.go b/pkg/net/retransmission/strategy_test.go index 476999d5ee..f0af9901dd 100644 --- a/pkg/net/retransmission/strategy_test.go +++ b/pkg/net/retransmission/strategy_test.go @@ -157,3 +157,25 @@ func TestBackoffStrategy_ConcurrentTick(t *testing.T) { ) } } + +// --- Benchmarks --- + +func BenchmarkBackoffStrategyTick(b *testing.B) { + strategy := WithBackoffStrategy() + noop := func() error { return nil } + b.ResetTimer() + for range b.N { + _ = strategy.Tick(noop) + } +} + +func BenchmarkStandardStrategyTick(b *testing.B) { + strategy := WithStandardStrategy() + var calls int + fn := func() error { calls++; return nil } + b.ResetTimer() + for range b.N { + _ = strategy.Tick(fn) + } + _ = calls +} diff --git a/pkg/net/retransmission/ticker.go b/pkg/net/retransmission/ticker.go index a9e3e8e802..147624e5ff 100644 --- a/pkg/net/retransmission/ticker.go +++ b/pkg/net/retransmission/ticker.go @@ -45,8 +45,8 @@ func NewTimeTicker(ctx context.Context, duration time.Duration) *Ticker { go func() { for { select { - case tick := <-timeTicker.C: - ticks <- uint64(tick.Unix()) + case <-timeTicker.C: + ticks <- 0 case <-ctx.Done(): timeTicker.Stop() diff --git a/pkg/net/security/handshake/marshaling_test.go b/pkg/net/security/handshake/marshaling_test.go index 5bbebc625d..d141994362 100644 --- a/pkg/net/security/handshake/marshaling_test.go +++ b/pkg/net/security/handshake/marshaling_test.go @@ -43,12 +43,14 @@ func TestFuzzAct1MessageRoundtrip(t *testing.T) { protocol1: protocol, } - _ = pbutils.RoundTrip(message, &Act1Message{}) + if err := pbutils.RoundTrip(message, &Act1Message{}); err != nil { + t.Fatal(err) + } } } func TestFuzzAct1MessageUnmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&Act1Message{}) + pbutils.AssertUnmarshalDoesNotPanic(&Act1Message{}) } func TestAct2MessageRoundTrip(t *testing.T) { @@ -96,12 +98,14 @@ func TestFuzzAct2MessageRoundtrip(t *testing.T) { protocol2: protocol, } - _ = pbutils.RoundTrip(message, &Act2Message{}) + if err := pbutils.RoundTrip(message, &Act2Message{}); err != nil { + t.Fatal(err) + } } } func TestFuzzAct2MessageUnmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&Act2Message{}) + pbutils.AssertUnmarshalDoesNotPanic(&Act2Message{}) } func TestAct3MessageRoundTrip(t *testing.T) { @@ -139,10 +143,12 @@ func TestFuzzAct3MessageRoundtrip(t *testing.T) { challenge: challenge, } - _ = pbutils.RoundTrip(message, &Act3Message{}) + if err := pbutils.RoundTrip(message, &Act3Message{}); err != nil { + t.Fatal(err) + } } } func TestFuzzAct3MessageUnmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&Act3Message{}) + pbutils.AssertUnmarshalDoesNotPanic(&Act3Message{}) } diff --git a/pkg/operator/key.go b/pkg/operator/key.go index b368c32b11..aa3a4d50b9 100644 --- a/pkg/operator/key.go +++ b/pkg/operator/key.go @@ -134,7 +134,7 @@ func MarshalCompressed(publicKey *PublicKey) []byte { byteLength := (curveBitSize + 7) / 8 compressed := make([]byte, 1+byteLength) - compressed[0] = byte(publicKey.Y.Bit(0)) | 2 + compressed[0] = byte(publicKey.Y.Bit(0)&1) | 2 publicKey.X.FillBytes(compressed[1:]) return compressed diff --git a/pkg/persistence/descriptor.go b/pkg/persistence/descriptor.go new file mode 100644 index 0000000000..1989605c12 --- /dev/null +++ b/pkg/persistence/descriptor.go @@ -0,0 +1,21 @@ +package persistence + +// dataDescriptor is the simplest possible implementation of DataDescriptor +// interface that can be used by a storage when reading data. +type dataDescriptor struct { + name string + directory string + readFunc func() ([]byte, error) +} + +func (dd *dataDescriptor) Name() string { + return dd.name +} + +func (dd *dataDescriptor) Directory() string { + return dd.directory +} + +func (dd *dataDescriptor) Content() ([]byte, error) { + return dd.readFunc() +} diff --git a/pkg/persistence/disk_persistence.go b/pkg/persistence/disk_persistence.go new file mode 100644 index 0000000000..3b364db1cb --- /dev/null +++ b/pkg/persistence/disk_persistence.go @@ -0,0 +1,372 @@ +package persistence + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "sync" + "time" +) + +const ( + currentDir = "current" + archiveDir = "archive" + snapshotDir = "snapshot" + + maxFileNameLength = 128 +) + +type basicDiskPersistence struct { + dataDir string +} + +type protectedDiskPersistence struct { + dataDir string + + snapshotMutex sync.Mutex + snapshotSuffixGenerator func() string +} + +// NewBasicDiskHandle creates on-disk data persistence handle +func NewBasicDiskHandle(path string) (BasicHandle, error) { + if err := CheckStoragePermission(path); err != nil { + return nil, err + } + + return &basicDiskPersistence{path}, nil +} + +// NewProtectedDiskHandle creates on-disk data persistence handle +func NewProtectedDiskHandle(path string) (ProtectedHandle, error) { + if err := CheckStoragePermission(path); err != nil { + return nil, err + } + + if err := EnsureDirectoryExists(path, currentDir); err != nil { + return nil, err + } + + if err := EnsureDirectoryExists(path, archiveDir); err != nil { + return nil, err + } + + if err := EnsureDirectoryExists(path, snapshotDir); err != nil { + return nil, err + } + + snapshotSuffixGenerator := func() string { + timestamp := time.Now().UnixMilli() + return fmt.Sprintf(".%d", timestamp) + } + + return &protectedDiskPersistence{ + path, + sync.Mutex{}, + snapshotSuffixGenerator, + }, nil +} + +func (ds *basicDiskPersistence) currentDirPath() string { + return filepath.Clean(ds.dataDir) +} + +func (ds *protectedDiskPersistence) currentDirPath() string { + return filepath.Join(ds.dataDir, currentDir) +} + +func (ds *basicDiskPersistence) Save(data []byte, dirName, fileName string) error { + return save(ds.currentDirPath(), data, dirName, fileName) +} + +func (ds *protectedDiskPersistence) Save(data []byte, dirName, fileName string) error { + return save(ds.currentDirPath(), data, dirName, fileName) +} + +func save(directoryPath string, data []byte, dirName, fileName string) error { + if len(dirName) > maxFileNameLength { + return fmt.Errorf( + "the maximum directory name length of [%v] exceeded for [%v]", + maxFileNameLength, + dirName, + ) + } + + if len(fileName) > maxFileNameLength { + return fmt.Errorf( + "the maximum file name length of [%v] exceeded for [%v]", + maxFileNameLength, + fileName, + ) + } + + err := EnsureDirectoryExists(directoryPath, dirName) + if err != nil { + return err + } + + return Write(filepath.Join(directoryPath, dirName, fileName), data) +} + +func (ds *basicDiskPersistence) ReadAll() (<-chan DataDescriptor, <-chan error) { + return readAll(ds.currentDirPath()) +} + +func (ds *protectedDiskPersistence) ReadAll() (<-chan DataDescriptor, <-chan error) { + return readAll(ds.currentDirPath()) +} + +func (ds *basicDiskPersistence) Delete(dirName string, fileName string) error { + dirPath := ds.currentDirPath() + filePath := filepath.Join(dirPath, dirName, fileName) + + return remove(filePath) +} + +func (ds *protectedDiskPersistence) Snapshot(data []byte, dirName, fileName string) error { + if len(dirName) > maxFileNameLength { + return fmt.Errorf( + "the maximum directory name length of [%v] exceeded for [%v]", + maxFileNameLength, + dirName, + ) + } + + snapshotSuffix := ds.snapshotSuffixGenerator() + + maxSnapshotFileNameLength := maxFileNameLength - len(snapshotSuffix) + if len(fileName) > maxSnapshotFileNameLength { + return fmt.Errorf( + "the maximum file name length of [%v] exceeded for [%v]", + maxSnapshotFileNameLength, + fileName, + ) + } + + ds.snapshotMutex.Lock() + defer ds.snapshotMutex.Unlock() + + dirPath := filepath.Join(ds.dataDir, snapshotDir) + err := EnsureDirectoryExists(dirPath, dirName) + if err != nil { + return err + } + + filePath := filepath.Join(dirPath, dirName, fileName+snapshotSuffix) + + // very unlikely but better fail than overwrite an existing file + if !isNonExistingFile(filePath) { + return fmt.Errorf( + "could not create unique snapshot; " + + "snapshot name collision has been detected", + ) + } + + return Write(filePath, data) +} + +func isNonExistingFile(filePath string) bool { + _, err := os.Stat(filePath) + return os.IsNotExist(err) +} + +func (ds *protectedDiskPersistence) Archive(directory string) error { + if len(directory) > maxFileNameLength { + return fmt.Errorf( + "the maximum directory name length of [%v] exceeded for [%v]", + maxFileNameLength, + directory, + ) + } + + from := filepath.Join(ds.dataDir, currentDir, directory) + to := filepath.Join(ds.dataDir, archiveDir, directory) + + return moveAll(from, to) +} + +// CheckStoragePermission returns an error if we don't have both read and write access to a directory. +func CheckStoragePermission(dirBasePath string) error { + _, err := ioutil.ReadDir(dirBasePath) + if err != nil { + return fmt.Errorf("cannot read from the storage directory: [%v]", err) + } + + tempFile, err := ioutil.TempFile(dirBasePath, "write-test.*.tmp") + if err != nil { + return fmt.Errorf("cannot write to the storage directory: [%v]", err) + } + + defer os.RemoveAll(tempFile.Name()) + + return nil +} + +// EnsureDirectoryExists creates a new directory in a base path if it doesn't +// exist, returns nil if it does, and errors out if the base path doesn't exist. +func EnsureDirectoryExists(dirBasePath, newDirName string) error { + dirPath := filepath.Join(dirBasePath, newDirName) + if _, err := os.Stat(dirPath); os.IsNotExist(err) { + err = os.Mkdir(dirPath, 0o750) + if err != nil { + return fmt.Errorf( + "error occurred while creating a dir: [%w]; "+ + "please make sure the parent directory [%s] exists", + err, + dirBasePath, + ) + } + } + + return nil +} + +// Write creates and writes data to a file +func Write(filePath string, data []byte) error { + writeFile, err := os.Create(filepath.Clean(filePath)) + if err != nil { + return err + } + + defer closeFile(writeFile) + + _, err = writeFile.Write(data) + if err != nil { + return err + } + + err = writeFile.Sync() + if err != nil { + return err + } + + return nil +} + +// Read a file from a file system +func Read(filePath string) ([]byte, error) { + // #nosec G304 (file path provided as taint input) + // This line opens a file from the predefined storage. + // There is no user input. + readFile, err := os.Open(filePath) + if err != nil { + return nil, err + } + + defer closeFile(readFile) + + data, err := ioutil.ReadAll(readFile) + if err != nil { + return nil, err + } + + return data, nil +} + +// remove a file from a file system +func remove(filePath string) error { + return os.Remove(filePath) +} + +func closeFile(file *os.File) { + err := file.Close() + if err != nil { + logger.Errorf("could not close file [%v]: [%v]", file.Name(), err) + } +} + +// readAll reads all files from the provided directoryPath and outputs them +// as DataDescriptors into the first returned output channel. All errors +// occurred during file system reading are sent to the second output channel +// returned from this function. The output can be later processed using +// pipeline pattern. This function is non-blocking and returned channels are +// not buffered. Channels are closed when there is no more to be read. +func readAll(directoryPath string) (<-chan DataDescriptor, <-chan error) { + dataChannel := make(chan DataDescriptor) + errorChannel := make(chan error) + + go func() { + defer close(dataChannel) + defer close(errorChannel) + + files, err := ioutil.ReadDir(directoryPath) + if err != nil { + errorChannel <- fmt.Errorf( + "could not read the directory [%v]: [%v]", + directoryPath, + err, + ) + } + + for _, file := range files { + if file.IsDir() { + dir, err := ioutil.ReadDir(filepath.Join(directoryPath, file.Name())) + if err != nil { + errorChannel <- fmt.Errorf( + "could not read the directory [%s/%s]: [%v]", + directoryPath, + file.Name(), + err, + ) + } + + for _, dirFile := range dir { + // capture shared loop variables for the closure + dirName := file.Name() + fileName := dirFile.Name() + + readFunc := func() ([]byte, error) { + return Read(filepath.Join( + directoryPath, + dirName, + fileName, + )) + } + dataChannel <- &dataDescriptor{fileName, dirName, readFunc} + } + } + } + }() + + return dataChannel, errorChannel +} + +func moveAll(directoryFromPath, directoryToPath string) error { + _, err := os.Stat(directoryToPath) + + // target directory does not exist, we can move everything + if os.IsNotExist(err) { + err := os.Rename(directoryFromPath, directoryToPath) + if err != nil { + return fmt.Errorf("error occurred while moving a dir: [%v]", err) + } + + return nil + } + + // unexpected error occurred while checking target directory existence, + // returning + if err != nil { + return fmt.Errorf("could not stat target directory: [%v]", err) + } + + // target directory does exit, we need to append files + files, err := ioutil.ReadDir(directoryFromPath) + if err != nil { + return fmt.Errorf("could not read directory [%v]: [%v]", directoryFromPath, err) + } + for _, file := range files { + from := filepath.Join(directoryFromPath, file.Name()) + to := filepath.Join(directoryToPath, file.Name()) + err := os.Rename(from, to) + if err != nil { + return err + } + } + err = os.RemoveAll(directoryFromPath) + if err != nil { + return fmt.Errorf("error occurred while removing archived dir: [%v]", err) + } + + return nil +} diff --git a/pkg/persistence/disk_persistence_test.go b/pkg/persistence/disk_persistence_test.go new file mode 100644 index 0000000000..e44fb35fbb --- /dev/null +++ b/pkg/persistence/disk_persistence_test.go @@ -0,0 +1,546 @@ +package persistence + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "reflect" + "strings" + "sync" + "testing" +) + +var ( + dirCurrent = "current" + dirArchive = "archive" + dirSnapshot = "snapshot" + + dirName1 = "0x424242" + fileName11 = "file11" + fileName12 = "file12" + + dirName2 = "0x777777" + fileName21 = "file21" + + fileContent = []byte{115, 111, 109, 101, 10} + + errExpectedRead = fmt.Errorf("cannot read from the storage directory: ") + errExpectedWrite = fmt.Errorf("cannot write to the storage directory: ") + + // 128 characters + maxAllowedName = "0cc2abf49e067b3bede8426d9369c6952655d33629f44610536445c00c974c7e2740dfac967dbfceeeec0af88cd48a5d8c1c167df93cad1b8301a4a204c9f235" + // 129 charactes + notAllowedName = "0cc2abf49e067b3bede8426d9369c6952655d33629f44610536445c00c974c7e2740dfac967dbfceeeec0af88cd48a5d8c1c167df93cad1b8301a4a204c9f235a" + + errDirectoryNameLength = fmt.Errorf("the maximum directory name length of [128] exceeded for [%v]", notAllowedName) + errFileNameLength = fmt.Errorf("the maximum file name length of [128] exceeded for [%v]", notAllowedName) +) + +func TestDiskPersistence_Save(t *testing.T) { + var tests = map[string]struct { + initDiskPersistenceFn func(t *testing.T) (RWHandle, string) + expectedFilePath string + }{ + "basic disk persistence": { + initDiskPersistenceFn: func(t *testing.T) (RWHandle, string) { return initBasicDiskPersistence(t) }, + expectedFilePath: filepath.Join(dirName1, fileName11), + }, + "protected disk persistence": { + initDiskPersistenceFn: func(t *testing.T) (RWHandle, string) { return initProtectedDiskPersistence(t) }, + expectedFilePath: filepath.Join(dirCurrent, dirName1, fileName11), + }, + } + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + diskHandle, dataDir := test.initDiskPersistenceFn(t) + + if err := diskHandle.Save(fileContent, dirName1, fileName11); err != nil { + t.Fatal(err) + } + + assertExist(t, dataDir, test.expectedFilePath, "check file after save") + }) + } +} + +func TestDiskPersistence_SaveMaxAllowed(t *testing.T) { + var tests = map[string]struct { + initDiskPersistenceFn func(t *testing.T) (RWHandle, string) + expectedFilePath string + }{ + "basic disk persistence": { + initDiskPersistenceFn: func(t *testing.T) (RWHandle, string) { return initBasicDiskPersistence(t) }, + expectedFilePath: filepath.Join(maxAllowedName, maxAllowedName), + }, + "protected disk persistence": { + initDiskPersistenceFn: func(t *testing.T) (RWHandle, string) { return initProtectedDiskPersistence(t) }, + expectedFilePath: filepath.Join(dirCurrent, maxAllowedName, maxAllowedName), + }, + } + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + diskHandle, dataDir := test.initDiskPersistenceFn(t) + + if err := diskHandle.Save(fileContent, maxAllowedName, maxAllowedName); err != nil { + t.Fatal(err) + } + + assertExist(t, dataDir, test.expectedFilePath, "check file after save") + }) + } +} + +func TestDiskPersistence_RefuseSave(t *testing.T) { + var tests = map[string]struct { + initDiskPersistenceFn func(t *testing.T) (RWHandle, string) + }{ + "basic disk persistence": { + initDiskPersistenceFn: func(t *testing.T) (RWHandle, string) { return initBasicDiskPersistence(t) }, + }, + "protected disk persistence": { + initDiskPersistenceFn: func(t *testing.T) (RWHandle, string) { return initProtectedDiskPersistence(t) }, + }, + } + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + diskHandle, _ := test.initDiskPersistenceFn(t) + + err := diskHandle.Save(fileContent, notAllowedName, fileName11) + if err == nil { + t.Fatalf("expected error") + } + if errDirectoryNameLength.Error() != err.Error() { + t.Fatalf( + "unexpected error returned\nexpected: [%v]\nactual: [%v]", + errDirectoryNameLength.Error(), + err.Error(), + ) + } + + err = diskHandle.Save(fileContent, dirName1, notAllowedName) + if err == nil { + t.Fatalf("expected error") + } + if errFileNameLength.Error() != err.Error() { + t.Fatalf( + "unexpected error returned\nexpected: [%v]\nactual: [%v]", + errFileNameLength.Error(), + err.Error(), + ) + } + }) + } +} + +func TestProtectedDiskPersistence_Snapshot(t *testing.T) { + diskHandle, dataDir := initProtectedDiskPersistence(t) + + counter := 0 + diskHandle.snapshotSuffixGenerator = func() string { + counter++ + return fmt.Sprintf(".%d", counter) + } + + for i := 0; i < 3; i++ { + err := diskHandle.Snapshot(fileContent, dirName1, fileName11) + if err != nil { + t.Fatal(err) + } + } + + pathToFile := filepath.Join(dirSnapshot, dirName1, fileName11+".1") + + assertExist(t, dataDir, pathToFile, "check file 1 after snapshot") + + pathToFile = filepath.Join(dirSnapshot, dirName1, fileName11+".2") + + assertExist(t, dataDir, pathToFile, "check file 2 after snapshot") + + pathToFile = filepath.Join(dirSnapshot, dirName1, fileName11+".3") + + assertExist(t, dataDir, pathToFile, "check file 3 after snapshot") +} + +func TestProtectedDiskPersistence_SnapshotMaxAllowed(t *testing.T) { + diskHandle, dataDir := initProtectedDiskPersistence(t) + + snapshotSuffix := ".suffix" + diskHandle.snapshotSuffixGenerator = func() string { + return snapshotSuffix + } + + maxAllowedSnapshotName := maxAllowedName[0 : len(maxAllowedName)-len(snapshotSuffix)] + err := diskHandle.Snapshot(fileContent, maxAllowedName, maxAllowedSnapshotName) + if err != nil { + t.Fatal(err) + } + + pathToFile := filepath.Join( + dirSnapshot, + maxAllowedName, + maxAllowedSnapshotName+snapshotSuffix, + ) + + assertExist(t, dataDir, pathToFile, "check file after snapshot") +} + +func TestProtectedDiskPersistence_RefuseSnapshot_MaxAllowedExceeded(t *testing.T) { + diskHandle, _ := initProtectedDiskPersistence(t) + + snapshotSuffix := ".suffix" + diskHandle.snapshotSuffixGenerator = func() string { + return snapshotSuffix + } + + err := diskHandle.Snapshot(fileContent, notAllowedName, fileName11) + if err == nil { + t.Fatalf("expected error") + } + + if errDirectoryNameLength.Error() != err.Error() { + t.Fatalf( + "unexpected error returned\nexpected: [%v]\nactual: [%v]", + errDirectoryNameLength.Error(), + err.Error(), + ) + } + + err = diskHandle.Snapshot(fileContent, dirName1, notAllowedName) + if err == nil { + t.Fatalf("expected error") + } + + errSnapshotFileNameLength := fmt.Errorf( + "the maximum file name length of [%d] exceeded for [%v]", + 128-len(snapshotSuffix), + notAllowedName, + ) + + if errSnapshotFileNameLength.Error() != err.Error() { + t.Fatalf( + "unexpected error returned\nexpected: [%v]\nactual: [%v]", + errFileNameLength.Error(), + err.Error(), + ) + } + +} + +func TestProtectedDiskPersistence_RefuseSnapshot_NameCollision(t *testing.T) { + diskHandle, dataDir := initProtectedDiskPersistence(t) + + // snapshot suffix generator return always the same suffix in order to + // cause name collision. + snapshotSuffix := ".suffix" + diskHandle.snapshotSuffixGenerator = func() string { + return snapshotSuffix + } + + err := diskHandle.Snapshot(fileContent, dirName1, fileName11) + if err != nil { + t.Fatal(err) + } + + pathToFile := filepath.Join( + dirSnapshot, + dirName1, + fileName11+snapshotSuffix, + ) + + assertExist(t, dataDir, pathToFile, "check file after snapshot") + + err = diskHandle.Snapshot(fileContent, dirName1, fileName11) + + expectedDuplicateError := fmt.Errorf( + "could not create unique snapshot; " + + "snapshot name collision has been detected", + ) + if err == nil || (!reflect.DeepEqual(expectedDuplicateError, err)) { + t.Fatalf( + "unexpected error\nexpected: [%v]\nactual: [%v]", + expectedDuplicateError, + err, + ) + } +} + +func TestDiskPersistence_StoragePermission(t *testing.T) { + if os.Geteuid() == 0 { + t.Skip("cannot verify storage permission enforcement when running as root; " + + "root bypasses Unix file permission checks entirely") + } + var tests = map[string]struct { + newDiskPersistenceFn func(dataDir string) (RWHandle, error) + }{ + "basic disk persistence": { + newDiskPersistenceFn: func(dataDir string) (RWHandle, error) { return NewBasicDiskHandle(dataDir) }, + }, + "protected disk persistence": { + newDiskPersistenceFn: func(dataDir string) (RWHandle, error) { return NewProtectedDiskHandle(dataDir) }, + }, + } + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + tempDir := filepath.Join(t.TempDir(), "data_storage") + + err := os.Mkdir(tempDir, 0000) // d--------- + if _, err := os.Stat(tempDir); os.IsNotExist(err) { + t.Fatalf("dir [%+v] was supposed to be created", tempDir) + } + + _, err = test.newDiskPersistenceFn(tempDir) + if err == nil || !strings.Contains(err.Error(), errExpectedRead.Error()) { + t.Fatalf("error on read was supposed to be returned") + } + + os.Chmod(tempDir, 0444) // dr--r--r + + _, err = NewProtectedDiskHandle(tempDir) + if err == nil || !strings.Contains(err.Error(), errExpectedWrite.Error()) { + t.Fatalf("error on write was supposed to be returned") + } + }) + } +} + +func TestDiskPersistence_ReadAll(t *testing.T) { + var tests = map[string]struct { + initDiskPersistenceFn func(t *testing.T) (RWHandle, string) + expectedFilePath string + }{ + "basic disk persistence": { + initDiskPersistenceFn: func(t *testing.T) (RWHandle, string) { return initBasicDiskPersistence(t) }, + expectedFilePath: filepath.Join(maxAllowedName, maxAllowedName), + }, + "protected disk persistence": { + initDiskPersistenceFn: func(t *testing.T) (RWHandle, string) { return initProtectedDiskPersistence(t) }, + expectedFilePath: filepath.Join(dirCurrent, maxAllowedName, maxAllowedName), + }, + } + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + diskHandle, _ := test.initDiskPersistenceFn(t) + + expectedBytes := [][]byte{fileContent, fileContent, fileContent} + + diskHandle.Save(fileContent, dirName1, fileName11) + diskHandle.Save(fileContent, dirName1, fileName12) + diskHandle.Save(fileContent, dirName2, fileName21) + + dataChannel, errChannel := diskHandle.ReadAll() + + var descriptors []DataDescriptor + var errors []error + + var wg sync.WaitGroup + wg.Add(2) + + go func() { + for e := range errChannel { + errors = append(errors, e) + } + wg.Done() + }() + + go func() { + for d := range dataChannel { + descriptors = append(descriptors, d) + } + wg.Done() + }() + + wg.Wait() + + for err := range errors { + t.Fatal(err) + } + + if len(descriptors) != 3 { + t.Fatalf( + "Number of descriptors does not match\nExpected: [%v]\nActual: [%v]", + 3, + len(descriptors), + ) + } + + for i := 0; i < 3; i++ { + fileContent, err := descriptors[i].Content() + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(expectedBytes[i], fileContent) { + t.Errorf( + "unexpected file content [%d]\nexpected: [%v]\nactual: [%v]\n", + i, + expectedBytes[i], + fileContent, + ) + } + } + }) + } +} + +func TestProtectedDiskPersistence_Archive(t *testing.T) { + diskHandle, dataDir := initProtectedDiskPersistence(t) + + pathMoveFrom := filepath.Join(dirCurrent, dirName1) + pathMoveTo := filepath.Join(dirArchive, dirName1) + + diskHandle.Save(fileContent, dirName1, fileName11) + + assertExist(t, dataDir, pathMoveFrom, "check path from before archive") + assertNotExist(t, dataDir, pathMoveTo, "check path to before archive") + + diskHandle.Archive(dirName1) + + assertNotExist(t, dataDir, pathMoveFrom, "check path from after archive") + assertExist(t, dataDir, pathMoveTo, "check path to after archive") + +} + +func TestProtectedDiskPersistence_ArchiveMaxAllowed(t *testing.T) { + diskHandle, dataDir := initProtectedDiskPersistence(t) + + pathMoveFrom := filepath.Join(dirCurrent, maxAllowedName) + pathMoveTo := filepath.Join(dirArchive, maxAllowedName) + + diskHandle.Save(fileContent, maxAllowedName, maxAllowedName) + + assertExist(t, dataDir, pathMoveFrom, "check path from before archive") + assertNotExist(t, dataDir, pathMoveTo, "check path to before archive") + + err := diskHandle.Archive(maxAllowedName) + if err != nil { + t.Fatal(err) + } + + assertNotExist(t, dataDir, pathMoveFrom, "check path from after archive") + assertExist(t, dataDir, pathMoveTo, "check path to after archive") + +} + +func TestProtectedDiskPersistence_RefuseArchive(t *testing.T) { + diskHandle, _ := initProtectedDiskPersistence(t) + + err := diskHandle.Archive(notAllowedName) + if err == nil { + t.Fatalf("expected error") + } + if errDirectoryNameLength.Error() != err.Error() { + t.Fatalf( + "unexpected error returned\nexpected: [%v]\nactual: [%v]", + errDirectoryNameLength.Error(), + err.Error(), + ) + } +} + +func TestProtectedDiskPersistence_AppendToArchive(t *testing.T) { + diskHandle, dataDir := initProtectedDiskPersistence(t) + + pathMoveFrom := filepath.Join(dataDir, dirCurrent, dirName1) + pathMoveTo := filepath.Join(dataDir, dirArchive, dirName1) + + diskHandle.Save(fileContent, dirName1, fileName11) + diskHandle.Save(fileContent, dirName1, fileName12) + diskHandle.Archive(dirName1) + + diskHandle.Save(fileContent, dirName1, "/file13") + diskHandle.Save(fileContent, dirName1, "/file14") + diskHandle.Archive(dirName1) + + assertNotExist(t, dataDir, pathMoveFrom, "check path from after archive") + + files, _ := ioutil.ReadDir(pathMoveTo) + if len(files) != 4 { + t.Fatalf( + "unexpected number of files\nexpected: [%v]\nactual: [%v]", + 4, + len(files), + ) + } +} + +func TestBasicDiskPersistence_Delete(t *testing.T) { + diskHandle, dataDir := initBasicDiskPersistence(t) + + pathToDir := filepath.Join(dirName1) + pathToFile := filepath.Join(pathToDir, fileName11) + + diskHandle.Save(fileContent, dirName1, fileName11) + + assertExist(t, dataDir, pathToDir, "check directory before delete") + assertExist(t, dataDir, pathToFile, "check file before delete") + + if err := diskHandle.Delete(dirName1, fileName11); err != nil { + t.Fatalf("unexpected error for Delete call: %v", err) + } + + assertExist(t, dataDir, pathToDir, "check directory after delete") + assertNotExist(t, dataDir, pathToFile, "check file after delete") + +} + +func TestBasicDiskPersistence_RefuseDelete(t *testing.T) { + diskHandle, dataDir := initBasicDiskPersistence(t) + + expectedError := fmt.Errorf( + "remove %s: no such file or directory", + filepath.Join(dataDir, dirName1, fileName11), + ) + + err := diskHandle.Delete(dirName1, fileName11) + if err == nil { + t.Fatalf("expected error") + } + if expectedError.Error() != err.Error() { + t.Fatalf( + "unexpected error returned\nexpected: [%v]\nactual: [%v]", + expectedError.Error(), + err.Error(), + ) + } +} + +func initBasicDiskPersistence(t *testing.T) (*basicDiskPersistence, string) { + dataDir := t.TempDir() + handle, err := NewBasicDiskHandle(dataDir) + if err != nil { + t.Fatalf("failed to initialize disk handle: %v", err) + } + return handle.(*basicDiskPersistence), dataDir +} +func initProtectedDiskPersistence(t *testing.T) (*protectedDiskPersistence, string) { + dataDir := t.TempDir() + handle, err := NewProtectedDiskHandle(dataDir) + if err != nil { + t.Fatalf("failed to initialize disk handle: %v", err) + } + return handle.(*protectedDiskPersistence), dataDir +} + +func assertExist(t *testing.T, dataDir, path, message string) { + _, err := os.Stat(filepath.Join(dataDir, path)) + if err != nil { + if os.IsNotExist(err) { + t.Fatalf("%s: path [%s] does not exist, but is expected to exist", message, path) + } + t.Fatalf("%s: unexpected error for path [%s]: %v", message, path, err) + } +} + +func assertNotExist(t *testing.T, dataDir, path, message string) { + _, err := os.Stat(filepath.Join(dataDir, path)) + if err == nil { + t.Fatalf("%s: path [%s] exist, but is expected to does not exist", message, path) + } + + if os.IsNotExist(err) { + return + } + t.Fatalf("%s: unexpected error for path [%s]: %v", message, path, err) +} diff --git a/pkg/persistence/encrypted_persistence.go b/pkg/persistence/encrypted_persistence.go new file mode 100644 index 0000000000..7424341ba9 --- /dev/null +++ b/pkg/persistence/encrypted_persistence.go @@ -0,0 +1,111 @@ +package persistence + +import ( + "crypto/sha256" + + "github.com/keep-network/keep-core/pkg/encryption" +) + +// KeyLength represents the byte size of the key. +const KeyLength = encryption.KeyLength + +type encryptedPersistance[H RWHandle] struct { + box encryption.Box + delegate H +} + +type encryptedBasicPersistence struct { + encryptedPersistance[BasicHandle] +} + +type encryptedProtectedPersistence struct { + encryptedPersistance[ProtectedHandle] +} + +// NewEncryptedBasicPersistence creates an adapter for the disk persistence to store data +// in an encrypted format. +func NewEncryptedBasicPersistence(handle BasicHandle, password string) BasicHandle { + return &encryptedBasicPersistence{ + encryptedPersistance: encryptedPersistance[BasicHandle]{ + box: encryption.NewBox(sha256.Sum256([]byte(password))), + delegate: handle, + }, + } +} + +// NewEncryptedProtectedPersistence creates an adapter for the disk persistence to store data +// in an encrypted format. +func NewEncryptedProtectedPersistence(handle ProtectedHandle, password string) ProtectedHandle { + return &encryptedProtectedPersistence{ + encryptedPersistance[ProtectedHandle]{ + box: encryption.NewBox(sha256.Sum256([]byte(password))), + delegate: handle, + }, + } +} + +func (ep *encryptedPersistance[H]) Save(data []byte, directory string, name string) error { + encrypted, err := ep.box.Encrypt(data) + if err != nil { + return err + } + + return ep.delegate.Save(encrypted, directory, name) +} + +func (ep *encryptedPersistance[H]) ReadAll() (<-chan DataDescriptor, <-chan error) { + outputData := make(chan DataDescriptor) + outputErrors := make(chan error) + + inputData, inputErrors := ep.delegate.ReadAll() + + // pass thru all errors from the input to the output channel without + // changing anything + go func() { + defer close(outputErrors) + for err := range inputErrors { + outputErrors <- err + } + }() + + // pipe input data descriptor channel to the output data descriptor channel + // decorading the descriptor passed so that the content is decrypted on read + go func() { + defer close(outputData) + for descriptor := range inputData { + // capture shared loop variable's value for the closure + d := descriptor + + outputData <- &dataDescriptor{ + name: d.Name(), + directory: d.Directory(), + readFunc: func() ([]byte, error) { + content, err := d.Content() + if err != nil { + return nil, err + } + return ep.box.Decrypt(content) + }, + } + } + }() + + return outputData, outputErrors +} + +func (ep *encryptedBasicPersistence) Delete(directory string, name string) error { + return ep.delegate.Delete(directory, name) +} + +func (ep *encryptedProtectedPersistence) Archive(directory string) error { + return ep.delegate.Archive(directory) +} + +func (ep *encryptedProtectedPersistence) Snapshot(data []byte, directory string, name string) error { + encrypted, err := ep.box.Encrypt(data) + if err != nil { + return err + } + + return ep.delegate.Snapshot(encrypted, directory, name) +} diff --git a/pkg/persistence/encrypted_persistence_test.go b/pkg/persistence/encrypted_persistence_test.go new file mode 100644 index 0000000000..ad0ae0ec76 --- /dev/null +++ b/pkg/persistence/encrypted_persistence_test.go @@ -0,0 +1,174 @@ +package persistence + +import ( + "bytes" + "sync" + "testing" + + "crypto/sha256" + + "github.com/keep-network/keep-core/pkg/encryption" +) + +const accountPassword = "grzeski" + +var ( + dataToEncrypt1 = []byte{'b', 'o', 'l', 'e', 'k'} + dataToEncrypt2 = []byte{'l', 'o', 'l', 'e', 'k'} + dataToEncrypt = [][]byte{dataToEncrypt1, dataToEncrypt2} +) + +func TestSaveReadAndDecryptData(t *testing.T) { + var tests = map[string]struct { + initEncryptedPersistenceFn func() RWHandle + expectedFilePath string + }{ + "basic encrypted persistence": { + initEncryptedPersistenceFn: func() RWHandle { + return NewEncryptedBasicPersistence(&delegatePersistenceMock{}, accountPassword) + }, + }, + "protected encrypted persistence": { + initEncryptedPersistenceFn: func() RWHandle { + return NewEncryptedProtectedPersistence(&delegatePersistenceMock{}, accountPassword) + }, + }, + } + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + encryptedPersistence := test.initEncryptedPersistenceFn() + + err := encryptedPersistence.Save(dataToEncrypt1, "dir1", "name1") + if err != nil { + t.Fatalf("Error occurred while saving data [%v]", err) + } + encryptedPersistence.Save(dataToEncrypt2, "dir2", "name2") + if err != nil { + t.Fatalf("Error occurred while saving data [%v]", err) + } + + decryptedChan, errChan := encryptedPersistence.ReadAll() + + var decrypted [][]byte + var errors []error + + var wg sync.WaitGroup + wg.Add(2) + + go func() { + for err := range errChan { + errors = append(errors, err) + } + wg.Done() + }() + + go func() { + for d := range decryptedChan { + content, err := d.Content() + if err != nil { + errors = append(errors, err) + } + + decrypted = append(decrypted, content) + } + wg.Done() + }() + + wg.Wait() + + for err := range errors { + t.Fatal(err) + } + + if len(decrypted) != len(dataToEncrypt) { + t.Fatalf( + "Unexpected number of decrypted items\nExpected: [%v]\nActual: [%v]", + len(dataToEncrypt), + len(decrypted), + ) + } + + for i := 0; i < len(dataToEncrypt); i++ { + if !bytes.Equal(dataToEncrypt[i], decrypted[i]) { + t.Errorf( + "unexpected decrypted item [%d]\nexpected: [%v]\nactual: [%v]\n", + i, + dataToEncrypt[i], + decrypted[i], + ) + } + } + }) + } +} + +type delegatePersistenceMock struct{} + +func (dpm *delegatePersistenceMock) Save(data []byte, directory string, name string) error { + // noop + return nil +} + +func (dpm *delegatePersistenceMock) Snapshot(data []byte, directory string, name string) error { + // noop + return nil +} + +func (dpm *delegatePersistenceMock) ReadAll() (<-chan DataDescriptor, <-chan error) { + encrypted := encryptData() + + outputData := make(chan DataDescriptor, 2) + outputErrors := make(chan error) + + outputData <- &testDataDescriptor{"1", "dir", encrypted[0]} + outputData <- &testDataDescriptor{"2", "dir", encrypted[1]} + + close(outputData) + close(outputErrors) + + return outputData, outputErrors +} + +func (dpm *delegatePersistenceMock) Archive(directory string) error { + // noop + return nil +} + +func (dpm *delegatePersistenceMock) Delete(directory string, name string) error { + // noop + return nil +} + +type testDataDescriptor struct { + name string + directory string + content []byte +} + +func (tdd *testDataDescriptor) Name() string { + return tdd.name +} + +func (tdd *testDataDescriptor) Directory() string { + return tdd.directory +} + +func (tdd *testDataDescriptor) Content() ([]byte, error) { + return tdd.content, nil +} + +func encryptData() [][]byte { + passwordBytes := []byte(accountPassword) + box := encryption.NewBox(sha256.Sum256(passwordBytes)) + + encryptedData1, err := box.Encrypt(dataToEncrypt1) + if err != nil { + panic("Error occurred while encrypting data") + } + encryptedData2, err := box.Encrypt(dataToEncrypt2) + if err != nil { + panic("Error occurred while encrypting data") + } + + return [][]byte{encryptedData1, encryptedData2} +} diff --git a/pkg/persistence/persistence.go b/pkg/persistence/persistence.go new file mode 100644 index 0000000000..4b4c511f84 --- /dev/null +++ b/pkg/persistence/persistence.go @@ -0,0 +1,59 @@ +// Package persistence adds a layer which handles data storage. This package +// separates the data from the business layer and is responsible for saving and +// retrieving it. +package persistence + +import "github.com/ipfs/go-log" + +var logger = log.Logger("keep-persistence") + +// RWHandle is an interface for data persistence. Underlying implementation +// can write and read data e.g. to disk, cache, or hardware module. +type RWHandle interface { + // Save takes the provided data and persists it under the given name in the + // provided directory appropriate for the given persistent storage + // implementation. + Save(data []byte, directory string, name string) error + + // ReadAll returns all non-archived data. It returns two channels: the first + // channel returned is a non-buffered channel streaming DataDescriptors of + // all data read. The second channel is a non-buffered channel streaming all + // errors occurred during reading. Returned channels can be integrated + // in a pipeline pattern. The function is non-blocking. Channels are closed + // when there is no more to be read. + ReadAll() (<-chan DataDescriptor, <-chan error) +} + +// BasicHandle is an interface for data persistence. Underlying implementation +// can read, write and remove data. +type BasicHandle interface { + RWHandle + + // Delete removes a file under the given name in the provided directory + // appropriate for the given persistent storage implementation. + Delete(directory string, name string) error +} + +// ProtectedHandle is an interface for data persistence. Underlying implementation +// can read and write data, but it cannot remove the data. Instead of removing +// the data it can archive them or take snapshots. +type ProtectedHandle interface { + RWHandle + + // Archive marks the entire directory with the name provided as archived + // so that the data in that directory is not returned from ReadAll. + Archive(directory string) error + + // Snapshot takes the provided data and persists it as an unique snapshot + // file in the provided directory appropriate for the given persistent + // storage implementation. + Snapshot(data []byte, directory string, name string) error +} + +// DataDescriptor is an interface representing data saved in the persistence +// layer represented by Handle. +type DataDescriptor interface { + Name() string + Directory() string + Content() ([]byte, error) +} diff --git a/pkg/protocol/announcer/announcer.go b/pkg/protocol/announcer/announcer.go index 54860aa0ee..6da85d49df 100644 --- a/pkg/protocol/announcer/announcer.go +++ b/pkg/protocol/announcer/announcer.go @@ -47,11 +47,11 @@ func (am *announcementMessage) Unmarshal(bytes []byte) error { ) } - if senderID := pbMessage.SenderID; senderID > group.MaxMemberIndex { - return fmt.Errorf("invalid member index value: [%v]", senderID) - } else { - am.senderID = group.MemberIndex(senderID) + senderID, err := group.MemberIndexFromUint32(pbMessage.SenderID) + if err != nil { + return err } + am.senderID = senderID am.protocolID = pbMessage.ProtocolID am.sessionID = pbMessage.SessionID diff --git a/pkg/protocol/announcer/announcer_test.go b/pkg/protocol/announcer/announcer_test.go index b96b69f8da..664370a5dc 100644 --- a/pkg/protocol/announcer/announcer_test.go +++ b/pkg/protocol/announcer/announcer_test.go @@ -58,12 +58,14 @@ func TestFuzzAnnouncementMessage_MarshalingRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(msg, &announcementMessage{}) + if err := pbutils.RoundTrip(msg, &announcementMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzAnnouncementMessage_Unmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&announcementMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&announcementMessage{}) } func TestAnnouncer(t *testing.T) { diff --git a/pkg/protocol/group/group_test.go b/pkg/protocol/group/group_test.go index 1233ce544d..acb907bd26 100644 --- a/pkg/protocol/group/group_test.go +++ b/pkg/protocol/group/group_test.go @@ -189,8 +189,8 @@ func TestOperatingMembers(t *testing.T) { "all but one inactive": { initialMembers: []MemberIndex{28, 19, 29}, updateFunc: func(g *Group) { - g.MarkMemberAsDisqualified(19) - g.MarkMemberAsDisqualified(29) + g.MarkMemberAsInactive(19) + g.MarkMemberAsInactive(29) }, expectedOperatingMembers: []MemberIndex{28}, }, diff --git a/pkg/protocol/group/member_index.go b/pkg/protocol/group/member_index.go new file mode 100644 index 0000000000..e647717050 --- /dev/null +++ b/pkg/protocol/group/member_index.go @@ -0,0 +1,34 @@ +package group + +import "fmt" + +// MemberIndexFromUint32 converts a wire or persisted member index without +// truncating it, accepting any value in the range [0, MaxMemberIndex]. Zero +// retains its existing meaning at each protocol boundary; validation of +// group membership belongs to the protocol using the index. Persisted-signer +// callers must use MemberIndexFromUint32NonZero instead, since a persisted +// signer's own index is never re-checked against group membership after +// being loaded. +func MemberIndexFromUint32(value uint32) (MemberIndex, error) { + if value > MaxMemberIndex { + return 0, fmt.Errorf("invalid member index value: [%v]", value) + } + return MemberIndex(value), nil +} + +// MemberIndexFromUint32NonZero converts a persisted member index, rejecting +// both out-of-range values and zero. Persisted-signer decode paths never +// re-check group membership after loading their own index, so a zero index +// must be rejected here: MembershipValidator.IsValidMembership computes +// int(memberID-1), which silently wraps a MemberIndex(0) to 255 and matches +// no real group position. +func MemberIndexFromUint32NonZero(value uint32) (MemberIndex, error) { + memberIndex, err := MemberIndexFromUint32(value) + if err != nil { + return 0, err + } + if memberIndex == 0 { + return 0, fmt.Errorf("invalid member index value: [%v]", value) + } + return memberIndex, nil +} diff --git a/pkg/protocol/group/member_index_test.go b/pkg/protocol/group/member_index_test.go new file mode 100644 index 0000000000..92fdb4ccfc --- /dev/null +++ b/pkg/protocol/group/member_index_test.go @@ -0,0 +1,24 @@ +package group + +import ( + "fmt" + "math" + "testing" +) + +func TestMemberIndexFromUint32(t *testing.T) { + for _, value := range []uint32{0, 1, 255, 256, math.MaxUint32} { + t.Run(fmt.Sprint(value), func(t *testing.T) { + index, err := MemberIndexFromUint32(value) + if value > MaxMemberIndex { + if err == nil { + t.Fatal("expected out-of-range index to be rejected") + } + return + } + if err != nil || uint32(index) != value { + t.Fatalf("index %d: got %d, %v", value, index, err) + } + }) + } +} diff --git a/pkg/protocol/inactivity/marshalling.go b/pkg/protocol/inactivity/marshaling.go similarity index 71% rename from pkg/protocol/inactivity/marshalling.go rename to pkg/protocol/inactivity/marshaling.go index f117f015a4..f700d371c1 100644 --- a/pkg/protocol/inactivity/marshalling.go +++ b/pkg/protocol/inactivity/marshaling.go @@ -1,23 +1,13 @@ +// marshaling.go: protobuf (un)marshaling for the public types in this package. package inactivity import ( - "fmt" - "google.golang.org/protobuf/proto" "github.com/keep-network/keep-core/pkg/protocol/group" "github.com/keep-network/keep-core/pkg/protocol/inactivity/gen/pb" ) -func validateMemberIndex(protoIndex uint32) error { - // Protobuf does not have uint8 type, so we are using uint32. When - // unmarshalling message, we need to make sure we do not overflow. - if protoIndex > group.MaxMemberIndex { - return fmt.Errorf("invalid member index value: [%v]", protoIndex) - } - return nil -} - // Marshal converts this claimSignatureMessage to a byte array suitable // for network communication. func (csm *claimSignatureMessage) Marshal() ([]byte, error) { @@ -38,10 +28,11 @@ func (csm *claimSignatureMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } - csm.senderID = group.MemberIndex(pbMsg.SenderID) + csm.senderID = senderID claimHash, err := ClaimHashFromBytes(pbMsg.ClaimHash) if err != nil { diff --git a/pkg/protocol/inactivity/marshalling_test.go b/pkg/protocol/inactivity/marshaling_test.go similarity index 88% rename from pkg/protocol/inactivity/marshalling_test.go rename to pkg/protocol/inactivity/marshaling_test.go index 5e0a2d771d..f0bcd265ac 100644 --- a/pkg/protocol/inactivity/marshalling_test.go +++ b/pkg/protocol/inactivity/marshaling_test.go @@ -56,10 +56,12 @@ func TestFuzzClaimSignatureMessage_MarshalingRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &claimSignatureMessage{}) + if err := pbutils.RoundTrip(message, &claimSignatureMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzClaimSignatureMessage_Unmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&claimSignatureMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&claimSignatureMessage{}) } diff --git a/pkg/protocol/state/sync_machine.go b/pkg/protocol/state/sync_machine.go index a6f2ec20ff..7d23fcc8ce 100644 --- a/pkg/protocol/state/sync_machine.go +++ b/pkg/protocol/state/sync_machine.go @@ -72,7 +72,7 @@ func (sm *SyncMachine) Execute(startBlockHeight uint64) (SyncState, uint64, erro err := sm.blockCounter.WaitForBlockHeight(startBlockHeight) if err != nil { cancelCtx() - return nil, 0, fmt.Errorf("failed to wait for the execution start block") + return nil, 0, fmt.Errorf("failed to wait for the execution start block: [%w]", err) } lastStateEndBlockHeight := startBlockHeight diff --git a/pkg/rate/limiter.go b/pkg/rate/limiter.go new file mode 100644 index 0000000000..cc1f48d655 --- /dev/null +++ b/pkg/rate/limiter.go @@ -0,0 +1,103 @@ +package rate + +import ( + "context" + "time" + + "golang.org/x/sync/semaphore" + "golang.org/x/time/rate" +) + +var ( + // DefaultRequestsPerSecondLimit specifies the default maximum average number + // of requests per second. + DefaultRequestsPerSecondLimit = 150 + + // DefaultConcurrencyLimit specifies the default number of concurrent requests + // which can be executed against the target at the same time. + DefaultConcurrencyLimit = 30 +) + +// Limiter is a helper tool which allows controlling the number and +// concurrency of requests made against a generic target. +type Limiter struct { + limiter *rate.Limiter + semaphore *semaphore.Weighted + acquirePermitTimeout time.Duration +} + +// LimiterConfig represents the configuration of the rate limiter. +type LimiterConfig struct { + // RequestsPerSecondLimit sets the maximum average number of requests + // per second. It's important to note that in short periods of time + // the actual average may exceed this limit slightly. + RequestsPerSecondLimit int + + // ConcurrencyLimit sets the maximum number of concurrent requests which + // can be executed against the target at the same time. + ConcurrencyLimit int + + // AcquirePermitTimeout determines how long a request can wait trying + // to acquire a permit from the rate limiter. + AcquirePermitTimeout time.Duration +} + +// NewLimiter creates a new rate limiter instance basing on given config. +func NewLimiter( + config *LimiterConfig, +) *Limiter { + l := &Limiter{} + + if config.RequestsPerSecondLimit > 0 { + l.limiter = rate.NewLimiter( + rate.Limit(config.RequestsPerSecondLimit), + 1, + ) + } + + if config.ConcurrencyLimit > 0 { + l.semaphore = semaphore.NewWeighted( + int64(config.ConcurrencyLimit), + ) + } + + if config.AcquirePermitTimeout > 0 { + l.acquirePermitTimeout = config.AcquirePermitTimeout + } else { + l.acquirePermitTimeout = 5 * time.Minute + } + + return l +} + +// AcquirePermit acquires the permit. +func (l *Limiter) AcquirePermit() error { + ctx, cancel := context.WithTimeout( + context.Background(), + l.acquirePermitTimeout, + ) + defer cancel() + + if l.limiter != nil { + err := l.limiter.Wait(ctx) + if err != nil { + return err + } + } + + if l.semaphore != nil { + err := l.semaphore.Acquire(ctx, 1) + if err != nil { + return err + } + } + + return nil +} + +// ReleasePermit releases the permit. +func (l *Limiter) ReleasePermit() { + if l.semaphore != nil { + l.semaphore.Release(1) + } +} diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index 9110906c9e..b62e1b01d8 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -5,7 +5,7 @@ import ( "path" "path/filepath" - "github.com/keep-network/keep-common/pkg/persistence" + "github.com/keep-network/keep-core/pkg/persistence" ) // Config stores meta-info about keeping data on disk diff --git a/pkg/tbtc/chain.go b/pkg/tbtc/chain.go index a58599f273..ab34295952 100644 --- a/pkg/tbtc/chain.go +++ b/pkg/tbtc/chain.go @@ -2,6 +2,8 @@ package tbtc import ( "crypto/ecdsa" + "fmt" + "math" "math/big" "time" @@ -352,7 +354,10 @@ type DepositRevealedEvent struct { BlockNumber uint64 } -func (dre *DepositRevealedEvent) unpack(extraData *[32]byte) *Deposit { +func (dre *DepositRevealedEvent) unpack(extraData *[32]byte) (*Deposit, error) { + if dre.Amount > math.MaxInt64 { + return nil, fmt.Errorf("deposit amount exceeds int64 range: [%v]", dre.Amount) + } return &Deposit{ Utxo: &bitcoin.UnspentTransactionOutput{ Outpoint: &bitcoin.TransactionOutpoint{ @@ -368,7 +373,7 @@ func (dre *DepositRevealedEvent) unpack(extraData *[32]byte) *Deposit { RefundLocktime: dre.RefundLocktime, Vault: dre.Vault, ExtraData: extraData, - } + }, nil } func (dre *DepositRevealedEvent) GetWalletPublicKeyHash() [20]byte { diff --git a/pkg/tbtc/coordination.go b/pkg/tbtc/coordination.go index 2dd75e9614..18e5e721d3 100644 --- a/pkg/tbtc/coordination.go +++ b/pkg/tbtc/coordination.go @@ -380,9 +380,6 @@ func (ce *coordinationExecutor) coordinate( startTime := time.Now() - // Record duration metric once at the end using defer - var coordinationFailed bool - seed, err := ce.getSeed(window.coordinationBlock) if err != nil { return nil, fmt.Errorf("failed to compute coordination seed: [%v]", err) @@ -431,7 +428,6 @@ func (ce *coordinationExecutor) coordinate( // no point to keep the context active as retransmissions do not // occur anyway. cancelCtx() - coordinationFailed = true if ce.metricsRecorder != nil { ce.metricsRecorder.IncrementCounter(clientinfo.MetricCoordinationFailedTotal, 1) } @@ -455,7 +451,6 @@ func (ce *coordinationExecutor) coordinate( append(actionsChecklist, ActionNoop), ) if err != nil { - coordinationFailed = true // Record as leader timeout observation, not as a failure of this node. // The actual failure is on the leader's side. if ce.metricsRecorder != nil { @@ -498,7 +493,7 @@ func (ce *coordinationExecutor) coordinate( execLogger.Infof("coordination completed with result: [%s]", result) // Record successful coordination counter - if ce.metricsRecorder != nil && !coordinationFailed { + if ce.metricsRecorder != nil { ce.metricsRecorder.IncrementCounter(clientinfo.MetricCoordinationProceduresExecutedTotal, 1) ce.metricsRecorder.RecordDuration(clientinfo.MetricCoordinationDurationSeconds, time.Since(startTime)) } @@ -561,6 +556,7 @@ func (ce *coordinationExecutor) getLeader(seed [32]byte) chain.Address { // #nosec G404 (insecure random number source (rand)) // Shuffling operators does not require secure randomness. // Use first 8 bytes of the seed to initialize the RNG. + // #nosec G115 -- Preserve all 64 seed bits so existing operators select the same leader/actions. rng := rand.New(rand.NewSource(int64(binary.BigEndian.Uint64(seed[:8])))) // Shuffle the list of unique operators. @@ -608,15 +604,12 @@ func (ce *coordinationExecutor) getActionsChecklist( // proposal generator performs a full-history chain scan. if coordinationBlock < DepositSweepEveryWindowActivationBlock { if windowIndex%frequencyWindows == 0 { - actions = append(actions, ActionDepositSweep) - } - - if windowIndex%frequencyWindows == 0 { - actions = append(actions, ActionMovedFundsSweep) - } - - if windowIndex%frequencyWindows == 0 { - actions = append(actions, ActionMovingFunds) + actions = append( + actions, + ActionDepositSweep, + ActionMovedFundsSweep, + ActionMovingFunds, + ) } } else { actions = append(actions, ActionDepositSweep) @@ -634,6 +627,7 @@ func (ce *coordinationExecutor) getActionsChecklist( // #nosec G404 (insecure random number source (rand)) // Drawing a decision about heartbeat does not require secure randomness. // Use first 8 bytes of the seed to initialize the RNG. + // #nosec G115 -- Preserve all 64 seed bits so existing operators select the same leader/actions. rng := rand.New(rand.NewSource(int64(binary.BigEndian.Uint64(seed[:8])))) if rng.Float64() < coordinationHeartbeatProbability { actions = append(actions, ActionHeartbeat) @@ -685,8 +679,29 @@ func (ce *coordinationExecutor) executeLeaderRoutine( net.BackoffRetransmissionStrategy, ) if err != nil { + if proposal.ActionType() == ActionRedemption { + if ce.metricsRecorder != nil { + ce.metricsRecorder.IncrementCounter(clientinfo.MetricRedemptionProposalBroadcastFailedTotal, 1) + } + logger.With( + zap.String("event", "redemption_proposal_broadcast_failed"), + zap.String("walletPKH", fmt.Sprintf("0x%x", walletPublicKeyHash)), + zap.Uint64("coordinationBlock", coordinationBlock), + zap.Error(err), + ).Error("redemption proposal broadcast to wallet coordination channel failed") + } return nil, fmt.Errorf("failed to send coordination message: [%v]", err) } + if proposal.ActionType() == ActionRedemption { + if ce.metricsRecorder != nil { + ce.metricsRecorder.IncrementCounter(clientinfo.MetricRedemptionProposalBroadcastTotal, 1) + } + logger.With( + zap.String("event", "redemption_proposal_broadcast"), + zap.String("walletPKH", fmt.Sprintf("0x%x", walletPublicKeyHash)), + zap.Uint64("coordinationBlock", coordinationBlock), + ).Info("redemption proposal broadcast to wallet coordination channel") + } return proposal, nil } diff --git a/pkg/tbtc/coordination_test.go b/pkg/tbtc/coordination_test.go index c597048fb0..d292e9c4b5 100644 --- a/pkg/tbtc/coordination_test.go +++ b/pkg/tbtc/coordination_test.go @@ -7,6 +7,7 @@ import ( "fmt" "math/big" "reflect" + "sync" "testing" "time" @@ -644,11 +645,6 @@ func TestCoordinationExecutor_GetActionsChecklist(t *testing.T) { }, } - // Verify that the activation block constant is accessible and typed - // as uint64. This is a compile-time assertion placed outside the test - // loop since it does not vary per subtest. - var _ uint64 = DepositSweepEveryWindowActivationBlock - executor := &coordinationExecutor{} for testName, test := range tests { @@ -786,10 +782,6 @@ func TestCoordinationExecutor_GetActionsChecklist_PostActivation(t *testing.T) { }, } - // Compile-time assertion: DepositSweepEveryWindowActivationBlock must - // be typed as uint64. - var _ uint64 = DepositSweepEveryWindowActivationBlock - executor := &coordinationExecutor{} for testName, test := range tests { @@ -1245,6 +1237,14 @@ func TestCoordinationExecutor_ExecuteFollowerRoutine(t *testing.T) { localChain.Signing(), ) + // Wrap the follower's channel so the sender can wait until the follower + // routine has registered its message handler, rather than guessing with a + // fixed sleep. + followerChannel := &recvSignalingChannel{ + BroadcastChannel: follower1.channel, + recvRegistered: make(chan struct{}), + } + // Set up the executor for follower 1. executor := &coordinationExecutor{ // Set only relevant fields. @@ -1252,7 +1252,7 @@ func TestCoordinationExecutor_ExecuteFollowerRoutine(t *testing.T) { coordinatedWallet: coordinatedWallet, membersIndexes: coordinatedWallet.membersByOperator(follower1.address), operatorAddress: follower1.address, - broadcastChannel: follower1.channel, + broadcastChannel: followerChannel, membershipValidator: membershipValidator, } @@ -1260,9 +1260,13 @@ func TestCoordinationExecutor_ExecuteFollowerRoutine(t *testing.T) { defer cancelCtx() go func() { - // Give the follower routine some time to start and set up the - // broadcast channel handler. - time.Sleep(1 * time.Second) + // Wait until the follower routine has registered its broadcast channel + // handler; otherwise messages sent before registration are dropped. + select { + case <-followerChannel.recvRegistered: + case <-ctx.Done(): + return + } // Send message of wrong type. err := leader.channel.Send(ctx, &signingDoneMessage{ @@ -1557,3 +1561,17 @@ func (mcpg *mockCoordinationProposalGenerator) Generate( mcpg.calls, ) } + +// recvSignalingChannel wraps a broadcast channel and closes recvRegistered the +// first time a handler is installed via Recv. It lets a test deterministically +// wait for the receiver to be ready instead of relying on a fixed sleep. +type recvSignalingChannel struct { + net.BroadcastChannel + recvRegistered chan struct{} + once sync.Once +} + +func (c *recvSignalingChannel) Recv(ctx context.Context, handler func(m net.Message)) { + c.BroadcastChannel.Recv(ctx, handler) + c.once.Do(func() { close(c.recvRegistered) }) +} diff --git a/pkg/tbtc/coordination_window_metrics.go b/pkg/tbtc/coordination_window_metrics.go index 2b57fc4c52..470eadb907 100644 --- a/pkg/tbtc/coordination_window_metrics.go +++ b/pkg/tbtc/coordination_window_metrics.go @@ -2,6 +2,7 @@ package tbtc import ( "fmt" + "sort" "sync" "time" @@ -218,16 +219,13 @@ func (cwm *coordinationWindowMetrics) recordWalletCoordination( wm.WalletsFailed++ } - // Track leader leaderStr := leader.String() wm.Leaders[leaderStr]++ - // Track action type if actionType != "" { wm.ActionTypes[actionType]++ } - // Track faults faultDetails := make([]faultDetail, 0, len(faults)) for _, fault := range faults { faultTypeStr := fault.faultType.String() @@ -285,13 +283,9 @@ func (cwm *coordinationWindowMetrics) GetRecentWindows(limit int) []*windowMetri } // Sort in descending order (most recent first) - for i := 0; i < len(indices)-1; i++ { - for j := i + 1; j < len(indices); j++ { - if indices[i] < indices[j] { - indices[i], indices[j] = indices[j], indices[i] - } - } - } + sort.Slice(indices, func(i, j int) bool { + return indices[i] > indices[j] + }) // Limit results if limit > 0 && limit < len(indices) { @@ -321,17 +315,13 @@ func (cwm *coordinationWindowMetrics) cleanupOldWindows() { } // Sort in ascending order (oldest first) - for i := 0; i < len(indices)-1; i++ { - for j := i + 1; j < len(indices); j++ { - if indices[i] > indices[j] { - indices[i], indices[j] = indices[j], indices[i] - } - } - } + sort.Slice(indices, func(i, j int) bool { + return indices[i] < indices[j] + }) // Remove oldest windows - windowsToRemove := len(cwm.windows) - int(cwm.maxWindowsToTrack) - for i := 0; i < windowsToRemove; i++ { + windowsToRemove := uint64(len(cwm.windows)) - cwm.maxWindowsToTrack + for i := uint64(0); i < windowsToRemove; i++ { delete(cwm.windows, indices[i]) } } diff --git a/pkg/tbtc/coordination_window_metrics_test.go b/pkg/tbtc/coordination_window_metrics_test.go index 274613f765..8d5ceb92fc 100644 --- a/pkg/tbtc/coordination_window_metrics_test.go +++ b/pkg/tbtc/coordination_window_metrics_test.go @@ -346,3 +346,91 @@ func TestCoordinationWindowMetrics_Concurrent(t *testing.T) { _ = cwm.GetSummary() _ = cwm.GetRecentWindows(5) } + +// TestCleanupOldWindows_BoundsMapSize inserts 2000 windows into a store capped +// at 100 and asserts the map never exceeds the cap. This guards against a +// regression where cleanupOldWindows stops enforcing the bound, causing +// unbounded memory growth on long-running nodes. +func TestCleanupOldWindows_BoundsMapSize(t *testing.T) { + const maxWindows = 100 + cwm := newTestWindowMetrics(maxWindows) + leader := chain.Address("0xleader") + + for i := uint64(1); i <= 2000; i++ { + window := newCoordinationWindow(i * 900) + cwm.recordWalletCoordination(window, [20]byte{byte(i % 256)}, leader, "Heartbeat", true, 0, nil, nil) + } + + summary := cwm.GetSummary() + if int(summary.TotalWindows) > maxWindows { + t.Errorf( + "cleanupOldWindows not enforcing bound: got %d windows, want <= %d", + summary.TotalWindows, maxWindows, + ) + } +} + +// --- Benchmarks --- + +func populateWindowMetrics(b *testing.B, cwm *coordinationWindowMetrics, n int) { + b.Helper() + leader := chain.Address("0xleader") + for i := uint64(1); i <= uint64(n); i++ { + window := newCoordinationWindow(i * 900) + cwm.recordWalletCoordination(window, [20]byte{}, leader, "Heartbeat", true, 0, nil, nil) + } +} + +func BenchmarkGetRecentWindows_100Windows(b *testing.B) { + cwm := newTestWindowMetrics(200) + populateWindowMetrics(b, cwm, 100) + b.ResetTimer() + for range b.N { + _ = cwm.GetRecentWindows(100) + } +} + +func BenchmarkGetRecentWindows_1000Windows(b *testing.B) { + cwm := newTestWindowMetrics(2000) + populateWindowMetrics(b, cwm, 1000) + b.ResetTimer() + for range b.N { + _ = cwm.GetRecentWindows(1000) + } +} + +func BenchmarkGetSummary_100Windows(b *testing.B) { + cwm := newTestWindowMetrics(200) + populateWindowMetrics(b, cwm, 100) + b.ResetTimer() + for range b.N { + _ = cwm.GetSummary() + } +} + +func BenchmarkGetSummary_1000Windows(b *testing.B) { + cwm := newTestWindowMetrics(2000) + populateWindowMetrics(b, cwm, 1000) + b.ResetTimer() + for range b.N { + _ = cwm.GetSummary() + } +} + +// BenchmarkCleanupOldWindows_1000Windows measures the O(n^2) bubble-sort +// cleanup pass when the store holds 1000 windows and needs to evict down to +// 900. This catches regressions in the cleanup algorithm before they affect +// long-running nodes. +func BenchmarkCleanupOldWindows_1000Windows(b *testing.B) { + const maxWindows uint64 = 900 + + for range b.N { + b.StopTimer() + cwm := newTestWindowMetrics(maxWindows) + for i := uint64(1); i <= 1000; i++ { + cwm.windows[i] = &windowMetrics{WindowIndex: i} + } + b.StartTimer() + cwm.cleanupOldWindows() + } +} diff --git a/pkg/tbtc/deduplicator.go b/pkg/tbtc/deduplicator.go index 37d0b1704f..5721a006b1 100644 --- a/pkg/tbtc/deduplicator.go +++ b/pkg/tbtc/deduplicator.go @@ -6,7 +6,7 @@ import ( "strconv" "time" - "github.com/keep-network/keep-common/pkg/cache" + "github.com/keep-network/keep-core/pkg/cache" ) const ( @@ -83,7 +83,7 @@ func (d *deduplicator) notifyDKGResultSubmitted( cacheKey := newDKGResultSeed.Text(16) + hex.EncodeToString(newDKGResultHash[:]) + - strconv.Itoa(int(newDKGResultBlock)) + strconv.FormatUint(newDKGResultBlock, 10) // If the key is not in the cache, that means the result was not handled // yet and the client should proceed with the execution. diff --git a/pkg/tbtc/deduplicator_test.go b/pkg/tbtc/deduplicator_test.go index b75432a8c0..3f62041c9e 100644 --- a/pkg/tbtc/deduplicator_test.go +++ b/pkg/tbtc/deduplicator_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - "github.com/keep-network/keep-common/pkg/cache" + "github.com/keep-network/keep-core/pkg/cache" ) const ( diff --git a/pkg/tbtc/deposit_sweep.go b/pkg/tbtc/deposit_sweep.go index e58ee88e25..58ca239375 100644 --- a/pkg/tbtc/deposit_sweep.go +++ b/pkg/tbtc/deposit_sweep.go @@ -11,6 +11,7 @@ import ( "go.uber.org/zap" "github.com/keep-network/keep-core/pkg/bitcoin" + "github.com/keep-network/keep-core/pkg/clientinfo" ) const ( @@ -50,15 +51,45 @@ const ( // the transaction is known on the Bitcoin chain. This delay is needed // as spreading the transaction over the Bitcoin network takes time. depositSweepBroadcastCheckDelay = 1 * time.Minute + // DepositScriptByteSize mirrors tbtcpg.DepositScriptByteSize, the worst-case + // deposit script size used to estimate the sweep transaction virtual size. + // Exported for the external tbtc_test package to compare it against the + // canonical tbtcpg value (guarded by TestSweepFeeConstantsMirrorTbtcpg). + DepositScriptByteSize = 126 ) +// DepositKey identifies a deposit by the outpoint of its funding transaction. +// +// Note: DepositKey is a named type; it replaced the anonymous struct +// previously used inline as the element type of +// DepositSweepProposal.DepositsKeys. Go does not allow assigning an +// anonymous-struct-typed slice literal to a named-struct-typed slice field, +// so code outside this module that builds a DepositSweepProposal from the +// old anonymous struct literal must switch to constructing []DepositKey +// values instead. +// +// Migrating from the old anonymous-struct literal: +// +// // Before: +// DepositsKeys: []struct{ +// FundingTxHash: chain.Hash(...), +// FundingOutputIndex: 0, +// }{...}, +// +// // After: +// DepositsKeys: []DepositKey{ +// {FundingTxHash: chain.Hash(...), FundingOutputIndex: 0}, +// ... +// }, +type DepositKey struct { + FundingTxHash bitcoin.Hash + FundingOutputIndex uint32 +} + // DepositSweepProposal represents a deposit sweep proposal issued by a // wallet's coordination leader. type DepositSweepProposal struct { - DepositsKeys []struct { - FundingTxHash bitcoin.Hash - FundingOutputIndex uint32 - } + DepositsKeys []DepositKey SweepTxFee *big.Int DepositsRevealBlocks []*big.Int } @@ -138,7 +169,7 @@ func (dsa *depositSweepAction) execute() error { // Record deposit sweep execution attempt if dsa.metricsRecorder != nil { - dsa.metricsRecorder.IncrementCounter("deposit_sweep_executions_total", 1) + dsa.metricsRecorder.IncrementCounter(clientinfo.MetricDepositSweepExecutionsTotal, 1) } validateProposalLogger := dsa.logger.With( @@ -157,12 +188,27 @@ func (dsa *depositSweepAction) execute() error { ) if err != nil { if dsa.metricsRecorder != nil { - dsa.metricsRecorder.IncrementCounter("deposit_sweep_executions_failed_total", 1) - dsa.metricsRecorder.RecordDuration("deposit_sweep_execution_duration_seconds", time.Since(executionStartTime)) + dsa.metricsRecorder.IncrementCounter(clientinfo.MetricDepositSweepExecutionsFailedTotal, 1) + dsa.metricsRecorder.RecordDuration(clientinfo.MetricDepositSweepExecutionDurationSeconds, time.Since(executionStartTime)) } return fmt.Errorf("validate proposal step failed: [%v]", err) } + // Follower-side observability for the below-floor sweep-fee soft check + // (threshold-network/keep-core#4171). ValidateDepositSweepProposal only warns + // in the logs when the leader's proposed fee is below the safe minimum; + // surface it as a counter too so operators can alert on underpriced proposals + // during a mixed-version rollout rather than grepping node logs. Log-only, + // like the check itself: the node still signs the proposal. + if dsa.metricsRecorder != nil { + if check, checkErr := checkSweepFeeFloor(dsa.proposal); checkErr == nil && + check.belowFloor { + dsa.metricsRecorder.IncrementCounter( + clientinfo.MetricDepositSweepFeeBelowFloorTotal, 1, + ) + } + } + walletMainUtxo, err := DetermineWalletMainUtxo( walletPublicKeyHash, dsa.chain, @@ -170,8 +216,8 @@ func (dsa *depositSweepAction) execute() error { ) if err != nil { if dsa.metricsRecorder != nil { - dsa.metricsRecorder.IncrementCounter("deposit_sweep_executions_failed_total", 1) - dsa.metricsRecorder.RecordDuration("deposit_sweep_execution_duration_seconds", time.Since(executionStartTime)) + dsa.metricsRecorder.IncrementCounter(clientinfo.MetricDepositSweepExecutionsFailedTotal, 1) + dsa.metricsRecorder.RecordDuration(clientinfo.MetricDepositSweepExecutionDurationSeconds, time.Since(executionStartTime)) } return fmt.Errorf( "error while determining wallet's main UTXO: [%v]", @@ -187,8 +233,8 @@ func (dsa *depositSweepAction) execute() error { ) if err != nil { if dsa.metricsRecorder != nil { - dsa.metricsRecorder.IncrementCounter("deposit_sweep_executions_failed_total", 1) - dsa.metricsRecorder.RecordDuration("deposit_sweep_execution_duration_seconds", time.Since(executionStartTime)) + dsa.metricsRecorder.IncrementCounter(clientinfo.MetricDepositSweepExecutionsFailedTotal, 1) + dsa.metricsRecorder.RecordDuration(clientinfo.MetricDepositSweepExecutionDurationSeconds, time.Since(executionStartTime)) } return fmt.Errorf( "error while ensuring wallet state is synced between "+ @@ -206,8 +252,8 @@ func (dsa *depositSweepAction) execute() error { ) if err != nil { if dsa.metricsRecorder != nil { - dsa.metricsRecorder.IncrementCounter("deposit_sweep_executions_failed_total", 1) - dsa.metricsRecorder.RecordDuration("deposit_sweep_execution_duration_seconds", time.Since(executionStartTime)) + dsa.metricsRecorder.IncrementCounter(clientinfo.MetricDepositSweepExecutionsFailedTotal, 1) + dsa.metricsRecorder.RecordDuration(clientinfo.MetricDepositSweepExecutionDurationSeconds, time.Since(executionStartTime)) } return fmt.Errorf( "error while assembling deposit sweep transaction: [%v]", @@ -222,8 +268,8 @@ func (dsa *depositSweepAction) execute() error { // Just in case. This should never happen. if dsa.proposalExpiryBlock < dsa.signingTimeoutSafetyMarginBlocks { if dsa.metricsRecorder != nil { - dsa.metricsRecorder.IncrementCounter("deposit_sweep_executions_failed_total", 1) - dsa.metricsRecorder.RecordDuration("deposit_sweep_execution_duration_seconds", time.Since(executionStartTime)) + dsa.metricsRecorder.IncrementCounter(clientinfo.MetricDepositSweepExecutionsFailedTotal, 1) + dsa.metricsRecorder.RecordDuration(clientinfo.MetricDepositSweepExecutionDurationSeconds, time.Since(executionStartTime)) } return fmt.Errorf("invalid proposal expiry block") } @@ -237,15 +283,15 @@ func (dsa *depositSweepAction) execute() error { ) if err != nil { if dsa.metricsRecorder != nil { - dsa.metricsRecorder.IncrementCounter("deposit_sweep_executions_failed_total", 1) - dsa.metricsRecorder.RecordDuration("deposit_sweep_execution_duration_seconds", time.Since(executionStartTime)) + dsa.metricsRecorder.IncrementCounter(clientinfo.MetricDepositSweepExecutionsFailedTotal, 1) + dsa.metricsRecorder.RecordDuration(clientinfo.MetricDepositSweepExecutionDurationSeconds, time.Since(executionStartTime)) } return fmt.Errorf("sign transaction step failed: [%v]", err) } // Record deposit sweep transaction signing duration if dsa.metricsRecorder != nil { - dsa.metricsRecorder.RecordDuration("deposit_sweep_tx_signing_duration_seconds", time.Since(signingStartTime)) + dsa.metricsRecorder.RecordDuration(clientinfo.MetricDepositSweepTxSigningDurationSeconds, time.Since(signingStartTime)) } broadcastTxLogger := dsa.logger.With( @@ -261,16 +307,16 @@ func (dsa *depositSweepAction) execute() error { ) if err != nil { if dsa.metricsRecorder != nil { - dsa.metricsRecorder.IncrementCounter("deposit_sweep_executions_failed_total", 1) - dsa.metricsRecorder.RecordDuration("deposit_sweep_execution_duration_seconds", time.Since(executionStartTime)) + dsa.metricsRecorder.IncrementCounter(clientinfo.MetricDepositSweepExecutionsFailedTotal, 1) + dsa.metricsRecorder.RecordDuration(clientinfo.MetricDepositSweepExecutionDurationSeconds, time.Since(executionStartTime)) } return fmt.Errorf("broadcast transaction step failed: [%v]", err) } // Record successful deposit sweep execution if dsa.metricsRecorder != nil { - dsa.metricsRecorder.IncrementCounter("deposit_sweep_executions_success_total", 1) - dsa.metricsRecorder.RecordDuration("deposit_sweep_execution_duration_seconds", time.Since(executionStartTime)) + dsa.metricsRecorder.IncrementCounter(clientinfo.MetricDepositSweepExecutionsSuccessTotal, 1) + dsa.metricsRecorder.RecordDuration(clientinfo.MetricDepositSweepExecutionDurationSeconds, time.Since(executionStartTime)) } return nil @@ -442,11 +488,16 @@ func ValidateDepositSweepProposal( ) } + deposit, err := matchingEvent.unpack(depositRequest.ExtraData) + if err != nil { + return nil, err + } + depositExtraInfo[i] = struct { *Deposit FundingTx *bitcoin.Transaction }{ - Deposit: matchingEvent.unpack(depositRequest.ExtraData), + Deposit: deposit, FundingTx: fundingTx, } } @@ -466,6 +517,41 @@ func ValidateDepositSweepProposal( "deposit sweep proposal is valid", ) + // Follower-side soft check on the proposed fee. The on-chain + // WalletProposalValidator only bounds the sweep fee from above, not below, + // so a misbehaving or unpatched leader can propose a fee at the ~1 sat/vByte + // relay floor that this node would otherwise sign - the same underpricing + // that jams the wallet (see threshold-network/keep-core#4171). We recompute + // the safe minimum (applying the 25% safety buffer that + // tbtcpg.applyWalletTxFeeFloor would also enforce on the leader side) and + // warn if the proposal is below it. + // + // This is intentionally log-only, not a rejection: rejecting a below-floor + // proposal here would, during a mixed-version rollout, split signers (patched + // nodes reject, unpatched nodes sign) and could stall signing. Hard + // enforcement belongs on-chain in the WalletProposalValidator, or behind a + // coordinated all-nodes upgrade. The threshold is recomputed in + // checkSweepFeeFloor using the same buffered floor + // (MinWalletTxSatPerVByteFee + WalletTxFeeBufferPercent) as + // warnIfProposedWalletTxFeeBelowBufferedFloor (proposal_fee_check.go); + // keep the size estimator in checkSweepFeeFloor in sync with the + // leader-side estimator in tbtcpg/deposit_sweep.go. + check, checkErr := checkSweepFeeFloor(proposal) + if checkErr != nil { + validateProposalLogger.Warnf( + "cannot estimate sweep tx size for the fee sanity check: [%v]", + checkErr, + ) + } else { + warnIfProposedWalletTxFeeBelowBufferedFloor( + validateProposalLogger, + MinWalletTxSatPerVByteFee, + check.sweepTxSize, + proposal.SweepTxFee, + "deposit sweep", + ) + } + deposits := make([]*Deposit, len(depositExtraInfo)) for i, dei := range depositExtraInfo { deposits[i] = dei.Deposit @@ -474,6 +560,66 @@ func ValidateDepositSweepProposal( return deposits, nil } +// sweepFeeCheck is the result of the follower-side soft check that recomputes +// the safe buffered-minimum sweep fee and compares it against the leader's +// proposed fee. +type sweepFeeCheck struct { + // sweepTxSize is the estimated virtual size, in vBytes, of the sweep + // transaction described by the proposal. + sweepTxSize int64 + // minSweepTxFee is the safe buffered-minimum total fee - the same + // MinWalletTxSatPerVByteFee/WalletTxFeeBufferPercent policy applied by + // warnIfProposedWalletTxFeeBelowBufferedFloor - the proposal is expected + // to meet or exceed. + minSweepTxFee *big.Int + // belowFloor is true when the proposal fails to meet the safe minimum, + // either because the proposed fee is strictly below minSweepTxFee or because + // no fee is set at all (proposal.SweepTxFee == nil, treated as below floor). + belowFloor bool +} + +// checkSweepFeeFloor recomputes the safe buffered-minimum sweep fee for the +// given proposal - via bufferedWalletTxFeeFloor (proposal_fee_check.go), the +// same helper warnIfProposedWalletTxFeeBelowBufferedFloor uses - and reports +// whether the proposed fee is below it. Extracting the decision from +// ValidateDepositSweepProposal keeps it directly testable (rather than +// asserting on logger output) and lets the follower emit a below-floor metric +// without recomputing the estimate inline. It returns an error only when the +// sweep transaction virtual size cannot be estimated, or when the buffered +// fee floor itself cannot be computed from the operator-configured policy +// (MinWalletTxSatPerVByteFee <= 0, non-positive tx size, or a negative +// WalletTxFeeBufferPercent) - see bufferedWalletTxFeeFloor. +func checkSweepFeeFloor(proposal *DepositSweepProposal) (sweepFeeCheck, error) { + sweepTxSize, err := bitcoin.NewTransactionSizeEstimator(). + AddPublicKeyHashInputs(1, true). + AddScriptHashInputs(len(proposal.DepositsKeys), DepositScriptByteSize, true). + AddPublicKeyHashOutputs(1, true). + VirtualSize() + if err != nil { + return sweepFeeCheck{}, err + } + + _, minSweepTxFee := bufferedWalletTxFeeFloor(MinWalletTxSatPerVByteFee, sweepTxSize) + if minSweepTxFee == nil { + return sweepFeeCheck{}, fmt.Errorf( + "cannot compute the safe buffered minimum sweep fee: degenerate "+ + "policy inputs (MinWalletTxSatPerVByteFee=[%d], "+ + "WalletTxFeeBufferPercent=[%d])", + MinWalletTxSatPerVByteFee, + WalletTxFeeBufferPercent, + ) + } + + belowFloor := proposal.SweepTxFee == nil || + proposal.SweepTxFee.Cmp(minSweepTxFee) < 0 + + return sweepFeeCheck{ + sweepTxSize: sweepTxSize, + minSweepTxFee: minSweepTxFee, + belowFloor: belowFloor, + }, nil +} + func (dsa *depositSweepAction) wallet() wallet { return dsa.sweepingWallet } diff --git a/pkg/tbtc/deposit_sweep_fee_check_test.go b/pkg/tbtc/deposit_sweep_fee_check_test.go new file mode 100644 index 0000000000..ad33796ed3 --- /dev/null +++ b/pkg/tbtc/deposit_sweep_fee_check_test.go @@ -0,0 +1,86 @@ +package tbtc + +import ( + "math/big" + "testing" +) + +// TestCheckSweepFeeFloor covers the follower-side soft check decision that backs +// the below-floor warning and metric (threshold-network/keep-core#4171). It +// exercises the boundary directly - proposals just below, exactly at, and above +// the safe minimum, plus a missing fee - so that a flipped comparison, a dropped +// nil branch, or an off-by-one at the boundary fails here rather than passing CI +// silently. The static drift guard in sweep_fee_sync_test.go does not cover this +// logic. +func TestCheckSweepFeeFloor(t *testing.T) { + proposalWithFee := func(fee *big.Int) *DepositSweepProposal { + return &DepositSweepProposal{ + DepositsKeys: make([]DepositKey, 1), + SweepTxFee: fee, + } + } + + // Read the recomputed safe minimum once so the boundary cases can be built + // relative to it without hard-coding the estimated virtual size. A missing + // fee is treated as below floor, but minSweepTxFee is still computed. + baseline, err := checkSweepFeeFloor(proposalWithFee(nil)) + if err != nil { + t.Fatalf("unexpected error computing baseline: [%v]", err) + } + minFee := baseline.minSweepTxFee + if minFee == nil || minFee.Sign() <= 0 { + t.Fatalf("expected a positive safe-minimum fee, got [%v]", minFee) + } + + oneBelow := new(big.Int).Sub(minFee, big.NewInt(1)) + oneAbove := new(big.Int).Add(minFee, big.NewInt(1)) + + tests := map[string]struct { + fee *big.Int + expectedBelowFloor bool + }{ + "fee missing is treated as below floor": { + fee: nil, + expectedBelowFloor: true, + }, + "fee one satoshi below floor is below floor": { + fee: oneBelow, + expectedBelowFloor: true, + }, + "fee exactly at floor is not below floor": { + fee: new(big.Int).Set(minFee), + expectedBelowFloor: false, + }, + "fee one satoshi above floor is not below floor": { + fee: oneAbove, + expectedBelowFloor: false, + }, + "zero fee is below floor": { + fee: big.NewInt(0), + expectedBelowFloor: true, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + check, err := checkSweepFeeFloor(proposalWithFee(tc.fee)) + if err != nil { + t.Fatalf("unexpected error: [%v]", err) + } + + if check.belowFloor != tc.expectedBelowFloor { + t.Errorf( + "unexpected belowFloor\nexpected: [%t]\nactual: [%t]", + tc.expectedBelowFloor, check.belowFloor, + ) + } + + if check.minSweepTxFee.Cmp(minFee) != 0 { + t.Errorf( + "unexpected minSweepTxFee\nexpected: [%d]\nactual: [%d]", + minFee, check.minSweepTxFee, + ) + } + }) + } +} diff --git a/pkg/tbtc/deposit_sweep_test.go b/pkg/tbtc/deposit_sweep_test.go index 00f501b827..d390f040c9 100644 --- a/pkg/tbtc/deposit_sweep_test.go +++ b/pkg/tbtc/deposit_sweep_test.go @@ -42,10 +42,7 @@ func TestDepositSweepAction_Execute(t *testing.T) { } // depositsKeys will be needed to build the proposal instance. - depositsKeys := make([]struct { - FundingTxHash bitcoin.Hash - FundingOutputIndex uint32 - }, len(scenario.Deposits)) + depositsKeys := make([]DepositKey, len(scenario.Deposits)) // depositsExtraInfo will be needed to perform on-chain proposal // validation. @@ -66,10 +63,7 @@ func TestDepositSweepAction_Execute(t *testing.T) { t.Fatal(err) } - depositsKeys[i] = struct { - FundingTxHash bitcoin.Hash - FundingOutputIndex uint32 - }{ + depositsKeys[i] = DepositKey{ FundingTxHash: fundingTxHash, FundingOutputIndex: fundingOutputIndex, } @@ -319,3 +313,149 @@ func TestAssembleDepositSweepTransaction(t *testing.T) { }) } } + +// capturingLogger wraps testutils.MockLogger and records Warnf calls for +// assertions. +type capturingLogger struct { + testutils.MockLogger + warnings []string +} + +func (cl *capturingLogger) Warnf(format string, args ...interface{}) { + cl.warnings = append(cl.warnings, fmt.Sprintf(format, args...)) +} + +// depositSweepFeeCheckChain is a minimal stub satisfying the chain interface +// ValidateDepositSweepProposal requires. Its ValidateDepositSweepProposal +// unconditionally reports the proposal as valid, and its other two methods +// are never invoked for a proposal with no deposits. This isolates the +// follower-side sweep-fee soft check (deposit_sweep.go, below the +// "calling chain for proposal validation" log line) from on-chain proposal +// validation and deposit-lookup concerns that the soft check does not +// depend on. +type depositSweepFeeCheckChain struct{} + +func (depositSweepFeeCheckChain) PastDepositRevealedEvents( + *DepositRevealedEventFilter, +) ([]*DepositRevealedEvent, error) { + return nil, nil +} + +func (depositSweepFeeCheckChain) ValidateDepositSweepProposal( + [20]byte, + *DepositSweepProposal, + []struct { + *Deposit + FundingTx *bitcoin.Transaction + }, +) error { + return nil +} + +func (depositSweepFeeCheckChain) GetDepositRequest( + bitcoin.Hash, + uint32, +) (*DepositChainRequest, bool, error) { + return nil, false, nil +} + +// TestValidateDepositSweepProposal_SweepFeeSoftCheck exercises the +// follower-side soft check on the leader-proposed sweep fee. The check is +// log-only by design (see threshold-network/keep-core#4171): it must warn +// about an unsafe fee but must never fail proposal validation because of it. +func TestValidateDepositSweepProposal_SweepFeeSoftCheck(t *testing.T) { + var walletPublicKeyHash [20]byte + stubChain := depositSweepFeeCheckChain{} + btcChain := newLocalBitcoinChain() + + // Compute the exact safe-minimum fee for a proposal with no deposits + // using the same estimator call the soft check itself performs + // (deposit_sweep.go), so the boundary between "below" and "at/above" the + // floor is derived rather than hardcoded. The floor is the buffered + // minimum that warnIfProposedWalletTxFeeBelowBufferedFloor + // (proposal_fee_check.go) recomputes from the bare sweep floor using the + // WalletTxFeeBufferPercent mirror (the + // 25% safety buffer that tbtcpg.applyWalletTxFeeFloor also reapplies on + // the leader side). Keeping the formula here in sync with the helper is + // exactly the property this test exercises. + sweepTxSize, err := bitcoin.NewTransactionSizeEstimator(). + AddPublicKeyHashInputs(1, true). + AddScriptHashInputs(0, DepositScriptByteSize, true). + AddPublicKeyHashOutputs(1, true). + VirtualSize() + if err != nil { + t.Fatal(err) + } + bufferedRate := (MinWalletTxSatPerVByteFee*(100+WalletTxFeeBufferPercent) + + 99) / 100 + minBufferedSweepTxFee := big.NewInt(int64(bufferedRate) * sweepTxSize) + + scenarios := map[string]struct { + fee *big.Int + expectWarn bool + }{ + "fee below the safe buffered minimum": { + fee: new(big.Int).Sub(minBufferedSweepTxFee, big.NewInt(1)), + expectWarn: true, + }, + "fee at the safe buffered minimum": { + fee: minBufferedSweepTxFee, + expectWarn: false, + }, + "fee above the safe buffered minimum": { + fee: new(big.Int).Add(minBufferedSweepTxFee, big.NewInt(1000)), + expectWarn: false, + }, + // A nil SweepTxFee cannot occur on the real production path (see the + // comment on the nil case in deposit_sweep.go): the on-chain + // WalletProposalValidator call a few lines above the soft check + // already ABI-packs the fee and panics first, and wire + // deserialization always constructs a non-nil value. This scenario + // exists to lock in the defense-in-depth behavior for callers, like + // this test's stub chain, that can hand the soft check a nil fee + // directly. + "nil fee from a test/mock caller": { + fee: nil, + expectWarn: true, + }, + } + + for name, scenario := range scenarios { + t.Run(name, func(t *testing.T) { + proposal := &DepositSweepProposal{ + SweepTxFee: scenario.fee, + } + + logger := &capturingLogger{} + + _, err := ValidateDepositSweepProposal( + logger, + walletPublicKeyHash, + proposal, + 0, + stubChain, + btcChain, + ) + if err != nil { + t.Fatalf( + "expected the log-only soft check to never fail "+ + "validation; got error: [%v]", + err, + ) + } + + gotWarn := len(logger.warnings) > 0 + if gotWarn != scenario.expectWarn { + t.Errorf( + "unexpected warning presence for fee [%v]\n"+ + "expected warning: %v\nactual warning: %v\n"+ + "captured warnings: %v", + scenario.fee, + scenario.expectWarn, + gotWarn, + logger.warnings, + ) + } + }) + } +} diff --git a/pkg/tbtc/dkg.go b/pkg/tbtc/dkg.go index 4385f25fd1..eb5ecda00b 100644 --- a/pkg/tbtc/dkg.go +++ b/pkg/tbtc/dkg.go @@ -13,11 +13,11 @@ import ( "go.uber.org/zap" "github.com/ipfs/go-log/v2" - "github.com/keep-network/keep-common/pkg/persistence" "github.com/keep-network/keep-core/pkg/chain" "github.com/keep-network/keep-core/pkg/clientinfo" "github.com/keep-network/keep-core/pkg/generator" "github.com/keep-network/keep-core/pkg/net" + "github.com/keep-network/keep-core/pkg/persistence" "github.com/keep-network/keep-core/pkg/protocol/announcer" "github.com/keep-network/keep-core/pkg/protocol/group" "github.com/keep-network/keep-core/pkg/tecdsa/dkg" @@ -506,7 +506,7 @@ func (de *dkgExecutor) registerSigner( de.groupParameters, ) if err != nil { - return nil, fmt.Errorf("failed to resolve final signing group members") + return nil, fmt.Errorf("failed to resolve final signing group members: [%w]", err) } // Just like the final and original group may differ, the diff --git a/pkg/tbtc/dkg_loop.go b/pkg/tbtc/dkg_loop.go index 4b7955abc9..dfbf804e3f 100644 --- a/pkg/tbtc/dkg_loop.go +++ b/pkg/tbtc/dkg_loop.go @@ -5,9 +5,10 @@ import ( "crypto/sha256" "encoding/binary" "fmt" - "github.com/keep-network/keep-core/pkg/protocol/announcer" "math/big" + "github.com/keep-network/keep-core/pkg/protocol/announcer" + "github.com/ipfs/go-log/v2" "github.com/keep-network/keep-core/pkg/chain" "github.com/keep-network/keep-core/pkg/protocol/group" @@ -92,6 +93,7 @@ func newDkgRetryLoop( // care in this piece of the code about the length of the seed and how this // seed is proposed. seedSha256 := sha256.Sum256(seed.Bytes()) + // #nosec G115 -- Preserve all 64 seed bits, including the sign bit, for deterministic retries. attemptSeed := int64(binary.BigEndian.Uint64(seedSha256[:8])) return &dkgRetryLoop{ diff --git a/pkg/tbtc/dkg_test.go b/pkg/tbtc/dkg_test.go index b177e03d10..d6abefd60e 100644 --- a/pkg/tbtc/dkg_test.go +++ b/pkg/tbtc/dkg_test.go @@ -753,11 +753,16 @@ func TestDkgExecutor_ExecuteDkgValidation_ValidResult_NotMember(t *testing.T) { } // TestDkgExecutor_ExecuteDkgValidation_ValidResult_OperatorIDError verifies -// that executeDkgValidation returns gracefully when the result is valid but -// operatorIDFn returns an error (unable to determine operator identity). +// that executeDkgValidation returns before scheduling DKG result approval when +// operatorIDFn fails. Members includes operator ID 0 - the zero value +// operatorIDFn returns alongside its error - so that if the early-return guard +// were dropped, that zero value would spuriously match a member and execution +// would reach DKGParameters(), which dkgParamsTrapChain fails the test on. An +// empty Members slice made this guard unobservable: the "not eligible" branch +// returned cleanly either way. func TestDkgExecutor_ExecuteDkgValidation_ValidResult_OperatorIDError(t *testing.T) { - c := Connect() - c.setDKGResultValidity(true) + c := &dkgParamsTrapChain{Connect(), t} + c.localChain.setDKGResultValidity(true) de := &dkgExecutor{ chain: c, @@ -766,7 +771,25 @@ func TestDkgExecutor_ExecuteDkgValidation_ValidResult_OperatorIDError(t *testing }, } - de.executeDkgValidation(big.NewInt(1), 0, &DKGChainResult{}, [32]byte{}) + result := &DKGChainResult{ + Members: chain.OperatorIDs{0, 2, 3, 4, 5}, + } + + de.executeDkgValidation(big.NewInt(1), 0, result, [32]byte{}) +} + +// dkgParamsTrapChain wraps localChain and fails the test if DKGParameters is +// called, proving that executeDkgValidation stops before reaching the +// approval-scheduling logic when operatorIDFn fails. +type dkgParamsTrapChain struct { + *localChain + t *testing.T +} + +func (c *dkgParamsTrapChain) DKGParameters() (*DKGParameters, error) { + c.t.Helper() + c.t.Fatal("DKGParameters should not be called when operatorIDFn fails") + return nil, nil } // TestDkgExecutor_ExecuteDkgValidation_ValidResult_MemberDKGParamsError verifies diff --git a/pkg/tbtc/fuzz_test.go b/pkg/tbtc/fuzz_test.go new file mode 100644 index 0000000000..6e5aa1fe3a --- /dev/null +++ b/pkg/tbtc/fuzz_test.go @@ -0,0 +1,212 @@ +package tbtc + +import ( + "bytes" + "encoding/binary" + "math" + "math/big" + "testing" +) + +// FuzzDepositSweepProposalRoundTrip exercises marshal and unmarshal of +// DepositSweepProposal across the accepted field domain, including reveal blocks +// at the top of the uint64 range that a fixed-count generator loop rarely reaches. +// +// Scope, stated precisely because it is easy to overstate: this target builds its +// proposals directly and clamps the fields itself, so it does NOT exercise +// fuzzDepositSweepProposal and would NOT fail if that generator were regressed to +// emitting unbounded reveal blocks again. The guard against that is +// TestFuzzDepositSweepProposalGeneratorContract in marshaling_test.go. +// +// What this target does guard is Marshal and Unmarshal themselves: that every +// value the marshaler claims to accept, notably a reveal block at 2^64-1, really +// does survive the round trip unchanged. +func FuzzDepositSweepProposalRoundTrip(f *testing.F) { + // Seed 1: Empty and all-zero inputs (zero fee, zero keys, zero reveal blocks). + f.Add([]byte{}) + f.Add([]byte{0x00}) + f.Add(make([]byte, 48)) + + // Seed 2: Small inputs producing small fees, indices, and reveal blocks. + f.Add([]byte{0x01}) + f.Add([]byte{0x00, 0x01, 0x00, 0x00, 0x03, 0xe8}) + + smallSeed := make([]byte, 0, 48) + smallSeed = append(smallSeed, 0x08) // fee len + smallSeed = append(smallSeed, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00}...) // fee = 256 + var smallHash [32]byte + smallHash[0] = 0x01 + smallSeed = append(smallSeed, smallHash[:]...) + smallSeed = binary.BigEndian.AppendUint32(smallSeed, 1) + smallSeed = binary.BigEndian.AppendUint64(smallSeed, 500) + f.Add(smallSeed) + + // Seed 3: Large in-range values near the top of the accepted domain [0, 2^64) + // including reveal blocks equal to MaxUint64 (2^64 - 1), max uint32 output index, + // and maximum 256-bit fee. + maxSeed := make([]byte, 0, 80) + maxSeed = append(maxSeed, 32) // fee len: 32 bytes of 0xFF + maxSeed = append(maxSeed, bytes.Repeat([]byte{0xFF}, 32)...) + maxSeed = append(maxSeed, bytes.Repeat([]byte{0xFF}, 32)...) // 32-byte hash + maxSeed = binary.BigEndian.AppendUint32(maxSeed, math.MaxUint32) + maxSeed = binary.BigEndian.AppendUint64(maxSeed, math.MaxUint64) // 2^64 - 1 + f.Add(maxSeed) + + f.Add(bytes.Repeat([]byte{0xFF}, 128)) + + f.Fuzz(func(t *testing.T, data []byte) { + proposal := buildFuzzedDepositSweepProposal(data) + + marshaled, err := proposal.Marshal() + if err != nil { + t.Fatalf("failed to marshal valid DepositSweepProposal: %v", err) + } + + unmarshaled := &DepositSweepProposal{} + if err := unmarshaled.Unmarshal(marshaled); err != nil { + t.Fatalf("failed to unmarshal DepositSweepProposal: %v", err) + } + + // Explicit field-by-field equality comparison to ensure exact mathematical + // value checks for *big.Int pointers and detailed diagnostic output on mismatch. + assertDepositSweepProposalEqual(t, proposal, unmarshaled) + }) +} + +func buildFuzzedDepositSweepProposal(data []byte) *DepositSweepProposal { + mod := new(big.Int).Lsh(big.NewInt(1), 64) + + if len(data) == 0 { + return &DepositSweepProposal{ + DepositsKeys: []DepositKey{}, + SweepTxFee: big.NewInt(0), + DepositsRevealBlocks: []*big.Int{}, + } + } + + r := bytes.NewReader(data) + + // 1. Fee: read 0..32 bytes and convert to non-negative *big.Int + feeLenByte, err := r.ReadByte() + if err != nil { + feeLenByte = 0 + } + feeLen := int(feeLenByte % 33) + feeBuf := make([]byte, feeLen) + _, _ = r.Read(feeBuf) + sweepTxFee := new(big.Int).SetBytes(feeBuf) + + // 2. DepositsKeys: read chunks of 36 bytes (32 bytes hash + 4 bytes index) + keys := make([]DepositKey, 0) + for r.Len() >= 36 { + var hash [32]byte + _, _ = r.Read(hash[:]) + var indexBuf [4]byte + _, _ = r.Read(indexBuf[:]) + index := binary.BigEndian.Uint32(indexBuf[:]) + keys = append(keys, DepositKey{ + FundingTxHash: hash, + FundingOutputIndex: index, + }) + } + + // 3. DepositsRevealBlocks: chunk remaining bytes into 8-byte uint64s / big.Ints + // clamped to [0, 2^64) + revealBlocks := make([]*big.Int, 0) + for r.Len() >= 8 { + var blockBuf [8]byte + _, _ = r.Read(blockBuf[:]) + val := binary.BigEndian.Uint64(blockBuf[:]) + revealBlocks = append(revealBlocks, new(big.Int).SetUint64(val)) + } + + // Any remaining bytes are turned into a big.Int mod 2^64 + if r.Len() > 0 { + remBuf := make([]byte, r.Len()) + _, _ = r.Read(remBuf) + block := new(big.Int).SetBytes(remBuf) + block.Mod(block, mod) + revealBlocks = append(revealBlocks, block) + } + + return &DepositSweepProposal{ + DepositsKeys: keys, + SweepTxFee: sweepTxFee, + DepositsRevealBlocks: revealBlocks, + } +} + +func assertDepositSweepProposalEqual(t *testing.T, expected, actual *DepositSweepProposal) { + t.Helper() + + if (expected == nil) != (actual == nil) { + t.Fatalf("proposal nilness mismatch: expected %v, got %v", expected, actual) + } + if expected == nil { + return + } + + // DepositsKeys comparison + if len(expected.DepositsKeys) != len(actual.DepositsKeys) { + t.Fatalf( + "DepositsKeys length mismatch: expected %d, got %d", + len(expected.DepositsKeys), + len(actual.DepositsKeys), + ) + } + for i := range expected.DepositsKeys { + if expected.DepositsKeys[i] != actual.DepositsKeys[i] { + t.Fatalf( + "DepositsKeys[%d] mismatch:\nexpected: %+v\nactual: %+v", + i, + expected.DepositsKeys[i], + actual.DepositsKeys[i], + ) + } + } + + // SweepTxFee comparison (*big.Int.Cmp) + if (expected.SweepTxFee == nil) != (actual.SweepTxFee == nil) { + t.Fatalf( + "SweepTxFee nilness mismatch: expected %v, got %v", + expected.SweepTxFee, + actual.SweepTxFee, + ) + } + if expected.SweepTxFee != nil && expected.SweepTxFee.Cmp(actual.SweepTxFee) != 0 { + t.Fatalf( + "SweepTxFee mismatch:\nexpected: %s\nactual: %s", + expected.SweepTxFee.String(), + actual.SweepTxFee.String(), + ) + } + + // DepositsRevealBlocks comparison (*big.Int.Cmp) + if len(expected.DepositsRevealBlocks) != len(actual.DepositsRevealBlocks) { + t.Fatalf( + "DepositsRevealBlocks length mismatch: expected %d, got %d", + len(expected.DepositsRevealBlocks), + len(actual.DepositsRevealBlocks), + ) + } + for i := range expected.DepositsRevealBlocks { + expBlock := expected.DepositsRevealBlocks[i] + actBlock := actual.DepositsRevealBlocks[i] + if (expBlock == nil) != (actBlock == nil) { + t.Fatalf( + "DepositsRevealBlocks[%d] nilness mismatch: expected %v, got %v", + i, + expBlock, + actBlock, + ) + } + if expBlock != nil && expBlock.Cmp(actBlock) != 0 { + t.Fatalf( + "DepositsRevealBlocks[%d] mismatch:\nexpected: %s\nactual: %s", + i, + expBlock.String(), + actBlock.String(), + ) + } + } +} diff --git a/pkg/tbtc/integer_conversion_test.go b/pkg/tbtc/integer_conversion_test.go new file mode 100644 index 0000000000..2a8dcb5a84 --- /dev/null +++ b/pkg/tbtc/integer_conversion_test.go @@ -0,0 +1,81 @@ +package tbtc + +import ( + "math" + "math/big" + "testing" + + "google.golang.org/protobuf/proto" + + "github.com/keep-network/keep-core/pkg/tbtc/gen/pb" +) + +func TestSignerUnmarshalMemberIndexBounds(t *testing.T) { + original, err := createMockSigner(t).Marshal() + if err != nil { + t.Fatal(err) + } + message := new(pb.Signer) + if err := proto.Unmarshal(original, message); err != nil { + t.Fatal(err) + } + for _, index := range []uint32{0, 1, 255, 256, math.MaxUint32} { + message.SigningGroupMemberIndex = index + data, err := proto.Marshal(message) + if err != nil { + t.Fatal(err) + } + decoded := new(signer) + err = decoded.Unmarshal(data) + if index == 0 || index > 255 { + if err == nil { + t.Fatalf("accepted invalid index %d", index) + } + } else if err != nil || uint32(decoded.signingGroupMemberIndex) != index { + t.Fatalf("index %d: got %d, %v", index, decoded.signingGroupMemberIndex, err) + } + } +} + +func TestDepositRevealBlockUnsignedRoundtrip(t *testing.T) { + blocks := []uint64{0, math.MaxInt64, math.MaxInt64 + 1, math.MaxUint64} + original := &DepositSweepProposal{SweepTxFee: big.NewInt(1)} + for _, block := range blocks { + original.DepositsRevealBlocks = append(original.DepositsRevealBlocks, new(big.Int).SetUint64(block)) + } + data, err := original.Marshal() + if err != nil { + t.Fatal(err) + } + decoded := new(DepositSweepProposal) + if err := decoded.Unmarshal(data); err != nil { + t.Fatal(err) + } + for i, want := range original.DepositsRevealBlocks { + if decoded.DepositsRevealBlocks[i].Cmp(want) != 0 { + t.Fatalf("block %d: got %v, want %v", i, decoded.DepositsRevealBlocks[i], want) + } + } +} + +func TestDepositRevealBlockMarshalBounds(t *testing.T) { + for _, block := range []*big.Int{nil, big.NewInt(-1), new(big.Int).Lsh(big.NewInt(1), 64)} { + proposal := &DepositSweepProposal{SweepTxFee: big.NewInt(1), DepositsRevealBlocks: []*big.Int{block}} + if _, err := proposal.Marshal(); err == nil { + t.Fatalf("accepted block %v", block) + } + } +} + +func TestDepositRevealedEventAmountBounds(t *testing.T) { + for _, value := range []uint64{0, 1, math.MaxInt64, math.MaxInt64 + 1, math.MaxUint64} { + deposit, err := (&DepositRevealedEvent{Amount: value}).unpack(nil) + if value > math.MaxInt64 { + if err == nil { + t.Fatalf("accepted amount %d", value) + } + } else if err != nil || uint64(deposit.Utxo.Value) != value { + t.Fatalf("amount %d: got %v, %v", value, deposit, err) + } + } +} diff --git a/pkg/tbtc/internal/test/manifest_test.go b/pkg/tbtc/internal/test/manifest_test.go new file mode 100644 index 0000000000..130d1c36b0 --- /dev/null +++ b/pkg/tbtc/internal/test/manifest_test.go @@ -0,0 +1,120 @@ +package test + +import ( + "os" + "path/filepath" + "runtime" + "testing" +) + +// Required fixture files in pkg/tbtc/internal/test/testdata. +// These slices explicitly enumerate all fixture files required by the test +// suite. Directory globbing is avoided because a glob that matches nothing +// would pass silently. +var ( + requiredDepositSweepFixtures = []string{ + "deposit_sweep_scenario_0.json", + "deposit_sweep_scenario_1.json", + "deposit_sweep_scenario_2.json", + "deposit_sweep_scenario_3.json", + "deposit_sweep_scenario_4.json", + } + + requiredRedemptionFixtures = []string{ + "redemption_scenario_0.json", + "redemption_scenario_1.json", + "redemption_scenario_2.json", + "redemption_scenario_3.json", + "redemption_scenario_4.json", + "redemption_scenario_5.json", + } + + requiredMovingFundsFixtures = []string{ + "moving_funds_scenario_0.json", + "moving_funds_scenario_1.json", + "moving_funds_scenario_2.json", + } + + requiredMovedFundsSweepFixtures = []string{ + "moved_funds_sweep_scenario_0.json", + "moved_funds_sweep_scenario_1.json", + } +) + +// TestRequiredFixturesPresent guards the test fixtures in testdata against +// accidental deletion or omission. +func TestRequiredFixturesPresent(t *testing.T) { + _, callerFileName, _, _ := runtime.Caller(0) + testDataDir := filepath.Join(filepath.Dir(callerFileName), "testdata") + + tests := []struct { + name string + required []string + load func() (int, error) + }{ + { + name: "DepositSweep", + required: requiredDepositSweepFixtures, + load: func() (int, error) { + scenarios, err := LoadDepositSweepTestScenarios() + return len(scenarios), err + }, + }, + { + name: "Redemption", + required: requiredRedemptionFixtures, + load: func() (int, error) { + scenarios, err := LoadRedemptionTestScenarios() + return len(scenarios), err + }, + }, + { + name: "MovingFunds", + required: requiredMovingFundsFixtures, + load: func() (int, error) { + scenarios, err := LoadMovingFundsTestScenarios() + return len(scenarios), err + }, + }, + { + name: "MovedFundsSweep", + required: requiredMovedFundsSweepFixtures, + load: func() (int, error) { + scenarios, err := LoadMovedFundsSweepTestScenarios() + return len(scenarios), err + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + if len(tc.required) == 0 { + t.Fatal("manifest is empty") + } + + for _, fileName := range tc.required { + filePath := filepath.Join(testDataDir, fileName) + if _, err := os.Stat(filePath); err != nil { + t.Errorf("missing required fixture file [%s]: %v", fileName, err) + } + } + + count, err := tc.load() + if err != nil { + t.Fatalf("loader failed: %v", err) + } + + if count == 0 { + t.Fatal("loader returned 0 scenarios") + } + + if count != len(tc.required) { + t.Errorf( + "unexpected scenario count: got %d, want %d", + count, + len(tc.required), + ) + } + }) + } +} diff --git a/pkg/tbtc/marshaling.go b/pkg/tbtc/marshaling.go index 02b5195e45..4b2b469a65 100644 --- a/pkg/tbtc/marshaling.go +++ b/pkg/tbtc/marshaling.go @@ -61,6 +61,11 @@ func (s *signer) Unmarshal(bytes []byte) error { return fmt.Errorf("cannot unmarshal signer: [%w]", err) } + memberIndex, err := group.MemberIndexFromUint32NonZero(pbSigner.SigningGroupMemberIndex) + if err != nil { + return err + } + walletPublicKey, err := unmarshalPublicKey(pbSigner.Wallet.PublicKey) if err != nil { return fmt.Errorf("cannot unmarshal wallet public key: [%w]", err) @@ -84,7 +89,7 @@ func (s *signer) Unmarshal(bytes []byte) error { publicKey: walletPublicKey, signingGroupOperators: walletSigningGroupOperators, } - s.signingGroupMemberIndex = group.MemberIndex(pbSigner.SigningGroupMemberIndex) + s.signingGroupMemberIndex = memberIndex s.privateKeyShare = privateKeyShare return nil @@ -113,7 +118,8 @@ func (sdm *signingDoneMessage) Unmarshal(bytes []byte) error { return fmt.Errorf("failed to unmarshal SigningDoneMessage: [%v]", err) } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } @@ -122,7 +128,7 @@ func (sdm *signingDoneMessage) Unmarshal(bytes []byte) error { return fmt.Errorf("cannot unmarshal signature: [%v]", err) } - sdm.senderID = group.MemberIndex(pbMsg.SenderID) + sdm.senderID = senderID sdm.message = new(big.Int).SetBytes(pbMsg.Message) sdm.attemptNumber = pbMsg.AttemptNumber sdm.signature = signature @@ -160,7 +166,8 @@ func (cm *coordinationMessage) Unmarshal(bytes []byte) error { return fmt.Errorf("failed to unmarshal CoordinationMessage: [%v]", err) } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } @@ -183,7 +190,7 @@ func (cm *coordinationMessage) Unmarshal(bytes []byte) error { return fmt.Errorf("failed to unmarshal proposal: [%v]", err) } - cm.senderID = group.MemberIndex(pbMsg.SenderID) + cm.senderID = senderID cm.coordinationBlock = pbMsg.CoordinationBlock cm.walletPublicKeyHash = walletPublicKeyHash cm.proposal = proposal @@ -306,6 +313,9 @@ func (dsp *DepositSweepProposal) Marshal() ([]byte, error) { depositsRevealBlocks := make([]uint64, len(dsp.DepositsRevealBlocks)) for i, block := range dsp.DepositsRevealBlocks { + if block == nil || !block.IsUint64() { + return nil, fmt.Errorf("invalid deposit reveal block: [%v]", block) + } depositsRevealBlocks[i] = block.Uint64() } @@ -326,10 +336,7 @@ func (dsp *DepositSweepProposal) Unmarshal(bytes []byte) error { } depositsKeys := make( - []struct { - FundingTxHash bitcoin.Hash - FundingOutputIndex uint32 - }, + []DepositKey, len(pbMsg.DepositsKeys), ) for i, depositKey := range pbMsg.DepositsKeys { @@ -344,10 +351,7 @@ func (dsp *DepositSweepProposal) Unmarshal(bytes []byte) error { ) } - depositsKeys[i] = struct { - FundingTxHash bitcoin.Hash - FundingOutputIndex uint32 - }{ + depositsKeys[i] = DepositKey{ FundingTxHash: hash, FundingOutputIndex: depositKey.FundingOutputIndex, } @@ -355,7 +359,7 @@ func (dsp *DepositSweepProposal) Unmarshal(bytes []byte) error { depositsRevealBlocks := make([]*big.Int, len(pbMsg.DepositsRevealBlocks)) for i, block := range pbMsg.DepositsRevealBlocks { - depositsRevealBlocks[i] = big.NewInt(int64(block)) + depositsRevealBlocks[i] = new(big.Int).SetUint64(block) } dsp.DepositsKeys = depositsKeys @@ -481,12 +485,3 @@ func marshalPublicKey(publicKey *ecdsa.PublicKey) ([]byte, error) { func unmarshalPublicKey(bytes []byte) (*ecdsa.PublicKey, error) { return secp256k1.Unmarshal(bytes) } - -func validateMemberIndex(protoIndex uint32) error { - // Protobuf does not have uint8 type, so we are using uint32. When - // unmarshalling message, we need to make sure we do not overflow. - if protoIndex > group.MaxMemberIndex { - return fmt.Errorf("invalid member index value: [%v]", protoIndex) - } - return nil -} diff --git a/pkg/tbtc/marshaling_test.go b/pkg/tbtc/marshaling_test.go index 32b6977f0a..c588c5aff2 100644 --- a/pkg/tbtc/marshaling_test.go +++ b/pkg/tbtc/marshaling_test.go @@ -53,7 +53,8 @@ func TestSignerMarshalling_NonTECDSAKey(t *testing.T) { func TestSignerUnmarshalling_InvalidPublicKey(t *testing.T) { marshaled, err := proto.Marshal(&pb.Signer{ - Wallet: &pb.Wallet{PublicKey: []byte{0x04}}, + Wallet: &pb.Wallet{PublicKey: []byte{0x04}}, + SigningGroupMemberIndex: 1, }) if err != nil { t.Fatal(err) @@ -131,12 +132,14 @@ func TestFuzzSigningDoneMessage_MarshalingRoundtrip(t *testing.T) { endBlock: endBlock, } - _ = pbutils.RoundTrip(doneMessage, &signingDoneMessage{}) + if err := pbutils.RoundTrip(doneMessage, &signingDoneMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzSigningDoneMessage_Unmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&signingDoneMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&signingDoneMessage{}) } func TestCoordinationMessage_MarshalingRoundtrip(t *testing.T) { @@ -186,10 +189,7 @@ func TestCoordinationMessage_MarshalingRoundtrip(t *testing.T) { }, "with deposit sweep proposal": { proposal: &DepositSweepProposal{ - DepositsKeys: []struct { - FundingTxHash bitcoin.Hash - FundingOutputIndex uint32 - }{ + DepositsKeys: []DepositKey{ { FundingTxHash: parseHash("709b55bd3da0f5a838125bd0ee20c5bfdd7caba173912d4281cae816b79a201b"), FundingOutputIndex: 0, @@ -282,7 +282,81 @@ func TestFuzzCoordinationMessage_MarshalingRoundtrip_WithHeartbeatProposal(t *te proposal: &proposal, } - _ = pbutils.RoundTrip(coordinationMsg, &coordinationMessage{}) + if err := pbutils.RoundTrip(coordinationMsg, &coordinationMessage{}); err != nil { + t.Fatal(err) + } + } +} + +// fuzzDepositSweepProposal generates a DepositSweepProposal that survives +// DepositSweepProposal.Marshal. Marshal rejects a reveal block that is nil or +// does not fit a uint64 ("invalid deposit reveal block", pkg/tbtc/marshaling.go), +// so every block must land in [0, 2^64). +// +// The default *big.Int generator in pbutils.FuzzFuncs() fills up to 512 +// big.Words, so a raw fuzzed block essentially never fits a uint64 and the +// round trip could never succeed - which the discarded error used to hide. +// Fuzz with the default field generators (FuzzNoCustom, so this function does +// not recurse), then clamp each block into the accepted range. +// +// The nil branch is defensive only: gofuzz allocates a pointer before invoking +// a custom func registered for that pointer type, so *big.Int fields are never +// nil while fuzzBigInt is registered. It matters if that registration is ever +// dropped, because Marshal dereferences SweepTxFee unconditionally and +// (*big.Int)(nil).Bytes() panics. +func fuzzDepositSweepProposal() func(*DepositSweepProposal, fuzz.Continue) { + mod := new(big.Int).Lsh(big.NewInt(1), 64) + + return func(proposal *DepositSweepProposal, c fuzz.Continue) { + c.FuzzNoCustom(proposal) + + for i, block := range proposal.DepositsRevealBlocks { + if block == nil { + block = new(big.Int) + proposal.DepositsRevealBlocks[i] = block + } + block.Mod(block, mod) + } + } +} + +// TestFuzzDepositSweepProposalGeneratorContract pins the contract the +// round-trip test above depends on: every proposal fuzzDepositSweepProposal +// emits must be marshalable. Dropping the clamp makes the round-trip test fail +// with "invalid deposit reveal block" only when a fuzzed block happens to +// exceed a uint64, so assert the contract directly instead of relying on the +// round-trip test's ten samples to notice. +func TestFuzzDepositSweepProposalGeneratorContract(t *testing.T) { + f := fuzz.New().NilChance(0.1). + NumElements(0, 512). + Funcs(append(pbutils.FuzzFuncs(), fuzzDepositSweepProposal())...) + + for i := 0; i < 200; i++ { + var proposal DepositSweepProposal + + f.Fuzz(&proposal) + + if proposal.SweepTxFee == nil { + t.Fatal("generated a nil SweepTxFee; Marshal would panic on it") + } + + for j, block := range proposal.DepositsRevealBlocks { + if block == nil { + t.Fatalf("generated a nil reveal block at index [%d]", j) + } + if !block.IsUint64() { + t.Fatalf( + "generated reveal block at index [%d] does not fit a "+ + "uint64: [%v]", + j, + block, + ) + } + } + + if _, err := proposal.Marshal(); err != nil { + t.Fatal(err) + } } } @@ -297,7 +371,7 @@ func TestFuzzCoordinationMessage_MarshalingRoundtrip_WithDepositSweepProposal(t f := fuzz.New().NilChance(0.1). NumElements(0, 512). - Funcs(pbutils.FuzzFuncs()...) + Funcs(append(pbutils.FuzzFuncs(), fuzzDepositSweepProposal())...) f.Fuzz(&senderID) f.Fuzz(&coordinationBlock) @@ -311,7 +385,9 @@ func TestFuzzCoordinationMessage_MarshalingRoundtrip_WithDepositSweepProposal(t proposal: &proposal, } - _ = pbutils.RoundTrip(coordinationMsg, &coordinationMessage{}) + if err := pbutils.RoundTrip(coordinationMsg, &coordinationMessage{}); err != nil { + t.Fatal(err) + } } } @@ -340,7 +416,9 @@ func TestFuzzCoordinationMessage_MarshalingRoundtrip_WithRedemptionProposal(t *t proposal: &proposal, } - _ = pbutils.RoundTrip(coordinationMsg, &coordinationMessage{}) + if err := pbutils.RoundTrip(coordinationMsg, &coordinationMessage{}); err != nil { + t.Fatal(err) + } } } @@ -369,7 +447,9 @@ func TestFuzzCoordinationMessage_MarshalingRoundtrip_WithMovingFundsProposal(t * proposal: &proposal, } - _ = pbutils.RoundTrip(coordinationMsg, &coordinationMessage{}) + if err := pbutils.RoundTrip(coordinationMsg, &coordinationMessage{}); err != nil { + t.Fatal(err) + } } } @@ -398,7 +478,9 @@ func TestFuzzCoordinationMessage_MarshalingRoundtrip_WithMovedFundsSweepProposal proposal: &proposal, } - _ = pbutils.RoundTrip(coordinationMsg, &coordinationMessage{}) + if err := pbutils.RoundTrip(coordinationMsg, &coordinationMessage{}); err != nil { + t.Fatal(err) + } } } @@ -427,10 +509,12 @@ func TestFuzzCoordinationMessage_MarshalingRoundtrip_WithNoopProposal(t *testing proposal: &proposal, } - _ = pbutils.RoundTrip(coordinationMsg, &coordinationMessage{}) + if err := pbutils.RoundTrip(coordinationMsg, &coordinationMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzCoordinationMessage_Unmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&coordinationMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&coordinationMessage{}) } diff --git a/pkg/tbtc/moving_funds.go b/pkg/tbtc/moving_funds.go index ef246d29aa..f23dee5463 100644 --- a/pkg/tbtc/moving_funds.go +++ b/pkg/tbtc/moving_funds.go @@ -7,9 +7,9 @@ import ( "github.com/ipfs/go-log/v2" - "github.com/keep-network/keep-common/pkg/chain/ethereum" "github.com/keep-network/keep-core/pkg/bitcoin" "github.com/keep-network/keep-core/pkg/chain" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil" "go.uber.org/zap" ) @@ -350,9 +350,60 @@ func ValidateMovingFundsProposal( validateProposalLogger.Infof("moving funds proposal is valid") + // Follower-side soft check on the proposed fee. The on-chain + // WalletProposalValidator only bounds the moving-funds fee from above, not + // below, so a misbehaving or unpatched leader can propose a fee at the + // ~1 sat/vByte relay floor that this node would otherwise sign - the same + // underpricing that jams the wallet (see + // threshold-network/keep-core#4171). We recompute the safe minimum + // (applying the 25% safety buffer that tbtcpg.applyWalletTxFeeFloor would + // also enforce on the leader side) and warn if the proposal is below it. + // + // This is intentionally log-only, not a rejection: rejecting a below-floor + // proposal here would, during a mixed-version rollout, split signers + // (patched nodes reject, unpatched nodes sign) and could stall signing. + // Hard enforcement belongs on-chain in the WalletProposalValidator, or + // behind a coordinated all-nodes upgrade. The threshold is recomputed in + // warnIfProposedWalletTxFeeBelowBufferedFloor (proposal_fee_check.go); + // keep the size estimator below in sync with the leader-side estimator + // in tbtcpg/moving_funds.go. + if movingFundsTxSize, sizeErr := bitcoin.NewTransactionSizeEstimator(). + AddPublicKeyHashInputs(1, true). + AddPublicKeyHashOutputs(len(proposal.TargetWallets), true). + VirtualSize(); sizeErr != nil { + validateProposalLogger.Warnf( + "cannot estimate moving funds tx size for the fee sanity "+ + "check: [%v]", + sizeErr, + ) + } else { + warnIfProposedWalletTxFeeBelowBufferedFloor( + validateProposalLogger, + MinWalletTxSatPerVByteFee, + movingFundsTxSize, + proposal.MovingFundsTxFee, + "moving funds", + ) + } + return nil } +// movingFundsSafetyMarginChain is the chain interface required to evaluate the +// moving funds safety margin and to determine whether a wallet is a pending +// moving funds target. +type movingFundsSafetyMarginChain interface { + BlockCounter() (chain.BlockCounter, error) + + GetWallet(walletPublicKeyHash [20]byte) (*WalletChainData, error) + + GetMovingFundsParameters() (MovingFundsParameters, error) + + PastMovingFundsCommitmentSubmittedEvents( + filter *MovingFundsCommitmentSubmittedEventFilter, + ) ([]*MovingFundsCommitmentSubmittedEvent, error) +} + // ValidateMovingFundsSafetyMargin checks if the moving funds safety margin // is in force. // @@ -370,17 +421,7 @@ func ValidateMovingFundsProposal( // wallets. In this case a longer safety margin should be used. func ValidateMovingFundsSafetyMargin( walletPublicKeyHash [20]byte, - chain interface { - BlockCounter() (chain.BlockCounter, error) - - GetWallet(walletPublicKeyHash [20]byte) (*WalletChainData, error) - - GetMovingFundsParameters() (MovingFundsParameters, error) - - PastMovingFundsCommitmentSubmittedEvents( - filter *MovingFundsCommitmentSubmittedEventFilter, - ) ([]*MovingFundsCommitmentSubmittedEvent, error) - }, + chain movingFundsSafetyMarginChain, ) error { // In most cases the safety margin of 24 hours should be enough. It will // allow the wallet to sweep the last deposits that were made before the @@ -447,17 +488,7 @@ func (mfa *movingFundsAction) actionType() WalletActionType { func isWalletPendingMovingFundsTarget( walletPublicKeyHash [20]byte, - chain interface { - BlockCounter() (chain.BlockCounter, error) - - GetWallet(walletPublicKeyHash [20]byte) (*WalletChainData, error) - - GetMovingFundsParameters() (MovingFundsParameters, error) - - PastMovingFundsCommitmentSubmittedEvents( - filter *MovingFundsCommitmentSubmittedEventFilter, - ) ([]*MovingFundsCommitmentSubmittedEvent, error) - }, + chain movingFundsSafetyMarginChain, ) (bool, error) { blockCounter, err := chain.BlockCounter() if err != nil { diff --git a/pkg/tbtc/node.go b/pkg/tbtc/node.go index fcf71ed5cb..5fd9f5aa3d 100644 --- a/pkg/tbtc/node.go +++ b/pkg/tbtc/node.go @@ -10,9 +10,9 @@ import ( "github.com/keep-network/keep-core/pkg/chain" "github.com/keep-network/keep-core/pkg/clientinfo" - "github.com/keep-network/keep-common/pkg/persistence" "github.com/keep-network/keep-core/pkg/generator" "github.com/keep-network/keep-core/pkg/net" + "github.com/keep-network/keep-core/pkg/persistence" ) const ( @@ -130,6 +130,11 @@ func newNode( proposalGenerator CoordinationProposalGenerator, config Config, ) (*node, error) { + transactionMonitor, err := newTransactionMonitor(btcChain, config.TransactionMonitor) + if err != nil { + return nil, err + } + walletRegistry, err := newWalletRegistry( keyStorePersistance, chain.CalculateWalletID, @@ -154,7 +159,7 @@ func newNode( inactivityClaimExecutors: make(map[string]*inactivityClaimExecutor), coordinationExecutors: make(map[string]*coordinationExecutor), proposalGenerator: proposalGenerator, - transactionMonitor: newTransactionMonitor(btcChain), + transactionMonitor: transactionMonitor, } // Archive any wallets that might have been closed or terminated while the @@ -228,6 +233,13 @@ func (n *node) setPerformanceMetrics(metrics interface { }); ok { pg.SetRedemptionMetricsRecorder(metrics) } + if pg, ok := n.proposalGenerator.(interface { + SetProposalMetricsRecorder(recorder interface { + IncrementCounter(name string, value float64) + }) + }); ok { + pg.SetProposalMetricsRecorder(metrics) + } // Update metrics recorder for all cached coordination executors // This is important because executors may be created before metrics are set diff --git a/pkg/tbtc/node_test.go b/pkg/tbtc/node_test.go index a756c69595..797fc35118 100644 --- a/pkg/tbtc/node_test.go +++ b/pkg/tbtc/node_test.go @@ -10,13 +10,13 @@ import ( "testing" "time" - "github.com/keep-network/keep-common/pkg/persistence" "github.com/keep-network/keep-core/internal/testutils" "github.com/keep-network/keep-core/pkg/bitcoin" "github.com/keep-network/keep-core/pkg/chain" "github.com/keep-network/keep-core/pkg/generator" "github.com/keep-network/keep-core/pkg/internal/tecdsatest" "github.com/keep-network/keep-core/pkg/net/local" + "github.com/keep-network/keep-core/pkg/persistence" "github.com/keep-network/keep-core/pkg/protocol/group" "github.com/keep-network/keep-core/pkg/tecdsa" ) @@ -50,6 +50,11 @@ func TestNode_GetSigningExecutor(t *testing.T) { // Populate the mock keystore with the mock signer's data. This is // required to make the node controlling the signer's wallet. keyStorePersistence := createMockKeyStorePersistence(t, signer) + nodeConfig := Config{ + PreParamsPoolSize: 1, + PreParamsGenerationTimeout: time.Hour, + TransactionMonitor: TransactionMonitorConfig{StuckThreshold: 45 * time.Minute}, + } node, err := newNode( groupParameters, @@ -60,11 +65,14 @@ func TestNode_GetSigningExecutor(t *testing.T) { &mockPersistenceHandle{}, newTestScheduler(t), &mockCoordinationProposalGenerator{}, - Config{PreParamsPoolSize: 1, PreParamsGenerationTimeout: time.Hour}, + nodeConfig, ) if err != nil { t.Fatal(err) } + if node.transactionMonitor.config.StuckThreshold != nodeConfig.TransactionMonitor.StuckThreshold { + t.Fatal("node did not pass its transaction monitor configuration to the monitor") + } walletPublicKey := signer.wallet.publicKey walletPublicKeyBytes, err := marshalPublicKey(walletPublicKey) diff --git a/pkg/tbtc/node_wallet_closure.go b/pkg/tbtc/node_wallet_closure.go index 25b5f68c71..a4667ae933 100644 --- a/pkg/tbtc/node_wallet_closure.go +++ b/pkg/tbtc/node_wallet_closure.go @@ -3,8 +3,8 @@ package tbtc import ( "fmt" - "github.com/keep-network/keep-common/pkg/chain/ethereum" "github.com/keep-network/keep-core/pkg/bitcoin" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil" ) // archiveClosedWallets archives closed or terminated wallets. diff --git a/pkg/tbtc/proposal_fee_check.go b/pkg/tbtc/proposal_fee_check.go new file mode 100644 index 0000000000..de99fc54c8 --- /dev/null +++ b/pkg/tbtc/proposal_fee_check.go @@ -0,0 +1,154 @@ +package tbtc + +import ( + "math/big" + + "github.com/ipfs/go-log/v2" +) + +// warnIfProposedWalletTxFeeBelowBufferedFloor is the follower-side soft +// (log-only, never rejects) check used by every wallet-tx proposal +// validator in this package: deposit sweep, redemption, and moving +// funds. It compares the leader's proposed total fee against the safe +// buffered minimum that tbtcpg.applyWalletTxFeeFloor would enforce for +// the same bare floor and vsize, so patched followers warn at the same +// threshold the leader was supposed to produce. The buffer is reapplied +// here because a leader proposing exactly-at-floor would otherwise slip +// past a bare-floor check and undersell the tx. +// +// The floor and the buffer percentage are read from the canonical +// package vars MinWalletTxSatPerVByteFee / WalletTxFeeBufferPercent +// (declared in tbtc.go), which Initialize populates from Config. +// tbtcpg.applyWalletTxFeeFloor reads the same vars, so a single source +// of truth is enforced - tuning the policy from the operator side +// automatically tunes both the leader-side floor application and the +// follower-side soft check. +// +// The threshold is computed with arbitrary-precision big.Int arithmetic +// (the proposed fee is already *big.Int, so this avoids both an int64 +// overflow on the buffered-rate product and a lossy conversion of +// minBufferedFee back into int64). The leader-side floor helper applies +// the same buffer formula with checked-arithmetic guards and returns +// ErrMaxFeeTooLow on implausible inputs; on such inputs the follower +// just sees a buffered fee above any reasonable proposed total and the +// check stays quiet, which is the same observable behavior as a leader +// that refused to broadcast. +// +// This is intentionally log-only, not a rejection: rejecting a +// below-floor proposal here would, during a mixed-version rollout, +// split signers (patched nodes reject, unpatched nodes sign) and could +// stall signing. Hard enforcement belongs on-chain in the +// WalletProposalValidator, or behind a coordinated all-nodes upgrade; +// see threshold-network/keep-core#4171. +// +// satPerVByteFloor is the bare minimum per-vByte fee rate (sat/vByte); +// pass MinWalletTxSatPerVByteFee for sweep/redemption/moving-funds +// validators. +// txVsize is the estimated transaction virtual size in vBytes, as +// returned by the caller-specific bitcoin.TransactionSizeEstimator. +// proposedFee is the leader's proposed total fee in satoshis; nil is +// treated as "no fee set" (defense-in-depth for test/mock chains; +// unreachable on the real production path where on-chain validation has +// already ABI-packed the fee and panicked on nil). +// actionLabel identifies the proposal type in the log message +// (e.g. "deposit sweep", "redemption", "moving funds"). +func warnIfProposedWalletTxFeeBelowBufferedFloor( + logger log.StandardLogger, + satPerVByteFloor int64, + txVsize int64, + proposedFee *big.Int, + actionLabel string, +) { + bufferedRate, minBufferedFee := bufferedWalletTxFeeFloor(satPerVByteFloor, txVsize) + if minBufferedFee == nil { + // Degenerate inputs; the caller has already surfaced the underlying + // estimation error (size estimator failure, nil fee that panicked in + // on-chain validation, etc.). This helper never escalates failures; + // it only adds a warning when the inputs are usable. + return + } + + switch { + // This branch is defense-in-depth for test/mock chain implementations + // and is not expected to be reachable on the real production path: + // by the time control reaches the validator, on-chain + // WalletProposalValidator has already ABI-packed the fee and panics + // on a nil *big.Int before this code ever runs. Likewise, a proposal + // decoded off the wire (Unmarshal in marshaling.go) always + // constructs the fee via new(big.Int).SetBytes(...), which never + // yields nil. + case proposedFee == nil: + logger.Warnf( + "%s proposal has no tx fee set; expected at least the safe "+ + "buffered minimum [%v] ([%v] buffered sat/vByte = [%d] "+ + "bare floor * %d%% buffer * [%d] vByte)", + actionLabel, + minBufferedFee, + bufferedRate, + satPerVByteFloor, + WalletTxFeeBufferPercent, + txVsize, + ) + case proposedFee.Cmp(minBufferedFee) < 0: + logger.Warnf( + "proposed %s tx fee [%v] is below the safe buffered minimum "+ + "[%v] ([%v] buffered sat/vByte = [%d] bare floor * %d%% "+ + "buffer * [%d] vByte); the leader may be underpricing the "+ + "tx, which risks it getting stuck in the mempool and "+ + "jamming the wallet", + actionLabel, + proposedFee, + minBufferedFee, + bufferedRate, + satPerVByteFloor, + WalletTxFeeBufferPercent, + txVsize, + ) + } +} + +// bufferedWalletTxFeeFloor computes the safe buffered minimum total fee (in +// satoshis) for a wallet tx of the given virtual size, applying the same +// MinWalletTxSatPerVByteFee/WalletTxFeeBufferPercent policy enforced by +// warnIfProposedWalletTxFeeBelowBufferedFloor above. It also returns the +// buffered per-vByte rate used to compute that fee, for inclusion in log +// messages. Extracted so callers that only need the below-floor boolean +// (e.g. the deposit sweep fee metric in checkSweepFeeFloor) share the exact +// same threshold as the log warning, rather than risking the two drifting +// apart. +// +// Both return values are nil on degenerate inputs (satPerVByteFloor <= 0, +// txVsize <= 0, or a negative buffer percent). +func bufferedWalletTxFeeFloor( + satPerVByteFloor int64, + txVsize int64, +) (bufferedRate, minBufferedFee *big.Int) { + if satPerVByteFloor <= 0 || txVsize <= 0 || WalletTxFeeBufferPercent < 0 { + return nil, nil + } + + // Compute the buffered threshold with arbitrary-precision arithmetic + // so an operator-tuned policy (large satPerVByteFloor or buffer + // ratio) cannot overflow int64 in this helper. The leader-side + // tbtcpg.applyWalletTxFeeFloor applies the same buffer formula but + // with checked-arithmetic guards and returns an error on the same + // implausible inputs; here the threshold simply ends up large enough + // that no realistic proposed fee trips the warning. + satPerVByte := big.NewInt(satPerVByteFloor) + numerator := new(big.Int).Add( + big.NewInt(100), + big.NewInt(WalletTxFeeBufferPercent), + ) + denominator := big.NewInt(100) + delta := big.NewInt(99) + + // bufferedRate = ceil(satPerVByteFloor * (100+Percent) / 100). + bufferedRate = new(big.Int).Mul(satPerVByte, numerator) + bufferedRate.Add(bufferedRate, delta) + bufferedRate.Quo(bufferedRate, denominator) + + // minBufferedFee = bufferedRate * txVsize. + minBufferedFee = new(big.Int).Mul(bufferedRate, big.NewInt(txVsize)) + + return bufferedRate, minBufferedFee +} diff --git a/pkg/tbtc/proposal_fee_check_test.go b/pkg/tbtc/proposal_fee_check_test.go new file mode 100644 index 0000000000..2b7999b787 --- /dev/null +++ b/pkg/tbtc/proposal_fee_check_test.go @@ -0,0 +1,237 @@ +package tbtc + +import ( + "fmt" + "math" + "math/big" + "testing" + + "github.com/ipfs/go-log/v2" +) + +// capturingFeeCheckLogger is a test double for log.StandardLogger that +// records every Warnf call so the follower-side soft check can be +// asserted on directly. +type capturingFeeCheckLogger struct { + warnings []string +} + +func (cl *capturingFeeCheckLogger) Warnf(format string, args ...interface{}) { + cl.warnings = append(cl.warnings, fmt.Sprintf(format, args...)) +} + +func (cl *capturingFeeCheckLogger) Errorf(format string, args ...interface{}) {} +func (cl *capturingFeeCheckLogger) Infof(format string, args ...interface{}) {} +func (cl *capturingFeeCheckLogger) Debugf(format string, args ...interface{}) {} +func (cl *capturingFeeCheckLogger) Warn(args ...interface{}) {} +func (cl *capturingFeeCheckLogger) Error(args ...interface{}) {} +func (cl *capturingFeeCheckLogger) Info(args ...interface{}) {} +func (cl *capturingFeeCheckLogger) Debug(args ...interface{}) {} +func (cl *capturingFeeCheckLogger) Fatal(args ...interface{}) {} +func (cl *capturingFeeCheckLogger) Fatalf(format string, args ...interface{}) {} +func (cl *capturingFeeCheckLogger) Panic(args ...interface{}) {} +func (cl *capturingFeeCheckLogger) Panicf(format string, args ...interface{}) {} + +// TestWarnIfProposedWalletTxFeeBelowBufferedFloor exercises the +// follower-side soft check end-to-end. The buffered threshold is +// derived from the policy vars + txVsize the same way the helper does +// (with big.Int math) so the boundary between "warn" and "no warn" +// is computed, not hardcoded. +func TestWarnIfProposedWalletTxFeeBelowBufferedFloor(t *testing.T) { + const vsize = 200 + + expectedBufferedRate := new(big.Int).Mul( + big.NewInt(MinWalletTxSatPerVByteFee), + new(big.Int).Add(big.NewInt(100), big.NewInt(WalletTxFeeBufferPercent)), + ) + expectedBufferedRate.Add( + expectedBufferedRate, + big.NewInt(99), + ) + expectedBufferedRate.Quo( + expectedBufferedRate, + big.NewInt(100), + ) + expectedMinBufferedFee := new(big.Int).Mul( + expectedBufferedRate, + big.NewInt(vsize), + ) + + scenarios := map[string]struct { + fee *big.Int + expectWarn bool + }{ + "fee below the safe buffered minimum": { + fee: new(big.Int).Sub(expectedMinBufferedFee, big.NewInt(1)), + expectWarn: true, + }, + "fee at the safe buffered minimum": { + fee: expectedMinBufferedFee, + expectWarn: false, + }, + "fee above the safe buffered minimum": { + fee: new(big.Int).Add(expectedMinBufferedFee, big.NewInt(1000)), + expectWarn: false, + }, + "nil fee from a test/mock caller": { + fee: nil, + expectWarn: true, + }, + } + + for name, scenario := range scenarios { + t.Run(name, func(t *testing.T) { + logger := &capturingFeeCheckLogger{} + + warnIfProposedWalletTxFeeBelowBufferedFloor( + logger, + MinWalletTxSatPerVByteFee, + vsize, + scenario.fee, + "test", + ) + + gotWarn := len(logger.warnings) > 0 + if gotWarn != scenario.expectWarn { + t.Errorf( + "unexpected warning presence for fee [%v]\n"+ + "expected warning: %v\nactual warning: %v\n"+ + "captured warnings: %v", + scenario.fee, + scenario.expectWarn, + gotWarn, + logger.warnings, + ) + } + }) + } +} + +// TestWarnIfProposedWalletTxFeeBelowBufferedFloor_OverflowBoundary locks +// in the big.Int arithmetic path: with a policy that would overflow +// int64 in naive (rate*Numerator or bufferedRate*txVsize) math, the +// helper still computes a correct threshold and warns only for fees +// that are actually below it. The leader-side tbtcpg.applyWalletTxFeeFloor +// rejects the same implausible input with a checked-arithmetic error; +// the follower-side helper has no MaxInt64 ceiling, so a leader that +func TestWarnIfProposedWalletTxFeeBelowBufferedFloor_OverflowBoundary(t *testing.T) { + const vsize = 200 + + originalFloor := MinWalletTxSatPerVByteFee + originalPercent := WalletTxFeeBufferPercent + t.Cleanup(func() { + MinWalletTxSatPerVByteFee = originalFloor + WalletTxFeeBufferPercent = originalPercent + }) + + // Percent set so numerator (100+Percent) is MaxInt64, so + // rate * numerator would overflow int64 in naive math. The big.Int + // path should compute a threshold of satPerVByteFloor * MaxInt64 + // sat/vByte / 100 * vsize vByte = 5 * MaxInt64 / 100 * 200 total, + // which no int64 fee can ever reach, so every realistic proposal + // trips the warning. + MinWalletTxSatPerVByteFee = 5 + WalletTxFeeBufferPercent = math.MaxInt64 - 100 + + logger := &capturingFeeCheckLogger{} + warnIfProposedWalletTxFeeBelowBufferedFloor( + logger, + MinWalletTxSatPerVByteFee, + vsize, + big.NewInt(1_000_000_000), // 1e9 sat, normal fee + "test", + ) + + if len(logger.warnings) == 0 { + t.Errorf( + "expected a warning for a normal fee under a MaxInt64-buffered " + + "threshold (the buffered minimum exceeds any int64 fee, so " + + "every realistic proposal trips the warning); got no warnings", + ) + } + + // And a nil fee still warns ... + logger = &capturingFeeCheckLogger{} + warnIfProposedWalletTxFeeBelowBufferedFloor( + logger, + MinWalletTxSatPerVByteFee, + vsize, + nil, + "test", + ) + if len(logger.warnings) == 0 { + t.Errorf( + "expected a warning for nil proposed fee regardless of " + + "buffered threshold", + ) + } + + // Percent > math.MaxInt64 - 100: where 100 + WalletTxFeeBufferPercent + // would wrap to negative in naive int64 math. With big.Int operations, + // the numerator does not wrap, producing positive bufferedRate and minBufferedFee. + t.Run("buffer percent exceeding MaxInt64 minus 100 does not wrap", func(t *testing.T) { + WalletTxFeeBufferPercent = math.MaxInt64 - 50 + + bufferedRate, minBufferedFee := bufferedWalletTxFeeFloor( + MinWalletTxSatPerVByteFee, + vsize, + ) + if bufferedRate == nil || minBufferedFee == nil { + t.Fatalf("expected non-nil buffered rate and fee") + } + if bufferedRate.Sign() <= 0 || minBufferedFee.Sign() <= 0 { + t.Fatalf( + "expected positive buffered rate and fee, got rate=[%v], fee=[%v]", + bufferedRate, + minBufferedFee, + ) + } + + testLogger := &capturingFeeCheckLogger{} + warnIfProposedWalletTxFeeBelowBufferedFloor( + testLogger, + MinWalletTxSatPerVByteFee, + vsize, + big.NewInt(1_000_000_000), + "test", + ) + if len(testLogger.warnings) == 0 { + t.Errorf("expected warning for fee under huge buffered threshold") + } + }) + + t.Run("buffer percent at MaxInt64 does not wrap", func(t *testing.T) { + WalletTxFeeBufferPercent = math.MaxInt64 + + bufferedRate, minBufferedFee := bufferedWalletTxFeeFloor( + MinWalletTxSatPerVByteFee, + vsize, + ) + if bufferedRate == nil || minBufferedFee == nil { + t.Fatalf("expected non-nil buffered rate and fee") + } + if bufferedRate.Sign() <= 0 || minBufferedFee.Sign() <= 0 { + t.Fatalf( + "expected positive buffered rate and fee, got rate=[%v], fee=[%v]", + bufferedRate, + minBufferedFee, + ) + } + + testLogger := &capturingFeeCheckLogger{} + warnIfProposedWalletTxFeeBelowBufferedFloor( + testLogger, + MinWalletTxSatPerVByteFee, + vsize, + big.NewInt(1_000_000_000), + "test", + ) + if len(testLogger.warnings) == 0 { + t.Errorf("expected warning for fee under MaxInt64 buffered threshold") + } + }) +} + +// Compile-time check that capturingFeeCheckLogger satisfies the +// log.StandardLogger interface used by warnIfProposedWalletTxFeeBelowBufferedFloor. +var _ log.StandardLogger = (*capturingFeeCheckLogger)(nil) diff --git a/pkg/tbtc/proposal_metrics_test.go b/pkg/tbtc/proposal_metrics_test.go new file mode 100644 index 0000000000..d1349b4ef2 --- /dev/null +++ b/pkg/tbtc/proposal_metrics_test.go @@ -0,0 +1,99 @@ +package tbtc + +import ( + "context" + "errors" + "testing" + "time" + + "github.com/keep-network/keep-core/pkg/clientinfo" + "github.com/keep-network/keep-core/pkg/net" + "github.com/keep-network/keep-core/pkg/protocol/group" +) + +type proposalCounter map[string]float64 + +func (m proposalCounter) IncrementCounter(name string, value float64) { m[name] += value } +func (m proposalCounter) SetGauge(string, float64) {} +func (m proposalCounter) RecordDuration(string, time.Duration) {} + +type proposalBroadcast struct { + net.BroadcastChannel + err error + message *coordinationMessage +} + +func (b *proposalBroadcast) Send(_ context.Context, message net.TaggedMarshaler, _ ...net.RetransmissionStrategy) error { + b.message = message.(*coordinationMessage) + return b.err +} + +func TestRedemptionProposalBroadcastMetrics(t *testing.T) { + for _, test := range []struct { + name string + proposal CoordinationProposal + err error + disabled bool + sent float64 + failed float64 + }{ + {"redemption sent", &RedemptionProposal{}, nil, false, 1, 0}, + {"redemption send fails", &RedemptionProposal{}, errors.New("broadcast unavailable"), false, 0, 1}, + {"no-op is not a redemption", &NoopProposal{}, nil, false, 0, 0}, + {"other action fails", &HeartbeatProposal{}, errors.New("broadcast unavailable"), false, 0, 0}, + {"disabled metrics", &RedemptionProposal{}, nil, true, 0, 0}, + } { + t.Run(test.name, func(t *testing.T) { + channel := &proposalBroadcast{err: test.err} + executor := &coordinationExecutor{ + coordinatedWallet: createMockSigner(t).wallet, + membersIndexes: []group.MemberIndex{2, 1}, + broadcastChannel: channel, + proposalGenerator: newMockCoordinationProposalGenerator(func([20]byte, []WalletActionType, uint) (CoordinationProposal, error) { + return test.proposal, nil + }), + } + recorder := proposalCounter{} + if !test.disabled { + executor.setMetricsRecorder(recorder) + } + _, err := executor.executeLeaderRoutine(context.Background(), 900, []WalletActionType{ActionRedemption}) + if (err != nil) != (test.err != nil) { + t.Fatalf("unexpected result: %v", err) + } + if channel.message == nil || channel.message.coordinationBlock != 900 || channel.message.proposal != test.proposal { + t.Fatal("expected the original proposal to be passed to broadcast") + } + if recorder[clientinfo.MetricRedemptionProposalBroadcastTotal] != test.sent || recorder[clientinfo.MetricRedemptionProposalBroadcastFailedTotal] != test.failed { + t.Fatalf("unexpected broadcast counters: %v", recorder) + } + }) + } +} + +type proposalMetricsSetter struct { + CoordinationProposalGenerator + recorder interface{ IncrementCounter(string, float64) } +} + +func (p *proposalMetricsSetter) SetProposalMetricsRecorder(recorder interface{ IncrementCounter(string, float64) }) { + p.recorder = recorder +} + +func TestNodeWiresProposalMetrics(t *testing.T) { + generator := &proposalMetricsSetter{} + n := &node{proposalGenerator: generator} + recorder := proposalCounter{} + n.setPerformanceMetrics(recorder) + if generator.recorder == nil { + t.Fatal("proposal generator did not receive the metrics recorder") + } + generator.recorder.IncrementCounter("wiring-test", 1) + if recorder["wiring-test"] != 1 { + t.Fatal("node passed the wrong recorder") + } + n.setPerformanceMetrics(nil) + if generator.recorder != nil { + t.Fatal("disabling node metrics must clear the generator recorder") + } +} diff --git a/pkg/tbtc/redemption.go b/pkg/tbtc/redemption.go index 8be91350c9..3813b0b5e8 100644 --- a/pkg/tbtc/redemption.go +++ b/pkg/tbtc/redemption.go @@ -3,6 +3,7 @@ package tbtc import ( "crypto/ecdsa" "fmt" + "math" "math/big" "time" @@ -348,6 +349,66 @@ func ValidateRedemptionProposal( "redemption proposal is valid", ) + // Follower-side soft check on the proposed fee. The on-chain + // WalletProposalValidator only bounds the redemption fee from above, not + // below, so a misbehaving or unpatched leader can propose a fee at the + // ~1 sat/vByte relay floor that this node would otherwise sign - the same + // underpricing that jams the wallet (see + // threshold-network/keep-core#4171). We recompute the safe minimum + // (applying the 25% safety buffer that tbtcpg.applyWalletTxFeeFloor would + // also enforce on the leader side) and warn if the proposal is below it. + // + // This is intentionally log-only, not a rejection: rejecting a below-floor + // proposal here would, during a mixed-version rollout, split signers + // (patched nodes reject, unpatched nodes sign) and could stall signing. + // Hard enforcement belongs on-chain in the WalletProposalValidator, or + // behind a coordinated all-nodes upgrade. The threshold is recomputed in + // warnIfProposedWalletTxFeeBelowBufferedFloor (proposal_fee_check.go); + // keep the size estimator below in sync with the leader-side estimator + // in tbtcpg/redemptions.go. + sizeEstimator := bitcoin.NewTransactionSizeEstimator(). + AddPublicKeyHashInputs(1, true). + AddPublicKeyHashOutputs(1, true) + canEstimate := true + for _, script := range proposal.RedeemersOutputScripts { + switch bitcoin.GetScriptType(script) { + case bitcoin.P2PKHScript: + sizeEstimator.AddPublicKeyHashOutputs(1, false) + case bitcoin.P2WPKHScript: + sizeEstimator.AddPublicKeyHashOutputs(1, true) + case bitcoin.P2SHScript: + sizeEstimator.AddScriptHashOutputs(1, false) + case bitcoin.P2WSHScript: + sizeEstimator.AddScriptHashOutputs(1, true) + default: + validateProposalLogger.Warnf( + "cannot estimate redemption tx size for the fee sanity " + + "check: non-standard redeemer output script type", + ) + canEstimate = false + } + if !canEstimate { + break + } + } + if canEstimate { + if redemptionTxSize, sizeErr := sizeEstimator.VirtualSize(); sizeErr != nil { + validateProposalLogger.Warnf( + "cannot estimate redemption tx size for the fee sanity "+ + "check: [%v]", + sizeErr, + ) + } else { + warnIfProposedWalletTxFeeBelowBufferedFloor( + validateProposalLogger, + MinWalletTxSatPerVByteFee, + redemptionTxSize, + proposal.RedemptionTxFee, + "redemption", + ) + } + } + requests := make([]*RedemptionRequest, len(proposal.RedeemersOutputScripts)) for i, script := range proposal.RedeemersOutputScripts { requestDisplayIndex := fmt.Sprintf( @@ -481,7 +542,14 @@ func assembleRedemptionTransaction( // The redeemable amount for a redemption request is the difference // between the requested amount and treasury fee computed upon // request creation. - redeemableAmount := int64(request.RequestedAmount - request.TreasuryFee) + if request.TreasuryFee > request.RequestedAmount { + return nil, fmt.Errorf("treasury fee exceeds requested amount") + } + amount := request.RequestedAmount - request.TreasuryFee + if amount > math.MaxInt64 { + return nil, fmt.Errorf("redeemable amount exceeds int64 range: [%v]", amount) + } + redeemableAmount := int64(amount) // The actual value of the redemption output is the difference between // the request's redeemable amount and share of the transaction fee // incurred by the given request. diff --git a/pkg/tbtc/redemption_test.go b/pkg/tbtc/redemption_test.go index f4fccb1ee8..4745687424 100644 --- a/pkg/tbtc/redemption_test.go +++ b/pkg/tbtc/redemption_test.go @@ -2,7 +2,10 @@ package tbtc import ( "context" + "fmt" + "math" "math/big" + "reflect" "testing" "time" @@ -270,6 +273,77 @@ func TestAssembleRedemptionTransaction(t *testing.T) { } } +func TestAssembleRedemptionTransaction_ValidationErrors(t *testing.T) { + scenarios, err := test.LoadRedemptionTestScenarios() + if err != nil { + t.Fatal(err) + } + scenario := scenarios[0] + + var tests = map[string]struct { + requestedAmount uint64 + treasuryFee uint64 + expectedError error + }{ + "treasury fee exceeds requested amount": { + requestedAmount: 10000, + treasuryFee: 10001, + expectedError: fmt.Errorf("treasury fee exceeds requested amount"), + }, + "redeemable amount exceeds int64 range": { + requestedAmount: math.MaxUint64, + treasuryFee: 0, + expectedError: fmt.Errorf( + "redeemable amount exceeds int64 range: [%v]", + uint64(math.MaxUint64), + ), + }, + } + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + bitcoinChain := newLocalBitcoinChain() + + err := bitcoinChain.BroadcastTransaction(scenario.InputTransaction) + if err != nil { + t.Fatal(err) + } + + requests := []*RedemptionRequest{ + { + Redeemer: scenario.RedemptionRequests[0].Redeemer, + RedeemerOutputScript: scenario.RedemptionRequests[0].RedeemerOutputScript, + RequestedAmount: test.requestedAmount, + TreasuryFee: test.treasuryFee, + TxMaxFee: scenario.RedemptionRequests[0].TxMaxFee, + RequestedAt: scenario.RedemptionRequests[0].RequestedAt, + }, + } + + feeDistribution := func(requests []*RedemptionRequest) []int64 { + return []int64{0} + } + + _, err = assembleRedemptionTransaction( + bitcoinChain, + scenario.WalletPublicKey, + scenario.WalletMainUtxo, + requests, + feeDistribution, + RedemptionChangeLast, + ) + + if !reflect.DeepEqual(test.expectedError, err) { + t.Errorf( + "unexpected error\nexpected: %v\nactual: %v\n", + test.expectedError, + err, + ) + } + }) + } +} + func TestWithRedemptionTotalFee(t *testing.T) { var tests = map[string]struct { totalFee int64 diff --git a/pkg/tbtc/registry.go b/pkg/tbtc/registry.go index 8e5e33595d..7578e67284 100644 --- a/pkg/tbtc/registry.go +++ b/pkg/tbtc/registry.go @@ -9,7 +9,7 @@ import ( "github.com/keep-network/keep-core/pkg/bitcoin" "github.com/keep-network/keep-core/pkg/crypto/secp256k1" - "github.com/keep-network/keep-common/pkg/persistence" + "github.com/keep-network/keep-core/pkg/persistence" ) // CalculateWalletIDFunc calculates the ECDSA wallet ID based on the provided diff --git a/pkg/tbtc/registry_test.go b/pkg/tbtc/registry_test.go index f0d4964ce1..a347f64cea 100644 --- a/pkg/tbtc/registry_test.go +++ b/pkg/tbtc/registry_test.go @@ -10,8 +10,8 @@ import ( "github.com/keep-network/keep-core/pkg/bitcoin" "github.com/keep-network/keep-core/pkg/tecdsa" - "github.com/keep-network/keep-common/pkg/persistence" "github.com/keep-network/keep-core/internal/testutils" + "github.com/keep-network/keep-core/pkg/persistence" ) func TestWalletRegistry_RegisterSigner(t *testing.T) { @@ -182,7 +182,6 @@ func TestWalletRegistry_getWalletByID(t *testing.T) { t.Fatal(err) } - // walletPublicKeyHash := bitcoin.PublicKeyHash(signer.wallet.publicKey) walletID, err := chain.CalculateWalletID(signer.wallet.publicKey) if err != nil { t.Fatal(err) diff --git a/pkg/tbtc/signing_loop.go b/pkg/tbtc/signing_loop.go index 7e787f1975..e57e522768 100644 --- a/pkg/tbtc/signing_loop.go +++ b/pkg/tbtc/signing_loop.go @@ -113,6 +113,7 @@ func newSigningRetryLoop( // not care in this piece of the code about the length of the message and // how this message is proposed. messageSha256 := sha256.Sum256(message.Bytes()) + // #nosec G115 -- Preserve all 64 seed bits, including the sign bit, for deterministic retries. attemptSeed := int64(binary.BigEndian.Uint64(messageSha256[:8])) return &signingRetryLoop{ @@ -532,11 +533,10 @@ func (srl *signingRetryLoop) excludedMembersIndexes( // Make sure we always use just the smallest required count of // signing members for performance reasons if len(includedMembersIndexes) > srl.groupParameters.HonestThreshold { - // #nosec G404 (insecure random number source (rand)) - // Shuffling does not require secure randomness. - rng := rand.New(rand.NewSource( - srl.attemptSeed + int64(srl.attemptCounter), - )) + // #nosec G115 -- Retry seed arithmetic intentionally wraps modulo 2^64 for compatibility. + seed := srl.attemptSeed + int64(srl.attemptCounter) + // #nosec G404 -- Shuffling does not require secure randomness. + rng := rand.New(rand.NewSource(seed)) // Sort in ascending order just in case. sort.Slice(includedMembersIndexes, func(i, j int) bool { return includedMembersIndexes[i] < includedMembersIndexes[j] diff --git a/pkg/tbtc/signing_loop_test.go b/pkg/tbtc/signing_loop_test.go index 5d9a5caaf6..bd674032ed 100644 --- a/pkg/tbtc/signing_loop_test.go +++ b/pkg/tbtc/signing_loop_test.go @@ -16,15 +16,29 @@ import ( "github.com/keep-network/keep-core/pkg/tecdsa/signing" ) -func TestSigningRetryLoop(t *testing.T) { - message := big.NewInt(100) +type signingRetryLoopTestCase struct { + signingGroupMemberIndex group.MemberIndex + ctxFn func() (context.Context, context.CancelFunc) + currentBlockFn getCurrentBlockFn + incomingAnnouncementsFn func(sessionID string) ([]group.MemberIndex, error) + signingAttemptFn signingAttemptFn + waitUntilAllDoneOutcomeFn func(attemptNumber uint64) (*signing.Result, uint64, error) + expectedOutgoingDoneChecks []*signingDoneMessage + expectedErr error + expectedResult *signingRetryLoopResult + expectedLastExecutedAttempt *signingAttemptParams + outgoingAnnouncementsCount uint +} - groupParameters := &GroupParameters{ +var ( + signingRetryLoopMessage = big.NewInt(100) + + signingRetryLoopGroupParameters = &GroupParameters{ GroupSize: 10, HonestThreshold: 6, } - signingGroupOperators := chain.Addresses{ + signingRetryLoopGroupOperators = chain.Addresses{ "address-1", "address-2", "address-8", @@ -37,35 +51,134 @@ func TestSigningRetryLoop(t *testing.T) { "address-8", } - signingGroupMembersIndexes := make([]group.MemberIndex, 0) - for i := range signingGroupOperators { - signingGroupMembersIndexes = append( - signingGroupMembersIndexes, - group.MemberIndex(i+1), - ) + signingRetryLoopMembersIndexes = []group.MemberIndex{ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, } - testResult := &signing.Result{ + signingRetryLoopTestResult = &signing.Result{ Signature: &tecdsa.Signature{ R: big.NewInt(300), S: big.NewInt(400), RecoveryID: 2, }, } +) + +func runSigningRetryLoopTests( + t *testing.T, + tests map[string]signingRetryLoopTestCase, +) { + t.Helper() + + for testName, test := range tests { + t.Run(testName, func(t *testing.T) { + announcer := &mockSigningAnnouncer{ + outgoingAnnouncements: make(map[string]group.MemberIndex), + incomingAnnouncementsFn: test.incomingAnnouncementsFn, + } + + doneCheck := &mockSigningDoneCheck{ + waitUntilAllDoneOutcomeFn: test.waitUntilAllDoneOutcomeFn, + } + + retryLoop := newSigningRetryLoop( + &testutils.MockLogger{}, + signingRetryLoopMessage, + 200, + test.signingGroupMemberIndex, + signingRetryLoopGroupOperators, + signingRetryLoopGroupParameters, + announcer, + doneCheck, + ) + + ctx, cancelCtx := test.ctxFn() + defer cancelCtx() + + var lastExecutedAttempt *signingAttemptParams + + result, err := retryLoop.start( + ctx, + func(context.Context, uint64) error { + return nil + }, + test.currentBlockFn, + func(params *signingAttemptParams) (*signing.Result, uint64, error) { + lastExecutedAttempt = params + return test.signingAttemptFn(params) + }, + ) + + if !reflect.DeepEqual(test.expectedErr, err) { + t.Errorf( + "unexpected error\n"+ + "expected: [%+v]\n"+ + "actual: [%+v]", + test.expectedErr, + err, + ) + } - var tests = map[string]struct { - signingGroupMemberIndex group.MemberIndex - ctxFn func() (context.Context, context.CancelFunc) - currentBlockFn getCurrentBlockFn - incomingAnnouncementsFn func(sessionID string) ([]group.MemberIndex, error) - signingAttemptFn signingAttemptFn - waitUntilAllDoneOutcomeFn func(attemptNumber uint64) (*signing.Result, uint64, error) - expectedOutgoingDoneChecks []*signingDoneMessage - expectedErr error - expectedResult *signingRetryLoopResult - expectedLastExecutedAttempt *signingAttemptParams - outgoingAnnouncementsCount uint - }{ + if !reflect.DeepEqual(test.expectedResult, result) { + t.Errorf( + "unexpected result\n"+ + "expected: [%+v]\n"+ + "actual: [%+v]", + test.expectedResult, + result, + ) + } + + if !reflect.DeepEqual(test.expectedLastExecutedAttempt, lastExecutedAttempt) { + t.Errorf( + "unexpected last executed attempt\n"+ + "expected: [%+v]\n"+ + "actual: [%+v]", + test.expectedLastExecutedAttempt, + lastExecutedAttempt, + ) + } + + if test.expectedLastExecutedAttempt != nil { + testutils.AssertIntsEqual( + t, + "outgoing announcements count", + int(test.outgoingAnnouncementsCount), + len(announcer.outgoingAnnouncements), + ) + + for sessionID, memberIndex := range announcer.outgoingAnnouncements { + testutils.AssertIntsEqual( + t, + fmt.Sprintf( + "outgoing announcement's member index "+ + "for session [%v]", + sessionID, + ), + int(test.signingGroupMemberIndex), + int(memberIndex), + ) + } + } + + if !reflect.DeepEqual( + test.expectedOutgoingDoneChecks, + doneCheck.outgoingDoneChecks, + ) { + t.Errorf( + "unexpected outgoing done checks\n"+ + "expected: [%v]\n"+ + "actual: [%v]", + test.expectedOutgoingDoneChecks, + doneCheck.outgoingDoneChecks, + ) + } + }) + } +} + +func TestSigningRetryLoop_SuccessOnInitialAttempt(t *testing.T) { + tests := map[string]signingRetryLoopTestCase{ "success on initial attempt": { signingGroupMemberIndex: 1, ctxFn: func() (context.Context, context.CancelFunc) { @@ -77,32 +190,32 @@ func TestSigningRetryLoop(t *testing.T) { incomingAnnouncementsFn: func( sessionID string, ) ([]group.MemberIndex, error) { - return signingGroupMembersIndexes, nil + return signingRetryLoopMembersIndexes, nil }, signingAttemptFn: func( attempt *signingAttemptParams, ) (*signing.Result, uint64, error) { - return testResult, 215, nil // an arbitrary end block + return signingRetryLoopTestResult, 215, nil // an arbitrary end block }, waitUntilAllDoneOutcomeFn: func(attemptNumber uint64) (*signing.Result, uint64, error) { // Simulate that the done check phase determines the same // end block as the executing signer. - return testResult, 215, nil + return signingRetryLoopTestResult, 215, nil }, expectedOutgoingDoneChecks: []*signingDoneMessage{ { senderID: 1, - message: message, + message: signingRetryLoopMessage, attemptNumber: 1, - signature: testResult.Signature, + signature: signingRetryLoopTestResult.Signature, endBlock: 215, }, }, expectedErr: nil, expectedResult: &signingRetryLoopResult{ - result: testResult, + result: signingRetryLoopTestResult, activityReport: &signingActivityReport{ - activeMembers: signingGroupMembersIndexes, + activeMembers: signingRetryLoopMembersIndexes, inactiveMembers: []group.MemberIndex{}, }, latestEndBlock: 215, // the end block resolved by the done check phase @@ -136,25 +249,25 @@ func TestSigningRetryLoop(t *testing.T) { signingAttemptFn: func( attempt *signingAttemptParams, ) (*signing.Result, uint64, error) { - return testResult, 215, nil // an arbitrary end block + return signingRetryLoopTestResult, 215, nil // an arbitrary end block }, waitUntilAllDoneOutcomeFn: func(attemptNumber uint64) (*signing.Result, uint64, error) { // Simulate that the done check phase determines the same // end block as the executing signer. - return testResult, 215, nil + return signingRetryLoopTestResult, 215, nil }, expectedOutgoingDoneChecks: []*signingDoneMessage{ { senderID: 1, - message: message, + message: signingRetryLoopMessage, attemptNumber: 1, - signature: testResult.Signature, + signature: signingRetryLoopTestResult.Signature, endBlock: 215, }, }, expectedErr: nil, expectedResult: &signingRetryLoopResult{ - result: testResult, + result: signingRetryLoopTestResult, activityReport: &signingActivityReport{ activeMembers: []group.MemberIndex{1, 2, 3, 6, 7, 9}, inactiveMembers: []group.MemberIndex{4, 5, 8, 10}, @@ -173,6 +286,13 @@ func TestSigningRetryLoop(t *testing.T) { }, outgoingAnnouncementsCount: 1, }, + } + + runSigningRetryLoopTests(t, tests) +} + +func TestSigningRetryLoop_RetryOnAttemptFailure(t *testing.T) { + tests := map[string]signingRetryLoopTestCase{ "missing announcements without honest majority on initial attempt": { signingGroupMemberIndex: 3, ctxFn: func() (context.Context, context.CancelFunc) { @@ -184,37 +304,37 @@ func TestSigningRetryLoop(t *testing.T) { incomingAnnouncementsFn: func( sessionID string, ) ([]group.MemberIndex, error) { - if sessionID == fmt.Sprintf("%v-%v", message, 1) { + if sessionID == fmt.Sprintf("%v-%v", signingRetryLoopMessage, 1) { // Minority of members announced their readiness. return []group.MemberIndex{1, 2, 3, 6, 7}, nil } - return signingGroupMembersIndexes, nil + return signingRetryLoopMembersIndexes, nil }, signingAttemptFn: func( attempt *signingAttemptParams, ) (*signing.Result, uint64, error) { - return testResult, 260, nil // an arbitrary end block + return signingRetryLoopTestResult, 260, nil // an arbitrary end block }, waitUntilAllDoneOutcomeFn: func(attemptNumber uint64) (*signing.Result, uint64, error) { // Simulate that the done check phase determines the same // end block as the executing signer. - return testResult, 260, nil + return signingRetryLoopTestResult, 260, nil }, expectedOutgoingDoneChecks: []*signingDoneMessage{ { senderID: 3, - message: message, + message: signingRetryLoopMessage, attemptNumber: 2, - signature: testResult.Signature, + signature: signingRetryLoopTestResult.Signature, endBlock: 260, }, }, expectedErr: nil, expectedResult: &signingRetryLoopResult{ - result: testResult, + result: signingRetryLoopTestResult, activityReport: &signingActivityReport{ - activeMembers: signingGroupMembersIndexes, + activeMembers: signingRetryLoopMembersIndexes, inactiveMembers: []group.MemberIndex{}, }, latestEndBlock: 260, // the end block resolved by the done check phase @@ -245,36 +365,36 @@ func TestSigningRetryLoop(t *testing.T) { incomingAnnouncementsFn: func( sessionID string, ) ([]group.MemberIndex, error) { - if sessionID == fmt.Sprintf("%v-%v", message, 1) { + if sessionID == fmt.Sprintf("%v-%v", signingRetryLoopMessage, 1) { return nil, fmt.Errorf("unexpected error") } - return signingGroupMembersIndexes, nil + return signingRetryLoopMembersIndexes, nil }, signingAttemptFn: func( attempt *signingAttemptParams, ) (*signing.Result, uint64, error) { - return testResult, 260, nil // an arbitrary end block + return signingRetryLoopTestResult, 260, nil // an arbitrary end block }, waitUntilAllDoneOutcomeFn: func(attemptNumber uint64) (*signing.Result, uint64, error) { // Simulate that the done check phase determines the same // end block as the executing signer. - return testResult, 260, nil + return signingRetryLoopTestResult, 260, nil }, expectedOutgoingDoneChecks: []*signingDoneMessage{ { senderID: 4, - message: message, + message: signingRetryLoopMessage, attemptNumber: 2, - signature: testResult.Signature, + signature: signingRetryLoopTestResult.Signature, endBlock: 260, }, }, expectedErr: nil, expectedResult: &signingRetryLoopResult{ - result: testResult, + result: signingRetryLoopTestResult, activityReport: &signingActivityReport{ - activeMembers: signingGroupMembersIndexes, + activeMembers: signingRetryLoopMembersIndexes, inactiveMembers: []group.MemberIndex{}, }, latestEndBlock: 260, // the end block resolved by the done check phase @@ -305,7 +425,7 @@ func TestSigningRetryLoop(t *testing.T) { incomingAnnouncementsFn: func( sessionID string, ) ([]group.MemberIndex, error) { - return signingGroupMembersIndexes, nil + return signingRetryLoopMembersIndexes, nil }, signingAttemptFn: func( attempt *signingAttemptParams, @@ -314,27 +434,27 @@ func TestSigningRetryLoop(t *testing.T) { return nil, 0, fmt.Errorf("invalid data") } - return testResult, 260, nil // an arbitrary end block + return signingRetryLoopTestResult, 260, nil // an arbitrary end block }, waitUntilAllDoneOutcomeFn: func(attemptNumber uint64) (*signing.Result, uint64, error) { // Simulate that the done check phase determines the same // end block as the executing signer. - return testResult, 260, nil + return signingRetryLoopTestResult, 260, nil }, expectedOutgoingDoneChecks: []*signingDoneMessage{ { senderID: 4, - message: message, + message: signingRetryLoopMessage, attemptNumber: 2, - signature: testResult.Signature, + signature: signingRetryLoopTestResult.Signature, endBlock: 260, }, }, expectedErr: nil, expectedResult: &signingRetryLoopResult{ - result: testResult, + result: signingRetryLoopTestResult, activityReport: &signingActivityReport{ - activeMembers: signingGroupMembersIndexes, + activeMembers: signingRetryLoopMembersIndexes, inactiveMembers: []group.MemberIndex{}, }, latestEndBlock: 260, // the end block resolved by the done check phase @@ -354,57 +474,6 @@ func TestSigningRetryLoop(t *testing.T) { }, outgoingAnnouncementsCount: 2, }, - "executing member excluded": { - signingGroupMemberIndex: 2, - ctxFn: func() (context.Context, context.CancelFunc) { - return context.WithTimeout(context.Background(), 10*time.Second) - }, - currentBlockFn: func() (uint64, error) { - return 200, nil // same as the initial start block - }, - incomingAnnouncementsFn: func( - sessionID string, - ) ([]group.MemberIndex, error) { - return signingGroupMembersIndexes, nil - }, - signingAttemptFn: func( - attempt *signingAttemptParams, - ) (*signing.Result, uint64, error) { - return nil, 0, fmt.Errorf("invalid data") - }, - waitUntilAllDoneOutcomeFn: func(attemptNumber uint64) (*signing.Result, uint64, error) { - // Simulate the result and the end block have been determined - // by listening for signing done checks. - if attemptNumber == 2 { - return testResult, 260, nil - } - - panic("undefined behavior") - }, - expectedOutgoingDoneChecks: nil, - expectedErr: nil, - expectedResult: &signingRetryLoopResult{ - result: testResult, - activityReport: &signingActivityReport{ - activeMembers: signingGroupMembersIndexes, - inactiveMembers: []group.MemberIndex{}, - }, - latestEndBlock: 260, // the end block resolved by the done check phase - attemptTimeoutBlock: 277, // start block of the second attempt + 30 - }, - // Member 2 is the executing one. The first attempt fails - // and is the last attempt executed by this member because member - // 2 is excluded from the second attempt that produced the signature. - expectedLastExecutedAttempt: &signingAttemptParams{ - number: 1, - startBlock: 206, - timeoutBlock: 236, // start block of the first attempt + 30 - excludedMembersIndexes: []group.MemberIndex{3, 7, 8, 10}, - }, - // The second announcement is done at the beginning of the - // second attempt for which member 2 is eventually excluded. - outgoingAnnouncementsCount: 2, - }, "done checks wait error": { signingGroupMemberIndex: 4, ctxFn: func() (context.Context, context.CancelFunc) { @@ -416,17 +485,17 @@ func TestSigningRetryLoop(t *testing.T) { incomingAnnouncementsFn: func( sessionID string, ) ([]group.MemberIndex, error) { - return signingGroupMembersIndexes, nil + return signingRetryLoopMembersIndexes, nil }, signingAttemptFn: func( attempt *signingAttemptParams, ) (*signing.Result, uint64, error) { if attempt.number == 1 { - return testResult, 215, nil // an arbitrary end block + return signingRetryLoopTestResult, 215, nil // an arbitrary end block } if attempt.number == 2 { - return testResult, 260, nil // an arbitrary end block + return signingRetryLoopTestResult, 260, nil // an arbitrary end block } panic("undefined behavior") @@ -439,29 +508,29 @@ func TestSigningRetryLoop(t *testing.T) { // Simulate that the done check phase determines the same // end block as the executing signer. - return testResult, 260, nil + return signingRetryLoopTestResult, 260, nil }, expectedOutgoingDoneChecks: []*signingDoneMessage{ { senderID: 4, - message: message, + message: signingRetryLoopMessage, attemptNumber: 1, - signature: testResult.Signature, + signature: signingRetryLoopTestResult.Signature, endBlock: 215, }, { senderID: 4, - message: message, + message: signingRetryLoopMessage, attemptNumber: 2, - signature: testResult.Signature, + signature: signingRetryLoopTestResult.Signature, endBlock: 260, }, }, expectedErr: nil, expectedResult: &signingRetryLoopResult{ - result: testResult, + result: signingRetryLoopTestResult, activityReport: &signingActivityReport{ - activeMembers: signingGroupMembersIndexes, + activeMembers: signingRetryLoopMembersIndexes, inactiveMembers: []group.MemberIndex{}, }, latestEndBlock: 260, // the end block resolved by the done check phase @@ -481,13 +550,17 @@ func TestSigningRetryLoop(t *testing.T) { }, outgoingAnnouncementsCount: 2, }, - "loop context done": { - signingGroupMemberIndex: 1, + } + + runSigningRetryLoopTests(t, tests) +} + +func TestSigningRetryLoop_ExecutingMemberExcluded(t *testing.T) { + tests := map[string]signingRetryLoopTestCase{ + "executing member excluded": { + signingGroupMemberIndex: 2, ctxFn: func() (context.Context, context.CancelFunc) { - ctx, cancelCtx := context.WithCancel(context.Background()) - // Cancel the context deliberately. - cancelCtx() - return ctx, cancelCtx + return context.WithTimeout(context.Background(), 10*time.Second) }, currentBlockFn: func() (uint64, error) { return 200, nil // same as the initial start block @@ -495,17 +568,53 @@ func TestSigningRetryLoop(t *testing.T) { incomingAnnouncementsFn: func( sessionID string, ) ([]group.MemberIndex, error) { - return signingGroupMembersIndexes, nil + return signingRetryLoopMembersIndexes, nil }, signingAttemptFn: func( attempt *signingAttemptParams, ) (*signing.Result, uint64, error) { return nil, 0, fmt.Errorf("invalid data") }, - expectedErr: context.Canceled, - expectedResult: nil, - expectedLastExecutedAttempt: nil, + waitUntilAllDoneOutcomeFn: func(attemptNumber uint64) (*signing.Result, uint64, error) { + // Simulate the result and the end block have been determined + // by listening for signing done checks. + if attemptNumber == 2 { + return signingRetryLoopTestResult, 260, nil + } + + panic("undefined behavior") + }, + expectedOutgoingDoneChecks: nil, + expectedErr: nil, + expectedResult: &signingRetryLoopResult{ + result: signingRetryLoopTestResult, + activityReport: &signingActivityReport{ + activeMembers: signingRetryLoopMembersIndexes, + inactiveMembers: []group.MemberIndex{}, + }, + latestEndBlock: 260, // the end block resolved by the done check phase + attemptTimeoutBlock: 277, // start block of the second attempt + 30 + }, + // Member 2 is the executing one. The first attempt fails + // and is the last attempt executed by this member because member + // 2 is excluded from the second attempt that produced the signature. + expectedLastExecutedAttempt: &signingAttemptParams{ + number: 1, + startBlock: 206, + timeoutBlock: 236, // start block of the first attempt + 30 + excludedMembersIndexes: []group.MemberIndex{3, 7, 8, 10}, + }, + // The second announcement is done at the beginning of the + // second attempt for which member 2 is eventually excluded. + outgoingAnnouncementsCount: 2, }, + } + + runSigningRetryLoopTests(t, tests) +} + +func TestSigningRetryLoop_PastBlockHandling(t *testing.T) { + tests := map[string]signingRetryLoopTestCase{ "signing in the past": { signingGroupMemberIndex: 1, ctxFn: func() (context.Context, context.CancelFunc) { @@ -517,7 +626,7 @@ func TestSigningRetryLoop(t *testing.T) { incomingAnnouncementsFn: func( sessionID string, ) ([]group.MemberIndex, error) { - return signingGroupMembersIndexes, nil + return signingRetryLoopMembersIndexes, nil }, signingAttemptFn: func( attempt *signingAttemptParams, @@ -545,32 +654,32 @@ func TestSigningRetryLoop(t *testing.T) { incomingAnnouncementsFn: func( sessionID string, ) ([]group.MemberIndex, error) { - return signingGroupMembersIndexes, nil + return signingRetryLoopMembersIndexes, nil }, signingAttemptFn: func( attempt *signingAttemptParams, ) (*signing.Result, uint64, error) { - return testResult, 260, nil // an arbitrary end block + return signingRetryLoopTestResult, 260, nil // an arbitrary end block }, waitUntilAllDoneOutcomeFn: func(attemptNumber uint64) (*signing.Result, uint64, error) { // Simulate that the done check phase determines the same // end block as the executing signer. - return testResult, 260, nil + return signingRetryLoopTestResult, 260, nil }, expectedOutgoingDoneChecks: []*signingDoneMessage{ { senderID: 3, - message: message, + message: signingRetryLoopMessage, attemptNumber: 2, - signature: testResult.Signature, + signature: signingRetryLoopTestResult.Signature, endBlock: 260, }, }, expectedErr: nil, expectedResult: &signingRetryLoopResult{ - result: testResult, + result: signingRetryLoopTestResult, activityReport: &signingActivityReport{ - activeMembers: signingGroupMembersIndexes, + activeMembers: signingRetryLoopMembersIndexes, inactiveMembers: []group.MemberIndex{}, }, latestEndBlock: 260, // the end block resolved by the done check phase @@ -593,111 +702,39 @@ func TestSigningRetryLoop(t *testing.T) { }, } - for testName, test := range tests { - t.Run(testName, func(t *testing.T) { - announcer := &mockSigningAnnouncer{ - outgoingAnnouncements: make(map[string]group.MemberIndex), - incomingAnnouncementsFn: test.incomingAnnouncementsFn, - } - - doneCheck := &mockSigningDoneCheck{ - waitUntilAllDoneOutcomeFn: test.waitUntilAllDoneOutcomeFn, - } - - retryLoop := newSigningRetryLoop( - &testutils.MockLogger{}, - message, - 200, - test.signingGroupMemberIndex, - signingGroupOperators, - groupParameters, - announcer, - doneCheck, - ) - - ctx, cancelCtx := test.ctxFn() - defer cancelCtx() - - var lastExecutedAttempt *signingAttemptParams - - result, err := retryLoop.start( - ctx, - func(context.Context, uint64) error { - return nil - }, - test.currentBlockFn, - func(params *signingAttemptParams) (*signing.Result, uint64, error) { - lastExecutedAttempt = params - return test.signingAttemptFn(params) - }, - ) - - if !reflect.DeepEqual(test.expectedErr, err) { - t.Errorf( - "unexpected error\n"+ - "expected: [%+v]\n"+ - "actual: [%+v]", - test.expectedErr, - err, - ) - } - - if !reflect.DeepEqual(test.expectedResult, result) { - t.Errorf( - "unexpected result\n"+ - "expected: [%+v]\n"+ - "actual: [%+v]", - test.expectedResult, - result, - ) - } - - if !reflect.DeepEqual(test.expectedLastExecutedAttempt, lastExecutedAttempt) { - t.Errorf( - "unexpected last executed attempt\n"+ - "expected: [%+v]\n"+ - "actual: [%+v]", - test.expectedLastExecutedAttempt, - lastExecutedAttempt, - ) - } - - if test.expectedLastExecutedAttempt != nil { - testutils.AssertIntsEqual( - t, - "outgoing announcements count", - int(test.outgoingAnnouncementsCount), - len(announcer.outgoingAnnouncements), - ) - - for sessionID, memberIndex := range announcer.outgoingAnnouncements { - testutils.AssertIntsEqual( - t, - fmt.Sprintf( - "outgoing announcement's member index "+ - "for session [%v]", - sessionID, - ), - int(test.signingGroupMemberIndex), - int(memberIndex), - ) - } - } + runSigningRetryLoopTests(t, tests) +} - if !reflect.DeepEqual( - test.expectedOutgoingDoneChecks, - doneCheck.outgoingDoneChecks, - ) { - t.Errorf( - "unexpected outgoing done checks\n"+ - "expected: [%v]\n"+ - "actual: [%v]", - test.expectedOutgoingDoneChecks, - doneCheck.outgoingDoneChecks, - ) - } - }) +func TestSigningRetryLoop_ContextDone(t *testing.T) { + tests := map[string]signingRetryLoopTestCase{ + "loop context done": { + signingGroupMemberIndex: 1, + ctxFn: func() (context.Context, context.CancelFunc) { + ctx, cancelCtx := context.WithCancel(context.Background()) + // Cancel the context deliberately. + cancelCtx() + return ctx, cancelCtx + }, + currentBlockFn: func() (uint64, error) { + return 200, nil // same as the initial start block + }, + incomingAnnouncementsFn: func( + sessionID string, + ) ([]group.MemberIndex, error) { + return signingRetryLoopMembersIndexes, nil + }, + signingAttemptFn: func( + attempt *signingAttemptParams, + ) (*signing.Result, uint64, error) { + return nil, 0, fmt.Errorf("invalid data") + }, + expectedErr: context.Canceled, + expectedResult: nil, + expectedLastExecutedAttempt: nil, + }, } + + runSigningRetryLoopTests(t, tests) } func TestSigningRetryLoop_GetCurrentBlockErrorCausesRetry(t *testing.T) { diff --git a/pkg/tbtc/sweep_fee_sync_test.go b/pkg/tbtc/sweep_fee_sync_test.go new file mode 100644 index 0000000000..fcfa901c68 --- /dev/null +++ b/pkg/tbtc/sweep_fee_sync_test.go @@ -0,0 +1,41 @@ +package tbtc_test + +import ( + "testing" + + "github.com/keep-network/keep-core/pkg/tbtc" + "github.com/keep-network/keep-core/pkg/tbtcpg" +) + +// TestSweepFeeConstantsMirrorTbtcpg guards the cross-package mirrors of +// constants that pkg/tbtc duplicates from pkg/tbtcpg. The follower-side +// soft check (threshold-network/keep-core#4171) uses the same +// DepositScriptByteSize as the leader-side estimator, so a drift would +// produce a sweep tx estimate that disagrees with what the leader built. +// +// The minimum-floor and buffer-percent constants are NOT mirrored: they +// live as canonical exported vars in pkg/tbtc (MinWalletTxSatPerVByteFee, +// WalletTxFeeBufferPercent), which pkg/tbtcpg reads directly via +// tbtc.X. The operator-tunable runtime policy has a single source of +// truth, so a drift here would be a build error rather than a silent +// inconsistency. +// +// This test lives in the external tbtc_test package precisely because +// that package can import both pkg/tbtc and pkg/tbtcpg without forming +// the cycle. It compares the two actual constants directly - not +// against hand-copied literals - so it fails whenever the pkg/tbtc +// mirror and the canonical tbtcpg value drift apart, regardless of +// which side was changed. A literal-based guard could be defeated by +// updating tbtcpg and the literal together while forgetting the +// pkg/tbtc mirror; comparing the live values closes that gap. +func TestSweepFeeConstantsMirrorTbtcpg(t *testing.T) { + if tbtc.DepositScriptByteSize != tbtcpg.DepositScriptByteSize { + t.Errorf( + "tbtc.DepositScriptByteSize [%d] has drifted from the canonical "+ + "tbtcpg.DepositScriptByteSize [%d]; the follower soft check would "+ + "estimate the sweep tx size incorrectly", + tbtc.DepositScriptByteSize, + tbtcpg.DepositScriptByteSize, + ) + } +} diff --git a/pkg/tbtc/tbtc.go b/pkg/tbtc/tbtc.go index fa009348b9..e3ef13ec73 100644 --- a/pkg/tbtc/tbtc.go +++ b/pkg/tbtc/tbtc.go @@ -10,11 +10,11 @@ import ( "github.com/ipfs/go-log" - "github.com/keep-network/keep-common/pkg/chain/ethereum" - "github.com/keep-network/keep-common/pkg/persistence" + "github.com/keep-network/keep-core/pkg/chain/ethereumutil" "github.com/keep-network/keep-core/pkg/clientinfo" "github.com/keep-network/keep-core/pkg/generator" "github.com/keep-network/keep-core/pkg/net" + "github.com/keep-network/keep-core/pkg/persistence" "github.com/keep-network/keep-core/pkg/sortition" ) @@ -80,10 +80,56 @@ const ( DefaultPreParamsGenerationTimeout = 2 * time.Minute DefaultPreParamsGenerationDelay = 10 * time.Second DefaultPreParamsGenerationConcurrency = 1 + + // DefaultWalletTxSatPerVByteFloor is the default minimum fee rate, in + // sat/vByte, applied to wallet Bitcoin transactions (deposit sweeps, + // redemptions, moving funds, moved funds sweeps). The default keeps + // the fee safely above the 1 sat/vByte relay floor while remaining + // far below the Bridge's maximum fee. See + // threshold-network/keep-core#4171. + DefaultWalletTxSatPerVByteFloor = 5 + // DefaultWalletTxFeeBufferPercent is the default safety-buffer + // percentage applied over the per-vByte fee rate. + DefaultWalletTxFeeBufferPercent = 25 ) var DefaultKeyGenerationConcurrency = runtime.GOMAXPROCS(0) +// MinWalletTxSatPerVByteFee and WalletTxFeeBufferPercent are the +// canonical runtime policy applied to every wallet Bitcoin transaction: +// both the leader-side floor application in +// tbtcpg.applyWalletTxFeeFloor and the follower-side soft check in +// tbtc.warnIfProposedWalletTxFeeBelowBufferedFloor read from these +// vars, so a single source of truth is enforced - tuning one side +// automatically tunes the other. +// +// They are vars (not consts) so operators can tune them via Config / +// Viper flags at startup, and so tests can override them via t.Cleanup. +// Initialize applies the Config values if non-zero; otherwise the +// DefaultWalletTx* constants above are kept. MinWalletTxSatPerVByteFee +// must be positive and WalletTxFeeBufferPercent must be non-negative; +// the helpers return an error if a runtime value violates this. +// +// A fee oracle can return an unusably low estimate (down to the +// 1 sat/vByte relay floor enforced by the Electrum client) in an +// uncongested mempool. Because these transactions spend or consolidate +// significant wallet value and are not RBF-enabled, they cannot be +// replaced once broadcast, so a floor-rate transaction can get stuck in +// the mempool and jam the wallet: no new wallet transaction can be +// built while the previous one is unconfirmed. The static floor and the +// 25% buffer are a stopgap for the current fire-and-forget, non-RBF +// wallet transaction path: because a stuck transaction cannot be +// fee-bumped, the fee must be right on the first broadcast. Once RBF / +// fee-bumping lands (Part B, tracked in #4171) the safety net shifts to +// monitor-and-bump, and this policy should be revisited rather than +// carried forward unchanged: the defensive buffer can be dropped and the +// floor relaxed toward the live estimate, keeping only a small +// relay-propagation minimum. +var ( + MinWalletTxSatPerVByteFee int64 = DefaultWalletTxSatPerVByteFloor + WalletTxFeeBufferPercent int64 = DefaultWalletTxFeeBufferPercent +) + // Config carries the config for tBTC protocol. type Config struct { // The size of the pre-parameters pool for tECDSA. @@ -96,6 +142,48 @@ type Config struct { PreParamsGenerationConcurrency int // Concurrency level for key-generation for tECDSA. KeyGenerationConcurrency int + // WalletTxSatPerVByteFloor is the minimum fee rate (sat/vByte) applied + // to wallet Bitcoin transactions. Zero means use + // DefaultWalletTxSatPerVByteFloor. Maps to the + // tbtc.walletTxSatPerVByteFloor flag / viper key. + WalletTxSatPerVByteFloor int + // WalletTxFeeBufferPercent is the safety-buffer percentage applied + // over the per-vByte fee rate. The buffered rate is + // ceil(rawRate * (100 + Percent) / 100). Zero means use + // DefaultWalletTxFeeBufferPercent. Maps to the + // tbtc.walletTxFeeBufferPercent flag / viper key. + WalletTxFeeBufferPercent int + // TransactionMonitor controls confirmation polling and stuck-transaction + // alerts. Omitted settings retain the default monitoring policy. + TransactionMonitor TransactionMonitorConfig +} + +// applyWalletTxFeePolicy applies the operator-tunable wallet-tx fee-floor +// policy from Config to the package-level policy vars. Zero-valued Config +// fields are skipped so a direct Config{} in tests retains the +// DefaultWalletTx* constants. Negative settings return an error. +func applyWalletTxFeePolicy(config Config) error { + if config.WalletTxSatPerVByteFloor < 0 { + return fmt.Errorf( + "negative wallet tx sat/vByte floor: [%d]", + config.WalletTxSatPerVByteFloor, + ) + } + if config.WalletTxFeeBufferPercent < 0 { + return fmt.Errorf( + "negative wallet tx fee buffer percent: [%d]", + config.WalletTxFeeBufferPercent, + ) + } + + if config.WalletTxSatPerVByteFloor > 0 { + MinWalletTxSatPerVByteFee = int64(config.WalletTxSatPerVByteFloor) + } + if config.WalletTxFeeBufferPercent > 0 { + WalletTxFeeBufferPercent = int64(config.WalletTxFeeBufferPercent) + } + + return nil } // Initialize kicks off the TBTC by initializing internal state, ensuring @@ -115,6 +203,10 @@ func Initialize( perfMetrics *clientinfo.PerformanceMetrics, ethereumNetwork ethereum.Network, ) error { + if err := applyWalletTxFeePolicy(config); err != nil { + return fmt.Errorf("cannot apply wallet tx fee policy: [%w]", err) + } + groupParameters := defaultGroupParameters(ethereumNetwork) if ethChain, ok := chain.(interface { diff --git a/pkg/tbtc/tbtc_test.go b/pkg/tbtc/tbtc_test.go new file mode 100644 index 0000000000..ab3d3e74de --- /dev/null +++ b/pkg/tbtc/tbtc_test.go @@ -0,0 +1,139 @@ +package tbtc + +import ( + "testing" +) + +func TestApplyWalletTxFeePolicy(t *testing.T) { + originalFloor := MinWalletTxSatPerVByteFee + originalPercent := WalletTxFeeBufferPercent + t.Cleanup(func() { + MinWalletTxSatPerVByteFee = originalFloor + WalletTxFeeBufferPercent = originalPercent + }) + + // A zero-valued Config (e.g. a test that constructs Config{}) must + // keep the package defaults so the leader-side and follower-side + // fee-floor logic keeps working without a CLI override. + t.Run("zero-valued config keeps defaults", func(t *testing.T) { + MinWalletTxSatPerVByteFee = DefaultWalletTxSatPerVByteFloor + WalletTxFeeBufferPercent = DefaultWalletTxFeeBufferPercent + + err := applyWalletTxFeePolicy(Config{}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if MinWalletTxSatPerVByteFee != DefaultWalletTxSatPerVByteFloor { + t.Errorf( + "expected default floor [%d], got [%d]", + DefaultWalletTxSatPerVByteFloor, + MinWalletTxSatPerVByteFee, + ) + } + if WalletTxFeeBufferPercent != DefaultWalletTxFeeBufferPercent { + t.Errorf( + "expected default buffer percent [%d], got [%d]", + DefaultWalletTxFeeBufferPercent, + WalletTxFeeBufferPercent, + ) + } + }) + + // An operator-supplied config (e.g. via a Viper flag) overrides + // every field that is non-zero. The leader-side floor application + // in tbtcpg.applyWalletTxFeeFloor and the follower-side soft check + // in warnIfProposedWalletTxFeeBelowBufferedFloor both read the + // same package vars, so a single tuning here propagates to both. + t.Run("non-zero config overrides defaults", func(t *testing.T) { + err := applyWalletTxFeePolicy(Config{ + WalletTxSatPerVByteFloor: 7, + WalletTxFeeBufferPercent: 30, + }) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if MinWalletTxSatPerVByteFee != 7 { + t.Errorf( + "expected floor [7], got [%d]", + MinWalletTxSatPerVByteFee, + ) + } + if WalletTxFeeBufferPercent != 30 { + t.Errorf( + "expected buffer percent [30], got [%d]", + WalletTxFeeBufferPercent, + ) + } + }) + + // Partial config: only the floor is tuned, the buffer percentage + // keeps the default. This is the realistic operator path where one + // knob is changed at a time during a rollout. + t.Run("partial config keeps unset defaults", func(t *testing.T) { + MinWalletTxSatPerVByteFee = DefaultWalletTxSatPerVByteFloor + WalletTxFeeBufferPercent = DefaultWalletTxFeeBufferPercent + + err := applyWalletTxFeePolicy(Config{ + WalletTxSatPerVByteFloor: 9, + }) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if MinWalletTxSatPerVByteFee != 9 { + t.Errorf( + "expected floor [9], got [%d]", + MinWalletTxSatPerVByteFee, + ) + } + if WalletTxFeeBufferPercent != DefaultWalletTxFeeBufferPercent { + t.Errorf( + "expected default buffer percent [%d], got [%d]", + DefaultWalletTxFeeBufferPercent, + WalletTxFeeBufferPercent, + ) + } + }) + + t.Run("negative floor returns error and preserves state", func(t *testing.T) { + MinWalletTxSatPerVByteFee = DefaultWalletTxSatPerVByteFloor + WalletTxFeeBufferPercent = DefaultWalletTxFeeBufferPercent + + err := applyWalletTxFeePolicy(Config{ + WalletTxSatPerVByteFloor: -1, + }) + if err == nil { + t.Fatalf("expected error for negative floor, got nil") + } + + if MinWalletTxSatPerVByteFee != DefaultWalletTxSatPerVByteFloor { + t.Errorf( + "expected floor to stay [%d], got [%d]", + DefaultWalletTxSatPerVByteFloor, + MinWalletTxSatPerVByteFee, + ) + } + }) + + t.Run("negative buffer percent returns error and preserves state", func(t *testing.T) { + MinWalletTxSatPerVByteFee = DefaultWalletTxSatPerVByteFloor + WalletTxFeeBufferPercent = DefaultWalletTxFeeBufferPercent + + err := applyWalletTxFeePolicy(Config{ + WalletTxFeeBufferPercent: -1, + }) + if err == nil { + t.Fatalf("expected error for negative buffer percent, got nil") + } + + if WalletTxFeeBufferPercent != DefaultWalletTxFeeBufferPercent { + t.Errorf( + "expected buffer percent to stay [%d], got [%d]", + DefaultWalletTxFeeBufferPercent, + WalletTxFeeBufferPercent, + ) + } + }) +} diff --git a/pkg/tbtc/transaction_monitor.go b/pkg/tbtc/transaction_monitor.go index 07dc0c2b3d..fd2517b27e 100644 --- a/pkg/tbtc/transaction_monitor.go +++ b/pkg/tbtc/transaction_monitor.go @@ -2,6 +2,7 @@ package tbtc import ( "context" + "fmt" "sort" "sync" "time" @@ -10,37 +11,9 @@ import ( "github.com/keep-network/keep-core/pkg/clientinfo" ) -const ( - // defaultStuckTransactionThreshold is how long a broadcast wallet - // transaction may remain unconfirmed before it is considered stuck and an - // alert is raised (~6 hours). - defaultStuckTransactionThreshold = 6 * time.Hour - - // transactionMonitorCheckInterval is how often the monitor polls the - // confirmation status of the tracked transactions. - transactionMonitorCheckInterval = 5 * time.Minute - - // transactionMonitorMinConfirmations is the number of confirmations at - // which a tracked transaction is considered mined and stops being tracked. - transactionMonitorMinConfirmations = uint(1) - - // transactionMonitorMaxTracked bounds the number of tracked transactions to - // prevent unbounded memory growth. - transactionMonitorMaxTracked = 1000 - - // transactionMonitorMaxTrackingAge is how long a still-unconfirmed - // transaction is tracked before the monitor gives up on it - e.g. it was - // dropped from the mempool and will never confirm. Bounding the tracking - // duration prevents never-confirming transactions from filling up the - // tracking table and starving monitoring of new transactions (~24 hours). - transactionMonitorMaxTrackingAge = 24 * time.Hour - - // transactionMonitorCheckBudget bounds the wall-clock time of a single check - // pass so that a slow chain call cannot stall monitoring of every remaining - // transaction; transactions not reached within the budget are handled on the - // next pass. - transactionMonitorCheckBudget = 2 * time.Minute -) +// transactionMonitorMinConfirmations is the number of confirmations at which +// a tracked transaction is considered mined and stops being tracked. +const transactionMonitorMinConfirmations = uint(1) // trackedTransaction holds the monitoring state of a single broadcast wallet // transaction. @@ -103,17 +76,23 @@ type transactionMonitor struct { mu sync.Mutex tracked map[bitcoin.Hash]*trackedTransaction - threshold time.Duration + config TransactionMonitorConfig metricsRecorder clientinfo.PerformanceMetricsRecorder } -func newTransactionMonitor(btcChain bitcoin.Chain) *transactionMonitor { - return &transactionMonitor{ - btcChain: btcChain, - tracked: make(map[bitcoin.Hash]*trackedTransaction), - threshold: defaultStuckTransactionThreshold, +func newTransactionMonitor( + btcChain bitcoin.Chain, + config TransactionMonitorConfig, +) (*transactionMonitor, error) { + if err := config.Validate(); err != nil { + return nil, fmt.Errorf("invalid transaction monitor configuration: %w", err) } + return &transactionMonitor{ + btcChain: btcChain, + tracked: make(map[bitcoin.Hash]*trackedTransaction), + config: config.withDefaults(), + }, nil } // setMetricsRecorder wires the performance metrics recorder used to expose the @@ -141,7 +120,7 @@ func (tm *transactionMonitor) track( return } - if len(tm.tracked) >= transactionMonitorMaxTracked { + if len(tm.tracked) >= tm.config.MaxTracked { // A full table means a real broadcast transaction goes unmonitored; // surface it as a metric (emitted outside the lock) as well as a log. recorder := tm.metricsRecorder @@ -150,7 +129,7 @@ func (tm *transactionMonitor) track( logger.Warnf( "transaction monitor tracking table is full ([%d]); transaction "+ "[%s] will not be monitored", - transactionMonitorMaxTracked, + tm.config.MaxTracked, txHash.Hex(bitcoin.ReversedByteOrder), ) if recorder != nil { @@ -170,7 +149,7 @@ func (tm *transactionMonitor) track( // run starts the monitor's polling loop. It blocks until the context is done. func (tm *transactionMonitor) run(ctx context.Context) { - ticker := time.NewTicker(transactionMonitorCheckInterval) + ticker := time.NewTicker(tm.config.CheckInterval) defer ticker.Stop() for { @@ -192,7 +171,7 @@ func (tm *transactionMonitor) run(ctx context.Context) { // concurrently but only inserts new entries, so the per-entry alerted flag is // only ever mutated here, under the mutex. func (tm *transactionMonitor) check(ctx context.Context) { - tm.checkWithBudget(ctx, transactionMonitorCheckBudget) + tm.checkWithBudget(ctx, tm.config.CheckBudget) } func (tm *transactionMonitor) checkWithBudget( @@ -251,7 +230,7 @@ func (tm *transactionMonitor) checkWithBudget( // threshold. This runs before the give-up eviction below so that a // transaction first observed after the maximum tracking age still fires // exactly one alert instead of being silently evicted. - if outstanding > tm.threshold && !t.alerted { + if outstanding > tm.config.StuckThreshold && !t.alerted { logger.Warnf( "wallet transaction [%s] for wallet [0x%x] has been unconfirmed "+ "for [%s] (threshold [%s]); it may be stuck in the mempool "+ @@ -260,7 +239,7 @@ func (tm *transactionMonitor) checkWithBudget( txHash.Hex(bitcoin.ReversedByteOrder), t.walletPublicKeyHash, outstanding.Round(time.Minute), - tm.threshold, + tm.config.StuckThreshold, ) // Mark as alerted under the lock, but emit the metric outside the @@ -281,7 +260,7 @@ func (tm *transactionMonitor) checkWithBudget( // Give up on transactions that have been unconfirmed for too long (e.g. // dropped from the mempool) so they cannot fill the tracking table. - if outstanding > transactionMonitorMaxTrackingAge { + if outstanding > tm.config.MaxTrackingAge { logger.Warnf( "giving up monitoring wallet transaction [%s] for wallet "+ "[0x%x]; it has been unconfirmed for [%s]", diff --git a/pkg/tbtc/transaction_monitor_config.go b/pkg/tbtc/transaction_monitor_config.go new file mode 100644 index 0000000000..56e1525ca2 --- /dev/null +++ b/pkg/tbtc/transaction_monitor_config.go @@ -0,0 +1,92 @@ +package tbtc + +import ( + "fmt" + "time" +) + +const ( + // DefaultTransactionMonitorStuckThreshold is the age at which an + // unconfirmed wallet transaction starts generating alerts. + DefaultTransactionMonitorStuckThreshold = 6 * time.Hour + // DefaultTransactionMonitorCheckInterval is the confirmation polling cadence. + DefaultTransactionMonitorCheckInterval = 5 * time.Minute + // DefaultTransactionMonitorMaxTracked bounds the in-memory tracking table. + DefaultTransactionMonitorMaxTracked = 1000 + // DefaultTransactionMonitorMaxTrackingAge bounds how long an unconfirmed + // transaction occupies the tracking table. + DefaultTransactionMonitorMaxTrackingAge = 24 * time.Hour + // DefaultTransactionMonitorCheckBudget bounds one confirmation-check pass. + DefaultTransactionMonitorCheckBudget = 2 * time.Minute + + // maxTransactionMonitorMaxTracked is the highest allowed in-memory + // tracking table size; guards against unbounded memory growth from a + // misconfigured deployment. + maxTransactionMonitorMaxTracked = 100_000 +) + +// TransactionMonitorConfig configures monitoring of broadcast wallet +// transactions. Zero values select the defaults; negative values are +// invalid. MaxTrackingAge must be at least the effective StuckThreshold +// after defaults are applied. +type TransactionMonitorConfig struct { + StuckThreshold time.Duration + CheckInterval time.Duration + MaxTracked int + MaxTrackingAge time.Duration + CheckBudget time.Duration +} + +func (c TransactionMonitorConfig) withDefaults() TransactionMonitorConfig { + if c.StuckThreshold == 0 { + c.StuckThreshold = DefaultTransactionMonitorStuckThreshold + } + if c.CheckInterval == 0 { + c.CheckInterval = DefaultTransactionMonitorCheckInterval + } + if c.MaxTracked == 0 { + c.MaxTracked = DefaultTransactionMonitorMaxTracked + } + if c.MaxTrackingAge == 0 { + c.MaxTrackingAge = DefaultTransactionMonitorMaxTrackingAge + } + if c.CheckBudget == 0 { + c.CheckBudget = DefaultTransactionMonitorCheckBudget + } + return c +} + +// Validate checks the effective configuration, including defaults for omitted +// fields. Transactions must remain tracked long enough to generate an alert. +func (c TransactionMonitorConfig) Validate() error { + c = c.withDefaults() + for _, setting := range []struct { + name string + value time.Duration + }{ + {"stuckThreshold", c.StuckThreshold}, + {"checkInterval", c.CheckInterval}, + {"maxTrackingAge", c.MaxTrackingAge}, + {"checkBudget", c.CheckBudget}, + } { + if setting.value < 0 { + return fmt.Errorf("tbtc.transactionMonitor.%s must not be negative", setting.name) + } + } + if c.MaxTracked < 0 { + return fmt.Errorf("tbtc.transactionMonitor.maxTracked must not be negative") + } + if c.MaxTracked > maxTransactionMonitorMaxTracked { + return fmt.Errorf( + "tbtc.transactionMonitor.maxTracked must not exceed %d", + maxTransactionMonitorMaxTracked, + ) + } + if c.MaxTrackingAge < c.StuckThreshold { + return fmt.Errorf( + "tbtc.transactionMonitor.maxTrackingAge (%s) must be at least stuckThreshold (%s)", + c.MaxTrackingAge, c.StuckThreshold, + ) + } + return nil +} diff --git a/pkg/tbtc/transaction_monitor_config_test.go b/pkg/tbtc/transaction_monitor_config_test.go new file mode 100644 index 0000000000..64de2e78a6 --- /dev/null +++ b/pkg/tbtc/transaction_monitor_config_test.go @@ -0,0 +1,154 @@ +package tbtc + +import ( + "context" + "strings" + "testing" + "time" + + "github.com/keep-network/keep-core/pkg/bitcoin" + "github.com/keep-network/keep-core/pkg/clientinfo" +) + +func TestTransactionMonitorConfig_Defaults(t *testing.T) { + monitor, err := newTransactionMonitor(newLocalBitcoinChain(), TransactionMonitorConfig{}) + if err != nil { + t.Fatal(err) + } + expected := TransactionMonitorConfig{ + StuckThreshold: 6 * time.Hour, + CheckInterval: 5 * time.Minute, + MaxTracked: 1000, + MaxTrackingAge: 24 * time.Hour, + CheckBudget: 2 * time.Minute, + } + if monitor.config != expected { + t.Fatalf("default configuration changed: got %+v, want %+v", monitor.config, expected) + } +} + +func TestTransactionMonitorConfig_Validation(t *testing.T) { + tests := map[string]struct { + config TransactionMonitorConfig + errorField string + }{ + "negative threshold": {TransactionMonitorConfig{StuckThreshold: -time.Second}, "stuckThreshold"}, + "negative interval": {TransactionMonitorConfig{CheckInterval: -time.Second}, "checkInterval"}, + "negative capacity": {TransactionMonitorConfig{MaxTracked: -1}, "maxTracked"}, + "negative age": {TransactionMonitorConfig{MaxTrackingAge: -time.Second}, "maxTrackingAge"}, + "negative budget": {TransactionMonitorConfig{CheckBudget: -time.Second}, "checkBudget"}, + "age below default threshold": {TransactionMonitorConfig{MaxTrackingAge: time.Hour}, "maxTrackingAge"}, + "threshold above default age": {TransactionMonitorConfig{StuckThreshold: 25 * time.Hour}, "maxTrackingAge"}, + "equal threshold and age": {TransactionMonitorConfig{StuckThreshold: time.Hour, MaxTrackingAge: time.Hour}, ""}, + "partial override": {TransactionMonitorConfig{CheckInterval: time.Minute}, ""}, + "capacity above ceiling": {TransactionMonitorConfig{MaxTracked: maxTransactionMonitorMaxTracked + 1}, "maxTracked"}, + } + for name, test := range tests { + t.Run(name, func(t *testing.T) { + _, err := newTransactionMonitor(newLocalBitcoinChain(), test.config) + if test.errorField == "" { + if err != nil { + t.Fatal(err) + } + } else if err == nil || !strings.Contains(err.Error(), test.errorField) { + t.Fatalf("expected error naming %s, got %v", test.errorField, err) + } + }) + } +} + +func TestTransactionMonitor_CustomThresholdCapacityAndAge(t *testing.T) { + monitor, err := newTransactionMonitor(newLocalBitcoinChain(), TransactionMonitorConfig{ + StuckThreshold: time.Hour, + MaxTracked: 2, + MaxTrackingAge: 2 * time.Hour, + }) + if err != nil { + t.Fatal(err) + } + recorder := newCountingMetricsRecorder() + monitor.setMetricsRecorder(recorder) + first, second, overflow := bitcoin.Hash{1}, bitcoin.Hash{2}, bitcoin.Hash{3} + monitor.track(first, [20]byte{1}) + monitor.track(second, [20]byte{1}) + monitor.track(overflow, [20]byte{1}) + if isTracked(monitor, overflow) || recorder.GetCounterValue(clientinfo.MetricUnmonitoredWalletTransactionsTotal) != 1 { + t.Fatal("custom tracking capacity was not enforced") + } + ageTransaction(monitor, first, 45*time.Minute) + ageTransaction(monitor, second, 90*time.Minute) + monitor.check(context.Background()) + if got := recorder.GetCounterValue(clientinfo.MetricStuckWalletTransactionsTotal); got != 1 { + t.Fatalf("expected one alert with the custom threshold, got %v", got) + } + if !isTracked(monitor, second) { + t.Fatal("transaction evicted before custom maximum age") + } + ageTransaction(monitor, second, time.Hour) + monitor.check(context.Background()) + if isTracked(monitor, second) { + t.Fatal("transaction retained past custom maximum age") + } + if got := recorder.GetCounterValue(clientinfo.MetricStuckWalletTransactionsTotal); got != 1 { + t.Fatalf("expected no duplicate alert before eviction, got %v", got) + } + monitor.track(overflow, [20]byte{1}) + if !isTracked(monitor, overflow) { + t.Fatal("evicted transaction did not free tracking capacity") + } +} + +func TestTransactionMonitor_CustomCheckBudget(t *testing.T) { + hash := bitcoin.Hash{1} + chain := newBlockingTransactionConfirmationsChain(hash) + monitor, err := newTransactionMonitor(chain, TransactionMonitorConfig{CheckBudget: 20 * time.Millisecond}) + if err != nil { + t.Fatal(err) + } + monitor.track(hash, [20]byte{1}) + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + monitor.check(ctx) + if ctx.Err() != nil { + t.Fatal("custom check budget did not cancel the blocked lookup before the parent deadline") + } + if chain.getLookupCount() != 1 { + t.Fatal("expected one confirmation lookup") + } +} + +func TestTransactionMonitor_CustomCheckInterval(t *testing.T) { + hash := bitcoin.Hash{1} + chain := newBlockingTransactionConfirmationsChain(hash) + monitor, err := newTransactionMonitor(chain, TransactionMonitorConfig{CheckInterval: 5 * time.Millisecond}) + if err != nil { + t.Fatal(err) + } + monitor.track(hash, [20]byte{1}) + ctx, cancel := context.WithCancel(context.Background()) + done := make(chan struct{}) + go func() { defer close(done); monitor.run(ctx) }() + t.Cleanup(func() { + cancel() + select { + case <-done: + case <-time.After(time.Second): + t.Error("monitor did not stop after cancellation") + } + }) + select { + case <-chain.lookupStarted: + case <-time.After(time.Second): + t.Fatal("custom polling interval did not trigger a confirmation check") + } +} + +func TestNewNode_RejectsInvalidTransactionMonitorConfig(t *testing.T) { + // Validation must precede persistence, chain access, and scheduler setup. + _, err := newNode(nil, nil, nil, nil, nil, nil, nil, nil, Config{ + TransactionMonitor: TransactionMonitorConfig{CheckInterval: -time.Second}, + }) + if err == nil || !strings.Contains(err.Error(), "checkInterval") { + t.Fatalf("expected monitor configuration rejection before node setup, got %v", err) + } +} diff --git a/pkg/tbtc/transaction_monitor_test.go b/pkg/tbtc/transaction_monitor_test.go index d6d92f5828..ccb6844679 100644 --- a/pkg/tbtc/transaction_monitor_test.go +++ b/pkg/tbtc/transaction_monitor_test.go @@ -115,7 +115,10 @@ func TestTransactionMonitor(t *testing.T) { chain := newLocalBitcoinChain() recorder := newCountingMetricsRecorder() - monitor := newTransactionMonitor(chain) + monitor, err := newTransactionMonitor(chain, TransactionMonitorConfig{}) + if err != nil { + t.Fatal(err) + } monitor.setMetricsRecorder(recorder) tx := &bitcoin.Transaction{} @@ -137,7 +140,7 @@ func TestTransactionMonitor(t *testing.T) { // deliberately: with a real clock the check-time drift always nudges the // elapsed time a hair past any exact backdated value, so it cannot be pinned // deterministically without an injectable clock. - ageTransaction(monitor, txHash, defaultStuckTransactionThreshold-time.Minute) + ageTransaction(monitor, txHash, DefaultTransactionMonitorStuckThreshold-time.Minute) monitor.check(context.Background()) if got := stuckCount(); got != 0 { t.Fatalf("expected no alert at the threshold boundary; got counter [%v]", got) @@ -166,7 +169,10 @@ func TestTransactionMonitor(t *testing.T) { // table. func TestTransactionMonitor_GivesUpOnNeverConfirming(t *testing.T) { recorder := newCountingMetricsRecorder() - monitor := newTransactionMonitor(newLocalBitcoinChain()) + monitor, err := newTransactionMonitor(newLocalBitcoinChain(), TransactionMonitorConfig{}) + if err != nil { + t.Fatal(err) + } monitor.setMetricsRecorder(recorder) tx := &bitcoin.Transaction{} @@ -177,7 +183,7 @@ func TestTransactionMonitor_GivesUpOnNeverConfirming(t *testing.T) { // the stuck threshold and the give-up age. It must still fire exactly one // stuck alert (the alert runs before eviction) and then be evicted rather // than tracked forever. - ageTransaction(monitor, txHash, transactionMonitorMaxTrackingAge+time.Minute) + ageTransaction(monitor, txHash, DefaultTransactionMonitorMaxTrackingAge+time.Minute) monitor.check(context.Background()) if got := recorder.GetCounterValue( @@ -196,7 +202,10 @@ func TestTransactionMonitor_GivesUpOnNeverConfirming(t *testing.T) { func TestTransactionMonitor_CheckBudgetBoundsLookup(t *testing.T) { blockedTxHash := bitcoin.Hash{1} chain := newBlockingTransactionConfirmationsChain(blockedTxHash) - monitor := newTransactionMonitor(chain) + monitor, err := newTransactionMonitor(chain, TransactionMonitorConfig{}) + if err != nil { + t.Fatal(err) + } monitor.track(blockedTxHash, [20]byte{}) @@ -255,7 +264,10 @@ func TestTransactionMonitor_BudgetExpiryStillAlertsOldest(t *testing.T) { blockedTxHash := bitcoin.Hash{1} // oldest; its lookup hangs until the budget expires chain := newBlockingTransactionConfirmationsChain(blockedTxHash) recorder := newCountingMetricsRecorder() - monitor := newTransactionMonitor(chain) + monitor, err := newTransactionMonitor(chain, TransactionMonitorConfig{}) + if err != nil { + t.Fatal(err) + } monitor.setMetricsRecorder(recorder) newerTxHash := bitcoin.Hash{2} @@ -264,8 +276,8 @@ func TestTransactionMonitor_BudgetExpiryStillAlertsOldest(t *testing.T) { // Both transactions are past the stuck threshold; the blocked one is older so // oldest-first ordering checks it first and its lookup consumes the budget. - ageTransaction(monitor, blockedTxHash, defaultStuckTransactionThreshold+2*time.Hour) - ageTransaction(monitor, newerTxHash, defaultStuckTransactionThreshold+time.Hour) + ageTransaction(monitor, blockedTxHash, DefaultTransactionMonitorStuckThreshold+2*time.Hour) + ageTransaction(monitor, newerTxHash, DefaultTransactionMonitorStuckThreshold+time.Hour) // Release the intentionally blocked backend on exit so its lookup goroutine // is never left parked. @@ -319,21 +331,24 @@ func TestTransactionMonitor_BudgetExpiryStillAlertsOldest(t *testing.T) { // past its bound. func TestTransactionMonitor_CapacityBound(t *testing.T) { recorder := newCountingMetricsRecorder() - monitor := newTransactionMonitor(newLocalBitcoinChain()) + monitor, err := newTransactionMonitor(newLocalBitcoinChain(), TransactionMonitorConfig{}) + if err != nil { + t.Fatal(err) + } monitor.setMetricsRecorder(recorder) const excess = 10 - for i := 0; i < transactionMonitorMaxTracked+excess; i++ { + for i := 0; i < DefaultTransactionMonitorMaxTracked+excess; i++ { var h bitcoin.Hash h[0] = byte(i) h[1] = byte(i >> 8) monitor.track(h, [20]byte{}) } - if got := trackedCount(monitor); got != transactionMonitorMaxTracked { + if got := trackedCount(monitor); got != DefaultTransactionMonitorMaxTracked { t.Fatalf( "expected tracking table bounded to [%d]; got [%d]", - transactionMonitorMaxTracked, + DefaultTransactionMonitorMaxTracked, got, ) } @@ -355,7 +370,10 @@ func TestTransactionMonitor_CapacityBound(t *testing.T) { // transactions oldest-first, so an old transaction near the stuck threshold is // never starved when a pass hits its time budget (Go map order is randomized). func TestTransactionMonitor_SnapshotByAge(t *testing.T) { - monitor := newTransactionMonitor(newLocalBitcoinChain()) + monitor, err := newTransactionMonitor(newLocalBitcoinChain(), TransactionMonitorConfig{}) + if err != nil { + t.Fatal(err) + } var h1, h2, h3 bitcoin.Hash h1[0], h2[0], h3[0] = 1, 2, 3 diff --git a/pkg/tbtc/wallet.go b/pkg/tbtc/wallet.go index b5d1edc311..eb4bce52f5 100644 --- a/pkg/tbtc/wallet.go +++ b/pkg/tbtc/wallet.go @@ -36,18 +36,18 @@ const ( // ParseWalletActionType parses the given value into a WalletActionType. func ParseWalletActionType(value uint8) (WalletActionType, error) { - switch value { - case 0: + switch WalletActionType(value) { + case ActionNoop: return ActionNoop, nil - case 1: + case ActionHeartbeat: return ActionHeartbeat, nil - case 2: + case ActionDepositSweep: return ActionDepositSweep, nil - case 3: + case ActionRedemption: return ActionRedemption, nil - case 4: + case ActionMovingFunds: return ActionMovingFunds, nil - case 5: + case ActionMovedFundsSweep: return ActionMovedFundsSweep, nil default: return 0, fmt.Errorf("unknown wallet action type [%v]", value) diff --git a/pkg/tbtcpg/chain.go b/pkg/tbtcpg/chain.go index af939852e5..a1bead42c5 100644 --- a/pkg/tbtcpg/chain.go +++ b/pkg/tbtcpg/chain.go @@ -133,7 +133,8 @@ type Chain interface { proposal *tbtc.MovingFundsProposal, ) error - // Submits the moving funds target wallets commitment. + // SubmitMovingFundsCommitment submits the moving funds target wallets + // commitment. SubmitMovingFundsCommitment( walletPublicKeyHash [20]byte, walletMainUTXO bitcoin.UnspentTransactionOutput, @@ -150,8 +151,8 @@ type Chain interface { proposal *tbtc.MovedFundsSweepProposal, ) error - // Computes the moving funds commitment hash from the provided public key - // hashes of target wallets. + // ComputeMovingFundsCommitmentHash computes the moving funds commitment hash + // from the provided public key hashes of target wallets. ComputeMovingFundsCommitmentHash(targetWallets [][20]byte) [32]byte // GetRedemptionDelay returns the processing delay for the given redemption. diff --git a/pkg/tbtcpg/chain_test.go b/pkg/tbtcpg/chain_test.go index cdff0f01e3..48754b3972 100644 --- a/pkg/tbtcpg/chain_test.go +++ b/pkg/tbtcpg/chain_test.go @@ -57,6 +57,7 @@ type LocalChain struct { operatorIDs map[chain.Address]uint32 redemptionDelays map[[32]byte]time.Duration depositMinAge uint32 + depositSweepMaxSizeErr error } func NewLocalChain() *LocalChain { @@ -870,9 +871,26 @@ func (lc *LocalChain) SetRedemptionRequestMinAge(redemptionRequestMinAge uint32) } func (lc *LocalChain) GetDepositSweepMaxSize() (uint16, error) { + lc.mutex.Lock() + defer lc.mutex.Unlock() + + if lc.depositSweepMaxSizeErr != nil { + return 0, lc.depositSweepMaxSizeErr + } + panic("unsupported") } +// SetDepositSweepMaxSizeError configures the error GetDepositSweepMaxSize +// returns, allowing tests to exercise the max-size-lookup failure path +// without a real chain implementation. +func (lc *LocalChain) SetDepositSweepMaxSizeError(err error) { + lc.mutex.Lock() + defer lc.mutex.Unlock() + + lc.depositSweepMaxSizeErr = err +} + func (lc *LocalChain) BlockCounter() (chain.BlockCounter, error) { lc.mutex.Lock() defer lc.mutex.Unlock() diff --git a/pkg/tbtcpg/deposit_sweep.go b/pkg/tbtcpg/deposit_sweep.go index 42b36de377..2ac5ac6295 100644 --- a/pkg/tbtcpg/deposit_sweep.go +++ b/pkg/tbtcpg/deposit_sweep.go @@ -18,9 +18,10 @@ import ( "github.com/keep-network/keep-core/pkg/tbtc" ) -// Use the worst-case 126-byte deposit script with embedded extra data for estimation. -// This will ensure that deposit sweep transaction fees are not underestimated. -const depositScriptByteSize = 126 +// DepositScriptByteSize is the worst-case 126-byte deposit script with embedded +// extra data used for transaction size estimation. This ensures that deposit +// sweep transaction fees are not underestimated. +const DepositScriptByteSize = 126 // DepositSweepLookBackBlocks is the look-back period in blocks used // when searching for submitted deposit-related events. It's equal to @@ -147,7 +148,7 @@ func FindDeposits( // The filterStartBlock parameter controls the earliest block from which // deposit-revealed events are queried. func findDeposits( - fnLogger log.StandardLogger, + taskLogger log.StandardLogger, chain Chain, btcChain bitcoin.Chain, walletPublicKeyHash [20]byte, @@ -156,7 +157,7 @@ func findDeposits( skipUnconfirmed bool, filterStartBlock uint64, ) ([]*Deposit, error) { - fnLogger.Infof("reading revealed deposits from chain") + taskLogger.Infof("reading revealed deposits from chain") depositMinAgeSeconds, err := chain.GetDepositMinAge() if err != nil { @@ -182,14 +183,14 @@ func findDeposits( ) } - fnLogger.Infof("found [%d] DepositRevealed events", len(depositRevealedEvents)) + taskLogger.Infof("found [%d] DepositRevealed events", len(depositRevealedEvents)) // Take the oldest first sort.SliceStable(depositRevealedEvents, func(i, j int) bool { return depositRevealedEvents[i].BlockNumber < depositRevealedEvents[j].BlockNumber }) - fnLogger.Infof("getting deposits details") + taskLogger.Infof("getting deposits details") resultSliceCapacity := len(depositRevealedEvents) if maxNumberOfDeposits > 0 { @@ -208,7 +209,7 @@ func findDeposits( depositKey := chain.BuildDepositKey(event.FundingTxHash, event.FundingOutputIndex) depositKeyStr := depositKey.Text(16) - fnLogger.Debugf("getting details of deposit [%s]", depositKeyStr) + taskLogger.Debugf("getting details of deposit [%s]", depositKeyStr) depositRequest, found, err := chain.GetDepositRequest( event.FundingTxHash, @@ -230,13 +231,13 @@ func findDeposits( matureAt := depositRequest.RevealedAt.Add(depositMinAge) if !timeNow.After(matureAt) { - fnLogger.Infof("deposit [%s] is not old enough", depositKeyStr) + taskLogger.Infof("deposit [%s] is not old enough", depositKeyStr) continue } isSwept := depositRequest.SweptAt.Unix() != 0 if skipSwept && isSwept { - fnLogger.Debugf("deposit [%s] is already swept", depositKeyStr) + taskLogger.Debugf("deposit [%s] is already swept", depositKeyStr) continue } @@ -245,14 +246,14 @@ func findDeposits( event.FundingTxHash, ) if err != nil { - fnLogger.Errorf( + taskLogger.Errorf( "failed to get bitcoin transaction confirmations: [%v]", err, ) } if skipUnconfirmed && confirmations < tbtc.DepositSweepRequiredFundingTxConfirmations { - fnLogger.Debugf( + taskLogger.Debugf( "deposit [%s] funding transaction doesn't have enough confirmations: [%d/%d]", depositKeyStr, confirmations, @@ -495,7 +496,7 @@ func (dst *DepositSweepTask) ProposeDepositsSweep( // the deposits stay unswept. Log it distinctly at WARN so operators // can tell this apart from a benign "no deposits to sweep" outcome; // in particular, a safe-minimum-fee abort (see - // minWalletTxSatPerVByteFee) can indicate a misconfigured, too-low + // MinWalletTxSatPerVByteFee) can indicate a misconfigured, too-low // per-deposit maximum fee that will strand deposits until governance // raises it. taskLogger.Warnf("cannot estimate sweep transaction fee: [%v]", err) @@ -507,22 +508,16 @@ func (dst *DepositSweepTask) ProposeDepositsSweep( taskLogger.Infof("sweep transaction fee: [%d]", fee) - depositsKeys := make([]struct { - FundingTxHash bitcoin.Hash - FundingOutputIndex uint32 - }, len(deposits)) + depositsKeys := make([]tbtc.DepositKey, len(deposits)) depositsRevealBlocks := make([]*big.Int, len(deposits)) for i, deposit := range deposits { - depositsKeys[i] = struct { - FundingTxHash bitcoin.Hash - FundingOutputIndex uint32 - }{ + depositsKeys[i] = tbtc.DepositKey{ FundingTxHash: deposit.FundingTxHash, FundingOutputIndex: deposit.FundingOutputIndex, } - depositsRevealBlocks[i] = big.NewInt(int64(deposit.RevealBlock)) + depositsRevealBlocks[i] = new(big.Int).SetUint64(deposit.RevealBlock) } proposal := &tbtc.DepositSweepProposal{ @@ -565,7 +560,7 @@ func (dst *DepositSweepTask) ProposeDepositsSweep( // - 1 P2WPKH output // // An error is returned if any estimated fee exceeds the maximum fee allowed by -// the Bridge contract, or if the minimum safe fee (see minWalletTxSatPerVByteFee) +// the Bridge contract, or if the minimum safe fee (see MinWalletTxSatPerVByteFee) // required to avoid a stuck, unbumpable sweep would itself exceed that Bridge // maximum. func EstimateDepositsSweepFee( @@ -596,7 +591,7 @@ func EstimateDepositsSweepFee( } else { sweepMaxSize, err := chain.GetDepositSweepMaxSize() if err != nil { - return nil, fmt.Errorf("cannot get sweep max size: [%v]", sweepMaxSize) + return nil, fmt.Errorf("cannot get sweep max size: [%w]", err) } for i := 1; i <= int(sweepMaxSize); i++ { @@ -635,11 +630,18 @@ func estimateDepositsSweepFee( depositsCount int, perDepositMaxFee uint64, ) (int64, int64, error) { + if depositsCount <= 0 { + return 0, 0, fmt.Errorf("invalid deposits count: [%v]", depositsCount) + } + if perDepositMaxFee > math.MaxUint64/uint64(depositsCount) { + return 0, 0, fmt.Errorf("maximum sweep fee exceeds uint64 range") + } + transactionSize, err := bitcoin.NewTransactionSizeEstimator(). // 1 P2WPKH main UTXO input. AddPublicKeyHashInputs(1, true). // depositsCount P2WSH deposit inputs. - AddScriptHashInputs(depositsCount, depositScriptByteSize, true). + AddScriptHashInputs(depositsCount, DepositScriptByteSize, true). // 1 P2WPKH output. AddPublicKeyHashOutputs(1, true). VirtualSize() @@ -659,7 +661,7 @@ func estimateDepositsSweepFee( // A raw estimate already above the Bridge maximum means the sweep is // uneconomical to perform; return an error. - if uint64(totalFee) > totalMaxFee { + if totalFee < 0 || uint64(totalFee) > totalMaxFee { return 0, 0, fmt.Errorf("estimated fee exceeds the maximum fee") } diff --git a/pkg/tbtcpg/deposit_sweep_fee_test.go b/pkg/tbtcpg/deposit_sweep_fee_test.go index 185da44781..139a0a9bf9 100644 --- a/pkg/tbtcpg/deposit_sweep_fee_test.go +++ b/pkg/tbtcpg/deposit_sweep_fee_test.go @@ -1,6 +1,7 @@ package tbtcpg_test import ( + "errors" "strings" "testing" @@ -12,7 +13,7 @@ import ( // with the given number of deposit inputs, mirroring the sizing that // EstimateDepositsSweepFee performs internally: 1 P2WPKH main-UTXO input, // depositsCount P2WSH deposit inputs, and 1 P2WPKH output. 126 == -// depositScriptByteSize. +// DepositScriptByteSize. func sweepVirtualSize(t *testing.T, depositsCount int) int64 { t.Helper() size, err := bitcoin.NewTransactionSizeEstimator(). @@ -34,7 +35,9 @@ func sweepVirtualSize(t *testing.T, depositsCount int) int64 { // the informational SatPerVByteFee and the TotalFee actually broadcast on-chain // are asserted, and multi-deposit sweeps (where transactionSize grows // sub-linearly while totalMaxFee grows linearly) are exercised on both the happy -// path and the floor-exceeds-cap error branch. +// path and the floor-exceeds-cap error branch. A depositsCount of 0 is also +// covered, verifying the max-size-lookup failure is reported with its real +// underlying cause rather than the zero-value size. func TestEstimateDepositsSweepFee_MinimumFloorAndBuffer(t *testing.T) { // Virtual sizes used to pin the cap and the expected total fee (the on-chain // value) relative to the fee rate. The cap and expected-total expectations @@ -48,6 +51,7 @@ func TestEstimateDepositsSweepFee_MinimumFloorAndBuffer(t *testing.T) { depositsCount int estimateSatPerVByte int64 perDepositMaxFee uint64 + sweepMaxSizeErr error expectedSatPerVByteFee int64 expectedTotalFee int64 expectErrorContains string @@ -56,8 +60,8 @@ func TestEstimateDepositsSweepFee_MinimumFloorAndBuffer(t *testing.T) { depositsCount: 1, estimateSatPerVByte: 1, perDepositMaxFee: 100000, - expectedSatPerVByteFee: 5, // max(5, ceil(1*1.25)=2) = 5 - expectedTotalFee: 5 * size1, + expectedSatPerVByteFee: 7, // max(5, 1) = 5 -> ceil(5*1.25) = 7 + expectedTotalFee: 7 * size1, }, "estimate above the floor is buffered by 25%": { depositsCount: 1, @@ -113,12 +117,25 @@ func TestEstimateDepositsSweepFee_MinimumFloorAndBuffer(t *testing.T) { perDepositMaxFee: uint64(size3), expectErrorContains: "minimum safe transaction fee", }, + "depositsCount of 0 with a failing max size lookup returns the wrapped error": { + depositsCount: 0, + // A depositsCount of 0 takes the "estimate for every count" branch, + // which looks up the max sweep size first. Inject a distinctive + // underlying error so the assertion below fails if that cause is + // ever dropped again (the bug this guards against formatted the + // zero-value max size instead of the real error). + sweepMaxSizeErr: errors.New("boom"), + expectErrorContains: "cannot get sweep max size: [boom]", + }, } for name, test := range tests { t.Run(name, func(t *testing.T) { tbtcChain := tbtcpg.NewLocalChain() tbtcChain.SetDepositParameters(0, 0, test.perDepositMaxFee, 0) + if test.sweepMaxSizeErr != nil { + tbtcChain.SetDepositSweepMaxSizeError(test.sweepMaxSizeErr) + } btcChain := tbtcpg.NewLocalBitcoinChain() btcChain.SetEstimateSatPerVByteFee(1, test.estimateSatPerVByte) @@ -137,6 +154,13 @@ func TestEstimateDepositsSweepFee_MinimumFloorAndBuffer(t *testing.T) { test.expectErrorContains, err, ) } + if test.sweepMaxSizeErr != nil && + !errors.Is(err, test.sweepMaxSizeErr) { + t.Fatalf( + "expected error to wrap [%v]; got [%v]", + test.sweepMaxSizeErr, err, + ) + } return } if err != nil { diff --git a/pkg/tbtcpg/deposit_sweep_test.go b/pkg/tbtcpg/deposit_sweep_test.go index dbfd9e24ea..8cecd517c0 100644 --- a/pkg/tbtcpg/deposit_sweep_test.go +++ b/pkg/tbtcpg/deposit_sweep_test.go @@ -15,22 +15,6 @@ import ( "github.com/keep-network/keep-core/pkg/tbtcpg/internal/test" ) -func TestDepositSweepLookBackBlocks(t *testing.T) { - // The look-back period should be 30 days at 12 seconds per block, - // matching the value used by MovedFundsSweepLookBackBlocks. - expectedValue := uint64(216000) - - if tbtcpg.DepositSweepLookBackBlocks != expectedValue { - t.Errorf( - "unexpected DepositSweepLookBackBlocks\n"+ - "expected: %d\n"+ - "actual: %d", - expectedValue, - tbtcpg.DepositSweepLookBackBlocks, - ) - } -} - func TestDepositSweepTask_FindDepositsToSweep_BoundedLookback(t *testing.T) { // When the current block (300000) exceeds the look-back window // (216000 blocks), the filter start block should be bounded: @@ -431,47 +415,100 @@ func setupVaultGroupingDeposit( return fundingTxHash } -func TestFindDepositsToSweep_VaultGrouping(t *testing.T) { +type vaultGroupingTestHarness struct { + tbtcChain *tbtcpg.LocalChain + btcChain *tbtcpg.LocalBitcoinChain + walletPublicKeyHash [20]byte + filterStartBlock uint64 + task *tbtcpg.DepositSweepTask +} + +func newVaultGroupingTestHarness(t *testing.T) *vaultGroupingTestHarness { + t.Helper() + currentBlock := uint64(300000) filterStartBlock := currentBlock - tbtcpg.DepositSweepLookBackBlocks walletPublicKeyHash := hexToByte20( "7670343fc00ccc2d0cd65360e6ad400697ea0fed", ) - t.Run("all nil vaults form single group", func(t *testing.T) { - tbtcChain := tbtcpg.NewLocalChain() - btcChain := tbtcpg.NewLocalBitcoinChain() + tbtcChain := tbtcpg.NewLocalChain() + btcChain := tbtcpg.NewLocalBitcoinChain() + + blockCounter := tbtcpg.NewMockBlockCounter() + blockCounter.SetCurrentBlock(currentBlock) + tbtcChain.SetBlockCounter(blockCounter) + tbtcChain.SetDepositMinAge(3600) + + task := tbtcpg.NewDepositSweepTask(tbtcChain, btcChain) + + return &vaultGroupingTestHarness{ + tbtcChain: tbtcChain, + btcChain: btcChain, + walletPublicKeyHash: walletPublicKeyHash, + filterStartBlock: filterStartBlock, + task: task, + } +} + +func (h *vaultGroupingTestHarness) setupDeposit( + t *testing.T, + fundingTxHashHex string, + outputIndex uint32, + blockNumber uint64, + vault *chain.Address, +) bitcoin.Hash { + t.Helper() + + return setupVaultGroupingDeposit( + t, + h.tbtcChain, + h.btcChain, + h.walletPublicKeyHash, + h.filterStartBlock, + fundingTxHashHex, + outputIndex, + blockNumber, + vault, + ) +} + +func (h *vaultGroupingTestHarness) findDeposits( + t *testing.T, + maxDeposits uint16, +) []*tbtcpg.DepositReference { + t.Helper() + + deposits, err := h.task.FindDepositsToSweep( + &testutils.MockLogger{}, + h.walletPublicKeyHash, + maxDeposits, + ) + if err != nil { + t.Fatal(err) + } + + return deposits +} - blockCounter := tbtcpg.NewMockBlockCounter() - blockCounter.SetCurrentBlock(currentBlock) - tbtcChain.SetBlockCounter(blockCounter) - tbtcChain.SetDepositMinAge(3600) +func TestFindDepositsToSweep_VaultGrouping_SingleVault(t *testing.T) { + t.Run("all nil vaults form single group", func(t *testing.T) { + h := newVaultGroupingTestHarness(t) - hash1 := setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f01", + hash1 := h.setupDeposit( + t, "a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f01", 0, 290000, nil, ) - hash2 := setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "b2c3d4e5f6071829304b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f0102", + hash2 := h.setupDeposit( + t, "b2c3d4e5f6071829304b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f0102", 0, 290001, nil, ) - hash3 := setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "c3d4e5f607182930415c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f010203", + hash3 := h.setupDeposit( + t, "c3d4e5f607182930415c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f010203", 0, 290002, nil, ) - task := tbtcpg.NewDepositSweepTask(tbtcChain, btcChain) - deposits, err := task.FindDepositsToSweep( - &testutils.MockLogger{}, - walletPublicKeyHash, - 10, - ) - if err != nil { - t.Fatal(err) - } + deposits := h.findDeposits(t, 10) if len(deposits) != 3 { t.Fatalf("expected 3 deposits, got %d", len(deposits)) @@ -487,234 +524,152 @@ func TestFindDepositsToSweep_VaultGrouping(t *testing.T) { } }) - t.Run("mixed vaults largest group selected", func(t *testing.T) { - tbtcChain := tbtcpg.NewLocalChain() - btcChain := tbtcpg.NewLocalBitcoinChain() - - blockCounter := tbtcpg.NewMockBlockCounter() - blockCounter.SetCurrentBlock(currentBlock) - tbtcChain.SetBlockCounter(blockCounter) - tbtcChain.SetDepositMinAge(3600) + t.Run("single deposit with vault", func(t *testing.T) { + h := newVaultGroupingTestHarness(t) vaultA := chain.Address("0xAA1122BB3344CC5566DD7788EE9900FF00112233") - // 3 deposits with vaultA (largest group). - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "1111111111111111111111111111111111111111111111111111111111111111", + h.setupDeposit( + t, "ee11111111111111111111111111111111111111111111111111111111111111", 0, 290000, &vaultA, ) - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "2222222222222222222222222222222222222222222222222222222222222222", - 0, 290001, &vaultA, + + deposits := h.findDeposits(t, 10) + + if len(deposits) != 1 { + t.Fatalf("expected 1 deposit, got %d", len(deposits)) + } + + if deposits[0].Vault == nil { + t.Errorf("expected non-nil vault for the single deposit") + } else if *deposits[0].Vault != vaultA { + t.Errorf( + "expected vault %s, got %s", + string(vaultA), + string(*deposits[0].Vault), + ) + } + }) + + t.Run("4 same vault deposits all returned", func(t *testing.T) { + h := newVaultGroupingTestHarness(t) + + singleVault := chain.Address("0xAA1122BB3344CC5566DD7788EE9900FF00112233") + + // 4 deposits all targeting the same vault. + h.setupDeposit( + t, "b100000000000000000000000000000000000000000000000000000000000001", + 0, 290000, &singleVault, ) - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "3333333333333333333333333333333333333333333333333333333333333333", - 0, 290002, &vaultA, + h.setupDeposit( + t, "b200000000000000000000000000000000000000000000000000000000000002", + 0, 290001, &singleVault, ) - - // 2 deposits with nil vault (minority group). - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "4444444444444444444444444444444444444444444444444444444444444444", - 0, 290003, nil, + h.setupDeposit( + t, "b300000000000000000000000000000000000000000000000000000000000003", + 0, 290002, &singleVault, ) - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "5555555555555555555555555555555555555555555555555555555555555555", - 0, 290004, nil, + h.setupDeposit( + t, "b400000000000000000000000000000000000000000000000000000000000004", + 0, 290003, &singleVault, ) - task := tbtcpg.NewDepositSweepTask(tbtcChain, btcChain) - deposits, err := task.FindDepositsToSweep( - &testutils.MockLogger{}, - walletPublicKeyHash, - 10, - ) - if err != nil { - t.Fatal(err) - } + deposits := h.findDeposits(t, 10) - // Only the 3 vaultA deposits should be returned. - if len(deposits) != 3 { - t.Fatalf("expected 3 deposits from largest vault group, got %d", len(deposits)) + if len(deposits) != 4 { + t.Fatalf("expected 4 deposits from single vault group, got %d", len(deposits)) } for _, d := range deposits { if d.Vault == nil { t.Errorf("expected non-nil vault for selected deposit") - } else if *d.Vault != vaultA { + } else if *d.Vault != singleVault { t.Errorf( "expected vault %s, got %s", - string(vaultA), + string(singleVault), string(*d.Vault), ) } } }) +} - t.Run("mixed vaults minority group excluded", func(t *testing.T) { - tbtcChain := tbtcpg.NewLocalChain() - btcChain := tbtcpg.NewLocalBitcoinChain() - - blockCounter := tbtcpg.NewMockBlockCounter() - blockCounter.SetCurrentBlock(currentBlock) - tbtcChain.SetBlockCounter(blockCounter) - tbtcChain.SetDepositMinAge(3600) +func TestFindDepositsToSweep_VaultGrouping_MajorityVaultSelected(t *testing.T) { + t.Run("mixed vaults largest group selected", func(t *testing.T) { + h := newVaultGroupingTestHarness(t) vaultA := chain.Address("0xAA1122BB3344CC5566DD7788EE9900FF00112233") // 3 deposits with vaultA (largest group). - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "1111111111111111111111111111111111111111111111111111111111111111", + h.setupDeposit( + t, "1111111111111111111111111111111111111111111111111111111111111111", 0, 290000, &vaultA, ) - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "2222222222222222222222222222222222222222222222222222222222222222", + h.setupDeposit( + t, "2222222222222222222222222222222222222222222222222222222222222222", 0, 290001, &vaultA, ) - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "3333333333333333333333333333333333333333333333333333333333333333", + h.setupDeposit( + t, "3333333333333333333333333333333333333333333333333333333333333333", 0, 290002, &vaultA, ) - // 2 nil vault deposits (minority group). - nilHash1 := setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "4444444444444444444444444444444444444444444444444444444444444444", + // 2 deposits with nil vault (minority group). + h.setupDeposit( + t, "4444444444444444444444444444444444444444444444444444444444444444", 0, 290003, nil, ) - nilHash2 := setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "5555555555555555555555555555555555555555555555555555555555555555", + h.setupDeposit( + t, "5555555555555555555555555555555555555555555555555555555555555555", 0, 290004, nil, ) - task := tbtcpg.NewDepositSweepTask(tbtcChain, btcChain) - deposits, err := task.FindDepositsToSweep( - &testutils.MockLogger{}, - walletPublicKeyHash, - 10, - ) - if err != nil { - t.Fatal(err) - } - - // Verify nil vault deposits are NOT in the results. - for _, d := range deposits { - if d.FundingTxHash == nilHash1 || d.FundingTxHash == nilHash2 { - t.Errorf( - "nil vault deposit %v should have been excluded", - d.FundingTxHash, - ) - } - } - }) - - t.Run("vault address case normalization", func(t *testing.T) { - tbtcChain := tbtcpg.NewLocalChain() - btcChain := tbtcpg.NewLocalBitcoinChain() - - blockCounter := tbtcpg.NewMockBlockCounter() - blockCounter.SetCurrentBlock(currentBlock) - tbtcChain.SetBlockCounter(blockCounter) - tbtcChain.SetDepositMinAge(3600) - - // Same vault address in different cases; should be treated - // as the same group after normalization. - vaultUpper := chain.Address("0xAbCdEf0011223344556677889900AaBbCcDdEeFf") - vaultLower := chain.Address("0xabcdef0011223344556677889900aabbccddeeff") - - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "aa11111111111111111111111111111111111111111111111111111111111111", - 0, 290000, &vaultUpper, - ) - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "bb22222222222222222222222222222222222222222222222222222222222222", - 0, 290001, &vaultLower, - ) - - // 1 nil vault deposit (minority group). - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "cc33333333333333333333333333333333333333333333333333333333333333", - 0, 290002, nil, - ) + deposits := h.findDeposits(t, 10) - task := tbtcpg.NewDepositSweepTask(tbtcChain, btcChain) - deposits, err := task.FindDepositsToSweep( - &testutils.MockLogger{}, - walletPublicKeyHash, - 10, - ) - if err != nil { - t.Fatal(err) - } - - // The two vault deposits should form a single group (case-insensitive - // normalization), making it the largest group (2 vs 1). - if len(deposits) != 2 { - t.Fatalf("expected 2 deposits from case-normalized vault group, got %d", len(deposits)) + // Only the 3 vaultA deposits should be returned. + if len(deposits) != 3 { + t.Fatalf("expected 3 deposits from largest vault group, got %d", len(deposits)) } for _, d := range deposits { if d.Vault == nil { t.Errorf("expected non-nil vault for selected deposit") + } else if *d.Vault != vaultA { + t.Errorf( + "expected vault %s, got %s", + string(vaultA), + string(*d.Vault), + ) } } }) t.Run("nil vault is separate group from named vault", func(t *testing.T) { - tbtcChain := tbtcpg.NewLocalChain() - btcChain := tbtcpg.NewLocalBitcoinChain() - - blockCounter := tbtcpg.NewMockBlockCounter() - blockCounter.SetCurrentBlock(currentBlock) - tbtcChain.SetBlockCounter(blockCounter) - tbtcChain.SetDepositMinAge(3600) + h := newVaultGroupingTestHarness(t) vaultA := chain.Address("0xAA1122BB3344CC5566DD7788EE9900FF00112233") // 3 nil vault deposits (largest group). - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "dd11111111111111111111111111111111111111111111111111111111111111", + h.setupDeposit( + t, "dd11111111111111111111111111111111111111111111111111111111111111", 0, 290000, nil, ) - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "dd22222222222222222222222222222222222222222222222222222222222222", + h.setupDeposit( + t, "dd22222222222222222222222222222222222222222222222222222222222222", 0, 290001, nil, ) - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "dd33333333333333333333333333333333333333333333333333333333333333", + h.setupDeposit( + t, "dd33333333333333333333333333333333333333333333333333333333333333", 0, 290002, nil, ) // 1 deposit with named vault (minority group). - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "dd44444444444444444444444444444444444444444444444444444444444444", + h.setupDeposit( + t, "dd44444444444444444444444444444444444444444444444444444444444444", 0, 290003, &vaultA, ) - task := tbtcpg.NewDepositSweepTask(tbtcChain, btcChain) - deposits, err := task.FindDepositsToSweep( - &testutils.MockLogger{}, - walletPublicKeyHash, - 10, - ) - if err != nil { - t.Fatal(err) - } + deposits := h.findDeposits(t, 10) // Only the 3 nil vault deposits should be returned. if len(deposits) != 3 { @@ -728,182 +683,51 @@ func TestFindDepositsToSweep_VaultGrouping(t *testing.T) { } }) - t.Run("single deposit with vault", func(t *testing.T) { - tbtcChain := tbtcpg.NewLocalChain() - btcChain := tbtcpg.NewLocalBitcoinChain() - - blockCounter := tbtcpg.NewMockBlockCounter() - blockCounter.SetCurrentBlock(currentBlock) - tbtcChain.SetBlockCounter(blockCounter) - tbtcChain.SetDepositMinAge(3600) - - vaultA := chain.Address("0xAA1122BB3344CC5566DD7788EE9900FF00112233") - - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "ee11111111111111111111111111111111111111111111111111111111111111", - 0, 290000, &vaultA, - ) - - task := tbtcpg.NewDepositSweepTask(tbtcChain, btcChain) - deposits, err := task.FindDepositsToSweep( - &testutils.MockLogger{}, - walletPublicKeyHash, - 10, - ) - if err != nil { - t.Fatal(err) - } - - if len(deposits) != 1 { - t.Fatalf("expected 1 deposit, got %d", len(deposits)) - } - - if deposits[0].Vault == nil { - t.Errorf("expected non-nil vault for the single deposit") - } else if *deposits[0].Vault != vaultA { - t.Errorf( - "expected vault %s, got %s", - string(vaultA), - string(*deposits[0].Vault), - ) - } - }) - - t.Run("tied vault groups deterministic selection", func(t *testing.T) { - tbtcChain := tbtcpg.NewLocalChain() - btcChain := tbtcpg.NewLocalBitcoinChain() - - blockCounter := tbtcpg.NewMockBlockCounter() - blockCounter.SetCurrentBlock(currentBlock) - tbtcChain.SetBlockCounter(blockCounter) - tbtcChain.SetDepositMinAge(3600) - - vaultA := chain.Address("0xAA1122BB3344CC5566DD7788EE9900FF00112233") - - // 2 nil vault deposits. - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "ff11111111111111111111111111111111111111111111111111111111111111", - 0, 290000, nil, - ) - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "ff22222222222222222222222222222222222222222222222222222222222222", - 0, 290001, nil, - ) - - // 2 deposits with vaultA. - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "ff33333333333333333333333333333333333333333333333333333333333333", - 0, 290002, &vaultA, - ) - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "ff44444444444444444444444444444444444444444444444444444444444444", - 0, 290003, &vaultA, - ) - - task := tbtcpg.NewDepositSweepTask(tbtcChain, btcChain) - deposits, err := task.FindDepositsToSweep( - &testutils.MockLogger{}, - walletPublicKeyHash, - 10, - ) - if err != nil { - t.Fatal(err) - } - - // Exactly one complete group should be selected (2 deposits). - if len(deposits) != 2 { - t.Fatalf("expected 2 deposits from one tied group, got %d", len(deposits)) - } - - // All returned deposits must belong to the same vault group: - // either all nil or all the same non-nil vault. - allNil := true - allVaultA := true - for _, d := range deposits { - if d.Vault != nil { - allNil = false - } - if d.Vault == nil || *d.Vault != vaultA { - allVaultA = false - } - } - if !allNil && !allVaultA { - t.Errorf("deposits are from mixed vault groups; expected a single group") - } - }) - t.Run("8 deposits 5 TBTCVault 2 nil 1 other returns 5 TBTCVault", func(t *testing.T) { - tbtcChain := tbtcpg.NewLocalChain() - btcChain := tbtcpg.NewLocalBitcoinChain() - - blockCounter := tbtcpg.NewMockBlockCounter() - blockCounter.SetCurrentBlock(currentBlock) - tbtcChain.SetBlockCounter(blockCounter) - tbtcChain.SetDepositMinAge(3600) + h := newVaultGroupingTestHarness(t) tbtcVault := chain.Address("0xTBTCVaultAddress1234567890abcdef12345678") otherVault := chain.Address("0xOtherVaultAddr1234567890abcdef1234567890") // 5 deposits with TBTCVault (largest group). - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "a100000000000000000000000000000000000000000000000000000000000001", + h.setupDeposit( + t, "a100000000000000000000000000000000000000000000000000000000000001", 0, 290000, &tbtcVault, ) - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "a200000000000000000000000000000000000000000000000000000000000002", + h.setupDeposit( + t, "a200000000000000000000000000000000000000000000000000000000000002", 0, 290001, &tbtcVault, ) - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "a300000000000000000000000000000000000000000000000000000000000003", + h.setupDeposit( + t, "a300000000000000000000000000000000000000000000000000000000000003", 0, 290002, &tbtcVault, ) - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "a400000000000000000000000000000000000000000000000000000000000004", + h.setupDeposit( + t, "a400000000000000000000000000000000000000000000000000000000000004", 0, 290003, &tbtcVault, ) - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "a500000000000000000000000000000000000000000000000000000000000005", + h.setupDeposit( + t, "a500000000000000000000000000000000000000000000000000000000000005", 0, 290004, &tbtcVault, ) // 2 deposits with nil vault. - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "a600000000000000000000000000000000000000000000000000000000000006", + h.setupDeposit( + t, "a600000000000000000000000000000000000000000000000000000000000006", 0, 290005, nil, ) - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "a700000000000000000000000000000000000000000000000000000000000007", + h.setupDeposit( + t, "a700000000000000000000000000000000000000000000000000000000000007", 0, 290006, nil, ) // 1 deposit with a different vault. - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "a800000000000000000000000000000000000000000000000000000000000008", + h.setupDeposit( + t, "a800000000000000000000000000000000000000000000000000000000000008", 0, 290007, &otherVault, ) - task := tbtcpg.NewDepositSweepTask(tbtcChain, btcChain) - deposits, err := task.FindDepositsToSweep( - &testutils.MockLogger{}, - walletPublicKeyHash, - 20, - ) - if err != nil { - t.Fatal(err) - } + deposits := h.findDeposits(t, 20) if len(deposits) != 5 { t.Fatalf("expected 5 TBTCVault deposits, got %d", len(deposits)) @@ -922,150 +746,201 @@ func TestFindDepositsToSweep_VaultGrouping(t *testing.T) { } }) - t.Run("4 same vault deposits all returned", func(t *testing.T) { - tbtcChain := tbtcpg.NewLocalChain() - btcChain := tbtcpg.NewLocalBitcoinChain() - - blockCounter := tbtcpg.NewMockBlockCounter() - blockCounter.SetCurrentBlock(currentBlock) - tbtcChain.SetBlockCounter(blockCounter) - tbtcChain.SetDepositMinAge(3600) + t.Run("3 vault groups returns largest", func(t *testing.T) { + h := newVaultGroupingTestHarness(t) - singleVault := chain.Address("0xAA1122BB3344CC5566DD7788EE9900FF00112233") + vaultA := chain.Address("0xAA1122BB3344CC5566DD7788EE9900FF00112233") + vaultB := chain.Address("0xBB2233CC4455DD6677EE8899FF00AA1122334455") + vaultC := chain.Address("0xCC3344DD5566EE7788FF9900AA1122BB33445566") - // 4 deposits all targeting the same vault. - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "b100000000000000000000000000000000000000000000000000000000000001", - 0, 290000, &singleVault, + // 3 deposits with vaultA (largest group). + h.setupDeposit( + t, "c100000000000000000000000000000000000000000000000000000000000001", + 0, 290000, &vaultA, ) - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "b200000000000000000000000000000000000000000000000000000000000002", - 0, 290001, &singleVault, + h.setupDeposit( + t, "c200000000000000000000000000000000000000000000000000000000000002", + 0, 290001, &vaultA, ) - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "b300000000000000000000000000000000000000000000000000000000000003", - 0, 290002, &singleVault, + h.setupDeposit( + t, "c300000000000000000000000000000000000000000000000000000000000003", + 0, 290002, &vaultA, ) - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "b400000000000000000000000000000000000000000000000000000000000004", - 0, 290003, &singleVault, + + // 2 deposits with vaultB. + h.setupDeposit( + t, "c400000000000000000000000000000000000000000000000000000000000004", + 0, 290003, &vaultB, + ) + h.setupDeposit( + t, "c500000000000000000000000000000000000000000000000000000000000005", + 0, 290004, &vaultB, ) - task := tbtcpg.NewDepositSweepTask(tbtcChain, btcChain) - deposits, err := task.FindDepositsToSweep( - &testutils.MockLogger{}, - walletPublicKeyHash, - 10, + // 1 deposit with vaultC. + h.setupDeposit( + t, "c600000000000000000000000000000000000000000000000000000000000006", + 0, 290005, &vaultC, ) - if err != nil { - t.Fatal(err) - } - if len(deposits) != 4 { - t.Fatalf("expected 4 deposits from single vault group, got %d", len(deposits)) + deposits := h.findDeposits(t, 20) + + if len(deposits) != 3 { + t.Fatalf("expected 3 deposits from vaultA group, got %d", len(deposits)) } for _, d := range deposits { if d.Vault == nil { t.Errorf("expected non-nil vault for selected deposit") - } else if *d.Vault != singleVault { + } else if *d.Vault != vaultA { t.Errorf( "expected vault %s, got %s", - string(singleVault), + string(vaultA), string(*d.Vault), ) } } }) +} - t.Run("3 vault groups returns largest", func(t *testing.T) { - tbtcChain := tbtcpg.NewLocalChain() - btcChain := tbtcpg.NewLocalBitcoinChain() - - blockCounter := tbtcpg.NewMockBlockCounter() - blockCounter.SetCurrentBlock(currentBlock) - tbtcChain.SetBlockCounter(blockCounter) - tbtcChain.SetDepositMinAge(3600) +func TestFindDepositsToSweep_VaultGrouping_MinorityVaultExcluded(t *testing.T) { + t.Run("mixed vaults minority group excluded", func(t *testing.T) { + h := newVaultGroupingTestHarness(t) vaultA := chain.Address("0xAA1122BB3344CC5566DD7788EE9900FF00112233") - vaultB := chain.Address("0xBB2233CC4455DD6677EE8899FF00AA1122334455") - vaultC := chain.Address("0xCC3344DD5566EE7788FF9900AA1122BB33445566") // 3 deposits with vaultA (largest group). - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "c100000000000000000000000000000000000000000000000000000000000001", + h.setupDeposit( + t, "1111111111111111111111111111111111111111111111111111111111111111", 0, 290000, &vaultA, ) - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "c200000000000000000000000000000000000000000000000000000000000002", + h.setupDeposit( + t, "2222222222222222222222222222222222222222222222222222222222222222", 0, 290001, &vaultA, ) - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "c300000000000000000000000000000000000000000000000000000000000003", + h.setupDeposit( + t, "3333333333333333333333333333333333333333333333333333333333333333", 0, 290002, &vaultA, ) - // 2 deposits with vaultB. - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "c400000000000000000000000000000000000000000000000000000000000004", - 0, 290003, &vaultB, + // 2 nil vault deposits (minority group). + nilHash1 := h.setupDeposit( + t, "4444444444444444444444444444444444444444444444444444444444444444", + 0, 290003, nil, ) - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "c500000000000000000000000000000000000000000000000000000000000005", - 0, 290004, &vaultB, + nilHash2 := h.setupDeposit( + t, "5555555555555555555555555555555555555555555555555555555555555555", + 0, 290004, nil, ) - // 1 deposit with vaultC. - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "c600000000000000000000000000000000000000000000000000000000000006", - 0, 290005, &vaultC, + deposits := h.findDeposits(t, 10) + + // Verify nil vault deposits are NOT in the results. + for _, d := range deposits { + if d.FundingTxHash == nilHash1 || d.FundingTxHash == nilHash2 { + t.Errorf( + "nil vault deposit %v should have been excluded", + d.FundingTxHash, + ) + } + } + }) +} + +func TestFindDepositsToSweep_VaultGrouping_AddressCaseNormalization(t *testing.T) { + t.Run("vault address case normalization", func(t *testing.T) { + h := newVaultGroupingTestHarness(t) + + // Same vault address in different cases; should be treated + // as the same group after normalization. + vaultUpper := chain.Address("0xAbCdEf0011223344556677889900AaBbCcDdEeFf") + vaultLower := chain.Address("0xabcdef0011223344556677889900aabbccddeeff") + + h.setupDeposit( + t, "aa11111111111111111111111111111111111111111111111111111111111111", + 0, 290000, &vaultUpper, + ) + h.setupDeposit( + t, "bb22222222222222222222222222222222222222222222222222222222222222", + 0, 290001, &vaultLower, ) - task := tbtcpg.NewDepositSweepTask(tbtcChain, btcChain) - deposits, err := task.FindDepositsToSweep( - &testutils.MockLogger{}, - walletPublicKeyHash, - 20, + // 1 nil vault deposit (minority group). + h.setupDeposit( + t, "cc33333333333333333333333333333333333333333333333333333333333333", + 0, 290002, nil, ) - if err != nil { - t.Fatal(err) - } - if len(deposits) != 3 { - t.Fatalf("expected 3 deposits from vaultA group, got %d", len(deposits)) + deposits := h.findDeposits(t, 10) + + // The two vault deposits should form a single group (case-insensitive + // normalization), making it the largest group (2 vs 1). + if len(deposits) != 2 { + t.Fatalf("expected 2 deposits from case-normalized vault group, got %d", len(deposits)) } for _, d := range deposits { if d.Vault == nil { t.Errorf("expected non-nil vault for selected deposit") - } else if *d.Vault != vaultA { - t.Errorf( - "expected vault %s, got %s", - string(vaultA), - string(*d.Vault), - ) } } }) +} - t.Run("post-reinitializer vault from chain request", func(t *testing.T) { - tbtcChain := tbtcpg.NewLocalChain() - btcChain := tbtcpg.NewLocalBitcoinChain() +func TestFindDepositsToSweep_VaultGrouping_TiedGroups(t *testing.T) { + t.Run("tied vault groups deterministic selection", func(t *testing.T) { + h := newVaultGroupingTestHarness(t) + + vaultA := chain.Address("0xAA1122BB3344CC5566DD7788EE9900FF00112233") + + // 2 nil vault deposits. + h.setupDeposit( + t, "ff11111111111111111111111111111111111111111111111111111111111111", + 0, 290000, nil, + ) + h.setupDeposit( + t, "ff22222222222222222222222222222222222222222222222222222222222222", + 0, 290001, nil, + ) + + // 2 deposits with vaultA. + h.setupDeposit( + t, "ff33333333333333333333333333333333333333333333333333333333333333", + 0, 290002, &vaultA, + ) + h.setupDeposit( + t, "ff44444444444444444444444444444444444444444444444444444444444444", + 0, 290003, &vaultA, + ) - blockCounter := tbtcpg.NewMockBlockCounter() - blockCounter.SetCurrentBlock(currentBlock) - tbtcChain.SetBlockCounter(blockCounter) - tbtcChain.SetDepositMinAge(3600) + deposits := h.findDeposits(t, 10) + + // Exactly one complete group should be selected (2 deposits). + if len(deposits) != 2 { + t.Fatalf("expected 2 deposits from one tied group, got %d", len(deposits)) + } + + // All returned deposits must belong to the same vault group: + // either all nil or all the same non-nil vault. + allNil := true + allVaultA := true + for _, d := range deposits { + if d.Vault != nil { + allNil = false + } + if d.Vault == nil || *d.Vault != vaultA { + allVaultA = false + } + } + if !allNil && !allVaultA { + t.Errorf("deposits are from mixed vault groups; expected a single group") + } + }) +} + +func TestFindDepositsToSweep_VaultGrouping_PostReinitializer(t *testing.T) { + t.Run("post-reinitializer vault from chain request", func(t *testing.T) { + h := newVaultGroupingTestHarness(t) tbtcVault := chain.Address("0xTBTCVaultAddress1234567890abcdef12345678") @@ -1075,21 +950,12 @@ func TestFindDepositsToSweep_VaultGrouping(t *testing.T) { // helper passes vault to DepositChainRequest.Vault which is // the field used by findDeposits() for building the Deposit // object. - setupVaultGroupingDeposit( - t, tbtcChain, btcChain, walletPublicKeyHash, filterStartBlock, - "d100000000000000000000000000000000000000000000000000000000000001", + h.setupDeposit( + t, "d100000000000000000000000000000000000000000000000000000000000001", 0, 290000, &tbtcVault, ) - task := tbtcpg.NewDepositSweepTask(tbtcChain, btcChain) - deposits, err := task.FindDepositsToSweep( - &testutils.MockLogger{}, - walletPublicKeyHash, - 10, - ) - if err != nil { - t.Fatal(err) - } + deposits := h.findDeposits(t, 10) if len(deposits) != 1 { t.Fatalf("expected 1 deposit, got %d", len(deposits)) diff --git a/pkg/tbtcpg/fee.go b/pkg/tbtcpg/fee.go index b1e2acc43e..9a3da0b96c 100644 --- a/pkg/tbtcpg/fee.go +++ b/pkg/tbtcpg/fee.go @@ -3,6 +3,10 @@ package tbtcpg import ( "errors" "fmt" + "math" + + "github.com/keep-network/keep-core/pkg/bitcoin" + "github.com/keep-network/keep-core/pkg/tbtc" ) // ErrMaxFeeTooLow indicates that the Bridge maximum total fee is too low to @@ -14,60 +18,76 @@ var ErrMaxFeeTooLow = errors.New( "minimum safe transaction fee exceeds the maximum fee", ) -// minWalletTxSatPerVByteFee is the minimum fee rate, in sat/vByte, applied to -// wallet Bitcoin transactions (deposit sweeps, redemptions, moving funds, moved -// funds sweeps). A fee oracle can return an unusably low estimate (down to the -// 1 sat/vByte relay floor enforced by the Electrum client) in an uncongested -// mempool. Because these transactions spend or consolidate significant wallet -// value and are not RBF-enabled, they cannot be replaced once broadcast, so a -// floor-rate transaction can get stuck in the mempool and jam the wallet: no -// new wallet transaction can be built while the previous one is unconfirmed. -// This minimum keeps the fee safely above the relay floor while remaining far -// below the Bridge's maximum fee. The value is intentionally conservative and -// could be made configurable; see threshold-network/keep-core#4171. -// -// NOTE: this static floor and the 25% buffer applied in applyWalletTxFeeFloor -// are a stopgap for the current fire-and-forget, non-RBF wallet transaction -// path: because a stuck transaction cannot be fee-bumped, the fee must be right -// on the first broadcast. Once RBF / fee-bumping lands (Part B, tracked in -// #4171) the safety net shifts to monitor-and-bump, and this policy should be -// revisited rather than carried forward unchanged: the defensive buffer can be -// dropped and the floor relaxed toward the live estimate, keeping only a small -// relay-propagation minimum. -const minWalletTxSatPerVByteFee = 5 +// maxWalletTxVsize and maxWalletTxEstimatedFee are sanity bounds on the +// applyWalletTxFeeFloor inputs. They are intentionally far above any +// realistic Bitcoin transaction (block weight caps vsize at ~4M weight +// units; a wallet tx fee over a few BTC is itself implausible) so +// legitimate callers never trip them. They are also defense-in-depth for +// the checked-arithmetic overflow guards below: a value within these +// bounds is guaranteed (modulo the explicit checks) to keep the internal +// int64 multiplications in range. +const ( + maxWalletTxVsize int64 = 10_000_000 // 10M vbytes; ~10x the 1M vbyte maximum Bitcoin block size. + maxWalletTxEstimatedFee int64 = 1_000_000_000 // 1e9 satoshis = 10 BTC. +) // applyWalletTxFeeFloor raises a raw oracle fee estimate to a safe value for a // non-RBF wallet transaction. It: -// - adds a 25% buffer over the oracle estimate so there is margin during the -// estimate-to-broadcast delay and the fee stays adaptive under congestion, -// - enforces a floor of minWalletTxSatPerVByteFee sat/vByte, and -// - bounds the result by maxTotalFee (the Bridge maximum total fee for the -// transaction). +// - enforces a floor of tbtc.MinWalletTxSatPerVByteFee sat/vByte, +// - applies a safety buffer (default 25%, controlled by +// tbtc.WalletTxFeeBufferPercent) over the effective per-vByte fee rate +// (ceil(max(rawRate, floor) * (100 + bufferPercent) / 100)) so there is +// margin during the estimate-to-broadcast delay and the fee stays +// adaptive under congestion, and +// - bounds the result by maxTotalFee (the Bridge maximum total fee for +// the transaction). +// +// It returns ErrMaxFeeTooLow if the safe buffered floor alone would exceed +// maxTotalFee - a safe transaction cannot be built, so the caller must +// not broadcast an underpriced one. estimatedFee is the raw oracle fee +// in satoshis and txVsize is the estimated transaction virtual size in +// vBytes. Both inputs are sanity-bounded against maxWalletTxEstimatedFee +// / maxWalletTxVsize to prevent int64 overflow in the internal +// multiplications when the oracle or size-estimator returns an +// implausible value; an input outside the bound is rejected with an +// error rather than silently overflowing. The buffer addition/multiplication +// and the final totalFee multiplication additionally have +// checked-arithmetic overflow guards so an operator-tuned +// tbtc.WalletTxFeeBufferPercent / tbtc.MinWalletTxSatPerVByteFee +// cannot bypass the bound by exceeding the int64 limit on its own. // -// It returns ErrMaxFeeTooLow if the minimum floor alone would exceed -// maxTotalFee - a safe transaction cannot be built, so the caller must not -// broadcast an underpriced one. estimatedFee is the raw oracle fee in satoshis -// and txVsize is the estimated transaction virtual size in vBytes. +// The policy values (the floor and the buffer percentage) live in +// pkg/tbtc as exported vars so the leader-side floor application +// (here) and the follower-side soft check +// (pkg/tbtc.warnIfProposedWalletTxFeeBelowBufferedFloor, used by every +// wallet-tx proposal validator) consume a single source of truth. +// Both sides enforce the same invariant: effective rate is +// ceil(max(rawRate, configuredFloor) * (100 + bufferPercent) / 100), +// and the follower threshold is the same buffered configured floor. +// Operator tuning one side automatically tunes the other. // -// The 25% buffer is applied to the truncated per-vByte rate -// (estimatedFee / txVsize). This is lossless only because EstimateFee returns -// the fee as satPerVByteFee * txVsize (an exact multiple of the vsize), so the -// integer division recovers the exact rate. If that contract ever changes so -// estimatedFee is no longer an exact multiple of txVsize, apply the buffer to -// estimatedFee directly instead of to the truncated rate; otherwise up to -// txVsize-1 sat is silently dropped before buffering and the tx is underpriced. +// The buffer is applied to the clamped per-vByte rate +// max(estimatedFee / txVsize, tbtc.MinWalletTxSatPerVByteFee). This is +// lossless only because EstimateFee returns the fee as satPerVByteFee * txVsize +// (an exact multiple of the vsize), so the integer division recovers the +// exact rate. If that contract ever changes so estimatedFee is no longer an +// exact multiple of txVsize, apply the buffer to estimatedFee directly instead +// of to the truncated rate; otherwise up to txVsize-1 sat is silently +// dropped before buffering and the tx is underpriced. // -// maxTotalFee bounds only the total transaction fee. Where the Bridge also -// enforces a per-request cap (e.g. the redemption TxMaxFee), satisfying that -// cap is the caller's or on-chain validation's responsibility; this helper is -// unaware of it. Callers are expected to reject a raw estimate already above -// maxTotalFee before calling (all current callers do); the result is in any -// case clamped down to maxTotalFee. +// maxTotalFee bounds only the total transaction fee. Where the Bridge +// also enforces a per-request cap (e.g. the redemption TxMaxFee), +// satisfying that cap is the caller's or on-chain validation's +// responsibility; this helper is unaware of it. Callers are expected to +// reject a raw estimate already above maxTotalFee before calling (all +// current callers do); the result is in any case clamped down to +// maxTotalFee, provided maxTotalFee meets or exceeds the safe buffered floor. // -// The buffer and floor are applied to the estimated vsize; a transaction whose -// real on-wire vsize is larger than estimated (e.g. a deposit sweep containing -// legacy P2SH inputs) can land slightly below the intended rate, but still far -// above the relay floor this guards against. +// The buffer and floor are applied to the estimated vsize; a +// transaction whose real on-wire vsize is larger than estimated (e.g. +// a deposit sweep containing legacy P2SH inputs) can land slightly +// below the intended rate, but still far above the relay floor this +// guards against. func applyWalletTxFeeFloor( estimatedFee int64, txVsize int64, @@ -76,30 +96,162 @@ func applyWalletTxFeeFloor( if txVsize <= 0 { return 0, fmt.Errorf("invalid transaction virtual size [%d]", txVsize) } + if txVsize > maxWalletTxVsize { + return 0, fmt.Errorf( + "implausible transaction virtual size [%d]; expected at most [%d]", + txVsize, maxWalletTxVsize, + ) + } + if estimatedFee < 0 { + return 0, fmt.Errorf("invalid estimated fee [%d]", estimatedFee) + } + if estimatedFee > maxWalletTxEstimatedFee { + return 0, fmt.Errorf( + "implausible estimated fee [%d]; expected at most [%d]", + estimatedFee, maxWalletTxEstimatedFee, + ) + } + if tbtc.MinWalletTxSatPerVByteFee <= 0 { + return 0, fmt.Errorf( + "implausible minimum fee rate [%d]; expected positive", + tbtc.MinWalletTxSatPerVByteFee, + ) + } + if tbtc.WalletTxFeeBufferPercent < 0 { + return 0, fmt.Errorf( + "invalid wallet tx fee buffer percent [%d]; must be non-negative", + tbtc.WalletTxFeeBufferPercent, + ) + } + const bufferDenominator = 100 + if tbtc.WalletTxFeeBufferPercent > math.MaxInt64-100 { + return 0, fmt.Errorf( + "implausible wallet tx fee buffer percent [%d]; addition would overflow", + tbtc.WalletTxFeeBufferPercent, + ) + } + bufferNumerator := 100 + tbtc.WalletTxFeeBufferPercent - // If even the minimum floor exceeds the Bridge maximum, a safe transaction - // cannot be constructed; error rather than silently broadcast underpriced. - if uint64(minWalletTxSatPerVByteFee*txVsize) > maxTotalFee { + rate := estimatedFee / txVsize + if rate < tbtc.MinWalletTxSatPerVByteFee { + rate = tbtc.MinWalletTxSatPerVByteFee + } + + // Checked-arithmetic guard for the buffer multiplication. Inputs + // are also bounded (maxWalletTxVsize / maxWalletTxEstimatedFee), so + // this is defense in depth: even if an operator tunes + // tbtc.WalletTxFeeBufferPercent to a huge value, we reject rate + // values whose product with bufferNumerator (plus + // bufferDenominator-1 for the ceiling) cannot fit in int64. + maxRateForBuffer := (math.MaxInt64 - (bufferDenominator - 1)) / bufferNumerator + if rate > maxRateForBuffer { + return 0, fmt.Errorf( + "implausible per-vByte rate [%d] would overflow when "+ + "applied with buffer percent [%d]; expected at most [%d]", + rate, + tbtc.WalletTxFeeBufferPercent, + maxRateForBuffer, + ) + } + + // ceil(rate * (100+Percent) / 100). Both rate and bufferNumerator + // are positive, so the multiplication cannot overflow; see the + // rate-vs-maxRateForBuffer check above. + rate = (rate*bufferNumerator + bufferDenominator - 1) / bufferDenominator + + // Compute the safe buffered minimum floor rate. Since rate >= MinWalletTxSatPerVByteFee + // and rate <= maxRateForBuffer, this calculation cannot overflow int64. + bufferedFloorRate := (tbtc.MinWalletTxSatPerVByteFee*bufferNumerator + + bufferDenominator - 1) / bufferDenominator + + // Checked-arithmetic guard: bufferedFloorRate * txVsize must fit in int64 + // to keep the int64 product in range. Both operands are positive int64. + if bufferedFloorRate > math.MaxInt64/txVsize { + return 0, fmt.Errorf( + "implausible buffered minimum fee rate [%d] for vsize [%d]; "+ + "product would overflow", + bufferedFloorRate, txVsize, + ) + } + + feeLimit := int64(math.MaxInt64) + if maxTotalFee <= math.MaxInt64 { + feeLimit = int64(maxTotalFee) + } + bufferedFloorProduct := bufferedFloorRate * txVsize + if bufferedFloorProduct > feeLimit { return 0, fmt.Errorf( "%w: minimum fee [%d], maximum fee [%d]", ErrMaxFeeTooLow, - minWalletTxSatPerVByteFee*txVsize, + bufferedFloorProduct, maxTotalFee, ) } - rate := estimatedFee / txVsize - rate = (rate*5 + 3) / 4 // ceil(rate * 1.25) - if rate < minWalletTxSatPerVByteFee { - rate = minWalletTxSatPerVByteFee + // Checked-arithmetic guard for the total-fee multiplication: rate * + // txVsize must fit in int64. rate is positive and txVsize is + // bounded above by maxWalletTxVsize, so this is defense in depth: an + // operator-tuned tbtc.MinWalletTxSatPerVByteFee (e.g. set to + // MaxInt64) would otherwise push rate past MaxInt64 / txVsize. + if rate > math.MaxInt64/txVsize { + return 0, fmt.Errorf( + "implausible buffered rate [%d] would overflow when multiplied "+ + "by txVsize [%d]; expected at most [%d]", + rate, txVsize, math.MaxInt64/txVsize, + ) } - // Clamp down to the Bridge maximum total fee. This can never drop the fee - // below the floor: the floor-vs-cap guard above already guaranteed - // maxTotalFee is at least the minimum floor total. + // Clamp down to the Bridge maximum total fee. This can never drop + // the fee below the safe buffered floor: the bufferedFloorProduct-vs-cap + // guard above already guaranteed maxTotalFee is at least the minimum + // safe buffered floor total. The product is guaranteed to fit in int64 by + // the rate*txVsize guard above. totalFee := rate * txVsize - if uint64(totalFee) > maxTotalFee { - totalFee = int64(maxTotalFee) + if totalFee > feeLimit { + totalFee = feeLimit + } + + return totalFee, nil +} + +// estimateCappedFee estimates the transaction fee for a transaction of the +// virtual size produced by the given size estimator, returning an error if +// the size or fee estimation itself fails. It returns feeTooHighErr if the +// estimated fee exceeds maxTotalFee. Otherwise, it applies the non-RBF +// wallet transaction fee buffer and minimum fee-rate floor via +// applyWalletTxFeeFloor, without exceeding maxTotalFee, and can return +// ErrMaxFeeTooLow or a validation error from that call. +func estimateCappedFee( + btcChain bitcoin.Chain, + sizeEstimator *bitcoin.TransactionSizeEstimator, + maxTotalFee uint64, + feeTooHighErr error, +) (int64, error) { + transactionSize, err := sizeEstimator.VirtualSize() + if err != nil { + return 0, fmt.Errorf( + "cannot estimate transaction virtual size: [%v]", + err, + ) + } + + feeEstimator := bitcoin.NewTransactionFeeEstimator(btcChain) + + totalFee, err := feeEstimator.EstimateFee(transactionSize) + if err != nil { + return 0, fmt.Errorf("cannot estimate transaction fee: [%v]", err) + } + + if totalFee < 0 || uint64(totalFee) > maxTotalFee { + return 0, feeTooHighErr + } + + // Enforce the safe minimum fee rate and buffer so a non-RBF wallet + // transaction is never broadcast below the floor where it could get + // stuck and jam the wallet. + totalFee, err = applyWalletTxFeeFloor(totalFee, transactionSize, maxTotalFee) + if err != nil { + return 0, err } return totalFee, nil diff --git a/pkg/tbtcpg/fee_test.go b/pkg/tbtcpg/fee_test.go index cdb522c53e..7274233fa0 100644 --- a/pkg/tbtcpg/fee_test.go +++ b/pkg/tbtcpg/fee_test.go @@ -1,10 +1,27 @@ package tbtcpg import ( + "math" "strings" "testing" + + "github.com/keep-network/keep-core/pkg/tbtc" ) +// withWalletTxFeePolicy saves the current wallet-tx fee-floor policy +// (floor, buffer percent) and registers a t.Cleanup that restores it. +// Tests overriding the canonical pkg/tbtc vars MUST use this helper so +// later tests in the same package see the production defaults. +func withWalletTxFeePolicy(t *testing.T) { + t.Helper() + originalFloor := tbtc.MinWalletTxSatPerVByteFee + originalPercent := tbtc.WalletTxFeeBufferPercent + t.Cleanup(func() { + tbtc.MinWalletTxSatPerVByteFee = originalFloor + tbtc.WalletTxFeeBufferPercent = originalPercent + }) +} + func TestApplyWalletTxFeeFloor(t *testing.T) { const vsize = 200 @@ -15,6 +32,12 @@ func TestApplyWalletTxFeeFloor(t *testing.T) { expectedFee int64 expectErrorContains string }{ + "unsigned maximum cap preserves the normal fee": { + estimatedFee: 4000, txVsize: vsize, maxTotalFee: math.MaxUint64, expectedFee: 5000, + }, + "signed maximum cap preserves the normal fee": { + estimatedFee: 4000, txVsize: vsize, maxTotalFee: math.MaxInt64, expectedFee: 5000, + }, "estimate above the floor is buffered by 25%": { estimatedFee: 4000, // rate 20 sat/vByte txVsize: vsize, @@ -25,7 +48,7 @@ func TestApplyWalletTxFeeFloor(t *testing.T) { estimatedFee: vsize, // rate 1 sat/vByte txVsize: vsize, maxTotalFee: 100000, - expectedFee: 1000, // max(5, ceil(1*1.25)=2)=5 sat/vByte * 200 + expectedFee: 1400, // max(5, 1) = 5 -> ceil(5*1.25)=7 sat/vByte * 200 }, "buffered fee above the cap is bounded to the cap": { estimatedFee: 4000, // rate 20 -> buffered 25 sat/vByte * 200 = 5000 @@ -40,15 +63,21 @@ func TestApplyWalletTxFeeFloor(t *testing.T) { expectedFee: 5000, }, "minimum floor exactly at the cap is allowed": { - estimatedFee: 100, // rate 0 -> floored to 5 sat/vByte + estimatedFee: 100, // rate 0 -> clamped to 5 -> buffered to 7 sat/vByte txVsize: vsize, - maxTotalFee: 1000, // exactly the 5 sat/vByte floor total (5*200) - expectedFee: 1000, + maxTotalFee: 1400, // exactly the 7 sat/vByte buffered floor total (7*200) + expectedFee: 1400, + }, + "cap at bare floor is rejected as below the buffered floor": { + estimatedFee: 100, + txVsize: vsize, + maxTotalFee: 1000, // 5 sat/vByte bare floor total (1000) < 7 sat/vByte buffered floor (1400) + expectErrorContains: "minimum safe transaction fee", }, "minimum floor above the cap returns an error": { estimatedFee: 100, txVsize: vsize, - maxTotalFee: 800, // below the 5 sat/vByte floor (1000) + maxTotalFee: 800, // below the 7 sat/vByte buffered floor (1400) expectErrorContains: "minimum safe transaction fee", }, "non-positive virtual size returns an error": { @@ -57,6 +86,24 @@ func TestApplyWalletTxFeeFloor(t *testing.T) { maxTotalFee: 100000, expectErrorContains: "invalid transaction virtual size", }, + "negative estimated fee returns an error": { + estimatedFee: -1, + txVsize: vsize, + maxTotalFee: 100000, + expectErrorContains: "invalid estimated fee", + }, + "implausibly large virtual size returns an error": { + estimatedFee: 1000, + txVsize: maxWalletTxVsize + 1, + maxTotalFee: 100000, + expectErrorContains: "implausible transaction virtual size", + }, + "implausibly large estimated fee returns an error": { + estimatedFee: maxWalletTxEstimatedFee + 1, + txVsize: vsize, + maxTotalFee: 100000, + expectErrorContains: "implausible estimated fee", + }, } for name, tc := range tests { @@ -91,3 +138,143 @@ func TestApplyWalletTxFeeFloor(t *testing.T) { }) } } + +// TestApplyWalletTxFeeFloor_BufferOverride verifies that the safety buffer +// is driven by the canonical pkg/tbtc WalletTxFeeBufferPercent var, not +// a hardcoded constant. A test that overrides the var MUST restore it +// via t.Cleanup so other tests see the production defaults. +func TestApplyWalletTxFeeFloor_BufferOverride(t *testing.T) { + const vsize = 200 + withWalletTxFeePolicy(t) + + // 50% buffer. At rate 20 sat/vByte the buffered rate becomes + // ceil(20 * 150 / 100) = 30 sat/vByte, total 6000. + tbtc.WalletTxFeeBufferPercent = 50 + + fee, err := applyWalletTxFeeFloor( + 4000, // rate 20 sat/vByte + vsize, + 100000, // well above the buffered 6000 + ) + if err != nil { + t.Fatalf("unexpected error: [%v]", err) + } + if fee != 6000 { + t.Errorf( + "unexpected fee with 50%% buffer\nexpected: [6000]\nactual: [%d]", + fee, + ) + } + + // Disable the buffer (Percent=0). The buffered rate equals the raw + // rate, so a 20 sat/vByte estimate stays at 20 sat/vByte (above the + // floor), total 4000. + tbtc.WalletTxFeeBufferPercent = 0 + + fee, err = applyWalletTxFeeFloor( + 4000, + vsize, + 100000, + ) + if err != nil { + t.Fatalf("unexpected error: [%v]", err) + } + if fee != 4000 { + t.Errorf( + "unexpected fee with buffer disabled\nexpected: [4000]\nactual: [%d]", + fee, + ) + } + + // Negative buffer values are rejected so the helper cannot apply a + // sub-floor buffer (a percent below 0 would make the multiplier + // less than 1x, undermining the safety margin). + tbtc.WalletTxFeeBufferPercent = -1 + _, err = applyWalletTxFeeFloor(4000, vsize, 100000) + if err == nil { + t.Fatalf("expected an error for Percent=-1") + } + if !strings.Contains(err.Error(), "invalid wallet tx fee buffer percent") { + t.Fatalf( + "expected error containing [invalid wallet tx fee buffer percent]; got [%v]", + err, + ) + } +} + +// TestApplyWalletTxFeeFloor_OverflowGuard verifies that the helper rejects +// configurations whose internal multiplications (rate * bufferNumerator, +// rate * txVsize, floor * txVsize) would overflow int64. The overflow +// guards are checked-arithmetic and are the hard guarantee; the +// input-cap (maxWalletTxVsize / maxWalletTxEstimatedFee) is +// defense-in-depth that can never be reached for sane operator-tuned +// values, so this test exercises the checked-arithmetic path +// explicitly. +func TestApplyWalletTxFeeFloor_OverflowGuard(t *testing.T) { + const vsize = 200 + withWalletTxFeePolicy(t) + + // Oversized buffer: buffer percent set to math.MaxInt64 so 100+Percent + // would overflow int64. The helper rejects this explicitly before addition. + tbtc.WalletTxFeeBufferPercent = math.MaxInt64 + + _, err := applyWalletTxFeeFloor( + 4000, + vsize, + 100000, + ) + if err == nil { + t.Fatalf("expected overflow error for Percent=MaxInt64") + } + if !strings.Contains(err.Error(), "addition would overflow") { + t.Fatalf( + "expected error containing [addition would overflow]; got [%v]", + err, + ) + } + + // Buffer percent set so the derived numerator (100+Percent) is + // close to MaxInt64: rate * numerator overflows for any + // non-trivial rate. The helper rejects this rather than silently + // wrapping around into the buffer math. + tbtc.WalletTxFeeBufferPercent = math.MaxInt64 - 100 + + _, err = applyWalletTxFeeFloor( + 4000, // rate 20 sat/vByte + vsize, + 100000, + ) + if err == nil { + t.Fatalf("expected overflow error for Percent=MaxInt64-100") + } + if !strings.Contains(err.Error(), "would overflow when applied with buffer") { + t.Fatalf( + "expected error containing [would overflow when applied with buffer]; got [%v]", + err, + ) + } + + // Restore sane buffer. + tbtc.WalletTxFeeBufferPercent = tbtc.DefaultWalletTxFeeBufferPercent + + // Floor so high that floor * txVsize would overflow int64. With + // estimatedFee=0 the raw rate is 0, but the floor forces rate to + // tbtc.MinWalletTxSatPerVByteFee, which the checked-arithmetic + // guard catches before any multiplication happens. + tbtc.MinWalletTxSatPerVByteFee = math.MaxInt64 / 2 + + _, err = applyWalletTxFeeFloor( + 0, // raw rate 0 + vsize, + math.MaxUint64, + ) + if err == nil { + t.Fatalf("expected overflow error for huge MinWalletTxSatPerVByteFee") + } + if !strings.Contains(err.Error(), "would overflow") { + t.Fatalf( + "expected error containing [would overflow]; got [%v]", + err, + ) + } +} diff --git a/pkg/tbtcpg/internal/test/manifest_test.go b/pkg/tbtcpg/internal/test/manifest_test.go new file mode 100644 index 0000000000..f6f9f8e8a9 --- /dev/null +++ b/pkg/tbtcpg/internal/test/manifest_test.go @@ -0,0 +1,103 @@ +package test + +import ( + "os" + "path/filepath" + "runtime" + "testing" +) + +// Required fixture files in pkg/tbtcpg/internal/test/testdata. +// These slices explicitly enumerate all fixture files required by the test +// suite. Directory globbing is avoided because a glob that matches nothing +// would pass silently. +var ( + requiredFindDepositsFixtures = []string{ + "find_deposits_scenario_0.json", + "find_deposits_scenario_1.json", + "find_deposits_scenario_2.json", + } + + requiredProposeSweepFixtures = []string{ + "propose_sweep_scenario_0.json", + "propose_sweep_scenario_1.json", + "propose_sweep_scenario_2.json", + } + + requiredFindPendingRedemptionsFixtures = []string{ + "find_pending_redemptions_scenario_0.json", + "find_pending_redemptions_scenario_1.json", + "find_pending_redemptions_scenario_2.json", + "find_pending_redemptions_scenario_3.json", + } +) + +// TestRequiredFixturesPresent guards the test fixtures in testdata against +// accidental deletion or omission. +func TestRequiredFixturesPresent(t *testing.T) { + _, callerFileName, _, _ := runtime.Caller(0) + testDataDir := filepath.Join(filepath.Dir(callerFileName), "testdata") + + tests := []struct { + name string + required []string + load func() (int, error) + }{ + { + name: "FindDeposits", + required: requiredFindDepositsFixtures, + load: func() (int, error) { + scenarios, err := LoadFindDepositsToSweepTestScenario() + return len(scenarios), err + }, + }, + { + name: "ProposeSweep", + required: requiredProposeSweepFixtures, + load: func() (int, error) { + scenarios, err := LoadProposeSweepTestScenario() + return len(scenarios), err + }, + }, + { + name: "FindPendingRedemptions", + required: requiredFindPendingRedemptionsFixtures, + load: func() (int, error) { + scenarios, err := LoadFindPendingRedemptionsTestScenario() + return len(scenarios), err + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + if len(tc.required) == 0 { + t.Fatal("manifest is empty") + } + + for _, fileName := range tc.required { + filePath := filepath.Join(testDataDir, fileName) + if _, err := os.Stat(filePath); err != nil { + t.Errorf("missing required fixture file [%s]: %v", fileName, err) + } + } + + count, err := tc.load() + if err != nil { + t.Fatalf("loader failed: %v", err) + } + + if count == 0 { + t.Fatal("loader returned 0 scenarios") + } + + if count != len(tc.required) { + t.Errorf( + "unexpected scenario count: got %d, want %d", + count, + len(tc.required), + ) + } + }) + } +} diff --git a/pkg/tbtcpg/internal/test/marshaling.go b/pkg/tbtcpg/internal/test/marshaling.go index 91c390df6e..44231c9c45 100644 --- a/pkg/tbtcpg/internal/test/marshaling.go +++ b/pkg/tbtcpg/internal/test/marshaling.go @@ -5,10 +5,12 @@ import ( "encoding/json" "errors" "fmt" - "github.com/keep-network/keep-core/pkg/tbtcpg" + "math" "math/big" "time" + "github.com/keep-network/keep-core/pkg/tbtcpg" + "github.com/keep-network/keep-core/internal/hexutils" "github.com/keep-network/keep-core/pkg/bitcoin" "github.com/keep-network/keep-core/pkg/tbtc" @@ -91,8 +93,19 @@ func (dsts *FindDepositsToSweepTestScenario) UnmarshalJSON(data []byte) error { for i, deposit := range unmarshaled.Deposits { d := new(Deposit) + if deposit.Age < 0 || deposit.Age > math.MaxInt64/int64(time.Second) || averageBlockTime.Milliseconds() <= 0 { + return fmt.Errorf("invalid age or average block time") + } age := time.Duration(deposit.Age) * time.Second - ageBlocks := uint64(age.Milliseconds() / averageBlockTime.Milliseconds()) + blockCount := age.Milliseconds() / averageBlockTime.Milliseconds() + if blockCount < 0 { + return fmt.Errorf("invalid block age") + } + ageBlocks := uint64(blockCount) + + if ageBlocks > currentBlock { + return fmt.Errorf("invalid block age: age exceeds current block") + } revealedAt := now.Add(-age) revealBlockNumber := currentBlock - ageBlocks @@ -170,10 +183,7 @@ func (dsp *depositSweepProposal) convert() ( copy(walletPublicKeyHash[:], hexToSlice(dsp.WalletPublicKeyHash)) } - result.DepositsKeys = make([]struct { - FundingTxHash bitcoin.Hash - FundingOutputIndex uint32 - }, len(dsp.DepositsKeys)) + result.DepositsKeys = make([]tbtc.DepositKey, len(dsp.DepositsKeys)) for i, depositKey := range dsp.DepositsKeys { fundingTxHash, err := bitcoin.NewHashFromString(depositKey.FundingTxHash, bitcoin.ReversedByteOrder) if err != nil { @@ -274,6 +284,8 @@ func (psts *ProposeSweepTestScenario) UnmarshalJSON(data []byte) error { // Unmarshal expected error if len(unmarshaled.ExpectedErr) > 0 { + // fmt.Errorf requires a constant format string; ExpectedErr is a + // plain string so use errors.New to avoid formatting interpretation. psts.ExpectedErr = errors.New(unmarshaled.ExpectedErr) } @@ -333,8 +345,19 @@ func (fprts *FindPendingRedemptionsTestScenario) UnmarshalJSON(data []byte) erro var wpkh [20]byte copy(wpkh[:], hexToSlice(pr.WalletPublicKeyHash)) + if pr.Age < 0 || pr.Age > math.MaxInt64/int64(time.Second) || averageBlockTime.Milliseconds() <= 0 { + return fmt.Errorf("invalid age or average block time") + } age := time.Duration(pr.Age) * time.Second - ageBlocks := uint64(age.Milliseconds() / averageBlockTime.Milliseconds()) + blockCount := age.Milliseconds() / averageBlockTime.Milliseconds() + if blockCount < 0 { + return fmt.Errorf("invalid block age") + } + ageBlocks := uint64(blockCount) + + if ageBlocks > currentBlock { + return fmt.Errorf("invalid block age: age exceeds current block") + } requestedAt := now.Add(-age) requestBlock := currentBlock - ageBlocks diff --git a/pkg/tbtcpg/moved_funds_sweep.go b/pkg/tbtcpg/moved_funds_sweep.go index 47b188f587..40fc2b2bdb 100644 --- a/pkg/tbtcpg/moved_funds_sweep.go +++ b/pkg/tbtcpg/moved_funds_sweep.go @@ -393,32 +393,10 @@ func EstimateMovedFundsSweepFee( AddPublicKeyHashInputs(inputCount, true). AddPublicKeyHashOutputs(1, true) - transactionSize, err := sizeEstimator.VirtualSize() - if err != nil { - return 0, fmt.Errorf( - "cannot estimate transaction virtual size: [%v]", - err, - ) - } - - feeEstimator := bitcoin.NewTransactionFeeEstimator(btcChain) - - totalFee, err := feeEstimator.EstimateFee(transactionSize) - if err != nil { - return 0, fmt.Errorf("cannot estimate transaction fee: [%v]", err) - } - - if uint64(totalFee) > sweepTxMaxTotalFee { - return 0, ErrSweepTxFeeTooHigh - } - - // Enforce the safe minimum fee rate and buffer so a non-RBF moved funds - // sweep transaction is never broadcast below the floor where it could get - // stuck and jam the wallet. - totalFee, err = applyWalletTxFeeFloor(totalFee, transactionSize, sweepTxMaxTotalFee) - if err != nil { - return 0, err - } - - return totalFee, nil + return estimateCappedFee( + btcChain, + sizeEstimator, + sweepTxMaxTotalFee, + ErrSweepTxFeeTooHigh, + ) } diff --git a/pkg/tbtcpg/moved_funds_sweep_test.go b/pkg/tbtcpg/moved_funds_sweep_test.go index d010b6613f..73813d68dc 100644 --- a/pkg/tbtcpg/moved_funds_sweep_test.go +++ b/pkg/tbtcpg/moved_funds_sweep_test.go @@ -453,9 +453,9 @@ func TestEstimateMovedFundsSweepFee(t *testing.T) { estimateSatPerVByte: 1, sweepTxMaxTotalFee: 3000, hasMainUtxo: false, - // raw 110 (110 vByte * 1 sat/vByte), buffered ceil(1*1.25)=2 is - // below the 5 sat/vByte floor, so clamped to 5 * 110 = 550. - expectedFee: 550, + // raw 110 (110 vByte * 1 sat/vByte), clamped to 5 sat/vByte floor + // and buffered to ceil(5*1.25)=7 sat/vByte * 110 = 770. + expectedFee: 770, expectedError: nil, }, "estimated fee too high": { @@ -468,8 +468,8 @@ func TestEstimateMovedFundsSweepFee(t *testing.T) { "minimum floor exceeds the max total fee": { estimateSatPerVByte: 1, // raw 110 (110 vByte * 1 sat/vByte) is below the cap, so it passes - // the raw-estimate guard, but the 5 sat/vByte floor total (550) - // exceeds the cap, so a safe sweep cannot be built. + // the raw-estimate guard, but the 7 sat/vByte buffered floor total + // (770) exceeds the cap, so a safe sweep cannot be built. sweepTxMaxTotalFee: 400, hasMainUtxo: false, expectedFee: 0, diff --git a/pkg/tbtcpg/moving_funds.go b/pkg/tbtcpg/moving_funds.go index 9f78e4a871..88fc006d8c 100644 --- a/pkg/tbtcpg/moving_funds.go +++ b/pkg/tbtcpg/moving_funds.go @@ -338,13 +338,13 @@ func (mft *MovingFundsTask) findNewTargetWallets( if wallet.State == tbtc.StateLive { targetWallets = append(targetWallets, walletPubKeyHash) } - if len(targetWallets) == int(targetWalletsCount) { + if uint64(len(targetWallets)) == targetWalletsCount { // Stop the iteration if enough live wallets have been gathered. break } } - if len(targetWallets) != int(targetWalletsCount) { + if uint64(len(targetWallets)) != targetWalletsCount { return nil, fmt.Errorf( "%w: required [%v] target wallets; gathered [%v]", ErrNotEnoughTargetWallets, @@ -639,32 +639,5 @@ func EstimateMovingFundsFee( AddPublicKeyHashInputs(1, true). AddPublicKeyHashOutputs(targetWalletsCount, true) - transactionSize, err := sizeEstimator.VirtualSize() - if err != nil { - return 0, fmt.Errorf( - "cannot estimate transaction virtual size: [%v]", - err, - ) - } - - feeEstimator := bitcoin.NewTransactionFeeEstimator(btcChain) - - totalFee, err := feeEstimator.EstimateFee(transactionSize) - if err != nil { - return 0, fmt.Errorf("cannot estimate transaction fee: [%v]", err) - } - - if uint64(totalFee) > txMaxTotalFee { - return 0, ErrFeeTooHigh - } - - // Enforce the safe minimum fee rate and buffer so a non-RBF moving funds - // transaction is never broadcast below the floor where it could get stuck - // and jam the wallet. - totalFee, err = applyWalletTxFeeFloor(totalFee, transactionSize, txMaxTotalFee) - if err != nil { - return 0, err - } - - return totalFee, nil + return estimateCappedFee(btcChain, sizeEstimator, txMaxTotalFee, ErrFeeTooHigh) } diff --git a/pkg/tbtcpg/moving_funds_test.go b/pkg/tbtcpg/moving_funds_test.go index c0b8a1913f..39183cdff8 100644 --- a/pkg/tbtcpg/moving_funds_test.go +++ b/pkg/tbtcpg/moving_funds_test.go @@ -667,9 +667,9 @@ func TestEstimateMovingFundsFee(t *testing.T) { "low estimate is raised to the minimum floor": { estimateSatPerVByte: 1, txMaxTotalFee: 6000, - // raw 203 (203 vByte * 1 sat/vByte), buffered ceil(1*1.25)=2 is - // below the 5 sat/vByte floor, so clamped to 5 * 203 = 1015. - expectedFee: 1015, + // raw 203 (203 vByte * 1 sat/vByte), clamped to 5 sat/vByte floor + // and buffered to ceil(5*1.25)=7 sat/vByte * 203 = 1421. + expectedFee: 1421, expectedError: nil, }, "estimated fee too high": { @@ -681,8 +681,8 @@ func TestEstimateMovingFundsFee(t *testing.T) { "minimum floor exceeds the max total fee": { estimateSatPerVByte: 1, // raw 203 (203 vByte * 1 sat/vByte) is below the cap, so it passes - // the raw-estimate guard, but the 5 sat/vByte floor total (1015) - // exceeds the cap, so a safe transaction cannot be built. + // the raw-estimate guard, but the 7 sat/vByte buffered floor total + // (1421) exceeds the cap, so a safe transaction cannot be built. txMaxTotalFee: 500, expectedFee: 0, expectedError: tbtcpg.ErrMaxFeeTooLow, diff --git a/pkg/tbtcpg/proposal_metrics_test.go b/pkg/tbtcpg/proposal_metrics_test.go new file mode 100644 index 0000000000..8839091860 --- /dev/null +++ b/pkg/tbtcpg/proposal_metrics_test.go @@ -0,0 +1,76 @@ +package tbtcpg + +import ( + "reflect" + "testing" + + "github.com/keep-network/keep-core/pkg/clientinfo" + "github.com/keep-network/keep-core/pkg/tbtc" +) + +// The node cannot import tbtcpg. Pin its exact structural setter signature. +var _ interface { + SetProposalMetricsRecorder(interface { + IncrementCounter(string, float64) + }) +} = (*ProposalGenerator)(nil) + +type proposalMetrics map[string]float64 + +func (m proposalMetrics) IncrementCounter(name string, value float64) { + m[name] += value +} + +func TestProposalGenerationMetrics(t *testing.T) { + for _, test := range []struct { + name string + redemption mockProposalTaskResult + fallback mockProposalTaskResult + attempts float64 + failures float64 + generated float64 + checklist []tbtc.WalletActionType + }{ + {"generated", resultProposal, resultEmpty, 1, 0, 1, nil}, + {"no pending requests", resultEmpty, resultEmpty, 1, 0, 0, nil}, + {"failure followed by successful fallback", resultError, resultProposal, 1, 1, 0, nil}, + {"failure followed by no-op fallback", resultError, resultEmpty, 1, 1, 0, nil}, + {"all tasks fail", resultError, resultError, 1, 1, 0, nil}, + {"redemption not scheduled", resultError, resultProposal, 0, 0, 0, []tbtc.WalletActionType{tbtc.ActionDepositSweep}}, + {"earlier task succeeds", resultError, resultProposal, 0, 0, 0, []tbtc.WalletActionType{tbtc.ActionDepositSweep, tbtc.ActionRedemption}}, + } { + t.Run(test.name, func(t *testing.T) { + walletPKH := [20]byte{1} + generator := &ProposalGenerator{tasks: []ProposalTask{ + &mockProposalTask{action: tbtc.ActionRedemption, results: map[[20]byte]mockProposalTaskResult{walletPKH: test.redemption}}, + &mockProposalTask{action: tbtc.ActionDepositSweep, results: map[[20]byte]mockProposalTaskResult{walletPKH: test.fallback}}, + }} + recorder := proposalMetrics{} + generator.SetProposalMetricsRecorder(recorder) + checklist := test.checklist + if checklist == nil { + checklist = []tbtc.WalletActionType{tbtc.ActionRedemption, tbtc.ActionDepositSweep} + } + _, _ = generator.Generate(&tbtc.CoordinationProposalRequest{WalletPublicKeyHash: walletPKH, ActionsChecklist: checklist}) + expected := map[string]float64{ + clientinfo.MetricRedemptionProposalGenerationTotal: test.attempts, + clientinfo.MetricRedemptionProposalGenerationFailedTotal: test.failures, + clientinfo.MetricRedemptionProposalGenerationSuccessTotal: test.generated, + } + for name, value := range expected { + if recorder[name] != value { + t.Errorf("%s: got %v, want %v", name, recorder[name], value) + } + } + before := make(proposalMetrics) + for name, value := range recorder { + before[name] = value + } + generator.SetProposalMetricsRecorder(nil) + _, _ = generator.Generate(&tbtc.CoordinationProposalRequest{WalletPublicKeyHash: walletPKH, ActionsChecklist: checklist}) + if !reflect.DeepEqual(before, recorder) { + t.Fatal("disabled recorder was still updated") + } + }) + } +} diff --git a/pkg/tbtcpg/redemptions.go b/pkg/tbtcpg/redemptions.go index d4d845ee6c..0a4f2c6a8f 100644 --- a/pkg/tbtcpg/redemptions.go +++ b/pkg/tbtcpg/redemptions.go @@ -2,6 +2,7 @@ package tbtcpg import ( "fmt" + "math" "math/big" "sort" "time" @@ -211,31 +212,49 @@ func (rt *RedemptionTask) ProposeRedemption( taskLogger.Infof("preparing a redemption proposal") - // Estimate fee if it's missing. Here we bound the estimate by the maximum - // total fee only. The per-request maximum fee (TxMaxFee, snapshotted per - // request at request creation) is enforced solely by the on-chain - // validation of the proposal and is not checked here. Note that the - // safe-minimum floor (see EstimateRedemptionFee) raises the total fee and - // therefore each request's fee share, so it can push a share above that - // request's per-request maximum even while the total stays within - // txMaxTotalFee; such a proposal is rejected only by on-chain validation. + // Estimate fee if it's missing. The Bridge enforces two independent caps + // on the redemption transaction fee: a flat total-fee cap (txMaxTotalFee) + // and a per-request fee-share cap (txMaxFee) applied once the total fee + // is split evenly across the redemption requests (see the on-chain + // mirroring logic in tbtc.withRedemptionTotalFee). Both caps are checked + // during the on-chain validation of the proposal, but only a bound that + // accounts for both keeps the safe-minimum floor (see + // EstimateRedemptionFee) from producing a fee either cap would reject. + // We derive an aggregate ceiling from the per-request cap - txMaxFee + // scaled by the number of requests, mirroring the on-chain per-request + // division - and bound the estimate by the tighter of the two caps. if fee <= 0 { taskLogger.Infof("estimating redemption transaction fee") - redemptionParams, err := rt.chain.GetRedemptionParameters() + redemptionParameters, err := rt.chain.GetRedemptionParameters() if err != nil { return nil, fmt.Errorf( - "cannot get redemption tx max total fee: [%w]", + "cannot get redemption tx max fee parameters: [%w]", err, ) } - txMaxFee := redemptionParams.TxMaxFee - txMaxTotalFee := redemptionParams.TxMaxTotalFee + + txMaxFee := redemptionParameters.TxMaxFee + txMaxTotalFee := redemptionParameters.TxMaxTotalFee + + maxTotalFee := txMaxTotalFee + requestCount := uint64(len(redeemersOutputScripts)) + // Skip the per-request cap when (a) no per-request cap is configured + // (txMaxFee == 0) or (b) the aggregate `txMaxFee * requestCount` would + // overflow uint64. In the overflow case we fall back to txMaxTotalFee + // rather than wrapping to a small value and silently rejecting every + // fee estimate; the on-chain per-request cap still applies regardless + // of how the off-chain ceiling was derived. + if txMaxFee == 0 || requestCount <= math.MaxUint64/txMaxFee { + if perRequestMaxTotalFee := txMaxFee * requestCount; perRequestMaxTotalFee < maxTotalFee { + maxTotalFee = perRequestMaxTotalFee + } + } estimatedFee, err := EstimateRedemptionFee( rt.btcChain, redeemersOutputScripts, - txMaxTotalFee, + maxTotalFee, ) if err != nil { return nil, fmt.Errorf( @@ -261,7 +280,7 @@ func (rt *RedemptionTask) ProposeRedemption( // diagnostic rather than an exact predictor. requestsCount := int64(len(redeemersOutputScripts)) maxShare := fee/requestsCount + fee%requestsCount - if uint64(maxShare) > txMaxFee { + if maxShare < 0 || uint64(maxShare) > txMaxFee { taskLogger.Warnf( "floored redemption fee share [%d] exceeds the per-request "+ "maximum fee [%d]; the proposal will likely be rejected "+ @@ -294,7 +313,7 @@ func (rt *RedemptionTask) ProposeRedemption( } func findPendingRedemptions( - fnLogger log.StandardLogger, + taskLogger log.StandardLogger, chain Chain, walletPublicKeyHash [20]byte, currentBlockNumber uint64, @@ -364,9 +383,9 @@ func findPendingRedemptions( eventsSet[hexutils.Encode(redemptionKey.Bytes())] = event } - fnLogger.Infof("found [%d] RedemptionRequested events", len(eventsSet)) + taskLogger.Infof("found [%d] RedemptionRequested events", len(eventsSet)) - fnLogger.Infof("checking pending redemptions details") + taskLogger.Infof("checking pending redemptions details") pendingRedemptions := make([]*RedemptionRequest, 0) @@ -375,7 +394,7 @@ redemptionRequestedLoop: for redemptionKey, event := range eventsSet { eventIndex++ - fnLogger.Debugf( + taskLogger.Debugf( "getting pending redemption details [%s]", redemptionKey, ) @@ -393,7 +412,7 @@ redemptionRequestedLoop: ) } if !found { - fnLogger.Infof( + taskLogger.Infof( "redemption request [%s] is no longer pending", redemptionKey, ) @@ -452,7 +471,7 @@ redemptionRequestedLoop: minAge = delay } - fnLogger.Infof( + taskLogger.Infof( "minimum age for redemption request [%s] is [%v]", redemption.RedemptionKey, minAge, @@ -469,7 +488,7 @@ redemptionRequestedLoop: // Check if timeout passed for the redemption request. if pendingRedemption.RequestedAt.Before(redemptionRequestsRangeStartTimestamp) { - fnLogger.Infof( + taskLogger.Infof( "redemption request [%s] has already timed out", pendingRedemption.RedemptionKey, ) @@ -489,7 +508,7 @@ redemptionRequestedLoop: // Check if enough time elapsed since the redemption request. if pendingRedemption.RequestedAt.After(rangeEndTimestamp) { - fnLogger.Infof( + taskLogger.Infof( "redemption request [%s] is not old enough", pendingRedemption.RedemptionKey, ) @@ -504,14 +523,18 @@ redemptionRequestedLoop: // EstimateRedemptionFee estimates fee for the redemption transaction that pays // the provided redeemers output scripts. The estimated fee is floored at a safe -// minimum rate and bounded above by txMaxTotalFee (the Bridge total-fee -// maximum), so a non-RBF redemption is not proposed below the floor where it -// could get stuck and jam the wallet. Only the total fee is bounded here; the -// per-request maximum fee is enforced separately by on-chain validation. +// minimum rate and bounded above by maxTotalFee, so a non-RBF redemption is +// never broadcast below the floor where it could get stuck and jam the wallet. +// +// maxTotalFee is the upper bound for the total transaction fee. The Bridge +// enforces both a flat total-fee cap and a separate per-request fee-share cap; +// this function only has visibility into the aggregate transaction, so callers +// must resolve those into a single ceiling - the tighter of the two - before +// calling this function. func EstimateRedemptionFee( btcChain bitcoin.Chain, redeemersOutputScripts []bitcoin.Script, - txMaxTotalFee uint64, + maxTotalFee uint64, ) (int64, error) { sizeEstimator := bitcoin.NewTransactionSizeEstimator(). // 1 P2WPKH main UTXO input. @@ -546,16 +569,15 @@ func EstimateRedemptionFee( return 0, fmt.Errorf("cannot estimate transaction fee: [%v]", err) } - // A raw estimate already above the Bridge maximum means the redemption is + // A raw estimate already above the maximum means the redemption is // uneconomical to perform at the required fee; return an error rather than // clamping to the maximum and broadcasting an underpriced transaction. - if uint64(totalFee) > txMaxTotalFee { + if totalFee < 0 || uint64(totalFee) > maxTotalFee { return 0, fmt.Errorf("estimated fee exceeds the maximum fee") } - // Enforce the safe minimum fee rate and buffer, bounded by the Bridge - // maximum. - totalFee, err = applyWalletTxFeeFloor(totalFee, transactionSize, txMaxTotalFee) + // Enforce the safe minimum fee rate and buffer, bounded by maxTotalFee. + totalFee, err = applyWalletTxFeeFloor(totalFee, transactionSize, maxTotalFee) if err != nil { return 0, err } diff --git a/pkg/tbtcpg/redemptions_test.go b/pkg/tbtcpg/redemptions_test.go index 2aef02fa73..fb4859cd44 100644 --- a/pkg/tbtcpg/redemptions_test.go +++ b/pkg/tbtcpg/redemptions_test.go @@ -3,6 +3,7 @@ package tbtcpg_test import ( "encoding/hex" "fmt" + "math" "math/big" "strings" "testing" @@ -50,16 +51,29 @@ func TestEstimateRedemptionFee(t *testing.T) { "low estimate is raised to the minimum floor": { estimateSatPerVByte: 1, txMaxTotalFee: 100000, - expectedFee: 1250, // max(5, ceil(1*1.25)=2)=5 sat/vByte * 250 vByte + expectedFee: 1750, // max(5, 1) = 5 -> ceil(5*1.25)=7 sat/vByte * 250 vByte = 1750 }, "minimum floor above the cap returns an error": { estimateSatPerVByte: 1, txMaxTotalFee: uint64(3 * vsize), // below the 5 sat/vByte floor expectErrorContains: "minimum safe transaction fee", }, + "buffered fee above the cap is bounded to the cap": { + // raw 4000 (250 vByte * 16 sat/vByte) is at or below the cap, so it + // passes the raw-estimate check; the 25% buffer lifts it to 5000, + // which is then bounded down to the cap rather than erroring. + estimateSatPerVByte: 16, + txMaxTotalFee: 4500, // between the raw 4000 and buffered 5000 + expectedFee: 4500, + }, "raw estimate above the cap returns an error": { - estimateSatPerVByte: 16, // raw 16*250 = 4000 - txMaxTotalFee: 3000, // below the raw estimate + // raw 5000 (250 vByte * 20 sat/vByte) already exceeds the cap, so the + // redemption is uneconomical and errors before the floor is applied, + // rather than broadcasting an underpriced transaction. This trades + // liveness (the redemption is not attempted this round) for not + // broadcasting a fee the Bridge would reject. + estimateSatPerVByte: 20, + txMaxTotalFee: 4000, // below the raw 5000 estimate expectErrorContains: "estimated fee exceeds the maximum fee", }, } @@ -207,21 +221,54 @@ func TestRedemptionAction_ProposeRedemption(t *testing.T) { var tests = map[string]struct { fee int64 + txMaxFee uint64 + txMaxTotalFee uint64 expectedProposal *tbtc.RedemptionProposal }{ "fee provided": { - fee: 10000, + fee: 10000, + txMaxFee: 6000, + txMaxTotalFee: 6000, expectedProposal: &tbtc.RedemptionProposal{ RedeemersOutputScripts: redeemersOutputScripts, RedemptionTxFee: big.NewInt(10000), }, }, "fee estimated": { - fee: 0, // trigger fee estimation + fee: 0, // trigger fee estimation + txMaxFee: 6000, + txMaxTotalFee: 6000, + expectedProposal: &tbtc.RedemptionProposal{ + RedeemersOutputScripts: redeemersOutputScripts, + // raw 4300 (172 vByte * 25 sat/vByte), buffered to + // ceil(25*1.25)=32 sat/vByte * 172 = 5504, below both caps. + RedemptionTxFee: big.NewInt(5504), + }, + }, + "fee estimated, bounded by the per-request fee-share cap": { + fee: 0, // trigger fee estimation + txMaxFee: 2500, // aggregated over 2 requests: 5000 + txMaxTotalFee: 100000, + expectedProposal: &tbtc.RedemptionProposal{ + RedeemersOutputScripts: redeemersOutputScripts, + // The buffered fee (5504, see above) would fit under + // txMaxTotalFee alone, but must also respect the per-request + // fee-share cap once aggregated over the 2 requests + // (2 * 2500 = 5000), which is the tighter of the two caps. + RedemptionTxFee: big.NewInt(5000), + }, + }, + "fee estimated, huge per-request cap falls back to txMaxTotalFee": { + fee: 0, // trigger fee estimation + txMaxFee: (math.MaxUint64 / 2) + 1, + txMaxTotalFee: 6000, expectedProposal: &tbtc.RedemptionProposal{ RedeemersOutputScripts: redeemersOutputScripts, // raw 4300 (172 vByte * 25 sat/vByte), buffered to - // ceil(25*1.25)=32 sat/vByte * 172 = 5504, below the cap. + // ceil(25*1.25)=32 sat/vByte * 172 = 5504, below both caps. + // The per-request cap aggregate overflows uint64, which + // would wrap to 0 in unchecked arithmetic and reject the + // estimate; checked multiplication keeps txMaxTotalFee. RedemptionTxFee: big.NewInt(5504), }, }, @@ -234,9 +281,9 @@ func TestRedemptionAction_ProposeRedemption(t *testing.T) { btcChain.SetEstimateSatPerVByteFee(1, 25) - // Fee estimation bounds the safe-minimum floor by the redemption - // tx max total fee; set a cap comfortably above the buffered fee. - tbtcChain.SetRedemptionParameters(0, 0, 0, 6000, 0, nil, 0) + // Fee estimation bounds the safe-minimum floor by the tighter of + // the redemption tx max fee (per-request) and max total fee. + tbtcChain.SetRedemptionParameters(0, 0, test.txMaxFee, test.txMaxTotalFee, 0, nil, 0) for _, script := range redeemersOutputScripts { tbtcChain.SetPendingRedemptionRequest( @@ -316,16 +363,31 @@ func TestRedemptionAction_ProposeRedemption_PerRequestFeeWarning(t *testing.T) { var tests = map[string]struct { txMaxFee uint64 + txMaxTotalFee uint64 + expectedFee int64 expectWarning bool }{ "worst-case share within the per-request cap": { - txMaxFee: 3000, // 2166 <= 3000 + // Aggregate cap = txMaxFee*count = 3000*3 = 9000, looser than + // txMaxTotalFee (8000), so the total-fee cap governs and the fee + // is unclamped; 2166 <= 3000 so no warning either. + txMaxFee: 3000, + txMaxTotalFee: 8000, + expectedFee: 6496, expectWarning: false, }, - "even share at the cap but last-request share exceeds it": { - // The even share 2165 equals the cap (a floor-division check would - // not warn), but the last request pays 2166 and would be rejected. + "total-fee cap clamps to a value whose remainder exceeds the per-request cap": { + // The aggregate per-request ceiling (txMaxFee*count = 2165*3 = + // 6495) is looser than txMaxTotalFee (6494), so txMaxTotalFee + // governs and the buffered fee (6496) is clamped down to 6494 - + // not a multiple of count, so the remainder still lands + // unevenly. The even share is floor(6494/3) = 2164 and the last + // request pays 2164 + 6494%3 = 2166, which exceeds txMaxFee + // (2165) even though the aggregate cap alone would not have + // forced an uneven split. txMaxFee: 2165, + txMaxTotalFee: 6494, + expectedFee: 6494, expectWarning: true, }, } @@ -337,9 +399,8 @@ func TestRedemptionAction_ProposeRedemption_PerRequestFeeWarning(t *testing.T) { btcChain.SetEstimateSatPerVByteFee(1, 25) - // txMaxFee at index 2; txMaxTotalFee at index 3, set comfortably - // above the estimated total (6496) so it does not bound the fee. - tbtcChain.SetRedemptionParameters(0, 0, test.txMaxFee, 8000, 0, nil, 0) + // txMaxFee at index 2; txMaxTotalFee at index 3. + tbtcChain.SetRedemptionParameters(0, 0, test.txMaxFee, test.txMaxTotalFee, 0, nil, 0) for _, script := range redeemersOutputScripts { tbtcChain.SetPendingRedemptionRequest( @@ -352,7 +413,7 @@ func TestRedemptionAction_ProposeRedemption_PerRequestFeeWarning(t *testing.T) { expectedProposal := &tbtc.RedemptionProposal{ RedeemersOutputScripts: redeemersOutputScripts, - RedemptionTxFee: big.NewInt(6496), + RedemptionTxFee: big.NewInt(test.expectedFee), } err := tbtcChain.SetRedemptionProposalValidationResult( diff --git a/pkg/tbtcpg/tbtcpg.go b/pkg/tbtcpg/tbtcpg.go index 38e2be8628..5036a1eb8d 100644 --- a/pkg/tbtcpg/tbtcpg.go +++ b/pkg/tbtcpg/tbtcpg.go @@ -19,6 +19,7 @@ import ( "github.com/ipfs/go-log/v2" "github.com/keep-network/keep-core/pkg/bitcoin" + "github.com/keep-network/keep-core/pkg/clientinfo" "github.com/keep-network/keep-core/pkg/tbtc" "go.uber.org/zap" "golang.org/x/exp/slices" @@ -42,7 +43,19 @@ type ProposalTask interface { // ProposalGenerator is a component responsible for generating coordination // proposals for tbtc wallets. type ProposalGenerator struct { - tasks []ProposalTask + tasks []ProposalTask + proposalMetrics interface { + IncrementCounter(name string, value float64) + } +} + +// SetProposalMetricsRecorder records redemption task outcomes, including errors +// followed by a successful fallback task. Keep the anonymous parameter in sync +// with the node's structural interface assertion to avoid an import cycle. +func (pg *ProposalGenerator) SetProposalMetricsRecorder(recorder interface { + IncrementCounter(name string, value float64) +}) { + pg.proposalMetrics = recorder } // SetRedemptionMetricsRecorder sets the metrics recorder for the redemption task. @@ -112,12 +125,24 @@ func (pg *ProposalGenerator) Generate( continue } + if action == tbtc.ActionRedemption && pg.proposalMetrics != nil { + pg.proposalMetrics.IncrementCounter(clientinfo.MetricRedemptionProposalGenerationTotal, 1) + } proposal, ok, err := pg.tasks[taskIndex].Run(request) if err != nil { - walletLogger.With( + if action == tbtc.ActionRedemption && pg.proposalMetrics != nil { + pg.proposalMetrics.IncrementCounter(clientinfo.MetricRedemptionProposalGenerationFailedTotal, 1) + } + taskFailedLogger := walletLogger.With( zap.String("action", action.String()), zap.Error(err), - ).Error("proposal task failed; continuing with next task") + ) + if action == tbtc.ActionRedemption { + taskFailedLogger = taskFailedLogger.With( + zap.String("event", "redemption_proposal_generation_failed"), + ) + } + taskFailedLogger.Error("proposal task failed; continuing with next task") taskErrors = append(taskErrors, fmt.Errorf("task [%s]: [%w]", action, err)) continue } @@ -130,6 +155,10 @@ func (pg *ProposalGenerator) Generate( continue } + if action == tbtc.ActionRedemption && pg.proposalMetrics != nil { + pg.proposalMetrics.IncrementCounter(clientinfo.MetricRedemptionProposalGenerationSuccessTotal, 1) + } + walletLogger.Infof( "proposal task [%s] completed with a result", action, diff --git a/pkg/tecdsa/dkg/dkg.go b/pkg/tecdsa/dkg/dkg.go index a2acfef876..5c5ce5c6e2 100644 --- a/pkg/tecdsa/dkg/dkg.go +++ b/pkg/tecdsa/dkg/dkg.go @@ -8,9 +8,9 @@ import ( "github.com/ipfs/go-log/v2" - "github.com/keep-network/keep-common/pkg/persistence" "github.com/keep-network/keep-core/pkg/generator" "github.com/keep-network/keep-core/pkg/net" + "github.com/keep-network/keep-core/pkg/persistence" "github.com/keep-network/keep-core/pkg/protocol/group" "github.com/keep-network/keep-core/pkg/protocol/state" ) diff --git a/pkg/tecdsa/dkg/integer_conversion_test.go b/pkg/tecdsa/dkg/integer_conversion_test.go new file mode 100644 index 0000000000..a53a66a7b7 --- /dev/null +++ b/pkg/tecdsa/dkg/integer_conversion_test.go @@ -0,0 +1,127 @@ +package dkg + +import ( + "testing" + + "google.golang.org/protobuf/proto" + + "github.com/keep-network/keep-core/pkg/tecdsa/dkg/gen/pb" +) + +// TestUnmarshal_SenderIDBounds verifies that every round message rejects a +// SenderID value that overflows group.MaxMemberIndex. +func TestUnmarshal_SenderIDBounds(t *testing.T) { + tests := map[string]struct { + marshal func(senderID uint32) ([]byte, error) + decode func(bytes []byte) error + }{ + "ephemeralPublicKeyMessage": { + marshal: func(senderID uint32) ([]byte, error) { + return proto.Marshal(&pb.EphemeralPublicKeyMessage{SenderID: senderID}) + }, + decode: func(bytes []byte) error { + return new(ephemeralPublicKeyMessage).Unmarshal(bytes) + }, + }, + "tssRoundOneMessage": { + marshal: func(senderID uint32) ([]byte, error) { + return proto.Marshal(&pb.TSSRoundOneMessage{SenderID: senderID}) + }, + decode: func(bytes []byte) error { + return new(tssRoundOneMessage).Unmarshal(bytes) + }, + }, + "tssRoundTwoMessage": { + marshal: func(senderID uint32) ([]byte, error) { + return proto.Marshal(&pb.TSSRoundTwoMessage{SenderID: senderID}) + }, + decode: func(bytes []byte) error { + return new(tssRoundTwoMessage).Unmarshal(bytes) + }, + }, + "tssRoundThreeMessage": { + marshal: func(senderID uint32) ([]byte, error) { + return proto.Marshal(&pb.TSSRoundThreeMessage{SenderID: senderID}) + }, + decode: func(bytes []byte) error { + return new(tssRoundThreeMessage).Unmarshal(bytes) + }, + }, + "tssFinalizationMessage": { + marshal: func(senderID uint32) ([]byte, error) { + return proto.Marshal(&pb.TSSFinalizationMessage{SenderID: senderID}) + }, + decode: func(bytes []byte) error { + return new(tssFinalizationMessage).Unmarshal(bytes) + }, + }, + "resultSignatureMessage": { + marshal: func(senderID uint32) ([]byte, error) { + return proto.Marshal(&pb.ResultSignatureMessage{SenderID: senderID}) + }, + decode: func(bytes []byte) error { + return new(resultSignatureMessage).Unmarshal(bytes) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + data, err := test.marshal(256) + if err != nil { + t.Fatal(err) + } + + if err := test.decode(data); err == nil { + t.Fatal("expected out-of-range SenderID to be rejected") + } + }) + } +} + +// TestUnmarshal_PeerMapKeyBounds verifies that the messages carrying a +// per-member map reject a map key that overflows group.MaxMemberIndex. +func TestUnmarshal_PeerMapKeyBounds(t *testing.T) { + overflowKeyMap := map[uint32][]byte{256: []byte{1}} + + tests := map[string]struct { + marshal func() ([]byte, error) + decode func(bytes []byte) error + }{ + "ephemeralPublicKeyMessage/EphemeralPublicKeys": { + marshal: func() ([]byte, error) { + return proto.Marshal(&pb.EphemeralPublicKeyMessage{ + SenderID: 1, + EphemeralPublicKeys: overflowKeyMap, + }) + }, + decode: func(bytes []byte) error { + return new(ephemeralPublicKeyMessage).Unmarshal(bytes) + }, + }, + "tssRoundTwoMessage/PeersPayload": { + marshal: func() ([]byte, error) { + return proto.Marshal(&pb.TSSRoundTwoMessage{ + SenderID: 1, + PeersPayload: overflowKeyMap, + }) + }, + decode: func(bytes []byte) error { + return new(tssRoundTwoMessage).Unmarshal(bytes) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + data, err := test.marshal() + if err != nil { + t.Fatal(err) + } + + if err := test.decode(data); err == nil { + t.Fatal("expected out-of-range peer map key to be rejected") + } + }) + } +} diff --git a/pkg/tecdsa/dkg/marshaling.go b/pkg/tecdsa/dkg/marshaling.go index 4e2815d62e..31344e0c10 100644 --- a/pkg/tecdsa/dkg/marshaling.go +++ b/pkg/tecdsa/dkg/marshaling.go @@ -1,3 +1,4 @@ +// marshaling.go: protobuf (un)marshaling for the public types in this package. package dkg import ( @@ -9,7 +10,6 @@ import ( "google.golang.org/protobuf/proto" timestamppb "google.golang.org/protobuf/types/known/timestamppb" - "github.com/keep-network/keep-core/pkg/crypto/ephemeral" "github.com/keep-network/keep-core/pkg/protocol/group" "github.com/keep-network/keep-core/pkg/tecdsa/dkg/gen/pb" ) @@ -17,14 +17,9 @@ import ( // Marshal converts this ephemeralPublicKeyMessage to a byte array suitable for // network communication. func (epkm *ephemeralPublicKeyMessage) Marshal() ([]byte, error) { - ephemeralPublicKeys, err := marshalPublicKeyMap(epkm.ephemeralPublicKeys) - if err != nil { - return nil, err - } - return proto.Marshal(&pb.EphemeralPublicKeyMessage{ SenderID: uint32(epkm.senderID), - EphemeralPublicKeys: ephemeralPublicKeys, + EphemeralPublicKeys: marshalPublicKeyMap(epkm.ephemeralPublicKeys), SessionID: epkm.sessionID, }) } @@ -37,10 +32,11 @@ func (epkm *ephemeralPublicKeyMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } - epkm.senderID = group.MemberIndex(pbMsg.SenderID) + epkm.senderID = senderID ephemeralPublicKeys, err := unmarshalPublicKeyMap(pbMsg.EphemeralPublicKeys) if err != nil { @@ -70,11 +66,12 @@ func (trom *tssRoundOneMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } - trom.senderID = group.MemberIndex(pbMsg.SenderID) + trom.senderID = senderID trom.broadcastPayload = pbMsg.BroadcastPayload trom.sessionID = pbMsg.SessionID @@ -104,20 +101,22 @@ func (trtm *tssRoundTwoMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } peersPayload := make(map[group.MemberIndex][]byte, len(pbMsg.PeersPayload)) for receiverID, payload := range pbMsg.PeersPayload { - if err := validateMemberIndex(receiverID); err != nil { + memberIndex, err := group.MemberIndexFromUint32(receiverID) + if err != nil { return err } - peersPayload[group.MemberIndex(receiverID)] = payload + peersPayload[memberIndex] = payload } - trtm.senderID = group.MemberIndex(pbMsg.SenderID) + trtm.senderID = senderID trtm.broadcastPayload = pbMsg.BroadcastPayload trtm.peersPayload = peersPayload trtm.sessionID = pbMsg.SessionID @@ -142,11 +141,12 @@ func (trtm *tssRoundThreeMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } - trtm.senderID = group.MemberIndex(pbMsg.SenderID) + trtm.senderID = senderID trtm.broadcastPayload = pbMsg.BroadcastPayload trtm.sessionID = pbMsg.SessionID @@ -170,57 +170,41 @@ func (tfm *tssFinalizationMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } - tfm.senderID = group.MemberIndex(pbMsg.SenderID) + tfm.senderID = senderID tfm.sessionID = pbMsg.SessionID return nil } -func validateMemberIndex(protoIndex uint32) error { - // Protobuf does not have uint8 type, so we are using uint32. When - // unmarshalling message, we need to make sure we do not overflow. - if protoIndex > group.MaxMemberIndex { - return fmt.Errorf("invalid member index value: [%v]", protoIndex) - } - return nil -} - func marshalPublicKeyMap( - publicKeys map[group.MemberIndex]*ephemeral.PublicKey, -) (map[uint32][]byte, error) { + publicKeys map[group.MemberIndex][]byte, +) map[uint32][]byte { marshalled := make(map[uint32][]byte, len(publicKeys)) - for id, publicKey := range publicKeys { - if publicKey == nil { - return nil, fmt.Errorf("nil public key for member [%v]", id) - } - - marshalled[uint32(id)] = publicKey.Marshal() + for id, keyBytes := range publicKeys { + marshalled[uint32(id)] = keyBytes } - return marshalled, nil + return marshalled } +// unmarshalPublicKeyMap converts the wire-format map to an internal byte map, +// validating member indices but deferring EC point parsing to use-time so that +// only the one key per message actually needed for ECDH is ever parsed. func unmarshalPublicKeyMap( publicKeys map[uint32][]byte, -) (map[group.MemberIndex]*ephemeral.PublicKey, error) { - var unmarshalled = make(map[group.MemberIndex]*ephemeral.PublicKey, len(publicKeys)) +) (map[group.MemberIndex][]byte, error) { + unmarshalled := make(map[group.MemberIndex][]byte, len(publicKeys)) for memberID, publicKeyBytes := range publicKeys { - if err := validateMemberIndex(memberID); err != nil { - return nil, err - } - - publicKey, err := ephemeral.UnmarshalPublicKey(publicKeyBytes) + memberIndex, err := group.MemberIndexFromUint32(memberID) if err != nil { - return nil, fmt.Errorf("could not unmarshal public key [%v]", err) + return nil, err } - - unmarshalled[group.MemberIndex(memberID)] = publicKey - + unmarshalled[memberIndex] = publicKeyBytes } - return unmarshalled, nil } @@ -244,10 +228,11 @@ func (rsm *resultSignatureMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } - rsm.senderID = group.MemberIndex(pbMsg.SenderID) + rsm.senderID = senderID resultHash, err := ResultSignatureHashFromBytes(pbMsg.ResultHash) if err != nil { diff --git a/pkg/tecdsa/dkg/marshaling_test.go b/pkg/tecdsa/dkg/marshaling_test.go index 314f19376c..152c0ceb6e 100644 --- a/pkg/tecdsa/dkg/marshaling_test.go +++ b/pkg/tecdsa/dkg/marshaling_test.go @@ -23,9 +23,10 @@ func TestEphemeralPublicKeyMessage_MarshalingRoundtrip(t *testing.T) { t.Fatal(err) } - publicKeys := make(map[group.MemberIndex]*ephemeral.PublicKey) - publicKeys[group.MemberIndex(211)] = keyPair1.PublicKey - publicKeys[group.MemberIndex(19)] = keyPair2.PublicKey + publicKeys := map[group.MemberIndex][]byte{ + group.MemberIndex(211): keyPair1.PublicKey.Marshal(), + group.MemberIndex(19): keyPair2.PublicKey.Marshal(), + } msg := &ephemeralPublicKeyMessage{ senderID: group.MemberIndex(38), @@ -48,7 +49,7 @@ func TestFuzzEphemeralPublicKeyMessage_MarshalingRoundtrip(t *testing.T) { for i := 0; i < 10; i++ { var ( senderID group.MemberIndex - ephemeralPublicKeys map[group.MemberIndex]*ephemeral.PublicKey + ephemeralPublicKeys map[group.MemberIndex][]byte sessionID string ) @@ -66,12 +67,14 @@ func TestFuzzEphemeralPublicKeyMessage_MarshalingRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &ephemeralPublicKeyMessage{}) + if err := pbutils.RoundTrip(message, &ephemeralPublicKeyMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzEphemeralPublicKeyMessage_Unmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&ephemeralPublicKeyMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&ephemeralPublicKeyMessage{}) } func TestTssRoundOneMessage_MarshalingRoundtrip(t *testing.T) { @@ -114,12 +117,14 @@ func TestFuzzTssRoundOneMessage_MarshalingRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &tssRoundOneMessage{}) + if err := pbutils.RoundTrip(message, &tssRoundOneMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzTssRoundOneMessage_Unmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&tssRoundOneMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&tssRoundOneMessage{}) } func TestTssRoundTwoMessage_MarshalingRoundtrip(t *testing.T) { @@ -169,12 +174,14 @@ func TestFuzzTssRoundTwoMessage_MarshalingRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &tssRoundTwoMessage{}) + if err := pbutils.RoundTrip(message, &tssRoundTwoMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzTssRoundTwoMessage_Unmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&tssRoundTwoMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&tssRoundTwoMessage{}) } func TestTssRoundThreeMessage_MarshalingRoundtrip(t *testing.T) { @@ -217,12 +224,14 @@ func TestFuzzTssRoundThreeMessage_MarshalingRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &tssRoundThreeMessage{}) + if err := pbutils.RoundTrip(message, &tssRoundThreeMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzTssRoundThreeMessage_Unmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&tssRoundThreeMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&tssRoundThreeMessage{}) } func TestTssFinalizationMessage_MarshalingRoundtrip(t *testing.T) { @@ -261,12 +270,14 @@ func TestFuzzTssFinalizationMessage_MarshalingRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &tssFinalizationMessage{}) + if err := pbutils.RoundTrip(message, &tssFinalizationMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzTssFinalizationMessage_Unmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&tssFinalizationMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&tssFinalizationMessage{}) } func TestResultSignatureMessage_MarshalingRoundtrip(t *testing.T) { @@ -315,12 +326,14 @@ func TestFuzzResultSignatureMessage_MarshalingRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &resultSignatureMessage{}) + if err := pbutils.RoundTrip(message, &resultSignatureMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzResultSignatureMessage_Unmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&resultSignatureMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&resultSignatureMessage{}) } func TestPreParamsMarshalling(t *testing.T) { @@ -351,3 +364,119 @@ func TestPreParamsMarshalling(t *testing.T) { t.Errorf("unmarshaled pre params data are invalid") } } + +// --- Benchmarks --- + +func BenchmarkMarshalEphemeralPublicKeyMessage(b *testing.B) { + kp1, err := ephemeral.GenerateKeyPair() + if err != nil { + b.Fatal(err) + } + kp2, err := ephemeral.GenerateKeyPair() + if err != nil { + b.Fatal(err) + } + msg := &ephemeralPublicKeyMessage{ + senderID: group.MemberIndex(38), + ephemeralPublicKeys: map[group.MemberIndex][]byte{ + group.MemberIndex(211): kp1.PublicKey.Marshal(), + group.MemberIndex(19): kp2.PublicKey.Marshal(), + }, + sessionID: "session-1", + } + b.ResetTimer() + for range b.N { + _, _ = msg.Marshal() + } +} + +func BenchmarkUnmarshalEphemeralPublicKeyMessage(b *testing.B) { + kp1, err := ephemeral.GenerateKeyPair() + if err != nil { + b.Fatal(err) + } + kp2, err := ephemeral.GenerateKeyPair() + if err != nil { + b.Fatal(err) + } + msg := &ephemeralPublicKeyMessage{ + senderID: group.MemberIndex(38), + ephemeralPublicKeys: map[group.MemberIndex][]byte{ + group.MemberIndex(211): kp1.PublicKey.Marshal(), + group.MemberIndex(19): kp2.PublicKey.Marshal(), + }, + sessionID: "session-1", + } + data, err := msg.Marshal() + if err != nil { + b.Fatal(err) + } + b.ResetTimer() + for range b.N { + _ = new(ephemeralPublicKeyMessage).Unmarshal(data) + } +} + +// buildEphemeralKeyMap generates n key pairs and returns the serialized public +// key map as it would appear in a real EphemeralPublicKeyMessage (one entry per peer). +func buildEphemeralKeyMap(b *testing.B, n int) map[group.MemberIndex][]byte { + b.Helper() + m := make(map[group.MemberIndex][]byte, n) + for i := 0; i < n; i++ { + kp, err := ephemeral.GenerateKeyPair() + if err != nil { + b.Fatal(err) + } + m[group.MemberIndex(i+1)] = kp.PublicKey.Marshal() + } + return m +} + +// BenchmarkMarshalEphemeralPublicKeyMessage_100Keys benchmarks marshaling with +// a realistic group size (100 members = 99 peer keys per message). +func BenchmarkMarshalEphemeralPublicKeyMessage_100Keys(b *testing.B) { + msg := &ephemeralPublicKeyMessage{ + senderID: group.MemberIndex(1), + ephemeralPublicKeys: buildEphemeralKeyMap(b, 99), + sessionID: "session-1", + } + b.ResetTimer() + for range b.N { + _, _ = msg.Marshal() + } +} + +// Benchmarks unmarshaling the wire-format bytes. EC point parsing is +// deferred to use-time in generateSymmetricKeys (protocol.go). +func BenchmarkUnmarshalEphemeralPublicKeyMessage_100Keys(b *testing.B) { + msg := &ephemeralPublicKeyMessage{ + senderID: group.MemberIndex(1), + ephemeralPublicKeys: buildEphemeralKeyMap(b, 99), + sessionID: "session-1", + } + data, err := msg.Marshal() + if err != nil { + b.Fatal(err) + } + b.ResetTimer() + for range b.N { + _ = new(ephemeralPublicKeyMessage).Unmarshal(data) + } +} + +func BenchmarkRoundTripDKGMessage(b *testing.B) { + msg := &tssRoundTwoMessage{ + senderID: group.MemberIndex(50), + broadcastPayload: []byte{1, 2, 3, 4, 5}, + peersPayload: map[group.MemberIndex][]byte{ + 1: {6, 7, 8, 9, 10}, + 2: {11, 12, 13, 14, 15}, + }, + sessionID: "session-1", + } + b.ResetTimer() + for range b.N { + data, _ := msg.Marshal() + _ = new(tssRoundTwoMessage).Unmarshal(data) + } +} diff --git a/pkg/tecdsa/dkg/member.go b/pkg/tecdsa/dkg/member.go index 0418d03bb2..f11e3fa504 100644 --- a/pkg/tecdsa/dkg/member.go +++ b/pkg/tecdsa/dkg/member.go @@ -326,7 +326,13 @@ func (ic *identityConverter) TssPartyIDToMemberIndex( return group.MemberIndex(0) } - return group.MemberIndex( - new(big.Int).Sub(partyID.KeyInt(), ic.seed).Int64(), - ) + index := new(big.Int).Sub(partyID.KeyInt(), ic.seed) + if !index.IsUint64() { + return 0 + } + value := index.Uint64() + if value > group.MaxMemberIndex { + return 0 + } + return group.MemberIndex(value) } diff --git a/pkg/tecdsa/dkg/member_test.go b/pkg/tecdsa/dkg/member_test.go index 3421c1b3ec..6dfeb98de8 100644 --- a/pkg/tecdsa/dkg/member_test.go +++ b/pkg/tecdsa/dkg/member_test.go @@ -184,3 +184,14 @@ func TestIdentityConverter_TssPartyIDToMemberIndex_Corrupted(t *testing.T) { testutils.AssertIntsEqual(t, "member ID", 0, int(memberIndex)) } + +func TestIdentityConverter_TssPartyIDToMemberIndex_Overflow(t *testing.T) { + converter := &identityConverter{seed: big.NewInt(300)} + partyID := tss.NewPartyID("556", "member-256", big.NewInt(556)) + + // index (556 - 300 = 256) exceeds group.MaxMemberIndex; the party ID is + // considered corrupted and MemberIndex(0) is returned. + memberIndex := converter.TssPartyIDToMemberIndex(partyID) + + testutils.AssertIntsEqual(t, "member ID", 0, int(memberIndex)) +} diff --git a/pkg/tecdsa/dkg/message.go b/pkg/tecdsa/dkg/message.go index ca9364ac57..fd87992e03 100644 --- a/pkg/tecdsa/dkg/message.go +++ b/pkg/tecdsa/dkg/message.go @@ -1,7 +1,6 @@ package dkg import ( - "github.com/keep-network/keep-core/pkg/crypto/ephemeral" "github.com/keep-network/keep-core/pkg/protocol/group" ) @@ -26,7 +25,7 @@ type message interface { type ephemeralPublicKeyMessage struct { senderID group.MemberIndex - ephemeralPublicKeys map[group.MemberIndex]*ephemeral.PublicKey + ephemeralPublicKeys map[group.MemberIndex][]byte sessionID string } diff --git a/pkg/tecdsa/dkg/preparams.go b/pkg/tecdsa/dkg/preparams.go index 370e5c35ca..8adc2ba031 100644 --- a/pkg/tecdsa/dkg/preparams.go +++ b/pkg/tecdsa/dkg/preparams.go @@ -12,8 +12,8 @@ import ( "github.com/bnb-chain/tss-lib/ecdsa/keygen" "github.com/ipfs/go-log/v2" - "github.com/keep-network/keep-common/pkg/persistence" "github.com/keep-network/keep-core/pkg/generator" + "github.com/keep-network/keep-core/pkg/persistence" ) // PreParams represents tECDSA DKG pre-parameters that were not yet consumed diff --git a/pkg/tecdsa/dkg/protocol.go b/pkg/tecdsa/dkg/protocol.go index de333b62e7..276765aff3 100644 --- a/pkg/tecdsa/dkg/protocol.go +++ b/pkg/tecdsa/dkg/protocol.go @@ -17,7 +17,7 @@ func (ekpgm *ephemeralKeyPairGeneratingMember) generateEphemeralKeyPair() ( *ephemeralPublicKeyMessage, error, ) { - ephemeralKeys := make(map[group.MemberIndex]*ephemeral.PublicKey) + ephemeralKeys := make(map[group.MemberIndex][]byte) // Calculate ephemeral key pair for every other group member for _, member := range ekpgm.group.MemberIndexes() { @@ -34,8 +34,8 @@ func (ekpgm *ephemeralKeyPairGeneratingMember) generateEphemeralKeyPair() ( // save the generated ephemeral key to our state ekpgm.ephemeralKeyPairs[member] = ephemeralKeyPair - // store the public key to the map for the message - ephemeralKeys[member] = ephemeralKeyPair.PublicKey + // store the serialized public key to the map for the message + ephemeralKeys[member] = ephemeralKeyPair.PublicKey.Marshal() } return &ephemeralPublicKeyMessage{ @@ -78,9 +78,30 @@ func (skgm *symmetricKeyGeneratingMember) generateSymmetricKeys( thisMemberEphemeralPrivateKey := ephemeralKeyPair.PrivateKey // Get the ephemeral public key broadcasted by the other group member, - // which was intended for this group member. - otherMemberEphemeralPublicKey := - ephemeralPubKeyMessage.ephemeralPublicKeys[skgm.id] + // which was intended for this group member, and parse it. Only this + // one key per message is needed for ECDH; the rest are validated for + // presence in isValidEphemeralPublicKeyMessage but never parsed. + otherMemberEphemeralPublicKey, err := ephemeral.UnmarshalPublicKey( + ephemeralPubKeyMessage.ephemeralPublicKeys[skgm.id], + ) + if err != nil { + // Mark the sender inactive on malformed key so the protocol can + // continue without it instead of aborting this member's async + // state. This preserves the pre-deferred-parse behavior, where + // network-layer unmarshaling dropped the whole message and the + // round waited for context end; in the current code the unmarshal + // happens at this site so the equivalent behavior is to skip the + // sender here. + skgm.logger.Warnf( + "[member:%v] could not unmarshal ephemeral public key "+ + "from member [%v]: [%v]; marking member as inactive", + skgm.id, + otherMember, + err, + ) + skgm.group.MarkMemberAsInactive(otherMember) + continue + } // Create symmetric key for the current group member and the other // group member by ECDH'ing the public and private key. diff --git a/pkg/tecdsa/dkg/protocol_test.go b/pkg/tecdsa/dkg/protocol_test.go index c997a29b02..0925fe66e0 100644 --- a/pkg/tecdsa/dkg/protocol_test.go +++ b/pkg/tecdsa/dkg/protocol_test.go @@ -166,16 +166,16 @@ func TestGenerateSymmetricKeys(t *testing.T) { // Assert all symmetric keys stored by this member are correct. for otherMemberID, actualKey := range member.symmetricKeys { - var otherMemberEphemeralPublicKey *ephemeral.PublicKey + var otherMemberEphemeralPublicKeyBytes []byte for _, message := range messages { if message.senderID == otherMemberID { - if ephemeralPublicKey, ok := message.ephemeralPublicKeys[member.id]; ok { - otherMemberEphemeralPublicKey = ephemeralPublicKey + if keyBytes, ok := message.ephemeralPublicKeys[member.id]; ok { + otherMemberEphemeralPublicKeyBytes = keyBytes } } } - if otherMemberEphemeralPublicKey == nil { + if otherMemberEphemeralPublicKeyBytes == nil { t.Errorf( "[member:%v] no ephemeral public key from member [%v]", member.id, @@ -183,6 +183,13 @@ func TestGenerateSymmetricKeys(t *testing.T) { ) } + otherMemberEphemeralPublicKey, err := ephemeral.UnmarshalPublicKey( + otherMemberEphemeralPublicKeyBytes, + ) + if err != nil { + t.Fatalf("could not unmarshal ephemeral public key: %v", err) + } + expectedKey := ephemeral.SymmetricKey( member.ephemeralKeyPairs[otherMemberID].PrivateKey.Ecdh( otherMemberEphemeralPublicKey, @@ -248,6 +255,78 @@ func TestGenerateSymmetricKeys_InvalidEphemeralPublicKeyMessage(t *testing.T) { } } +func TestGenerateSymmetricKeys_CorruptEphemeralPublicKeyBytes(t *testing.T) { + members, messages, err := initializeSymmetricKeyGeneratingMembersGroup( + dishonestThreshold, + groupSize, + ) + if err != nil { + t.Fatal(err) + } + + // Replace member 2's ephemeral public key for member 1 with garbage. + // The key is still present so isValidEphemeralPublicKeyMessage passes; + // only member 1 encounters the parse error during ECDH. + misbehavingMemberID := group.MemberIndex(2) + victimMemberID := group.MemberIndex(1) + messages[misbehavingMemberID-1].ephemeralPublicKeys[victimMemberID] = []byte{0x00, 0x01, 0x02} + + for _, member := range members { + var receivedMessages []*ephemeralPublicKeyMessage + for _, message := range messages { + if message.senderID != member.id { + receivedMessages = append(receivedMessages, message) + } + } + + err := member.generateSymmetricKeys(receivedMessages) + + // A corrupt key from one member must never abort another member's + // entire round: the sender is skipped instead. + if err != nil { + t.Errorf("[member:%v] unexpected error: %v", member.id, err) + } + + expectedKeysCount := groupSize - 1 + if member.id == victimMemberID { + // The victim skips the misbehaving sender, so it stores one + // fewer symmetric key than everyone else. + expectedKeysCount-- + + if _, ok := member.symmetricKeys[misbehavingMemberID]; ok { + t.Errorf( + "[member:%v] expected no symmetric key stored for "+ + "misbehaving member [%v]", + member.id, + misbehavingMemberID, + ) + } + } + + testutils.AssertIntsEqual( + t, + fmt.Sprintf("number of stored symmetric keys for member [%v]", member.id), + expectedKeysCount, + len(member.symmetricKeys), + ) + } + + // All members in this test share a single *group.Group instance (see + // initializeEphemeralKeyPairGeneratingMembersGroup), so the effect of + // the victim marking the misbehaving member inactive is visible from + // any member's reference to it. + if !reflect.DeepEqual( + []group.MemberIndex{misbehavingMemberID}, + members[0].group.InactiveMemberIndexes(), + ) { + t.Errorf( + "expected member [%v] to be marked inactive, got inactive members: %v", + misbehavingMemberID, + members[0].group.InactiveMemberIndexes(), + ) + } +} + func TestTssRoundOne(t *testing.T) { members, err := initializeTssRoundOneMembersGroup( dishonestThreshold, diff --git a/pkg/tecdsa/marshaling_test.go b/pkg/tecdsa/marshaling_test.go index 8cd9dc0321..afcd494173 100644 --- a/pkg/tecdsa/marshaling_test.go +++ b/pkg/tecdsa/marshaling_test.go @@ -95,10 +95,12 @@ func TestFuzzSignature_MarshalingRoundtrip(t *testing.T) { RecoveryID: recoveryID, } - _ = pbutils.RoundTrip(signature, &Signature{}) + if err := pbutils.RoundTrip(signature, &Signature{}); err != nil { + t.Fatal(err) + } } } func TestFuzzSignature_Unmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&Signature{}) + pbutils.AssertUnmarshalDoesNotPanic(&Signature{}) } diff --git a/pkg/tecdsa/retry/retry.go b/pkg/tecdsa/retry/retry.go index 798d3bed30..038fe804b0 100644 --- a/pkg/tecdsa/retry/retry.go +++ b/pkg/tecdsa/retry/retry.go @@ -57,6 +57,7 @@ func EvaluateRetryParticipantsForSigning( // #nosec G404 (insecure random number source (rand)) // Shuffling operators for retries does not require secure randomness. + // #nosec G115 -- Retry seed arithmetic intentionally wraps modulo 2^64 for compatibility. rng := rand.New(rand.NewSource(seed + int64(retryCount))) operators := make([]chain.Address, len(operatorToSeatCount)) diff --git a/pkg/tecdsa/signature.go b/pkg/tecdsa/signature.go index 52c0fa745c..59d4bcdd38 100644 --- a/pkg/tecdsa/signature.go +++ b/pkg/tecdsa/signature.go @@ -30,8 +30,9 @@ func NewSignature(data *common.SignatureData) *Signature { recoveryInt = (recoveryInt << 8) | int(recoveryBytes[0]) return &Signature{ - R: new(big.Int).SetBytes(data.GetR()), - S: new(big.Int).SetBytes(data.GetS()), + R: new(big.Int).SetBytes(data.GetR()), + S: new(big.Int).SetBytes(data.GetS()), + // #nosec G115 -- tss-lib signing output supplies a recovery ID in {0, 1, 2, 3}. RecoveryID: int8(recoveryInt), } } diff --git a/pkg/tecdsa/signing/integer_conversion_test.go b/pkg/tecdsa/signing/integer_conversion_test.go new file mode 100644 index 0000000000..6c1cd71973 --- /dev/null +++ b/pkg/tecdsa/signing/integer_conversion_test.go @@ -0,0 +1,170 @@ +package signing + +import ( + "testing" + + "google.golang.org/protobuf/proto" + + "github.com/keep-network/keep-core/pkg/tecdsa/signing/gen/pb" +) + +// TestUnmarshal_SenderIDBounds verifies that every round message rejects a +// SenderID value that overflows group.MaxMemberIndex. +func TestUnmarshal_SenderIDBounds(t *testing.T) { + tests := map[string]struct { + marshal func(senderID uint32) ([]byte, error) + decode func(bytes []byte) error + }{ + "ephemeralPublicKeyMessage": { + marshal: func(senderID uint32) ([]byte, error) { + return proto.Marshal(&pb.EphemeralPublicKeyMessage{SenderID: senderID}) + }, + decode: func(bytes []byte) error { + return new(ephemeralPublicKeyMessage).Unmarshal(bytes) + }, + }, + "tssRoundOneMessage": { + marshal: func(senderID uint32) ([]byte, error) { + return proto.Marshal(&pb.TSSRoundOneMessage{SenderID: senderID}) + }, + decode: func(bytes []byte) error { + return new(tssRoundOneMessage).Unmarshal(bytes) + }, + }, + "tssRoundTwoMessage": { + marshal: func(senderID uint32) ([]byte, error) { + return proto.Marshal(&pb.TSSRoundTwoMessage{SenderID: senderID}) + }, + decode: func(bytes []byte) error { + return new(tssRoundTwoMessage).Unmarshal(bytes) + }, + }, + "tssRoundThreeMessage": { + marshal: func(senderID uint32) ([]byte, error) { + return proto.Marshal(&pb.TSSRoundThreeMessage{SenderID: senderID}) + }, + decode: func(bytes []byte) error { + return new(tssRoundThreeMessage).Unmarshal(bytes) + }, + }, + "tssRoundFourMessage": { + marshal: func(senderID uint32) ([]byte, error) { + return proto.Marshal(&pb.TSSRoundFourMessage{SenderID: senderID}) + }, + decode: func(bytes []byte) error { + return new(tssRoundFourMessage).Unmarshal(bytes) + }, + }, + "tssRoundFiveMessage": { + marshal: func(senderID uint32) ([]byte, error) { + return proto.Marshal(&pb.TSSRoundFiveMessage{SenderID: senderID}) + }, + decode: func(bytes []byte) error { + return new(tssRoundFiveMessage).Unmarshal(bytes) + }, + }, + "tssRoundSixMessage": { + marshal: func(senderID uint32) ([]byte, error) { + return proto.Marshal(&pb.TSSRoundSixMessage{SenderID: senderID}) + }, + decode: func(bytes []byte) error { + return new(tssRoundSixMessage).Unmarshal(bytes) + }, + }, + "tssRoundSevenMessage": { + marshal: func(senderID uint32) ([]byte, error) { + return proto.Marshal(&pb.TSSRoundSevenMessage{SenderID: senderID}) + }, + decode: func(bytes []byte) error { + return new(tssRoundSevenMessage).Unmarshal(bytes) + }, + }, + "tssRoundEightMessage": { + marshal: func(senderID uint32) ([]byte, error) { + return proto.Marshal(&pb.TSSRoundEightMessage{SenderID: senderID}) + }, + decode: func(bytes []byte) error { + return new(tssRoundEightMessage).Unmarshal(bytes) + }, + }, + "tssRoundNineMessage": { + marshal: func(senderID uint32) ([]byte, error) { + return proto.Marshal(&pb.TSSRoundNineMessage{SenderID: senderID}) + }, + decode: func(bytes []byte) error { + return new(tssRoundNineMessage).Unmarshal(bytes) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + data, err := test.marshal(256) + if err != nil { + t.Fatal(err) + } + + if err := test.decode(data); err == nil { + t.Fatal("expected out-of-range SenderID to be rejected") + } + }) + } +} + +// TestUnmarshal_PeerMapKeyBounds verifies that the messages carrying a +// per-member map reject a map key that overflows group.MaxMemberIndex. +func TestUnmarshal_PeerMapKeyBounds(t *testing.T) { + overflowKeyMap := map[uint32][]byte{256: []byte{1}} + + tests := map[string]struct { + marshal func() ([]byte, error) + decode func(bytes []byte) error + }{ + "ephemeralPublicKeyMessage/EphemeralPublicKeys": { + marshal: func() ([]byte, error) { + return proto.Marshal(&pb.EphemeralPublicKeyMessage{ + SenderID: 1, + EphemeralPublicKeys: overflowKeyMap, + }) + }, + decode: func(bytes []byte) error { + return new(ephemeralPublicKeyMessage).Unmarshal(bytes) + }, + }, + "tssRoundOneMessage/PeersPayload": { + marshal: func() ([]byte, error) { + return proto.Marshal(&pb.TSSRoundOneMessage{ + SenderID: 1, + PeersPayload: overflowKeyMap, + }) + }, + decode: func(bytes []byte) error { + return new(tssRoundOneMessage).Unmarshal(bytes) + }, + }, + "tssRoundTwoMessage/PeersPayload": { + marshal: func() ([]byte, error) { + return proto.Marshal(&pb.TSSRoundTwoMessage{ + SenderID: 1, + PeersPayload: overflowKeyMap, + }) + }, + decode: func(bytes []byte) error { + return new(tssRoundTwoMessage).Unmarshal(bytes) + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + data, err := test.marshal() + if err != nil { + t.Fatal(err) + } + + if err := test.decode(data); err == nil { + t.Fatal("expected out-of-range peer map key to be rejected") + } + }) + } +} diff --git a/pkg/tecdsa/signing/marshaling.go b/pkg/tecdsa/signing/marshaling.go index 98040ca91c..791685d355 100644 --- a/pkg/tecdsa/signing/marshaling.go +++ b/pkg/tecdsa/signing/marshaling.go @@ -1,11 +1,9 @@ +// marshaling.go: protobuf (un)marshaling for the public types in this package. package signing import ( - "fmt" - "google.golang.org/protobuf/proto" - "github.com/keep-network/keep-core/pkg/crypto/ephemeral" "github.com/keep-network/keep-core/pkg/protocol/group" "github.com/keep-network/keep-core/pkg/tecdsa/signing/gen/pb" ) @@ -13,14 +11,9 @@ import ( // Marshal converts this ephemeralPublicKeyMessage to a byte array suitable for // network communication. func (epkm *ephemeralPublicKeyMessage) Marshal() ([]byte, error) { - ephemeralPublicKeys, err := marshalPublicKeyMap(epkm.ephemeralPublicKeys) - if err != nil { - return nil, err - } - return proto.Marshal(&pb.EphemeralPublicKeyMessage{ SenderID: uint32(epkm.senderID), - EphemeralPublicKeys: ephemeralPublicKeys, + EphemeralPublicKeys: marshalPublicKeyMap(epkm.ephemeralPublicKeys), SessionID: epkm.sessionID, }) } @@ -33,10 +26,11 @@ func (epkm *ephemeralPublicKeyMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } - epkm.senderID = group.MemberIndex(pbMsg.SenderID) + epkm.senderID = senderID ephemeralPublicKeys, err := unmarshalPublicKeyMap(pbMsg.EphemeralPublicKeys) if err != nil { @@ -72,20 +66,22 @@ func (trom *tssRoundOneMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } peersPayload := make(map[group.MemberIndex][]byte, len(pbMsg.PeersPayload)) for receiverID, payload := range pbMsg.PeersPayload { - if err := validateMemberIndex(receiverID); err != nil { + memberIndex, err := group.MemberIndexFromUint32(receiverID) + if err != nil { return err } - peersPayload[group.MemberIndex(receiverID)] = payload + peersPayload[memberIndex] = payload } - trom.senderID = group.MemberIndex(pbMsg.SenderID) + trom.senderID = senderID trom.broadcastPayload = pbMsg.BroadcastPayload trom.peersPayload = peersPayload trom.sessionID = pbMsg.SessionID @@ -115,20 +111,22 @@ func (trtm *tssRoundTwoMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } peersPayload := make(map[group.MemberIndex][]byte, len(pbMsg.PeersPayload)) for receiverID, payload := range pbMsg.PeersPayload { - if err := validateMemberIndex(receiverID); err != nil { + memberIndex, err := group.MemberIndexFromUint32(receiverID) + if err != nil { return err } - peersPayload[group.MemberIndex(receiverID)] = payload + peersPayload[memberIndex] = payload } - trtm.senderID = group.MemberIndex(pbMsg.SenderID) + trtm.senderID = senderID trtm.peersPayload = peersPayload trtm.sessionID = pbMsg.SessionID @@ -152,11 +150,12 @@ func (trtm *tssRoundThreeMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } - trtm.senderID = group.MemberIndex(pbMsg.SenderID) + trtm.senderID = senderID trtm.broadcastPayload = pbMsg.BroadcastPayload trtm.sessionID = pbMsg.SessionID @@ -180,11 +179,12 @@ func (trfm *tssRoundFourMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } - trfm.senderID = group.MemberIndex(pbMsg.SenderID) + trfm.senderID = senderID trfm.broadcastPayload = pbMsg.BroadcastPayload trfm.sessionID = pbMsg.SessionID @@ -208,11 +208,12 @@ func (trfm *tssRoundFiveMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } - trfm.senderID = group.MemberIndex(pbMsg.SenderID) + trfm.senderID = senderID trfm.broadcastPayload = pbMsg.BroadcastPayload trfm.sessionID = pbMsg.SessionID @@ -236,11 +237,12 @@ func (trsm *tssRoundSixMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } - trsm.senderID = group.MemberIndex(pbMsg.SenderID) + trsm.senderID = senderID trsm.broadcastPayload = pbMsg.BroadcastPayload trsm.sessionID = pbMsg.SessionID @@ -264,11 +266,12 @@ func (trsm *tssRoundSevenMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } - trsm.senderID = group.MemberIndex(pbMsg.SenderID) + trsm.senderID = senderID trsm.broadcastPayload = pbMsg.BroadcastPayload trsm.sessionID = pbMsg.SessionID @@ -292,11 +295,12 @@ func (trem *tssRoundEightMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } - trem.senderID = group.MemberIndex(pbMsg.SenderID) + trem.senderID = senderID trem.broadcastPayload = pbMsg.BroadcastPayload trem.sessionID = pbMsg.SessionID @@ -320,57 +324,41 @@ func (trnm *tssRoundNineMessage) Unmarshal(bytes []byte) error { return err } - if err := validateMemberIndex(pbMsg.SenderID); err != nil { + senderID, err := group.MemberIndexFromUint32(pbMsg.SenderID) + if err != nil { return err } - trnm.senderID = group.MemberIndex(pbMsg.SenderID) + trnm.senderID = senderID trnm.broadcastPayload = pbMsg.BroadcastPayload trnm.sessionID = pbMsg.SessionID return nil } -func validateMemberIndex(protoIndex uint32) error { - // Protobuf does not have uint8 type, so we are using uint32. When - // unmarshalling message, we need to make sure we do not overflow. - if protoIndex > group.MaxMemberIndex { - return fmt.Errorf("invalid member index value: [%v]", protoIndex) - } - return nil -} - func marshalPublicKeyMap( - publicKeys map[group.MemberIndex]*ephemeral.PublicKey, -) (map[uint32][]byte, error) { + publicKeys map[group.MemberIndex][]byte, +) map[uint32][]byte { marshalled := make(map[uint32][]byte, len(publicKeys)) - for id, publicKey := range publicKeys { - if publicKey == nil { - return nil, fmt.Errorf("nil public key for member [%v]", id) - } - - marshalled[uint32(id)] = publicKey.Marshal() + for id, keyBytes := range publicKeys { + marshalled[uint32(id)] = keyBytes } - return marshalled, nil + return marshalled } +// unmarshalPublicKeyMap converts the wire-format map to an internal byte map, +// validating member indices but deferring EC point parsing to use-time so that +// only the one key per message actually needed for ECDH is ever parsed. func unmarshalPublicKeyMap( publicKeys map[uint32][]byte, -) (map[group.MemberIndex]*ephemeral.PublicKey, error) { - var unmarshalled = make(map[group.MemberIndex]*ephemeral.PublicKey, len(publicKeys)) +) (map[group.MemberIndex][]byte, error) { + unmarshalled := make(map[group.MemberIndex][]byte, len(publicKeys)) for memberID, publicKeyBytes := range publicKeys { - if err := validateMemberIndex(memberID); err != nil { - return nil, err - } - - publicKey, err := ephemeral.UnmarshalPublicKey(publicKeyBytes) + memberIndex, err := group.MemberIndexFromUint32(memberID) if err != nil { - return nil, fmt.Errorf("could not unmarshal public key [%v]", err) + return nil, err } - - unmarshalled[group.MemberIndex(memberID)] = publicKey - + unmarshalled[memberIndex] = publicKeyBytes } - return unmarshalled, nil } diff --git a/pkg/tecdsa/signing/marshaling_test.go b/pkg/tecdsa/signing/marshaling_test.go index 19dd00f858..f32344b86d 100644 --- a/pkg/tecdsa/signing/marshaling_test.go +++ b/pkg/tecdsa/signing/marshaling_test.go @@ -1,12 +1,13 @@ package signing import ( + "reflect" + "testing" + fuzz "github.com/google/gofuzz" "github.com/keep-network/keep-core/pkg/crypto/ephemeral" "github.com/keep-network/keep-core/pkg/internal/pbutils" "github.com/keep-network/keep-core/pkg/protocol/group" - "reflect" - "testing" ) func TestEphemeralPublicKeyMessage_MarshalingRoundtrip(t *testing.T) { @@ -20,9 +21,10 @@ func TestEphemeralPublicKeyMessage_MarshalingRoundtrip(t *testing.T) { t.Fatal(err) } - publicKeys := make(map[group.MemberIndex]*ephemeral.PublicKey) - publicKeys[group.MemberIndex(211)] = keyPair1.PublicKey - publicKeys[group.MemberIndex(19)] = keyPair2.PublicKey + publicKeys := map[group.MemberIndex][]byte{ + group.MemberIndex(211): keyPair1.PublicKey.Marshal(), + group.MemberIndex(19): keyPair2.PublicKey.Marshal(), + } msg := &ephemeralPublicKeyMessage{ senderID: group.MemberIndex(38), @@ -45,7 +47,7 @@ func TestFuzzEphemeralPublicKeyMessage_MarshalingRoundtrip(t *testing.T) { for i := 0; i < 10; i++ { var ( senderID group.MemberIndex - ephemeralPublicKeys map[group.MemberIndex]*ephemeral.PublicKey + ephemeralPublicKeys map[group.MemberIndex][]byte sessionID string ) @@ -63,12 +65,14 @@ func TestFuzzEphemeralPublicKeyMessage_MarshalingRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &ephemeralPublicKeyMessage{}) + if err := pbutils.RoundTrip(message, &ephemeralPublicKeyMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzEphemeralPublicKeyMessage_Unmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&ephemeralPublicKeyMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&ephemeralPublicKeyMessage{}) } func TestTssRoundOneMessage_MarshalingRoundtrip(t *testing.T) { @@ -118,12 +122,14 @@ func TestFuzzTssRoundOneMessage_MarshalingRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &tssRoundOneMessage{}) + if err := pbutils.RoundTrip(message, &tssRoundOneMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzTssRoundOneMessage_Unmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&tssRoundOneMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&tssRoundOneMessage{}) } func TestTssRoundTwoMessage_MarshalingRoundtrip(t *testing.T) { @@ -169,12 +175,14 @@ func TestFuzzTssRoundTwoMessage_MarshalingRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &tssRoundTwoMessage{}) + if err := pbutils.RoundTrip(message, &tssRoundTwoMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzTssRoundTwoMessage_Unmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&tssRoundTwoMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&tssRoundTwoMessage{}) } func TestTssRoundThreeMessage_MarshalingRoundtrip(t *testing.T) { @@ -217,12 +225,14 @@ func TestFuzzTssRoundThreeMessage_MarshalingRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &tssRoundThreeMessage{}) + if err := pbutils.RoundTrip(message, &tssRoundThreeMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzTssRoundThreeMessage_Unmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&tssRoundThreeMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&tssRoundThreeMessage{}) } func TestTssRoundFourMessage_MarshalingRoundtrip(t *testing.T) { @@ -265,12 +275,14 @@ func TestFuzzTssRoundFourMessage_MarshalingRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &tssRoundFourMessage{}) + if err := pbutils.RoundTrip(message, &tssRoundFourMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzTssRoundFourMessage_Unmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&tssRoundFourMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&tssRoundFourMessage{}) } func TestTssRoundFiveMessage_MarshalingRoundtrip(t *testing.T) { @@ -313,12 +325,14 @@ func TestFuzzTssRoundFiveMessage_MarshalingRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &tssRoundFiveMessage{}) + if err := pbutils.RoundTrip(message, &tssRoundFiveMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzTssRoundFiveMessage_Unmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&tssRoundFiveMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&tssRoundFiveMessage{}) } func TestTssRoundSixMessage_MarshalingRoundtrip(t *testing.T) { @@ -361,12 +375,14 @@ func TestFuzzTssRoundSixMessage_MarshalingRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &tssRoundSixMessage{}) + if err := pbutils.RoundTrip(message, &tssRoundSixMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzTssRoundSixMessage_Unmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&tssRoundSixMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&tssRoundSixMessage{}) } func TestTssRoundSevenMessage_MarshalingRoundtrip(t *testing.T) { @@ -409,12 +425,14 @@ func TestFuzzTssRoundSevenMessage_MarshalingRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &tssRoundSevenMessage{}) + if err := pbutils.RoundTrip(message, &tssRoundSevenMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzTssRoundSevenMessage_Unmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&tssRoundSevenMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&tssRoundSevenMessage{}) } func TestTssRoundEightMessage_MarshalingRoundtrip(t *testing.T) { @@ -457,12 +475,14 @@ func TestFuzzTssRoundEightMessage_MarshalingRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &tssRoundEightMessage{}) + if err := pbutils.RoundTrip(message, &tssRoundEightMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzTssRoundEightMessage_Unmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&tssRoundEightMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&tssRoundEightMessage{}) } func TestTssRoundNineMessage_MarshalingRoundtrip(t *testing.T) { @@ -505,10 +525,174 @@ func TestFuzzTssRoundNineMessage_MarshalingRoundtrip(t *testing.T) { sessionID: sessionID, } - _ = pbutils.RoundTrip(message, &tssRoundNineMessage{}) + if err := pbutils.RoundTrip(message, &tssRoundNineMessage{}); err != nil { + t.Fatal(err) + } } } func TestFuzzTssRoundNineMessage_Unmarshaler(t *testing.T) { - pbutils.FuzzUnmarshaler(&tssRoundNineMessage{}) + pbutils.AssertUnmarshalDoesNotPanic(&tssRoundNineMessage{}) +} + +// --- Benchmarks --- + +func BenchmarkMarshalEphemeralPublicKeyMessage(b *testing.B) { + kp1, err := ephemeral.GenerateKeyPair() + if err != nil { + b.Fatal(err) + } + kp2, err := ephemeral.GenerateKeyPair() + if err != nil { + b.Fatal(err) + } + msg := &ephemeralPublicKeyMessage{ + senderID: group.MemberIndex(38), + ephemeralPublicKeys: map[group.MemberIndex][]byte{ + group.MemberIndex(211): kp1.PublicKey.Marshal(), + group.MemberIndex(19): kp2.PublicKey.Marshal(), + }, + sessionID: "session-1", + } + b.ResetTimer() + for range b.N { + _, _ = msg.Marshal() + } +} + +func BenchmarkUnmarshalEphemeralPublicKeyMessage(b *testing.B) { + kp1, err := ephemeral.GenerateKeyPair() + if err != nil { + b.Fatal(err) + } + kp2, err := ephemeral.GenerateKeyPair() + if err != nil { + b.Fatal(err) + } + msg := &ephemeralPublicKeyMessage{ + senderID: group.MemberIndex(38), + ephemeralPublicKeys: map[group.MemberIndex][]byte{ + group.MemberIndex(211): kp1.PublicKey.Marshal(), + group.MemberIndex(19): kp2.PublicKey.Marshal(), + }, + sessionID: "session-1", + } + data, err := msg.Marshal() + if err != nil { + b.Fatal(err) + } + b.ResetTimer() + for range b.N { + _ = new(ephemeralPublicKeyMessage).Unmarshal(data) + } +} + +// buildEphemeralKeyMap generates n key pairs and returns the serialized public +// key map as it would appear in a real EphemeralPublicKeyMessage (one entry per peer). +func buildEphemeralKeyMap(b *testing.B, n int) map[group.MemberIndex][]byte { + b.Helper() + m := make(map[group.MemberIndex][]byte, n) + for i := 0; i < n; i++ { + kp, err := ephemeral.GenerateKeyPair() + if err != nil { + b.Fatal(err) + } + m[group.MemberIndex(i+1)] = kp.PublicKey.Marshal() + } + return m +} + +// BenchmarkMarshalEphemeralPublicKeyMessage_100Keys benchmarks marshaling with +// a realistic group size (100 members = 99 peer keys per message). +func BenchmarkMarshalEphemeralPublicKeyMessage_100Keys(b *testing.B) { + msg := &ephemeralPublicKeyMessage{ + senderID: group.MemberIndex(1), + ephemeralPublicKeys: buildEphemeralKeyMap(b, 99), + sessionID: "session-1", + } + b.ResetTimer() + for range b.N { + _, _ = msg.Marshal() + } +} + +// Benchmarks unmarshaling the wire-format bytes. EC point parsing is +// deferred to use-time in generateSymmetricKeys (protocol.go). +func BenchmarkUnmarshalEphemeralPublicKeyMessage_100Keys(b *testing.B) { + msg := &ephemeralPublicKeyMessage{ + senderID: group.MemberIndex(1), + ephemeralPublicKeys: buildEphemeralKeyMap(b, 99), + sessionID: "session-1", + } + data, err := msg.Marshal() + if err != nil { + b.Fatal(err) + } + b.ResetTimer() + for range b.N { + _ = new(ephemeralPublicKeyMessage).Unmarshal(data) + } +} + +// BenchmarkMarshalSigningShareMessage benchmarks the heaviest per-member +// message in a signing round: round-one carries both broadcast and peer +// payloads. +func BenchmarkMarshalSigningShareMessage(b *testing.B) { + msg := &tssRoundOneMessage{ + senderID: group.MemberIndex(50), + broadcastPayload: []byte{1, 2, 3, 4, 5}, + peersPayload: map[group.MemberIndex][]byte{ + 1: {6, 7, 8, 9, 10}, + 2: {11, 12, 13, 14, 15}, + }, + sessionID: "session-1", + } + b.ResetTimer() + for range b.N { + _, _ = msg.Marshal() + } +} + +func BenchmarkUnmarshalSigningShareMessage(b *testing.B) { + msg := &tssRoundOneMessage{ + senderID: group.MemberIndex(50), + broadcastPayload: []byte{1, 2, 3, 4, 5}, + peersPayload: map[group.MemberIndex][]byte{ + 1: {6, 7, 8, 9, 10}, + 2: {11, 12, 13, 14, 15}, + }, + sessionID: "session-1", + } + data, err := msg.Marshal() + if err != nil { + b.Fatal(err) + } + b.ResetTimer() + for range b.N { + _ = new(tssRoundOneMessage).Unmarshal(data) + } +} + +func BenchmarkRoundTripEphemeralKey(b *testing.B) { + kp1, err := ephemeral.GenerateKeyPair() + if err != nil { + b.Fatal(err) + } + kp2, err := ephemeral.GenerateKeyPair() + if err != nil { + b.Fatal(err) + } + msg := &ephemeralPublicKeyMessage{ + senderID: group.MemberIndex(38), + ephemeralPublicKeys: map[group.MemberIndex][]byte{ + group.MemberIndex(211): kp1.PublicKey.Marshal(), + group.MemberIndex(19): kp2.PublicKey.Marshal(), + }, + sessionID: "session-1", + } + b.ResetTimer() + for range b.N { + data, _ := msg.Marshal() + _ = new(ephemeralPublicKeyMessage).Unmarshal(data) + } } diff --git a/pkg/tecdsa/signing/member.go b/pkg/tecdsa/signing/member.go index d506b8aa2d..dbe91939d7 100644 --- a/pkg/tecdsa/signing/member.go +++ b/pkg/tecdsa/signing/member.go @@ -330,5 +330,8 @@ func (ic *identityConverter) TssPartyIDToMemberIndex( return key.Cmp(partyID.KeyInt()) == 0 }) + if index < 0 || index >= group.MaxMemberIndex { + return 0 + } return group.MemberIndex(index + 1) } diff --git a/pkg/tecdsa/signing/member_test.go b/pkg/tecdsa/signing/member_test.go index a4f525a2d2..2e2ad1420a 100644 --- a/pkg/tecdsa/signing/member_test.go +++ b/pkg/tecdsa/signing/member_test.go @@ -204,3 +204,21 @@ func TestIdentityConverter_TssPartyIDToMemberIndex_Corrupted(t *testing.T) { testutils.AssertIntsEqual(t, "member ID", 0, int(memberIndex)) } + +func TestIdentityConverter_TssPartyIDToMemberIndex_Overflow(t *testing.T) { + keys := make([]*big.Int, group.MaxMemberIndex+1) + for i := range keys { + keys[i] = big.NewInt(int64(1000 + i)) + } + converter := &identityConverter{keys: keys} + + // The matching key sits at slice index group.MaxMemberIndex (the 256th + // entry), one past the last valid member index; it should never happen, + // so the party ID is considered corrupted and MemberIndex(0) is returned. + targetKey := keys[group.MaxMemberIndex] + partyID := tss.NewPartyID(targetKey.Text(10), "member-256", targetKey) + + memberIndex := converter.TssPartyIDToMemberIndex(partyID) + + testutils.AssertIntsEqual(t, "member ID", 0, int(memberIndex)) +} diff --git a/pkg/tecdsa/signing/message.go b/pkg/tecdsa/signing/message.go index df2980e4bf..7b7c6d6d38 100644 --- a/pkg/tecdsa/signing/message.go +++ b/pkg/tecdsa/signing/message.go @@ -1,7 +1,6 @@ package signing import ( - "github.com/keep-network/keep-core/pkg/crypto/ephemeral" "github.com/keep-network/keep-core/pkg/protocol/group" ) @@ -26,7 +25,7 @@ type message interface { type ephemeralPublicKeyMessage struct { senderID group.MemberIndex - ephemeralPublicKeys map[group.MemberIndex]*ephemeral.PublicKey + ephemeralPublicKeys map[group.MemberIndex][]byte sessionID string } diff --git a/pkg/tecdsa/signing/protocol.go b/pkg/tecdsa/signing/protocol.go index 9814a0c1a9..2c13ff641d 100644 --- a/pkg/tecdsa/signing/protocol.go +++ b/pkg/tecdsa/signing/protocol.go @@ -17,7 +17,7 @@ func (ekpgm *ephemeralKeyPairGeneratingMember) generateEphemeralKeyPair() ( *ephemeralPublicKeyMessage, error, ) { - ephemeralKeys := make(map[group.MemberIndex]*ephemeral.PublicKey) + ephemeralKeys := make(map[group.MemberIndex][]byte) // Calculate ephemeral key pair for every other group member for _, member := range ekpgm.group.MemberIndexes() { @@ -34,8 +34,8 @@ func (ekpgm *ephemeralKeyPairGeneratingMember) generateEphemeralKeyPair() ( // save the generated ephemeral key to our state ekpgm.ephemeralKeyPairs[member] = ephemeralKeyPair - // store the public key to the map for the message - ephemeralKeys[member] = ephemeralKeyPair.PublicKey + // store the serialized public key to the map for the message + ephemeralKeys[member] = ephemeralKeyPair.PublicKey.Marshal() } return &ephemeralPublicKeyMessage{ @@ -78,9 +78,30 @@ func (skgm *symmetricKeyGeneratingMember) generateSymmetricKeys( thisMemberEphemeralPrivateKey := ephemeralKeyPair.PrivateKey // Get the ephemeral public key broadcasted by the other group member, - // which was intended for this group member. - otherMemberEphemeralPublicKey := - ephemeralPubKeyMessage.ephemeralPublicKeys[skgm.id] + // which was intended for this group member, and parse it. Only this + // one key per message is needed for ECDH; the rest are validated for + // presence in isValidEphemeralPublicKeyMessage but never parsed. + otherMemberEphemeralPublicKey, err := ephemeral.UnmarshalPublicKey( + ephemeralPubKeyMessage.ephemeralPublicKeys[skgm.id], + ) + if err != nil { + // A single member's malformed key must not abort this member's + // entire round. Before the deferred-parse optimization, an + // unparseable key failed message unmarshaling at the network + // layer, so the whole message was dropped and the sender was + // simply treated as absent. Preserve that behavior here: skip + // the sender and mark it inactive instead of returning a fatal + // error that aborts this member's async state. + skgm.logger.Warnf( + "[member:%v] could not unmarshal ephemeral public key "+ + "from member [%v]: [%v]; marking member as inactive", + skgm.id, + otherMember, + err, + ) + skgm.group.MarkMemberAsInactive(otherMember) + continue + } // Create symmetric key for the current group member and the other // group member by ECDH'ing the public and private key. diff --git a/pkg/tecdsa/signing/protocol_test.go b/pkg/tecdsa/signing/protocol_test.go index d5bc520379..d5533bdd64 100644 --- a/pkg/tecdsa/signing/protocol_test.go +++ b/pkg/tecdsa/signing/protocol_test.go @@ -179,16 +179,16 @@ func TestGenerateSymmetricKeys(t *testing.T) { // Assert all symmetric keys stored by this member are correct. for otherMemberID, actualKey := range member.symmetricKeys { - var otherMemberEphemeralPublicKey *ephemeral.PublicKey + var otherMemberEphemeralPublicKeyBytes []byte for _, message := range messages { if message.senderID == otherMemberID { - if ephemeralPublicKey, ok := message.ephemeralPublicKeys[member.id]; ok { - otherMemberEphemeralPublicKey = ephemeralPublicKey + if keyBytes, ok := message.ephemeralPublicKeys[member.id]; ok { + otherMemberEphemeralPublicKeyBytes = keyBytes } } } - if otherMemberEphemeralPublicKey == nil { + if otherMemberEphemeralPublicKeyBytes == nil { t.Errorf( "[member:%v] no ephemeral public key from member [%v]", member.id, @@ -196,6 +196,13 @@ func TestGenerateSymmetricKeys(t *testing.T) { ) } + otherMemberEphemeralPublicKey, err := ephemeral.UnmarshalPublicKey( + otherMemberEphemeralPublicKeyBytes, + ) + if err != nil { + t.Fatalf("could not unmarshal ephemeral public key: %v", err) + } + expectedKey := ephemeral.SymmetricKey( member.ephemeralKeyPairs[otherMemberID].PrivateKey.Ecdh( otherMemberEphemeralPublicKey, @@ -261,6 +268,78 @@ func TestGenerateSymmetricKeys_InvalidEphemeralPublicKeyMessage(t *testing.T) { } } +func TestGenerateSymmetricKeys_CorruptEphemeralPublicKeyBytes(t *testing.T) { + members, messages, err := initializeSymmetricKeyGeneratingMembersGroup( + dishonestThreshold, + groupSize, + ) + if err != nil { + t.Fatal(err) + } + + // Replace member 2's ephemeral public key for member 1 with garbage. + // The key is still present so isValidEphemeralPublicKeyMessage passes; + // only member 1 encounters the parse error during ECDH. + misbehavingMemberID := group.MemberIndex(2) + victimMemberID := group.MemberIndex(1) + messages[misbehavingMemberID-1].ephemeralPublicKeys[victimMemberID] = []byte{0x00, 0x01, 0x02} + + for _, member := range members { + var receivedMessages []*ephemeralPublicKeyMessage + for _, message := range messages { + if message.senderID != member.id { + receivedMessages = append(receivedMessages, message) + } + } + + err := member.generateSymmetricKeys(receivedMessages) + + // A corrupt key from one member must never abort another member's + // entire round: the sender is skipped instead. + if err != nil { + t.Errorf("[member:%v] unexpected error: %v", member.id, err) + } + + expectedKeysCount := groupSize - 1 + if member.id == victimMemberID { + // The victim skips the misbehaving sender, so it stores one + // fewer symmetric key than everyone else. + expectedKeysCount-- + + if _, ok := member.symmetricKeys[misbehavingMemberID]; ok { + t.Errorf( + "[member:%v] expected no symmetric key stored for "+ + "misbehaving member [%v]", + member.id, + misbehavingMemberID, + ) + } + } + + testutils.AssertIntsEqual( + t, + fmt.Sprintf("number of stored symmetric keys for member [%v]", member.id), + expectedKeysCount, + len(member.symmetricKeys), + ) + } + + // All members in this test share a single *group.Group instance (see + // initializeEphemeralKeyPairGeneratingMembersGroup), so the effect of + // the victim marking the misbehaving member inactive is visible from + // any member's reference to it. + if !reflect.DeepEqual( + []group.MemberIndex{misbehavingMemberID}, + members[0].group.InactiveMemberIndexes(), + ) { + t.Errorf( + "expected member [%v] to be marked inactive, got inactive members: %v", + misbehavingMemberID, + members[0].group.InactiveMemberIndexes(), + ) + } +} + func TestTssRoundOne(t *testing.T) { members, err := initializeTssRoundOneMembersGroup( dishonestThreshold, diff --git a/pkg/wrappers/wrappers.go b/pkg/wrappers/wrappers.go new file mode 100644 index 0000000000..642c82b61b --- /dev/null +++ b/pkg/wrappers/wrappers.go @@ -0,0 +1,230 @@ +package wrappers + +import ( + "context" + "errors" + "fmt" + "math/rand/v2" + "time" +) + +// DoWithRetry executes the provided doFn as long as it returns an error or until +// a timeout is hit. It applies exponential backoff wait of backoffTime * 2^n +// before nth retry of doFn. In case the calculated backoff is longer than +// backoffMax, the backoffMax wait is applied. +// +// If the configured timeout elapses before doFn succeeds, DoWithRetry returns an +// error that matches ErrRetryTimeout via errors.Is. This signals that the retry +// budget was exhausted after repeated attempts, as opposed to a single attempt +// failing and returning immediately. Callers may use errors.Is(err, ErrRetryTimeout) +// to detect retry exhaustion, and errors.Unwrap to inspect the most recent error +// returned by doFn. +func DoWithRetry( + parentCtx context.Context, + backoffTime time.Duration, + backoffMax time.Duration, + timeout time.Duration, + doFn func(ctx context.Context) error, +) error { + ctx, cancel := context.WithTimeout(parentCtx, timeout) + defer cancel() + + var err error + for { + select { + case <-ctx.Done(): + return &retryTimeoutError{timeout: timeout, cause: err} + default: + err = doFn(ctx) + if err == nil { + return nil + } + + timedOut := backoffWait(ctx, backoffTime) + if timedOut { + return &retryTimeoutError{timeout: timeout, cause: err} + } + + backoffTime = calculateBackoff( + backoffTime, + backoffMax, + ) + } + } +} + +// ErrRetryTimeout is the sentinel error matched via errors.Is when a retry loop +// (DoWithRetry or DoWithDefaultRetry) exceeds its configured timeout without +// doFn ever succeeding. It indicates that the entire retry budget was exhausted, +// as opposed to an individual execution of doFn failing once and returning. +var ErrRetryTimeout = errors.New("retry timeout") + +// retryTimeoutError renders the historical "retry timeout [%v] exceeded; +// most recent error: [%v]" message verbatim while matching +// errors.Is(err, ErrRetryTimeout) and unwrapping to the most recent +// underlying error from doFn. +type retryTimeoutError struct { + timeout time.Duration + cause error +} + +func (e *retryTimeoutError) Error() string { + return fmt.Sprintf( + "retry timeout [%v] exceeded; most recent error: [%v]", + e.timeout, + e.cause, + ) +} + +func (e *retryTimeoutError) Unwrap() error { + return e.cause +} + +func (e *retryTimeoutError) Is(target error) bool { + return target == ErrRetryTimeout +} + +const ( + // DefaultDoBackoffTime is the default value of backoff time used by + // DoWithDefaultRetry function. + DefaultDoBackoffTime = 1 * time.Second + + // DefaultDoMaxBackoffTime is the default value of max backoff time used by + // DoWithDefaultRetry function. + DefaultDoMaxBackoffTime = 120 * time.Second +) + +// DoWithDefaultRetry executes the provided doFn as long as it returns an error or +// until a timeout is hit. It applies exponential backoff wait of +// DefaultBackoffTime * 2^n before nth retry of doFn. In case the calculated +// backoff is longer than DefaultMaxBackoffTime, the DefaultMaxBackoffTime is +// applied. +// +// Like DoWithRetry, if the timeout is reached before doFn succeeds, it returns an +// error matching ErrRetryTimeout via errors.Is. +func DoWithDefaultRetry( + parentCtx context.Context, + timeout time.Duration, + doFn func(ctx context.Context) error, +) error { + return DoWithRetry( + parentCtx, + DefaultDoBackoffTime, + DefaultDoMaxBackoffTime, + timeout, + doFn, + ) +} + +// ConfirmWithTimeout executes the provided confirmFn until it returns true or +// until it fails or until a timeout is hit. It applies exponential backoff wait +// of backoffTime * 2^n before nth execution of confirmFn. In case the +// calculated backoff is longer than backoffMax, the backoffMax is applied. +// In case confirmFn returns an error, ConfirmWithTimeout exits with the same +// error immediately. This is different from DoWithRetry behavior as the use +// case for this function is different. ConfirmWithTimeout is intended to be +// used to confirm a chain state and not to try to enforce a successful +// execution of some function. +func ConfirmWithTimeout( + parentCtx context.Context, + backoffTime time.Duration, + backoffMax time.Duration, + timeout time.Duration, + confirmFn func(ctx context.Context) (bool, error), +) (bool, error) { + ctx, cancel := context.WithTimeout(parentCtx, timeout) + defer cancel() + + for { + select { + case <-ctx.Done(): + return false, nil + default: + ok, err := confirmFn(ctx) + if err == nil && ok { + return true, nil + } + if err != nil { + return false, err + } + + timedOut := backoffWait(ctx, backoffTime) + if timedOut { + return false, nil + } + + backoffTime = calculateBackoff( + backoffTime, + backoffMax, + ) + } + } +} + +const ( + // DefaultConfirmBackoffTime is the default value of backoff time used by + // ConfirmWithDefaultTimeout function. + DefaultConfirmBackoffTime = 5 * time.Second + + // DefaultConfirmMaxBackoffTime is the default value of max backoff time + // used by ConfirmWithDefaultTimeout function. + DefaultConfirmMaxBackoffTime = 10 * time.Second +) + +// ConfirmWithTimeoutDefaultBackoff executed the provided confirmFn until it +// returns true or until it fails or until timeout is hit. It applies +// backoff wait of DefaultConfirmBackoffTime * 2^n before nth execution of +// confirmFn. In case the calculated backoff is longer than +// DefaultConfirmMaxBackoffTime, DefaultConfirmMaxBackoffTime is applied. +// In case confirmFn returns an error, ConfirmWithTimeoutDefaultBackoff exits +// with the same error immediately. This is different from DoWithDefaultRetry +// behavior as the use case for this function is different. +// ConfirmWithTimeoutDefaultBackoff is intended to be used to confirm a chain +// state and not to try to enforce a successful execution of some function. +func ConfirmWithTimeoutDefaultBackoff( + parentCtx context.Context, + timeout time.Duration, + confirmFn func(ctx context.Context) (bool, error), +) (bool, error) { + return ConfirmWithTimeout( + parentCtx, + DefaultConfirmBackoffTime, + DefaultConfirmMaxBackoffTime, + timeout, + confirmFn, + ) +} + +func calculateBackoff( + backoffPrev time.Duration, + backoffMax time.Duration, +) time.Duration { + backoff := backoffPrev + + backoff *= 2 + + // #nosec G404 + // we are fine with not using cryptographically secure random integer, + // it is just exponential backoff jitter + r := rand.Int64N(backoff.Nanoseconds()/10 + 1) + jitter := time.Duration(r) * time.Nanosecond + backoff += jitter + + if backoff > backoffMax { + backoff = backoffMax + } + + return backoff +} + +func backoffWait(ctx context.Context, waitTime time.Duration) bool { + timer := time.NewTimer(waitTime) + defer timer.Stop() + + select { + case <-ctx.Done(): + return true + case <-timer.C: + return false + } +} diff --git a/pkg/wrappers/wrappers_test.go b/pkg/wrappers/wrappers_test.go new file mode 100644 index 0000000000..fa8e31d5a8 --- /dev/null +++ b/pkg/wrappers/wrappers_test.go @@ -0,0 +1,283 @@ +package wrappers + +import ( + "context" + "errors" + "fmt" + "testing" + "time" +) + +func TestDoWithRetry(t *testing.T) { + backoffTime := 10 * time.Millisecond + backoffMax := 100 * time.Millisecond + timeout := 2 * time.Second + + actualFailCount := 0 + expectedFailCount := 4 + doFn := func(ctx context.Context) error { + if actualFailCount < expectedFailCount { + actualFailCount++ + return fmt.Errorf("try again please") + } + + return nil + } + + err := DoWithRetry(context.Background(), backoffTime, backoffMax, timeout, doFn) + if err != nil { + t.Fatal(err) + } + + if actualFailCount != expectedFailCount { + t.Errorf( + "unexpected fail count: actual [%v], expected [%v]", + actualFailCount, + expectedFailCount, + ) + } +} + +func TestDoWithRetryExceedTimeout(t *testing.T) { + backoffTime := 100 * time.Millisecond + backoffMax := 500 * time.Millisecond + timeout := 1 * time.Second + + actualFailCount := 0 + + // This function should be executed 4 times and timeout: + // 100 ms + // 200 ms + // 400 ms + // 500 ms <- here it should exceed 1s timeout + doFn := func(ctx context.Context) error { + if actualFailCount < 10 { + actualFailCount++ + return fmt.Errorf("try again please %d", actualFailCount) + } + + return nil + } + + err := DoWithRetry(context.Background(), backoffTime, backoffMax, timeout, doFn) + if err == nil { + t.Fatal("expected a timeout error") + } + + expectedLatestError := "try again please 4" + expectedError := "retry timeout [1s] exceeded; most recent error: [try again please 4]" + if err.Error() != expectedError { + t.Errorf( + "unexpected error message\nactual: [%v]\nexpected: [%v]", + err.Error(), + expectedError, + ) + } + if errors.Unwrap(err).Error() != expectedLatestError { + t.Errorf( + "unexpected error message\nactual: [%v]\nexpected: [%v]", + err.Error(), + expectedError, + ) + } + + // Callers must be able to classify retry exhaustion without matching on + // error text. + if !errors.Is(err, ErrRetryTimeout) { + t.Errorf("timeout error does not match ErrRetryTimeout: [%v]", err) + } + + expectedFailCount := 4 + if actualFailCount != expectedFailCount { + t.Errorf( + "unexpected fail count: actual [%v], expected [%v]", + actualFailCount, + expectedFailCount, + ) + } +} + +// TestDoWithRetryTimeoutBeforeFirstAttempt covers the path where the context +// is already done when DoWithRetry starts, so doFn never runs and there is no +// most-recent error to report. +// +// The nil cause renders as "" in the message: passing a nil error to a +// %w verb would print the literal "%!w()". The exact message is asserted +// below, so any change to the rendering is a conscious decision. +func TestDoWithRetryTimeoutBeforeFirstAttempt(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + attempted := false + doFn := func(ctx context.Context) error { + attempted = true + return nil + } + + err := DoWithRetry(ctx, 10*time.Millisecond, 100*time.Millisecond, time.Second, doFn) + if err == nil { + t.Fatal("expected a timeout error") + } + if attempted { + t.Error("doFn should not run when the context is already done") + } + + if !errors.Is(err, ErrRetryTimeout) { + t.Errorf("timeout error does not match ErrRetryTimeout: [%v]", err) + } + + if cause := errors.Unwrap(err); cause != nil { + t.Errorf("expected no wrapped cause, got [%v]", cause) + } + + expectedError := "retry timeout [1s] exceeded; most recent error: []" + if err.Error() != expectedError { + t.Errorf( + "unexpected error message\nactual: [%v]\nexpected: [%v]", + err.Error(), + expectedError, + ) + } +} + +func TestConfirmWithTimeout(t *testing.T) { + backoffTime := 10 * time.Millisecond + backoffMax := 100 * time.Millisecond + timeout := 2 * time.Second + + actualCheckCount := 0 + expectedCheckCount := 3 + confirmFn := func(ctx context.Context) (bool, error) { + if actualCheckCount < expectedCheckCount { + actualCheckCount++ + return false, nil + } + + return true, nil + } + + ok, err := ConfirmWithTimeout(context.Background(), backoffTime, backoffMax, timeout, confirmFn) + if err != nil { + t.Fatal(err) + } + if !ok { + t.Errorf("expected the check to eventually succeed") + } + + if actualCheckCount != expectedCheckCount { + t.Errorf( + "unexpected check count: actual [%v], expected [%v]", + actualCheckCount, + expectedCheckCount, + ) + } +} + +func TestConfirmWithTimeoutExceedTimeout(t *testing.T) { + backoffTime := 100 * time.Millisecond + backoffMax := 300 * time.Millisecond + timeout := 1 * time.Second + + actualCheckCount := 0 + + // This function should be executed 5 times and timeout: + // 100 ms + // 200 ms + // 300 ms + // 300 ms + // 300 ms <- here it should exceed 1s timeout + confirmFn := func(ctx context.Context) (bool, error) { + if actualCheckCount < 10 { + actualCheckCount++ + return false, nil + } + + return true, nil + } + + ok, err := ConfirmWithTimeout(context.Background(), backoffTime, backoffMax, timeout, confirmFn) + if err != nil { + t.Fatal(err) + } + if ok { + t.Errorf("expected the check to eventually fail") + } + + expectedCheckCount := 5 + if actualCheckCount != expectedCheckCount { + t.Errorf( + "unexpected check count: actual [%v], expected [%v]", + actualCheckCount, + expectedCheckCount, + ) + } +} + +func TestConfirmWithTimeoutFailure(t *testing.T) { + backoffTime := 100 * time.Millisecond + backoffMax := 300 * time.Millisecond + timeout := 1 * time.Second + + confirmFn := func(ctx context.Context) (bool, error) { + return false, fmt.Errorf("untada") + } + + ok, err := ConfirmWithTimeout(context.Background(), backoffTime, backoffMax, timeout, confirmFn) + if err == nil { + t.Fatal("expected an error") + } + if ok { + t.Errorf("should return false") + } + + expectedError := "untada" + if err.Error() != expectedError { + t.Errorf( + "unexpected error message\nactual: [%v]\nexpected: [%v]", + err.Error(), + expectedError, + ) + } +} + +func TestCalculateBackoff(t *testing.T) { + backoffInitial := 120 * time.Second + backoffMax := 300 * time.Second + + expectedMin := 240 * time.Second // 2 * backoffInitial + expectedMax := 265 * time.Second // 2 * backoffInitial * 110% + 1 + + for i := 0; i < 100; i++ { + backoff := calculateBackoff(backoffInitial, backoffMax) + + if backoff < expectedMin { + t.Errorf( + "backoff [%v] shorter than the expected minimum [%v]", + backoff, + expectedMin, + ) + } + + if backoff > expectedMax { + t.Errorf( + "backoff [%v] longer than the expected maximum [%v]", + backoff, + expectedMax, + ) + } + } +} + +func TestCalculateBackoffMax(t *testing.T) { + backoffInitial := 220 * time.Second + backoffMax := 300 * time.Second + + backoff := calculateBackoff(backoffInitial, backoffMax) + if backoff != backoffMax { + t.Errorf( + "expected max backoff of [%v]; has [%v]", + backoffMax, + backoff, + ) + } +} diff --git a/solidity/.gitattributes b/solidity/.gitattributes new file mode 100644 index 0000000000..2ef444a895 --- /dev/null +++ b/solidity/.gitattributes @@ -0,0 +1,2 @@ +# Unified patch context lines intentionally preserve source whitespace. +*/.yarn/patches/*.patch -whitespace diff --git a/solidity/docs/ethers-v6-compatibility.md b/solidity/docs/ethers-v6-compatibility.md new file mode 100644 index 0000000000..601345c084 --- /dev/null +++ b/solidity/docs/ethers-v6-compatibility.md @@ -0,0 +1,208 @@ +# Ethers v6 compatibility checks + +This prepares the two Solidity packages for +[#4295](https://github.com/threshold-network/keep-core/issues/4295). It retains +Hardhat 2.29.0, hardhat-deploy 1.0.4 and ES2020/CommonJS deployment exports. The +comparison baseline is commit `4f7fa861b`: the strict TypeScript/Waffle-removal +stack plus maintained deploy v1, Node 24/Yarn 4 and ethers 5.8.0. Contract sources, +committed live deployment records and OpenZeppelin manifests are unchanged. + +## Runtime and patches + +Tested with Node 24.11.1 and Yarn 4.12.0. Both immutable lockfile installs pass. +The active client is ethers 6.17.0, with Hardhat ethers 3.1.3, Chai Matchers 2.1.2, +TypeChain Hardhat 9.1.0, helpers 0.7.2, OpenZeppelin Upgrades 2.5.1 and Tenderly +2.1.1. Mocha/Chai and strict TypeScript are retained. Tenderly automatic +verification is explicitly disabled; existing explicit verification calls remain. + +Each package carries four reproducible Yarn patches: + +| Package | Reason | +| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| hardhat-helpers 0.7.2 | Accept ethers v6 BaseContract typings, preserve the old proxy deployment receipt fields, and select an explicit v4/v5 ProxyAdmin artifact for preparation with the retained upgrade plugin. | +| OpenZeppelin Upgrades 2.5.1 | Add the chain ID to Etherscan v2 verification queries used by hardhat-verify 2.1.3. This retains the v4 shared-admin creation behavior. | +| TypeChain ethers-v6 0.5.1 | Handle a contract function named `target`, which conflicts with the ethers v6 base-contract property. | +| Threshold contracts 1.3.0-dev.14 | Port three deployment API uses: the deployed staking address, JSON interface formatting and ZeroAddress. Solidity and artifacts are unchanged by this patch. | + +The helper's old deploy/OZ peer ranges and OZ 2's verify-v1 peer produce expected +peer warnings. They are not suppressed; the selected patched combinations are +covered by the checks below. Yarn resolutions and devDependency patches do not +propagate automatically into a downstream package installation. Consumers must +adopt the same compatible runtime and upstream fixes before release. + +## Test and build evidence + +- Both full suites pass: 962 Beacon tests and 679 ECDSA tests, with + ECDSA's existing 44 pending tests unchanged. +- Four additional Beacon confirmation tests pass using the local ethers provider: + one confirmation, a mined second confirmation, timeout, and missing transaction. +- Three additional initialization task tests pass: new stake/authorization/operator + setup, a rerun without transactions, and a stake top-up with increased authorization. +- Both strict TypeScript checks, CommonJS export builds and prepack artifact + exports pass. Full lint completes with warnings but no errors. +- WalletRegistry upgrade tests exercise layout rejection, existing proxy upgrades, + shared-admin ownership and authorized versus unauthorized calls. + +The confirmation helper uses `getTransaction(...).wait(...)` because the Hardhat +ethers v6 provider does not implement `waitForTransaction`. Published Beacon +scripts include its compiled `export/utils/wait-for-confirmations.js` dependency. +ECDSA's bundled Beacon scripts are regenerated from the same TypeScript sources, +including the missing-approval-function and already-approved guards. + +ECDSA's Beacon task imports use the same export resolver as deployments. Source +checkouts prefer a sibling Beacon build and otherwise load the committed v6 +task bundle. Packed ECDSA includes that bundle, so its compiled task entrypoints +also work with the pinned v5 Beacon dependency; an adjacent installed package is +not mistaken for a sibling source build. `RANDOM_BEACON_EXPORT_PATH` selects the +task exports too and never falls back if they are missing. + +Six ECDSA task regressions cover staking with distinct beneficiary/authorizer +accounts, direct registration, complete initialization with minimum +authorization and beta membership, idempotent reruns, stake/authorization +increases, and the development account-unlock provider API. The unlock check uses +an in-memory provider with no RPC connection. Before the task import fix, all +five initialization/registration checks failed at the pinned v5 API calls. + +## Production-contract deployment comparison + +Fresh deployments use real contracts and external producer scripts on a +non-forked in-process Hardhat network. The clock starts at 2024-01-01 UTC and +advances one second per transaction, so timestamp immutables in SortitionPools +are comparable. Each capture retains full blocks/receipts, deployment records, +exported artifacts and selected readers/code. The comparator checks the EVM +state root after every block, covering storage and balances beyond the selected +owner/governance readers. + +| Check | Beacon | ECDSA | +| ----------------------------------------------- | ------------- | -------------------------------- | +| Deployments | 16 | 22 | +| Transactions with identical resulting EVM state | 28 | 46 | +| `export.json` bytes | Identical | Identical | +| Addresses, runtime code, proxy slots and owners | Identical | Identical | +| Raw deployment-record bytes | Identical | Hash differences described below | +| Artifact inventory | Same 51 files | Same 52 files | + +Export SHA-256 values: + +```text +Beacon a7fe677b015af93102a99a276263bb1e8cbc84a06055c6dc98a636b681750083 +ECDSA 35e1886a916255779b9a02cda1ee75e84ec1cc6918965347682b8f1f82487333 +``` + +Six ECDSA transactions (blocks 33, 34, 35, 42, 45 and 46) use Hardhat's configured +16,777,216 gas limit through the new ethers signer. The baseline limits were +5,222,326; 443,289; 1,065,225; 15,799,896; 809,383; and 683,960 respectively. Only +the gas-limit field and derived signatures, transaction hashes and block headers +differ. Actual gas used, receipt contents other than hashes, transaction inputs, +fee prices, event data, state roots and ownership all match. The comparator +permits these exact gas changes and translates only their known hash fields; +it rejects other record changes. Raw ECDSA deployment records are consequently +not byte-identical. + +In each package, only the TokenStaking artifact changes: OpenZeppelin's newer +compiler integration adds `storageLayout` to this compiler-override artifact. +The layout matches the actual compiler build-info output. Removing that added +field leaves an identical parsed artifact, including ABI, bytecode, deployed +bytecode and metadata. Every other artifact is byte-identical. The comparison +does not silently waive arbitrary artifact differences. + +## Reproduce + +Install and run `yarn prepack` in both packages at the baseline and candidate. +Use Node 24 and the checked-in lockfiles. From each package directory, capture +into a new directory with the candidate's isolated configuration: + +```sh +COMPAT_DIR=/absolute/path/to/candidate/solidity/scripts/ethers-v6-compatibility +HARDHAT_CONFIG="$COMPAT_DIR/hardhat.config.cjs" \ + USE_EXTERNAL_DEPLOY=true MIGRATION_CAPTURE_DIR=/tmp/new-capture \ + node "$COMPAT_DIR/capture.cjs" +``` + +Leave `TEST_USE_STUBS_BEACON`, `TEST_USE_STUBS_ECDSA`, `FORKING_URL` and +`FORKING_BLOCK` unset. The capture rejects a fork, a public network, test stubs or +an existing destination. Compare matching package captures: + +```sh +node "$COMPAT_DIR/compare.cjs" /tmp/v5-capture /tmp/v6-capture --ethers-v6 +``` + +After both candidate prepack steps, run from `solidity/ecdsa`: + +```sh +node ../scripts/ethers-v6-compatibility/pack-and-capture.cjs \ + /tmp/new-packed-consumer /tmp/v6-ecdsa-capture +``` + +This packs and extracts the actual two npm archives and checks their exported +files, artifact counts and Beacon support module. It reuses the installed ECDSA +consumer's plugins; it does not validate dependency installation from scratch. +It executes both producers' compiled deployment scripts through explicit packed +paths and requires byte-identical state, exports, artifacts and deployment +records versus the ethers v6 source capture, without the v5 gas exceptions. +It also compares all bundled JavaScript with Beacon's compiled source and runs +the six ECDSA task checks through the packed ECDSA entrypoints: first with the +explicit packed v6 Beacon exports, then with the pinned v5 dependency installed +beside ECDSA to exercise its shipped task bundle. +`RANDOM_BEACON_EXPORT_PATH` fails on missing export directories (including +`tasks/`) rather than using sibling or bundled sources. `ECDSA_EXPORT_PATH` is +confined to the capture config. + +For the committed fallback check, temporarily move Beacon's ignored `export/` +directory aside in **both** trees, capture ECDSA, and restore the directories. +Compare those matching v5/v6 fallback captures with `--ethers-v6`. This check +also passes: all 46 transaction state roots and the selected code/state match, +with the same six gas-limit changes and TokenStaking layout addition described +above. The captured `inputs.json` confirms the bundled deploy path was selected. + +The fallback deliberately obtains artifacts from the pinned old Beacon npm +package. Nine Beacon contracts consequently have older compiler metadata than +the sibling build, on both toolchains. Do not compare a fallback capture with a +sibling-build capture and ignore those code differences. The bundled JavaScript +itself must exactly match the newly compiled source. The full ECDSA suite is also +run with the sibling export unavailable. + +## Publication lifecycle + +Both `prepublishOnly` hooks use helpers 0.7.2's `export-deployment-artifacts` +task. They honor npm's `--network` option and default to `hardhat` when it is +omitted. From a fresh copy of either package with dependencies installed: + +```sh +yarn deploy:test --network hardhat --write true +npm publish --dry-run --offline --registry=http://127.0.0.1:1 \ + --access=public --tag=development --network=hardhat +``` + +This exercises `prepublishOnly`, `prepack`, and ECDSA's `prepare` without +publishing a package. The deployment export requires an empty `artifacts/` +directory. Check that the exported records match `deployments/hardhat/` and +appear in npm's package contents. Use separate fresh copies to check the +omitted-network default and `--network=sepolia` with the checked-in Sepolia +deployment snapshots. + +## Limits and release gates + +The publishing jobs in +[`npm-random-beacon.yml`](../../.github/workflows/npm-random-beacon.yml) and +[`npm-ecdsa.yml`](../../.github/workflows/npm-ecdsa.yml) are disabled with +`if: ${{ false }}`. This blocks both automatic pushes to `main` and manual +dispatches on any ref, protecting the existing `development` and `latest` npm +tags. Re-enable the jobs in a coordinated release change only after the consumer +runtime migration, upstream fixes, release channel agreement, and ECDSA's pin to +a compatible published Beacon version are ready and the actual packed producers +pass the full ECDSA and tbtc-v2 consumer checks. Local packing and the offline +publication lifecycle checks above remain available while the jobs are disabled. + +These checks do not deploy to mainnet/Sepolia, contact explorer verification +services, run the full tbtc-v2 consumer, or authorize package publication. The +manual WalletRegistry V2 script is ported to v6 (and now saves a parsed ABI array) +but its complete operator workflow is not exercised here. The deputy-admin +script remains disabled. The separate Rocketh experiment covers a representative +proxy path, not all of these scripts. + +Do not publish these executable exports into an ethers v5 consumer line. Obtain +upstream helper/Threshold fixes or carry the reviewed patches in each consumer, +publish Beacon on the agreed release channel, pin ECDSA to that new release, then +validate the actual tbtc-v2 consumer. See the [migration decision and remaining +gates](hardhat-3-migration.md). Keep #4295 open. diff --git a/solidity/docs/hardhat-3-migration.md b/solidity/docs/hardhat-3-migration.md new file mode 100644 index 0000000000..5b620e42d4 --- /dev/null +++ b/solidity/docs/hardhat-3-migration.md @@ -0,0 +1,83 @@ +# Hardhat 3 and deployment export migration + +Status: ethers v6 preparation on Hardhat 2, 2026-09-08. Track the runtime migration +in [#4209](https://github.com/threshold-network/keep-core/issues/4209), plugin +changes in [#4213](https://github.com/threshold-network/keep-core/issues/4213), and +cross-package deployment conversion in +[#4295](https://github.com/threshold-network/keep-core/issues/4295). + +## Decision + +Target Hardhat 3, hardhat-deploy v2 and Rocketh, with viem in the deployment layer +and ethers v6 plus Mocha/Chai for tests. Keep Hardhat 2 and maintained +hardhat-deploy v1 available while consumers migrate. Prefer separate, versioned +release lines for the CommonJS/v1 and ESM/Rocketh executable APIs. Same-package +dual publication is possible, but adds a second runtime contract to every +producer and remains an alternative requiring consumer agreement. + +The dependency order is: + +```text +@threshold-network/solidity-contracts -> random-beacon -> ecdsa -> tbtc-v2 +``` + +Consumers execute the producers' `export/deploy` scripts. Module format, runtime +plugins and imported support files are therefore public APIs. Treat them +separately from the data APIs: `export/artifacts`, `export.json`, and committed +network deployment records. CommonJS alone does not make an ethers v6 script +compatible with an ethers v5 consumer. + +## Preparation in this stack + +Both packages use ethers v6, its Hardhat Chai Matchers integration and TypeChain +generator, while retaining Hardhat 2.29.0, maintained hardhat-deploy 1.0.4 and +ES2020/CommonJS exports. Waffle is removed. Strict TypeScript remains enabled. +Tests, tasks, deployment scripts and mock helpers use bigint and ethers v6 APIs. + +The helper moves to 0.7.2, which already uses ethers v6. Its declared deployment +and upgrade peers still need compatibility patches: this stack retains +OpenZeppelin Upgrades 2.5.1 and the shared OpenZeppelin v4 ProxyAdmin behavior. +Other patches preserve proxy receipt fields, support the verification plugin's +Etherscan v2 API, handle a TypeChain reserved name and adapt the three ethers v5 +API uses in the pinned Threshold deployment export. See the +[checks and patch inventory](ethers-v6-compatibility.md). + +ECDSA pins the existing Beacon dependency to `2.1.0-dev.18`. Until coordinated +publication supplies an ethers v6 Beacon package, ECDSA's source checkout uses +its sibling or refreshed bundled deployment scripts and tasks. Packed ECDSA +exports carry the executable bundle too. The explicit +`RANDOM_BEACON_EXPORT_PATH` override allows actual tarball checks without those +fallbacks. The pin is a reproducibility measure, not a claim that the old npm +scripts gained ethers v6 compatibility. + +## Remaining gates + +| Gate | Required work | +| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Release contract | Agree new major versions/channels and the maintenance period for old consumers. Publish upstream contracts, Beacon, ECDSA, then tbtc-v2. Update ECDSA to the newly published Beacon version before releasing executable ethers v6 exports. | +| Hardhat 3 test runtime | Move to compatible Hardhat 3 ethers/Mocha/Chai plugins after this ethers v6 preparation. Inventory each remaining plugin, task and configuration hook. | +| Shared helpers | Port or replace the used Hardhat 2 helper APIs. Version 0.7.2 is an ethers v6 preparation path, not a Hardhat 3 implementation. Move temporary patches upstream or explicitly carry them in each consumer. | +| Producer scripts | Convert the Threshold, Beacon and ECDSA deployment scripts to the agreed ESM/Rocketh API. Convert fixture loading, named-account resolution, tags and dependency ordering together. | +| Data exports | Provide a deliberately compatible legacy exporter. Compare actual production-contract output, receipts, start blocks, ABIs, libraries, initialization and artifacts; native Rocketh JSON is a different schema. | +| Proxies and upgrades | Preserve storage validation, manifests, existing-proxy import, shared-admin ownership and upgrade authorization. Account explicitly for the disabled deputy-admin script and manual V2 upgrade path. | +| Consumers | Run real packed producers in ECDSA and tbtc-v2 with sibling/bundled fallbacks disabled. Run both full suites and fresh integrated deployments. Test the old release line until the last consumer migrates. | + +The package versions inspected for the feasibility work were +[hardhat-deploy 2.0.26](https://registry.npmjs.org/hardhat-deploy/2.0.26), +[Rocketh node 0.21.0](https://registry.npmjs.org/@rocketh%2fnode/0.21.0), and +[OpenZeppelin Hardhat Upgrades 4.1.0](https://registry.npmjs.org/@openzeppelin%2fhardhat-upgrades/4.1.0). +The published deploy-v2 CommonJS entry throws a migration error; it is not a +working v1 adapter. Rocketh node supports multiple script directories, giving a +mechanism for external producer discovery. OpenZeppelin supplies a Hardhat 3 +plugin, so plugin absence is no longer a blocker; compatibility with this +repository's complete proxy workflow still needs proof. + +The isolated feasibility experiment validates a representative packed producer, +legacy exporter and explicit OpenZeppelin v4 proxy/admin flow. That evidence +supports proceeding with staged implementation; it does not establish the full +cross-repository release gate. Coordinate proxy defaults with +[tbtc-v2 #1130](https://github.com/threshold-network/tbtc-v2/issues/1130) and the +client-library direction with +[tbtc-v2 #1128](https://github.com/threshold-network/tbtc-v2/issues/1128). + +Keep #4209, #4213 and #4295 open until their respective migrations are complete. diff --git a/solidity/ecdsa/.dockerignore b/solidity/ecdsa/.dockerignore index 17165d83c9..1e58a46276 100644 --- a/solidity/ecdsa/.dockerignore +++ b/solidity/ecdsa/.dockerignore @@ -2,6 +2,12 @@ .* !.yarnrc.yml +# Include local dependency patches, but exclude Yarn caches and install state. +!.yarn +.yarn/** +!.yarn/patches +!.yarn/patches/** + # Documentation docs/ diff --git a/solidity/ecdsa/.eslintignore b/solidity/ecdsa/.eslintignore deleted file mode 100644 index a3a7d575dc..0000000000 --- a/solidity/ecdsa/.eslintignore +++ /dev/null @@ -1,9 +0,0 @@ -artifacts/ -build/ -cache/ -deployments/ -export/ -external/ -hardhat-dependency-compiler/ -typechain/ -export.json diff --git a/solidity/ecdsa/.eslintrc b/solidity/ecdsa/.eslintrc deleted file mode 100644 index df96de4050..0000000000 --- a/solidity/ecdsa/.eslintrc +++ /dev/null @@ -1,34 +0,0 @@ -{ - "root": true, - "extends": ["@thesis-co"], - "rules": { - "import/no-extraneous-dependencies": [ - "error", - { - "devDependencies": [ - "./test/**/*.ts", - "./tasks/**/*.ts", - "hardhat.config.ts" - ] - } - ], - "@typescript-eslint/no-use-before-define": "off", - "no-plusplus": ["error", { "allowForLoopAfterthoughts": true }], - "@typescript-eslint/consistent-type-imports": "warn", - "import/order": [ - "warn", - { - "groups": ["builtin", "external", "parent", "sibling", "index", "type"], - "newlines-between": "always" - } - ] - }, - "overrides": [ - { - "files": ["./deploy/**"], - "rules": { - "no-console": "off" - } - } - ] -} diff --git a/solidity/ecdsa/.gitattributes b/solidity/ecdsa/.gitattributes new file mode 100644 index 0000000000..5329fb1bc8 --- /dev/null +++ b/solidity/ecdsa/.gitattributes @@ -0,0 +1,4 @@ +external/random-beacon-export/artifacts/** linguist-generated=true +tasks/legacy-random-beacon/** linguist-generated=true +# Preserve the upstream generated task's bytes, including its trailing space. +tasks/legacy-random-beacon/initialize.js whitespace=-blank-at-eol diff --git a/solidity/ecdsa/.gitignore b/solidity/ecdsa/.gitignore index 0706648c4b..a4dd8097f0 100644 --- a/solidity/ecdsa/.gitignore +++ b/solidity/ecdsa/.gitignore @@ -6,9 +6,12 @@ external/npm hardhat-dependency-compiler/ export.json gasReporterOutput.json +.yarn/install-state.gz # Contract artifacts artifacts/ +!external/random-beacon-export/artifacts/ +!external/random-beacon-export/artifacts/** deployments/* !deployments/mainnet !deployments/sepolia @@ -16,6 +19,11 @@ deployments/* # OpenZeppelin .openzeppelin/unknown-*.json +# Yarn Berry runtime state +.yarn/install-state.gz +.yarn/cache/ +.yarn/build-state.yml + # Environment variables (NEVER commit private keys!) .env .env.local @@ -25,3 +33,6 @@ deployments/* # Migration results (may contain sensitive info) migration-results.json + +# Yarn +.yarn/install-state.gz diff --git a/solidity/ecdsa/.nvmrc b/solidity/ecdsa/.nvmrc index a77793ecc5..9e2934aa34 100644 --- a/solidity/ecdsa/.nvmrc +++ b/solidity/ecdsa/.nvmrc @@ -1 +1 @@ -lts/hydrogen +24.11.1 diff --git a/solidity/ecdsa/.prettierignore b/solidity/ecdsa/.prettierignore index 346b0af6db..ad10ee7a10 100644 --- a/solidity/ecdsa/.prettierignore +++ b/solidity/ecdsa/.prettierignore @@ -9,3 +9,6 @@ typechain/ docgen-templates/ export.json gasReporterOutput.json +contracts/legacy/ +tasks/legacy-random-beacon/ +.hardhat/ diff --git a/solidity/ecdsa/.prettierrc.js b/solidity/ecdsa/.prettierrc.js index 49faa7bb98..d2d19766cd 100644 --- a/solidity/ecdsa/.prettierrc.js +++ b/solidity/ecdsa/.prettierrc.js @@ -1,5 +1,7 @@ module.exports = { - ...require("@thesis-co/prettier-config"), + semi: false, + trailingComma: "all", + plugins: ["prettier-plugin-solidity", "prettier-plugin-sh"], overrides: [ { files: "*.sol", diff --git a/solidity/ecdsa/.solhint.json b/solidity/ecdsa/.solhint.json index 0343773c2d..4b1a7f9a59 100644 --- a/solidity/ecdsa/.solhint.json +++ b/solidity/ecdsa/.solhint.json @@ -1,8 +1,42 @@ { - "extends": "keep", "plugins": [], "rules": { - "func-visibility": ["error", { "ignoreConstructors": true }], - "no-inline-assembly": "off" + "max-states-count": ["warn", 15], + "no-unused-vars": "error", + "payable-fallback": "warn", + "reason-string": [ + "error", + { + "maxLength": 250 + } + ], + "constructor-syntax": "error", + "quotes": ["error", "double"], + "event-name-capwords": "warn", + "func-name-mixedcase": "warn", + "use-forbidden-name": "error", + "imports-on-top": "error", + "ordering": "warn", + "visibility-modifier-order": "error", + "avoid-call-value": "error", + "avoid-low-level-calls": "error", + "avoid-sha3": "error", + "avoid-suicide": "error", + "avoid-throw": "error", + "avoid-tx-origin": "error", + "check-send-result": "error", + "func-visibility": [ + "error", + { + "ignoreConstructors": true + } + ], + "multiple-sends": "error", + "no-complex-fallback": "error", + "no-inline-assembly": "off", + "not-rely-on-block-hash": "error", + "not-rely-on-time": "error", + "reentrancy": "error", + "state-visibility": "error" } } diff --git a/solidity/ecdsa/.solhintignore b/solidity/ecdsa/.solhintignore index ef4020b604..17b3430392 100644 --- a/solidity/ecdsa/.solhintignore +++ b/solidity/ecdsa/.solhintignore @@ -1,2 +1,3 @@ hardhat-dependency-compiler/ node_modules/ +contracts/legacy/ diff --git a/solidity/ecdsa/.tsconfig-eslint.json b/solidity/ecdsa/.tsconfig-eslint.json deleted file mode 120000 index a46cad2975..0000000000 --- a/solidity/ecdsa/.tsconfig-eslint.json +++ /dev/null @@ -1 +0,0 @@ -./node_modules/@thesis-co/eslint-config/.tsconfig-eslint.json \ No newline at end of file diff --git a/solidity/ecdsa/.tsconfig-eslint.json b/solidity/ecdsa/.tsconfig-eslint.json new file mode 100644 index 0000000000..960aa2533d --- /dev/null +++ b/solidity/ecdsa/.tsconfig-eslint.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "include": ["**/*.ts"], + "exclude": [ + "node_modules", + "build", + "cache", + "export", + "external", + "typechain" + ] +} diff --git a/solidity/ecdsa/.yarn/patches/@keep-network-hardhat-helpers-npm-0.7.2-086cf3da54.patch b/solidity/ecdsa/.yarn/patches/@keep-network-hardhat-helpers-npm-0.7.2-086cf3da54.patch new file mode 100644 index 0000000000..3acb0a3521 --- /dev/null +++ b/solidity/ecdsa/.yarn/patches/@keep-network-hardhat-helpers-npm-0.7.2-086cf3da54.patch @@ -0,0 +1,520 @@ +diff --git a/dist/contracts.d.ts b/dist/contracts.d.ts +index e67607c..de33123 100644 +--- a/dist/contracts.d.ts ++++ b/dist/contracts.d.ts +@@ -1,7 +1,7 @@ +-import type { Contract } from "ethers"; ++import type { BaseContract, Contract } from "ethers"; + import type { HardhatRuntimeEnvironment } from "hardhat/types"; + export interface HardhatContractsHelpers { +- getContract(deploymentName: string): Promise; ++ getContract(deploymentName: string): Promise; + } + export default function (hre: HardhatRuntimeEnvironment): HardhatContractsHelpers; + //# sourceMappingURL=contracts.d.ts.map +\ No newline at end of file +diff --git a/dist/upgrades.d.ts b/dist/upgrades.d.ts +index 2eb5874..a07f2ae 100644 +--- a/dist/upgrades.d.ts ++++ b/dist/upgrades.d.ts +@@ -1,24 +1,24 @@ + import "@openzeppelin/hardhat-upgrades"; +-import type { Contract, ContractTransaction } from "ethers"; ++import type { BaseContract, Contract, ContractTransaction } from "ethers"; + import type { FactoryOptions, HardhatRuntimeEnvironment } from "hardhat/types"; + import type { Deployment } from "hardhat-deploy/dist/types"; + import type { DeployProxyOptions, UpgradeProxyOptions } from "@openzeppelin/hardhat-upgrades/src/utils/options"; + import { Libraries } from "hardhat-deploy/types"; + export interface HardhatUpgradesHelpers { +- deployProxy(name: string, opts?: UpgradesDeployOptions): Promise<[T, Deployment]>; +- upgradeProxy(currentContractName: string, newContractName: string, opts?: UpgradesUpgradeOptions): Promise<[T, Deployment]>; ++ deployProxy(name: string, opts?: UpgradesDeployOptions): Promise<[T, Deployment]>; ++ upgradeProxy(currentContractName: string, newContractName: string, opts?: UpgradesUpgradeOptions): Promise<[T, Deployment]>; + prepareProxyUpgrade(proxyDeploymentName: string, newContractName: string, opts?: UpgradesPrepareProxyUpgradeOptions): Promise<{ + newImplementationAddress: string; + preparedTransaction: ContractTransaction; + }>; + } + type CustomFactoryOptions = FactoryOptions & { + libraries?: Libraries; + }; + export interface UpgradesDeployOptions { + contractName?: string; + initializerArgs?: unknown[]; + factoryOpts?: CustomFactoryOptions; + proxyOpts?: DeployProxyOptions; + } + export interface UpgradesUpgradeOptions { +@@ -27,19 +27,19 @@ export interface UpgradesUpgradeOptions { + factoryOpts?: CustomFactoryOptions; + proxyOpts?: UpgradeProxyOptions; + } + export interface UpgradesPrepareProxyUpgradeOptions { + contractName?: string; + factoryOpts?: CustomFactoryOptions; + callData?: string; + } + /** + * Deploys contract as a TransparentProxy. + * + * @param {HardhatRuntimeEnvironment} hre Hardhat runtime environment. + * @param {string} name Contract Name + * @param {UpgradesDeployOptions} opts + */ +-export declare function deployProxy(hre: HardhatRuntimeEnvironment, name: string, opts?: UpgradesDeployOptions): Promise<[T, Deployment]>; ++export declare function deployProxy(hre: HardhatRuntimeEnvironment, name: string, opts?: UpgradesDeployOptions): Promise<[T, Deployment]>; + export default function (hre: HardhatRuntimeEnvironment): HardhatUpgradesHelpers; + export {}; + //# sourceMappingURL=upgrades.d.ts.map +\ No newline at end of file +diff --git a/dist/upgrades.js b/dist/upgrades.js +index 6367def..cfb0e32 100644 +--- a/dist/upgrades.js ++++ b/dist/upgrades.js +@@ -1,54 +1,85 @@ + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.deployProxy = void 0; + require("@openzeppelin/hardhat-upgrades"); +-const utils_1 = require("@openzeppelin/hardhat-upgrades/dist/utils"); ++const ProxyAdminV4 = require("@openzeppelin/upgrades-core/artifacts/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json"); ++const ProxyAdminV5 = require("@openzeppelin/upgrades-core/artifacts/@openzeppelin/contracts-v5/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json"); + const upgrades_core_1 = require("@openzeppelin/upgrades-core"); + /** + * Deploys contract as a TransparentProxy. + * + * @param {HardhatRuntimeEnvironment} hre Hardhat runtime environment. + * @param {string} name Contract Name + * @param {UpgradesDeployOptions} opts + */ ++// Preserve the receipt metadata published by hardhat-helpers 0.6. ++function toDeploymentReceipt(receipt) { ++ return { ++ to: receipt.to, ++ from: receipt.from, ++ contractAddress: receipt.contractAddress, ++ transactionIndex: receipt.index, ++ gasUsed: receipt.gasUsed.toString(), ++ logsBloom: receipt.logsBloom, ++ blockHash: receipt.blockHash, ++ transactionHash: receipt.hash, ++ logs: receipt.logs.map((log) => ({ ++ transactionIndex: log.transactionIndex, ++ blockNumber: log.blockNumber, ++ transactionHash: log.transactionHash, ++ address: log.address, ++ topics: [...log.topics], ++ data: log.data, ++ logIndex: log.index, ++ blockHash: log.blockHash, ++ // Mined receipt logs omit the removed field in the existing export format. ++ removed: undefined, ++ })), ++ blockNumber: receipt.blockNumber, ++ cumulativeGasUsed: receipt.cumulativeGasUsed.toString(), ++ status: receipt.status, ++ byzantium: receipt.status !== null, ++ } ++} + async function deployProxy(hre, name, opts) { + const { ethers, upgrades, deployments, artifacts } = hre; + const { log } = deployments; + const existingDeployment = await deployments.getOrNull(name); + if (existingDeployment) { + throw new Error(`${name} was already deployed at ${existingDeployment.address}`); + } + const contractFactory = await ethers.getContractFactory(opts?.contractName || name, opts?.factoryOpts); + const contractInstance = (await upgrades.deployProxy(contractFactory, opts?.initializerArgs, opts?.proxyOpts)); + const deploymentTransaction = contractInstance.deploymentTransaction(); + // Let the transaction propagate across the ethereum nodes. This is mostly to + // wait for all Alchemy nodes to catch up their state. + const transactionReceipt = await deploymentTransaction?.wait(1); + const contractAddress = await contractInstance.getAddress(); + const transactionHash = deploymentTransaction?.hash; + log(`Deployed ${name} as ${opts?.proxyOpts?.kind || "transparent"} proxy at ${contractAddress} (tx: ${transactionHash})`); + const artifact = artifacts.readArtifactSync(opts?.contractName || name); + const implementation = await upgrades.erc1967.getImplementationAddress(contractAddress); + if (!transactionReceipt || !transactionHash) { + throw new Error(`Could not find transaction receipt for transaction hash: ${transactionHash}`); + } + const deployment = { + address: contractAddress, + abi: artifact.abi, + transactionHash: transactionHash, + implementation: implementation, ++ receipt: toDeploymentReceipt(transactionReceipt), + libraries: opts?.factoryOpts?.libraries, + devdoc: "Contract deployed as upgradable proxy", + args: opts?.proxyOpts?.constructorArgs, + }; + await deployments.save(name, deployment); + return [contractInstance, deployment]; + } + exports.deployProxy = deployProxy; + /** + * Upgrades previously deployed contract. + * + * @param {HardhatRuntimeEnvironment} hre Hardhat runtime environment. + * @param {string} proxyDeploymentName Name of the proxy deployment that will be + * upgraded. + * @param {string} newContractName Name of the new implementation contract. +@@ -72,30 +103,31 @@ async function upgradeProxy(hre, proxyDeploymentName, newContractName, opts) { + const contractAddress = await newContractInstance.getAddress(); + const transactionHash = deploymentTransaction?.hash; + log(`Upgraded ${proxyDeploymentName} proxy contract (address: ${proxyDeployment.address}) ` + + `in tx: ${transactionHash}`); + const artifact = artifacts.readArtifactSync(opts?.contractName || newContractName); + const implementation = await upgrades.erc1967.getImplementationAddress(contractAddress); + log(`New ${proxyDeploymentName} proxy contract implementation address is: ${implementation}`); + if (!transactionReceipt || !transactionHash) { + throw new Error(`Could not find transaction receipt for transaction hash: ${transactionHash}`); + } + const deployment = { + address: contractAddress, + abi: artifact.abi, + transactionHash: transactionHash, + implementation: implementation, ++ receipt: toDeploymentReceipt(transactionReceipt), + libraries: opts?.factoryOpts?.libraries, + devdoc: "Contract deployed as upgradable proxy", + args: opts?.proxyOpts?.constructorArgs, + }; + await deployments.save(proxyDeploymentName, deployment); + return [newContractInstance, deployment]; + } + /** + * Prepare upgrade of deployed contract. + * It deploys new implementation contract and prepares transaction to upgrade + * the proxy contract to the new implementation thorough a Proxy Admin instance. + * The transaction has to be executed by the owner of the Proxy Admin. + * + * @param {HardhatRuntimeEnvironment} hre Hardhat runtime environment. + * @param {string} proxyDeploymentName Name of the proxy deployment that will be +@@ -108,40 +140,40 @@ async function prepareProxyUpgrade(hre, proxyDeploymentName, newContractName, op + const signer = await ethers.provider.getSigner(); + const { log } = deployments; + const proxyDeployment = await deployments.get(proxyDeploymentName); + const implementationContractFactory = await ethers.getContractFactory(opts?.contractName || newContractName, opts?.factoryOpts); + const newImplementationAddress = (await upgrades.prepareUpgrade(proxyDeployment.address, implementationContractFactory, { + kind: "transparent", + getTxResponse: false, + })); + log(`new implementation contract deployed at: ${newImplementationAddress}`); + const proxyAdminAddress = await hre.upgrades.erc1967.getAdminAddress(proxyDeployment.address); + let proxyAdmin; + let upgradeTxData; + const proxyInterfaceVersion = await (0, upgrades_core_1.getUpgradeInterfaceVersion)(hre.network.provider, proxyAdminAddress); + switch (proxyInterfaceVersion) { + case "5.0.0": { +- proxyAdmin = await (0, utils_1.attachProxyAdminV5)(hre, proxyAdminAddress, signer); ++ proxyAdmin = await hre.ethers.getContractAt(ProxyAdminV5.abi, proxyAdminAddress, signer); + upgradeTxData = proxyAdmin.interface.encodeFunctionData("upgradeAndCall", [ + proxyDeployment.address, + newImplementationAddress, + opts?.callData ?? "0x", + ]); + break; + } + default: { +- proxyAdmin = await (0, utils_1.attachProxyAdminV4)(hre, proxyAdminAddress, signer); ++ proxyAdmin = await hre.ethers.getContractAt(ProxyAdminV4.abi, proxyAdminAddress, signer); + if (opts?.callData) { + upgradeTxData = proxyAdmin.interface.encodeFunctionData("upgradeAndCall", [proxyDeployment.address, newImplementationAddress, opts?.callData]); + } + else { + upgradeTxData = proxyAdmin.interface.encodeFunctionData("upgrade", [ + proxyDeployment.address, + newImplementationAddress, + ]); + } + } + } + const preparedTransaction = { + from: (await proxyAdmin.owner()), + to: proxyAdminAddress, + data: upgradeTxData, +diff --git a/src/contracts.ts b/src/contracts.ts +index dc82311..b8f4d3a 100644 +--- a/src/contracts.ts ++++ b/src/contracts.ts +@@ -1,23 +1,23 @@ +-import type { Contract } from "ethers" ++import type { BaseContract, Contract } from "ethers" + import type { HardhatRuntimeEnvironment } from "hardhat/types" + + export interface HardhatContractsHelpers { +- getContract(deploymentName: string): Promise ++ getContract(deploymentName: string): Promise + } + +-async function getContract( ++async function getContract( + hre: HardhatRuntimeEnvironment, + deploymentName: string + ): Promise { + const deployment = await hre.deployments.get(deploymentName) + + return (await hre.ethers.getContractAt( + deployment.abi, + deployment.address + )) as T + } + + export default function ( + hre: HardhatRuntimeEnvironment + ): HardhatContractsHelpers { + return { +diff --git a/src/upgrades.ts b/src/upgrades.ts +index 22edb53..c7abdf3 100644 +--- a/src/upgrades.ts ++++ b/src/upgrades.ts +@@ -1,47 +1,77 @@ + import "@openzeppelin/hardhat-upgrades" + + import type { ++ BaseContract, + Contract, + ContractFactory, + ContractTransaction, + ContractTransactionResponse, ++ TransactionReceipt, + } from "ethers" + import type { + Artifact, + FactoryOptions, + HardhatRuntimeEnvironment, + } from "hardhat/types" +-import type { Deployment } from "hardhat-deploy/dist/types" ++import type { Deployment, Receipt } from "hardhat-deploy/dist/types" + import type { + DeployProxyOptions, + UpgradeProxyOptions, + } from "@openzeppelin/hardhat-upgrades/src/utils/options" + import { Libraries } from "hardhat-deploy/types" +-import { +- attachProxyAdminV4, +- attachProxyAdminV5, +-} from "@openzeppelin/hardhat-upgrades/dist/utils" ++import ProxyAdminV4 from "@openzeppelin/upgrades-core/artifacts/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json" ++import ProxyAdminV5 from "@openzeppelin/upgrades-core/artifacts/@openzeppelin/contracts-v5/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json" + + import { getUpgradeInterfaceVersion } from "@openzeppelin/upgrades-core" + ++// Preserve the receipt metadata published by hardhat-helpers 0.6. ++function toDeploymentReceipt(receipt: TransactionReceipt): Receipt { ++ return { ++ to: receipt.to, ++ from: receipt.from, ++ contractAddress: receipt.contractAddress, ++ transactionIndex: receipt.index, ++ gasUsed: receipt.gasUsed.toString(), ++ logsBloom: receipt.logsBloom, ++ blockHash: receipt.blockHash, ++ transactionHash: receipt.hash, ++ logs: receipt.logs.map((log) => ({ ++ transactionIndex: log.transactionIndex, ++ blockNumber: log.blockNumber, ++ transactionHash: log.transactionHash, ++ address: log.address, ++ topics: [...log.topics], ++ data: log.data, ++ logIndex: log.index, ++ blockHash: log.blockHash, ++ // Mined receipt logs omit the removed field in the existing export format. ++ removed: undefined, ++ })), ++ blockNumber: receipt.blockNumber, ++ cumulativeGasUsed: receipt.cumulativeGasUsed.toString(), ++ status: receipt.status, ++ byzantium: receipt.status !== null, ++ } ++} ++ + export interface HardhatUpgradesHelpers { +- deployProxy( ++ deployProxy( + name: string, + opts?: UpgradesDeployOptions + ): Promise<[T, Deployment]> +- upgradeProxy( ++ upgradeProxy( + currentContractName: string, + newContractName: string, + opts?: UpgradesUpgradeOptions + ): Promise<[T, Deployment]> + prepareProxyUpgrade( + proxyDeploymentName: string, + newContractName: string, + opts?: UpgradesPrepareProxyUpgradeOptions + ): Promise<{ + newImplementationAddress: string + preparedTransaction: ContractTransaction + }> + } + + type CustomFactoryOptions = FactoryOptions & { +@@ -63,31 +93,31 @@ export interface UpgradesUpgradeOptions { + } + + export interface UpgradesPrepareProxyUpgradeOptions { + contractName?: string + factoryOpts?: CustomFactoryOptions + callData?: string + } + + /** + * Deploys contract as a TransparentProxy. + * + * @param {HardhatRuntimeEnvironment} hre Hardhat runtime environment. + * @param {string} name Contract Name + * @param {UpgradesDeployOptions} opts + */ +-export async function deployProxy( ++export async function deployProxy( + hre: HardhatRuntimeEnvironment, + name: string, + opts?: UpgradesDeployOptions + ): Promise<[T, Deployment]> { + const { ethers, upgrades, deployments, artifacts } = hre + const { log } = deployments + + const existingDeployment = await deployments.getOrNull(name) + if (existingDeployment) { + throw new Error( + `${name} was already deployed at ${existingDeployment.address}` + ) + } + + const contractFactory: ContractFactory = await ethers.getContractFactory( +@@ -121,50 +151,51 @@ export async function deployProxy( + const implementation = await upgrades.erc1967.getImplementationAddress( + contractAddress + ) + + if (!transactionReceipt || !transactionHash) { + throw new Error( + `Could not find transaction receipt for transaction hash: ${transactionHash}` + ) + } + + const deployment: Deployment = { + address: contractAddress, + abi: artifact.abi, + transactionHash: transactionHash, + implementation: implementation, ++ receipt: toDeploymentReceipt(transactionReceipt), + libraries: opts?.factoryOpts?.libraries, + devdoc: "Contract deployed as upgradable proxy", + args: opts?.proxyOpts?.constructorArgs, + } + + await deployments.save(name, deployment) + + return [contractInstance, deployment] + } + + /** + * Upgrades previously deployed contract. + * + * @param {HardhatRuntimeEnvironment} hre Hardhat runtime environment. + * @param {string} proxyDeploymentName Name of the proxy deployment that will be + * upgraded. + * @param {string} newContractName Name of the new implementation contract. + * @param {UpgradesDeployOptions} opts + */ +-async function upgradeProxy( ++async function upgradeProxy( + hre: HardhatRuntimeEnvironment, + proxyDeploymentName: string, + newContractName: string, + opts?: UpgradesUpgradeOptions + ): Promise<[T, Deployment]> { + const { ethers, upgrades, deployments, artifacts } = hre + const { log } = deployments + + const proxyDeployment: Deployment = await deployments.get(proxyDeploymentName) + + const newContract: ContractFactory = await ethers.getContractFactory( + opts?.contractName || newContractName, + opts?.factoryOpts + ) + +@@ -205,30 +236,31 @@ async function upgradeProxy( + log( + `New ${proxyDeploymentName} proxy contract implementation address is: ${implementation}` + ) + + if (!transactionReceipt || !transactionHash) { + throw new Error( + `Could not find transaction receipt for transaction hash: ${transactionHash}` + ) + } + + const deployment: Deployment = { + address: contractAddress, + abi: artifact.abi, + transactionHash: transactionHash, + implementation: implementation, ++ receipt: toDeploymentReceipt(transactionReceipt), + libraries: opts?.factoryOpts?.libraries, + devdoc: "Contract deployed as upgradable proxy", + args: opts?.proxyOpts?.constructorArgs, + } + + await deployments.save(proxyDeploymentName, deployment) + + return [newContractInstance, deployment] + } + + /** + * Prepare upgrade of deployed contract. + * It deploys new implementation contract and prepares transaction to upgrade + * the proxy contract to the new implementation thorough a Proxy Admin instance. + * The transaction has to be executed by the owner of the Proxy Admin. +@@ -273,44 +305,44 @@ async function prepareProxyUpgrade( + + const proxyAdminAddress = await hre.upgrades.erc1967.getAdminAddress( + proxyDeployment.address + ) + + let proxyAdmin: Contract + let upgradeTxData: string + + const proxyInterfaceVersion = await getUpgradeInterfaceVersion( + hre.network.provider, + proxyAdminAddress + ) + + switch (proxyInterfaceVersion) { + case "5.0.0": { +- proxyAdmin = await attachProxyAdminV5(hre, proxyAdminAddress, signer) ++ proxyAdmin = await hre.ethers.getContractAt(ProxyAdminV5.abi, proxyAdminAddress, signer) + + upgradeTxData = proxyAdmin.interface.encodeFunctionData( + "upgradeAndCall", + [ + proxyDeployment.address, + newImplementationAddress, + opts?.callData ?? "0x", + ] + ) + break + } + default: { +- proxyAdmin = await attachProxyAdminV4(hre, proxyAdminAddress, signer) ++ proxyAdmin = await hre.ethers.getContractAt(ProxyAdminV4.abi, proxyAdminAddress, signer) + + if (opts?.callData) { + upgradeTxData = proxyAdmin.interface.encodeFunctionData( + "upgradeAndCall", + [proxyDeployment.address, newImplementationAddress, opts?.callData] + ) + } else { + upgradeTxData = proxyAdmin.interface.encodeFunctionData("upgrade", [ + proxyDeployment.address, + newImplementationAddress, + ]) + } + } + } + diff --git a/solidity/ecdsa/.yarn/patches/@openzeppelin-hardhat-upgrades-npm-2.5.1-etherscan-v2.patch b/solidity/ecdsa/.yarn/patches/@openzeppelin-hardhat-upgrades-npm-2.5.1-etherscan-v2.patch new file mode 100644 index 0000000000..06d2c0a560 --- /dev/null +++ b/solidity/ecdsa/.yarn/patches/@openzeppelin-hardhat-upgrades-npm-2.5.1-etherscan-v2.patch @@ -0,0 +1,85 @@ +diff --git a/src/utils/etherscan-api.ts b/src/utils/etherscan-api.ts +--- a/src/utils/etherscan-api.ts ++++ b/src/utils/etherscan-api.ts +@@ -2,36 +2,39 @@ + import { HardhatRuntimeEnvironment } from 'hardhat/types'; + + import { request } from 'undici'; + + import debug from './debug'; + import { Etherscan } from '@nomicfoundation/hardhat-verify/etherscan'; + + /** + * Call the configured Etherscan API with the given parameters. + * + * @param etherscan Etherscan instance + * @param params The API parameters to call with + * @returns The Etherscan API response + */ + export async function callEtherscanApi(etherscan: Etherscan, params: any): Promise { + const parameters = new URLSearchParams({ ...params, apikey: etherscan.apiKey }); ++ if (etherscan.chainId !== undefined) { ++ parameters.set('chainid', etherscan.chainId); ++ } + + const response = await request(etherscan.apiUrl, { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: parameters.toString(), + }); + + if (!(response.statusCode >= 200 && response.statusCode <= 299)) { + const responseBodyText = await response.body.text(); + throw new UpgradesError( + `Etherscan API call failed with status ${response.statusCode}, response: ${responseBodyText}`, + ); + } + + const responseBodyJson = await response.body.json(); + debug('Etherscan response', JSON.stringify(responseBodyJson)); + + return responseBodyJson; + } + +diff --git a/dist/utils/etherscan-api.js b/dist/utils/etherscan-api.js +--- a/dist/utils/etherscan-api.js ++++ b/dist/utils/etherscan-api.js +@@ -4,35 +4,38 @@ + }; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.verifyAndGetStatus = exports.RESPONSE_OK = exports.getEtherscanInstance = exports.callEtherscanApi = void 0; + const upgrades_core_1 = require("@openzeppelin/upgrades-core"); + const undici_1 = require("undici"); + const debug_1 = __importDefault(require("./debug")); + const etherscan_1 = require("@nomicfoundation/hardhat-verify/etherscan"); + /** + * Call the configured Etherscan API with the given parameters. + * + * @param etherscan Etherscan instance + * @param params The API parameters to call with + * @returns The Etherscan API response + */ + async function callEtherscanApi(etherscan, params) { + const parameters = new URLSearchParams({ ...params, apikey: etherscan.apiKey }); ++ if (etherscan.chainId !== undefined) { ++ parameters.set('chainid', etherscan.chainId); ++ } + const response = await (0, undici_1.request)(etherscan.apiUrl, { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: parameters.toString(), + }); + if (!(response.statusCode >= 200 && response.statusCode <= 299)) { + const responseBodyText = await response.body.text(); + throw new upgrades_core_1.UpgradesError(`Etherscan API call failed with status ${response.statusCode}, response: ${responseBodyText}`); + } + const responseBodyJson = await response.body.json(); + (0, debug_1.default)('Etherscan response', JSON.stringify(responseBodyJson)); + return responseBodyJson; + } + exports.callEtherscanApi = callEtherscanApi; + /** + * Gets an Etherscan instance based on Hardhat config. + * Throws an error if Etherscan API key is not present in config. + */ + async function getEtherscanInstance(hre) { diff --git a/solidity/ecdsa/.yarn/patches/@threshold-network-solidity-contracts-npm-1.3.0-dev.14-ethers-v6.patch b/solidity/ecdsa/.yarn/patches/@threshold-network-solidity-contracts-npm-1.3.0-dev.14-ethers-v6.patch new file mode 100644 index 0000000000..3e3b7c21ed --- /dev/null +++ b/solidity/ecdsa/.yarn/patches/@threshold-network-solidity-contracts-npm-1.3.0-dev.14-ethers-v6.patch @@ -0,0 +1,28 @@ +diff --git a/export/deploy/07_deploy_token_staking.js b/export/deploy/07_deploy_token_staking.js +--- a/export/deploy/07_deploy_token_staking.js ++++ b/export/deploy/07_deploy_token_staking.js +@@ -62,10 +62,10 @@ + })]; + case 4: + tokenStaking = _a.sent(); +- tokenStakingAddress = tokenStaking.address; ++ tokenStakingAddress = tokenStaking.target; + log("Deployed TokenStaking with TransparentProxy at ".concat(tokenStakingAddress)); + implementationInterface = tokenStaking.interface; +- jsonAbi = implementationInterface.format(hardhat_1.ethers.utils.FormatTypes.json); ++ jsonAbi = implementationInterface.formatJson(); + tokenStakingDeployment = { + address: tokenStakingAddress, + abi: JSON.parse(jsonAbi), +diff --git a/export/deploy/30_deploy_tokenholder_timelock.js b/export/deploy/30_deploy_tokenholder_timelock.js +--- a/export/deploy/30_deploy_tokenholder_timelock.js ++++ b/export/deploy/30_deploy_tokenholder_timelock.js +@@ -51,7 +51,7 @@ + case 1: + deployer = (_a.sent()).deployer; + proposers = []; +- executors = [ethers_1.ethers.constants.AddressZero]; ++ executors = [ethers_1.ethers.ZeroAddress]; + minDelay = 172800 // 2 days in seconds (2 * 24 * 60 * 60) + ; + return [4 /*yield*/, deployments.deploy("TokenholderTimelock", { diff --git a/solidity/ecdsa/.yarn/patches/@typechain-ethers-v6-npm-0.5.1-e825560376.patch b/solidity/ecdsa/.yarn/patches/@typechain-ethers-v6-npm-0.5.1-e825560376.patch new file mode 100644 index 0000000000..85cccd3381 --- /dev/null +++ b/solidity/ecdsa/.yarn/patches/@typechain-ethers-v6-npm-0.5.1-e825560376.patch @@ -0,0 +1,13 @@ +diff --git a/dist/codegen/reserved-keywords.js b/dist/codegen/reserved-keywords.js +index f5a47b105a31e5ae3a6e40da476a37f748d962d9..f05f5ec9582c56a264fe6a61f7a098e2008047a3 100644 +--- a/dist/codegen/reserved-keywords.js ++++ b/dist/codegen/reserved-keywords.js +@@ -1,7 +1,7 @@ + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.reservedKeywordsLabels = exports.reservedKeywords = void 0; +-exports.reservedKeywords = new Set(['signer', 'provider', 'deployTransaction', 'deployed', 'fallback', 'connect']); ++exports.reservedKeywords = new Set(['signer', 'provider', 'deployTransaction', 'deployed', 'fallback', 'connect', 'target']); + exports.reservedKeywordsLabels = new Set([ + 'class', + 'function', diff --git a/solidity/ecdsa/Dockerfile b/solidity/ecdsa/Dockerfile index 3c16d830b8..2e55e8d2ca 100644 --- a/solidity/ecdsa/Dockerfile +++ b/solidity/ecdsa/Dockerfile @@ -1,4 +1,4 @@ -FROM node:22.23.1-alpine +FROM node:24.11.1-alpine RUN apk add --update --no-cache \ git \ @@ -8,16 +8,32 @@ RUN apk add --update --no-cache \ rm -rf /usr/share/man ENV WORK_DIR=/ecdsa +ENV HOME=/home/node +ENV COREPACK_DEFAULT_TO_LATEST=0 -RUN mkdir -p $WORK_DIR +# `corepack enable` must run as root: it writes shims into root-owned +# /usr/local/bin. `corepack prepare` (below, after `USER node`) must run as +# node: it writes Corepack's per-user cache under $HOME. `chown` targets only +# $WORK_DIR here because `yarn install` creates node_modules inside it; +# dependency/source ownership is set later via `COPY --chown`. +# Native dependencies need a compiler while Yarn packs Git dependencies; the +# build tools are installed/removed as root since `apk` requires root. +RUN apk add --no-cache --virtual .build-deps python3 make g++ && \ + corepack enable && mkdir -p $WORK_DIR && chown node:node $WORK_DIR WORKDIR $WORK_DIR +USER node # Use `https://` instead of unauthenticated `git://` protocol. RUN git config --global url."https://".insteadOf git:// -COPY package*.json yarn.lock .yarnrc.yml ./ -RUN corepack enable && corepack prepare yarn@4.8.1 --activate && yarn install --immutable +COPY --chown=node:node package*.json yarn.lock .yarnrc.yml ./ +COPY --chown=node:node .yarn/patches/ ./.yarn/patches/ +RUN corepack prepare yarn@4.12.0 --activate && yarn install --immutable -COPY . ./ +USER root +RUN apk del .build-deps +USER node + +COPY --chown=node:node . ./ ENTRYPOINT ["npx", "hardhat"] diff --git a/solidity/ecdsa/README.adoc b/solidity/ecdsa/README.adoc index ef3d2f653b..f97da3e695 100644 --- a/solidity/ecdsa/README.adoc +++ b/solidity/ecdsa/README.adoc @@ -422,8 +422,8 @@ presented below. Please make sure you have the following prerequisites installed on your machine: -- https://nodejs.org[Node.js] >=14 -- https://yarnpkg.com[Yarn] >=1.22 +- https://nodejs.org[Node.js] >=24.0.0 +- https://yarnpkg.com[Yarn] >=4.12.0 (via Corepack) === Build contracts diff --git a/solidity/ecdsa/contracts/Allowlist.sol b/solidity/ecdsa/contracts/Allowlist.sol index a4fada0c79..f49394615a 100644 --- a/solidity/ecdsa/contracts/Allowlist.sol +++ b/solidity/ecdsa/contracts/Allowlist.sol @@ -84,10 +84,10 @@ contract Allowlist is Ownable2StepUpgradeable { /// a non-zero weight, the function reverts. /// @param stakingProvider The staking provider's address /// @param weight The weight of the new staking provider - function addStakingProvider(address stakingProvider, uint96 weight) - external - onlyOwner - { + function addStakingProvider( + address stakingProvider, + uint96 weight + ) external onlyOwner { if (stakingProvider == address(0)) { revert ZeroAddress(); } @@ -122,10 +122,10 @@ contract Allowlist is Ownable2StepUpgradeable { /// /// @param stakingProvider The staking provider's address /// @param newWeight The new requested weight of this staking provider - function requestWeightDecrease(address stakingProvider, uint96 newWeight) - external - onlyOwner - { + function requestWeightDecrease( + address stakingProvider, + uint96 newWeight + ) external onlyOwner { StakingProviderInfo storage info = stakingProviders[stakingProvider]; uint96 currentWeight = info.weight; @@ -152,10 +152,9 @@ contract Allowlist is Ownable2StepUpgradeable { /// requested weight decrease for the given staking provider. /// @param stakingProvider The staking provider's address /// @return The new weight of the staking provider - function approveAuthorizationDecrease(address stakingProvider) - external - returns (uint96) - { + function approveAuthorizationDecrease( + address stakingProvider + ) external returns (uint96) { if (msg.sender != address(walletRegistry)) { revert NotWalletRegistry(); } @@ -184,11 +183,10 @@ contract Allowlist is Ownable2StepUpgradeable { /// @dev The function signature maintains compatibility with Threshold /// TokenStaking contract to minimize the TIP-092 impact on the /// WalletRegistry contract. - function authorizedStake(address stakingProvider, address) - external - view - returns (uint96) - { + function authorizedStake( + address stakingProvider, + address + ) external view returns (uint96) { return stakingProviders[stakingProvider].weight; } @@ -214,7 +212,9 @@ contract Allowlist is Ownable2StepUpgradeable { /// @dev The function signature maintains compatibility with Threshold /// TokenStaking contract to minimize the TIP-092 impact on the /// WalletRegistry contract. - function rolesOf(address stakingProvider) + function rolesOf( + address stakingProvider + ) external view returns ( diff --git a/solidity/ecdsa/contracts/EcdsaDkgValidator.sol b/solidity/ecdsa/contracts/EcdsaDkgValidator.sol index fb02b3e28a..4007c84af0 100644 --- a/solidity/ecdsa/contracts/EcdsaDkgValidator.sol +++ b/solidity/ecdsa/contracts/EcdsaDkgValidator.sol @@ -23,8 +23,8 @@ pragma solidity 0.8.17; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; -import "@keep-network/random-beacon/contracts/libraries/BytesLib.sol"; -import "@keep-network/sortition-pools/contracts/SortitionPool.sol"; +import "./legacy/random-beacon/libraries/BytesLib.sol"; +import "./legacy/sortition/SortitionPool.sol"; import "./libraries/EcdsaDkg.sol"; /// @title DKG result validator @@ -107,11 +107,9 @@ contract EcdsaDkgValidator { /// ranges, and order of arrays. /// @return isValid true if the result is valid, false otherwise /// @return errorMsg validation error message; empty for a valid result - function validateFields(EcdsaDkg.Result calldata result) - public - pure - returns (bool isValid, string memory errorMsg) - { + function validateFields( + EcdsaDkg.Result calldata result + ) public pure returns (bool isValid, string memory errorMsg) { if (result.groupPubKey.length != publicKeyByteSize) { return (false, "Malformed group public key"); } @@ -128,7 +126,7 @@ contract EcdsaDkgValidator { if ( misbehavedMembersIndices[0] < 1 || misbehavedMembersIndices[misbehavedMembersIndices.length - 1] > - groupSize + groupSize ) { return (false, "Corrupted misbehaved members indices"); } @@ -186,11 +184,10 @@ contract EcdsaDkgValidator { /// result against group members selected by the sortition pool. /// @param seed seed used to start the DKG and select group members /// @return true if group members matches; false otherwise - function validateGroupMembers(EcdsaDkg.Result calldata result, uint256 seed) - public - view - returns (bool) - { + function validateGroupMembers( + EcdsaDkg.Result calldata result, + uint256 seed + ) public view returns (bool) { uint32[] calldata resultMembers = result.members; uint32[] memory actualGroupMembers = sortitionPool.selectGroup( groupSize, @@ -262,11 +259,9 @@ contract EcdsaDkgValidator { /// @param result DKG result /// @return true if calculated result's group members hash matches with the /// one that is challenged. - function validateMembersHash(EcdsaDkg.Result calldata result) - public - pure - returns (bool) - { + function validateMembersHash( + EcdsaDkg.Result calldata result + ) public pure returns (bool) { if (result.misbehavedMembersIndices.length > 0) { // members that generated a group signing key uint32[] memory groupMembers = new uint32[]( diff --git a/solidity/ecdsa/contracts/WalletRegistry.sol b/solidity/ecdsa/contracts/WalletRegistry.sol index 55fd9a8e26..a578be4e22 100644 --- a/solidity/ecdsa/contracts/WalletRegistry.sol +++ b/solidity/ecdsa/contracts/WalletRegistry.sol @@ -23,12 +23,12 @@ import {EcdsaDkg as DKG} from "./libraries/EcdsaDkg.sol"; import {EcdsaInactivity as Inactivity} from "./libraries/EcdsaInactivity.sol"; import {EcdsaDkgValidator as DKGValidator} from "./EcdsaDkgValidator.sol"; -import "@keep-network/sortition-pools/contracts/SortitionPool.sol"; -import "@keep-network/random-beacon/contracts/api/IRandomBeacon.sol"; -import "@keep-network/random-beacon/contracts/api/IRandomBeaconConsumer.sol"; -import "@keep-network/random-beacon/contracts/Reimbursable.sol"; -import "@keep-network/random-beacon/contracts/ReimbursementPool.sol"; -import "@keep-network/random-beacon/contracts/Governable.sol"; +import "./legacy/sortition/SortitionPool.sol"; +import "./legacy/random-beacon/api/IRandomBeacon.sol"; +import "./legacy/random-beacon/api/IRandomBeaconConsumer.sol"; +import "./legacy/random-beacon/Reimbursable.sol"; +import "./legacy/random-beacon/ReimbursementPool.sol"; +import "./legacy/random-beacon/Governable.sol"; import "@threshold-network/solidity-contracts/contracts/staking/IApplication.sol"; import "@threshold-network/solidity-contracts/contracts/staking/IStaking.sol"; @@ -489,10 +489,9 @@ contract WalletRegistry is /// @dev Can be called only by the contract guvnor, which should be the /// wallet registry governance contract. /// @param recipient Recipient of withdrawn rewards. - function withdrawIneligibleRewards(address recipient) - external - onlyGovernance - { + function withdrawIneligibleRewards( + address recipient + ) external onlyGovernance { sortitionPool.withdrawIneligible(recipient); } @@ -649,10 +648,9 @@ contract WalletRegistry is /// wallet registry governance contract. The caller is responsible for /// validating parameters. /// @param _randomBeacon Random Beacon address. - function upgradeRandomBeacon(IRandomBeacon _randomBeacon) - external - onlyGovernance - { + function upgradeRandomBeacon( + IRandomBeacon _randomBeacon + ) external onlyGovernance { randomBeacon = _randomBeacon; emit RandomBeaconUpgraded(address(_randomBeacon)); } @@ -663,10 +661,9 @@ contract WalletRegistry is /// validating parameters. The wallet owner has to implement `IWalletOwner` /// interface. /// @param _walletOwner New wallet owner address. - function updateWalletOwner(IWalletOwner _walletOwner) - external - onlyGovernance - { + function updateWalletOwner( + IWalletOwner _walletOwner + ) external onlyGovernance { walletOwner = _walletOwner; emit WalletOwnerUpdated(address(_walletOwner)); } @@ -754,7 +751,8 @@ contract WalletRegistry is uint256 maliciousDkgResultNotificationRewardMultiplier, uint256 sortitionPoolRewardsBanDuration ) external onlyGovernance { - _maliciousDkgResultNotificationRewardMultiplier = maliciousDkgResultNotificationRewardMultiplier; + _maliciousDkgResultNotificationRewardMultiplier = + maliciousDkgResultNotificationRewardMultiplier; _sortitionPoolRewardsBanDuration = sortitionPoolRewardsBanDuration; emit RewardParametersUpdated( maliciousDkgResultNotificationRewardMultiplier, @@ -768,10 +766,9 @@ contract WalletRegistry is /// validating parameters. /// @param maliciousDkgResultSlashingAmount New malicious DKG result /// slashing amount. - function updateSlashingParameters(uint96 maliciousDkgResultSlashingAmount) - external - onlyGovernance - { + function updateSlashingParameters( + uint96 maliciousDkgResultSlashingAmount + ) external onlyGovernance { _maliciousDkgResultSlashingAmount = maliciousDkgResultSlashingAmount; emit SlashingParametersUpdated(maliciousDkgResultSlashingAmount); } @@ -1184,11 +1181,9 @@ contract WalletRegistry is /// @param result DKG result. /// @return True if the result is valid. If the result is invalid it returns /// false and an error message. - function isDkgResultValid(DKG.Result calldata result) - external - view - returns (bool, string memory) - { + function isDkgResultValid( + DKG.Result calldata result + ) external view returns (bool, string memory) { return dkg.isResultValid(result); } @@ -1252,11 +1247,9 @@ contract WalletRegistry is return dkg.hasDkgTimedOut(); } - function getWallet(bytes32 walletID) - external - view - returns (Wallets.Wallet memory) - { + function getWallet( + bytes32 walletID + ) external view returns (Wallets.Wallet memory) { return wallets.registry[walletID]; } @@ -1265,11 +1258,9 @@ contract WalletRegistry is /// concatenation of X and Y coordinates. /// @param walletID ID of the wallet. /// @return Uncompressed public key of the wallet. - function getWalletPublicKey(bytes32 walletID) - external - view - returns (bytes memory) - { + function getWalletPublicKey( + bytes32 walletID + ) external view returns (bytes memory) { return wallets.getWalletPublicKey(walletID); } @@ -1292,11 +1283,9 @@ contract WalletRegistry is /// is what is used for operator's weight in the sortition pool. /// If the authorized stake minus the pending authorization decrease /// is below the minimum authorization, eligible stake is 0. - function eligibleStake(address stakingProvider) - external - view - returns (uint96) - { + function eligibleStake( + address stakingProvider + ) external view returns (uint96) { return authorization.eligibleStake( _currentAuthorizationSource(), @@ -1307,11 +1296,9 @@ contract WalletRegistry is /// @notice Returns the amount of rewards available for withdrawal for the /// given staking provider. Reverts if staking provider has not /// registered the operator address. - function availableRewards(address stakingProvider) - external - view - returns (uint96) - { + function availableRewards( + address stakingProvider + ) external view returns (uint96) { address operator = stakingProviderToOperator(stakingProvider); if (operator == address(0)) revert UnknownOperator(); return sortitionPool.getAvailableRewards(operator); @@ -1320,11 +1307,9 @@ contract WalletRegistry is /// @notice Returns the amount of stake that is pending authorization /// decrease for the given staking provider. If no authorization /// decrease has been requested, returns zero. - function pendingAuthorizationDecrease(address stakingProvider) - external - view - returns (uint96) - { + function pendingAuthorizationDecrease( + address stakingProvider + ) external view returns (uint96) { return authorization.pendingAuthorizationDecrease(stakingProvider); } @@ -1333,30 +1318,24 @@ contract WalletRegistry is /// If the sortition pool state was not updated yet by the operator /// after requesting the authorization decrease, returns /// `type(uint64).max`. - function remainingAuthorizationDecreaseDelay(address stakingProvider) - external - view - returns (uint64) - { + function remainingAuthorizationDecreaseDelay( + address stakingProvider + ) external view returns (uint64) { return authorization.remainingAuthorizationDecreaseDelay(stakingProvider); } /// @notice Returns operator registered for the given staking provider. - function stakingProviderToOperator(address stakingProvider) - public - view - returns (address) - { + function stakingProviderToOperator( + address stakingProvider + ) public view returns (address) { return authorization.stakingProviderToOperator[stakingProvider]; } /// @notice Returns staking provider of the given operator. - function operatorToStakingProvider(address operator) - public - view - returns (address) - { + function operatorToStakingProvider( + address operator + ) public view returns (address) { return authorization.operatorToStakingProvider[operator]; } diff --git a/solidity/ecdsa/contracts/WalletRegistryGovernance.sol b/solidity/ecdsa/contracts/WalletRegistryGovernance.sol index 14bd4176f5..bb89370bd6 100644 --- a/solidity/ecdsa/contracts/WalletRegistryGovernance.sol +++ b/solidity/ecdsa/contracts/WalletRegistryGovernance.sol @@ -16,10 +16,10 @@ pragma solidity 0.8.17; import "./WalletRegistry.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; -import "@keep-network/random-beacon/contracts/ReimbursementPool.sol"; +import "./legacy/random-beacon/ReimbursementPool.sol"; import {IWalletOwner} from "./api/IWalletOwner.sol"; -import {IRandomBeacon} from "@keep-network/random-beacon/contracts/api/IRandomBeacon.sol"; +import {IRandomBeacon} from "./legacy/random-beacon/api/IRandomBeacon.sol"; /// @title Wallet Registry Governance /// @notice Owns the `WalletRegistry` contract and is responsible for updating @@ -280,10 +280,9 @@ contract WalletRegistryGovernance is Ownable { /// @notice Begins the governance delay update process. /// @dev Can be called only by the contract owner. /// @param _newGovernanceDelay New governance delay - function beginGovernanceDelayUpdate(uint256 _newGovernanceDelay) - external - onlyOwner - { + function beginGovernanceDelayUpdate( + uint256 _newGovernanceDelay + ) external onlyOwner { newGovernanceDelay = _newGovernanceDelay; /* solhint-disable not-rely-on-time */ governanceDelayChangeInitiated = block.timestamp; @@ -342,10 +341,9 @@ contract WalletRegistryGovernance is Ownable { /// @notice Begins the wallet owner update process. /// @dev Can be called only by the contract owner. /// @param _newWalletOwner New wallet owner address - function beginWalletOwnerUpdate(address _newWalletOwner) - external - onlyOwner - { + function beginWalletOwnerUpdate( + address _newWalletOwner + ) external onlyOwner { require( address(_newWalletOwner) != address(0), "New wallet owner address cannot be zero" @@ -375,10 +373,9 @@ contract WalletRegistryGovernance is Ownable { /// @notice Begins the minimum authorization amount update process. /// @dev Can be called only by the contract owner. /// @param _newMinimumAuthorization New minimum authorization amount. - function beginMinimumAuthorizationUpdate(uint96 _newMinimumAuthorization) - external - onlyOwner - { + function beginMinimumAuthorizationUpdate( + uint96 _newMinimumAuthorization + ) external onlyOwner { /* solhint-disable not-rely-on-time */ newMinimumAuthorization = _newMinimumAuthorization; minimumAuthorizationChangeInitiated = block.timestamp; @@ -460,7 +457,8 @@ contract WalletRegistryGovernance is Ownable { uint64 _newAuthorizationDecreaseChangePeriod ) external onlyOwner { /* solhint-disable not-rely-on-time */ - newAuthorizationDecreaseChangePeriod = _newAuthorizationDecreaseChangePeriod; + newAuthorizationDecreaseChangePeriod = + _newAuthorizationDecreaseChangePeriod; authorizationDecreaseChangePeriodChangeInitiated = block.timestamp; emit AuthorizationDecreaseChangePeriodUpdateStarted( _newAuthorizationDecreaseChangePeriod, @@ -505,7 +503,8 @@ contract WalletRegistryGovernance is Ownable { uint96 _newMaliciousDkgResultSlashingAmount ) external onlyOwner { /* solhint-disable not-rely-on-time */ - newMaliciousDkgResultSlashingAmount = _newMaliciousDkgResultSlashingAmount; + newMaliciousDkgResultSlashingAmount = + _newMaliciousDkgResultSlashingAmount; maliciousDkgResultSlashingAmountChangeInitiated = block.timestamp; emit MaliciousDkgResultSlashingAmountUpdateStarted( _newMaliciousDkgResultSlashingAmount, @@ -550,7 +549,8 @@ contract WalletRegistryGovernance is Ownable { "Maximum value is 100" ); - newMaliciousDkgResultNotificationRewardMultiplier = _newMaliciousDkgResultNotificationRewardMultiplier; + newMaliciousDkgResultNotificationRewardMultiplier = + _newMaliciousDkgResultNotificationRewardMultiplier; maliciousDkgResultNotificationRewardMultiplierChangeInitiated = block .timestamp; emit MaliciousDkgResultNotificationRewardMultiplierUpdateStarted( @@ -681,7 +681,8 @@ contract WalletRegistryGovernance is Ownable { uint256 _newNotifyOperatorInactivityGasOffset ) external onlyOwner { /* solhint-disable not-rely-on-time */ - newNotifyOperatorInactivityGasOffset = _newNotifyOperatorInactivityGasOffset; + newNotifyOperatorInactivityGasOffset = + _newNotifyOperatorInactivityGasOffset; notifyOperatorInactivityGasOffsetChangeInitiated = block.timestamp; emit NotifyOperatorInactivityGasOffsetUpdateStarted( _newNotifyOperatorInactivityGasOffset, @@ -777,7 +778,8 @@ contract WalletRegistryGovernance is Ownable { uint256 _newNotifyDkgTimeoutNegativeGasOffset ) external onlyOwner { /* solhint-disable not-rely-on-time */ - newNotifyDkgTimeoutNegativeGasOffset = _newNotifyDkgTimeoutNegativeGasOffset; + newNotifyDkgTimeoutNegativeGasOffset = + _newNotifyDkgTimeoutNegativeGasOffset; notifyDkgTimeoutNegativeGasOffsetChangeInitiated = block.timestamp; emit NotifyDkgTimeoutNegativeGasOffsetUpdateStarted( _newNotifyDkgTimeoutNegativeGasOffset, @@ -821,10 +823,9 @@ contract WalletRegistryGovernance is Ownable { /// @notice Begins the reimbursement pool update process. /// @dev Can be called only by the contract owner. /// @param _newReimbursementPool New reimbursement pool. - function beginReimbursementPoolUpdate(address payable _newReimbursementPool) - external - onlyOwner - { + function beginReimbursementPoolUpdate( + address payable _newReimbursementPool + ) external onlyOwner { require( address(_newReimbursementPool) != address(0), "New reimbursement pool address cannot be zero" @@ -864,7 +865,8 @@ contract WalletRegistryGovernance is Ownable { uint256 _newSortitionPoolRewardsBanDuration ) external onlyOwner { /* solhint-disable not-rely-on-time */ - newSortitionPoolRewardsBanDuration = _newSortitionPoolRewardsBanDuration; + newSortitionPoolRewardsBanDuration = + _newSortitionPoolRewardsBanDuration; sortitionPoolRewardsBanDurationChangeInitiated = block.timestamp; emit SortitionPoolRewardsBanDurationUpdateStarted( _newSortitionPoolRewardsBanDuration, @@ -900,10 +902,9 @@ contract WalletRegistryGovernance is Ownable { /// @notice Begins the DKG seed timeout update process. /// @dev Can be called only by the contract owner. /// @param _newDkgSeedTimeout New DKG seed timeout in blocks - function beginDkgSeedTimeoutUpdate(uint256 _newDkgSeedTimeout) - external - onlyOwner - { + function beginDkgSeedTimeoutUpdate( + uint256 _newDkgSeedTimeout + ) external onlyOwner { /* solhint-disable not-rely-on-time */ require(_newDkgSeedTimeout > 0, "DKG seed timeout must be > 0"); newDkgSeedTimeout = _newDkgSeedTimeout; @@ -1071,7 +1072,8 @@ contract WalletRegistryGovernance is Ownable { _newSubmitterPrecedencePeriodLength > 0, "DKG submitter precedence period length must be > 0" ); - newSubmitterPrecedencePeriodLength = _newSubmitterPrecedencePeriodLength; + newSubmitterPrecedencePeriodLength = + _newSubmitterPrecedencePeriodLength; dkgSubmitterPrecedencePeriodLengthChangeInitiated = block.timestamp; emit DkgSubmitterPrecedencePeriodLengthUpdateStarted( _newSubmitterPrecedencePeriodLength, @@ -1360,11 +1362,9 @@ contract WalletRegistryGovernance is Ownable { /// can be committed. /// @param changeTimestamp Timestamp indicating the beginning of the change. /// @return Remaining time in seconds. - function getRemainingChangeTime(uint256 changeTimestamp) - internal - view - returns (uint256) - { + function getRemainingChangeTime( + uint256 changeTimestamp + ) internal view returns (uint256) { require(changeTimestamp > 0, "Change not initiated"); /* solhint-disable-next-line not-rely-on-time */ uint256 elapsed = block.timestamp - changeTimestamp; diff --git a/solidity/ecdsa/contracts/api/IWalletRegistry.sol b/solidity/ecdsa/contracts/api/IWalletRegistry.sol index fc5fac6f7a..0b2b150b32 100644 --- a/solidity/ecdsa/contracts/api/IWalletRegistry.sol +++ b/solidity/ecdsa/contracts/api/IWalletRegistry.sol @@ -61,10 +61,9 @@ interface IWalletRegistry { /// concatenation of X and Y coordinates. /// @param walletID ID of the wallet. /// @return Uncompressed public key of the wallet. - function getWalletPublicKey(bytes32 walletID) - external - view - returns (bytes memory); + function getWalletPublicKey( + bytes32 walletID + ) external view returns (bytes memory); /// @notice Check current wallet creation state. function getWalletCreationState() external view returns (EcdsaDkg.State); diff --git a/solidity/ecdsa/contracts/legacy/random-beacon/Governable.sol b/solidity/ecdsa/contracts/legacy/random-beacon/Governable.sol new file mode 100644 index 0000000000..4a052c10c8 --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/random-beacon/Governable.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-3.0-only +// +// ▓▓▌ ▓▓ ▐▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▄ +// ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ +// ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓ ▐▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓ +// ▓▓▓▓▓▓▄▄▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▄▄▄▄ ▓▓▓▓▓▓▄▄▄▄ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓ +// ▓▓▓▓▓▓▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ +// ▓▓▓▓▓▓▀▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓▀▀▀▀ ▓▓▓▓▓▓▀▀▀▀ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀ +// ▓▓▓▓▓▓ ▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ +// ▓▓▓▓▓▓▓▓▓▓ █▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ +// ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ +// +// Trust math, not hardware. + +pragma solidity 0.8.17; + +/// @notice Governable contract. +/// @dev A constructor is not defined, which makes the contract compatible with +/// upgradable proxies. This requires calling explicitly `_transferGovernance` +/// function in a child contract. +abstract contract Governable { + // Governance of the contract + // The variable should be initialized by the implementing contract. + // slither-disable-next-line uninitialized-state + address public governance; + + // Reserved storage space in case we need to add more variables, + // since there are upgradeable contracts that inherit from this one. + // See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + // slither-disable-next-line unused-state + uint256[49] private __gap; + + event GovernanceTransferred(address oldGovernance, address newGovernance); + + modifier onlyGovernance() virtual { + require(governance == msg.sender, "Caller is not the governance"); + _; + } + + /// @notice Transfers governance of the contract to `newGovernance`. + function transferGovernance(address newGovernance) + external + virtual + onlyGovernance + { + require( + newGovernance != address(0), + "New governance is the zero address" + ); + _transferGovernance(newGovernance); + } + + function _transferGovernance(address newGovernance) internal virtual { + address oldGovernance = governance; + governance = newGovernance; + emit GovernanceTransferred(oldGovernance, newGovernance); + } +} diff --git a/solidity/ecdsa/contracts/legacy/random-beacon/LICENSE b/solidity/ecdsa/contracts/legacy/random-beacon/LICENSE new file mode 100644 index 0000000000..e72bfddabc --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/random-beacon/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/solidity/ecdsa/contracts/legacy/random-beacon/README.md b/solidity/ecdsa/contracts/legacy/random-beacon/README.md new file mode 100644 index 0000000000..6e7a38c1ab --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/random-beacon/README.md @@ -0,0 +1,11 @@ +# Legacy Beacon support contracts + +These seven unmodified source files come from +`@keep-network/random-beacon@2.1.0-dev.18`. Original GPL-3.0-only headers and the +license are retained. Tarball and file hashes are recorded in +`../../../external/random-beacon-export/VENDOR.json`. + +They preserve ECDSA's existing interfaces, reimbursement/storage inheritance, +and legacy test helpers without installing the published Beacon package and +its sortition dependency. Changes must be explicit and reviewed alongside +legacy deployment and upgrade compatibility. diff --git a/solidity/ecdsa/contracts/legacy/random-beacon/Reimbursable.sol b/solidity/ecdsa/contracts/legacy/random-beacon/Reimbursable.sol new file mode 100644 index 0000000000..3fe4a663dc --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/random-beacon/Reimbursable.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-3.0-only +// +// ▓▓▌ ▓▓ ▐▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▄ +// ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ +// ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓ ▐▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓ +// ▓▓▓▓▓▓▄▄▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▄▄▄▄ ▓▓▓▓▓▓▄▄▄▄ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓ +// ▓▓▓▓▓▓▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ +// ▓▓▓▓▓▓▀▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓▀▀▀▀ ▓▓▓▓▓▓▀▀▀▀ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀ +// ▓▓▓▓▓▓ ▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ +// ▓▓▓▓▓▓▓▓▓▓ █▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ +// ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ +// +// Trust math, not hardware. + +pragma solidity 0.8.17; + +import "./ReimbursementPool.sol"; + +abstract contract Reimbursable { + // The variable should be initialized by the implementing contract. + // slither-disable-next-line uninitialized-state + ReimbursementPool public reimbursementPool; + + // Reserved storage space in case we need to add more variables, + // since there are upgradeable contracts that inherit from this one. + // See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + // slither-disable-next-line unused-state + uint256[49] private __gap; + + event ReimbursementPoolUpdated(address newReimbursementPool); + + modifier refundable(address receiver) { + uint256 gasStart = gasleft(); + _; + reimbursementPool.refund(gasStart - gasleft(), receiver); + } + + modifier onlyReimbursableAdmin() virtual { + _; + } + + function updateReimbursementPool(ReimbursementPool _reimbursementPool) + external + onlyReimbursableAdmin + { + emit ReimbursementPoolUpdated(address(_reimbursementPool)); + + reimbursementPool = _reimbursementPool; + } +} diff --git a/solidity/ecdsa/contracts/legacy/random-beacon/ReimbursementPool.sol b/solidity/ecdsa/contracts/legacy/random-beacon/ReimbursementPool.sol new file mode 100644 index 0000000000..bf664254ab --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/random-beacon/ReimbursementPool.sol @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-3.0-only +// +// ▓▓▌ ▓▓ ▐▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▄ +// ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ +// ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓ ▐▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓ +// ▓▓▓▓▓▓▄▄▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▄▄▄▄ ▓▓▓▓▓▓▄▄▄▄ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓ +// ▓▓▓▓▓▓▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ +// ▓▓▓▓▓▓▀▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓▀▀▀▀ ▓▓▓▓▓▓▀▀▀▀ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀ +// ▓▓▓▓▓▓ ▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ +// ▓▓▓▓▓▓▓▓▓▓ █▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ +// ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ +// +// Trust math, not hardware. + +pragma solidity 0.8.17; + +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; + +contract ReimbursementPool is Ownable, ReentrancyGuard { + /// @notice Authorized contracts that can interact with the reimbursment pool. + /// Authorization can be granted and removed by the owner. + mapping(address => bool) public isAuthorized; + + /// @notice Static gas includes: + /// - cost of the refund function + /// - base transaction cost + uint256 public staticGas; + + /// @notice Max gas price used to reimburse a transaction submitter. Protects + /// against malicious operator-miners. + uint256 public maxGasPrice; + + event StaticGasUpdated(uint256 newStaticGas); + + event MaxGasPriceUpdated(uint256 newMaxGasPrice); + + event SendingEtherFailed(uint256 refundAmount, address receiver); + + event AuthorizedContract(address thirdPartyContract); + + event UnauthorizedContract(address thirdPartyContract); + + event FundsWithdrawn(uint256 withdrawnAmount, address receiver); + + constructor(uint256 _staticGas, uint256 _maxGasPrice) { + staticGas = _staticGas; + maxGasPrice = _maxGasPrice; + } + + /// @notice Receive ETH + receive() external payable {} + + /// @notice Refunds ETH to a spender for executing specific transactions. + /// @dev Ignoring the result of sending ETH to a receiver is made on purpose. + /// For EOA receiving ETH should always work. If a receiver is a smart + /// contract, then we do not want to fail a transaction, because in some + /// cases the refund is done at the very end of multiple calls where all + /// the previous calls were already paid off. It is a receiver's smart + /// contract resposibility to make sure it can receive ETH. + /// @dev Only authorized contracts are allowed calling this function. + /// @param gasSpent Gas spent on a transaction that needs to be reimbursed. + /// @param receiver Address where the reimbursment is sent. + function refund(uint256 gasSpent, address receiver) external nonReentrant { + require( + isAuthorized[msg.sender], + "Contract is not authorized for a refund" + ); + require(receiver != address(0), "Receiver's address cannot be zero"); + + uint256 gasPrice = tx.gasprice < maxGasPrice + ? tx.gasprice + : maxGasPrice; + + uint256 refundAmount = (gasSpent + staticGas) * gasPrice; + + /* solhint-disable avoid-low-level-calls */ + // slither-disable-next-line low-level-calls,unchecked-lowlevel + (bool sent, ) = receiver.call{value: refundAmount}(""); + /* solhint-enable avoid-low-level-calls */ + if (!sent) { + // slither-disable-next-line reentrancy-events + emit SendingEtherFailed(refundAmount, receiver); + } + } + + /// @notice Authorize a contract that can interact with this reimbursment pool. + /// Can be authorized by the owner only. + /// @param _contract Authorized contract. + function authorize(address _contract) external onlyOwner { + isAuthorized[_contract] = true; + + emit AuthorizedContract(_contract); + } + + /// @notice Unauthorize a contract that was previously authorized to interact + /// with this reimbursment pool. Can be unauthorized by the + /// owner only. + /// @param _contract Authorized contract. + function unauthorize(address _contract) external onlyOwner { + delete isAuthorized[_contract]; + + emit UnauthorizedContract(_contract); + } + + /// @notice Setting a static gas cost for executing a transaction. Can be set + /// by the owner only. + /// @param _staticGas Static gas cost. + function setStaticGas(uint256 _staticGas) external onlyOwner { + staticGas = _staticGas; + + emit StaticGasUpdated(_staticGas); + } + + /// @notice Setting a max gas price for transactions. Can be set by the + /// owner only. + /// @param _maxGasPrice Max gas price used to reimburse tx submitters. + function setMaxGasPrice(uint256 _maxGasPrice) external onlyOwner { + maxGasPrice = _maxGasPrice; + + emit MaxGasPriceUpdated(_maxGasPrice); + } + + /// @notice Withdraws all ETH from this pool which are sent to a given + /// address. Can be set by the owner only. + /// @param receiver An address where ETH is sent. + function withdrawAll(address receiver) external onlyOwner { + withdraw(address(this).balance, receiver); + } + + /// @notice Withdraws ETH amount from this pool which are sent to a given + /// address. Can be set by the owner only. + /// @param amount Amount to withdraw from the pool. + /// @param receiver An address where ETH is sent. + function withdraw(uint256 amount, address receiver) public onlyOwner { + require( + address(this).balance >= amount, + "Insufficient contract balance" + ); + require(receiver != address(0), "Receiver's address cannot be zero"); + + emit FundsWithdrawn(amount, receiver); + + /* solhint-disable avoid-low-level-calls */ + // slither-disable-next-line low-level-calls,arbitrary-send + (bool sent, ) = receiver.call{value: amount}(""); + /* solhint-enable avoid-low-level-calls */ + require(sent, "Failed to send Ether"); + } +} diff --git a/solidity/ecdsa/contracts/legacy/random-beacon/api/IRandomBeacon.sol b/solidity/ecdsa/contracts/legacy/random-beacon/api/IRandomBeacon.sol new file mode 100644 index 0000000000..4b80c8b115 --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/random-beacon/api/IRandomBeacon.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-3.0-only +// +// ▓▓▌ ▓▓ ▐▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▄ +// ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ +// ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓ ▐▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓ +// ▓▓▓▓▓▓▄▄▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▄▄▄▄ ▓▓▓▓▓▓▄▄▄▄ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓ +// ▓▓▓▓▓▓▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ +// ▓▓▓▓▓▓▀▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓▀▀▀▀ ▓▓▓▓▓▓▀▀▀▀ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀ +// ▓▓▓▓▓▓ ▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ +// ▓▓▓▓▓▓▓▓▓▓ █▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ +// ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ +// +// Trust math, not hardware. + +pragma solidity 0.8.17; + +import "./IRandomBeaconConsumer.sol"; + +/// @title Random Beacon interface +interface IRandomBeacon { + /// @notice Creates a request to generate a new relay entry. Requires a + /// request fee denominated in T token. + /// @param callbackContract Beacon consumer callback contract. + function requestRelayEntry(IRandomBeaconConsumer callbackContract) external; +} diff --git a/solidity/ecdsa/contracts/legacy/random-beacon/api/IRandomBeaconConsumer.sol b/solidity/ecdsa/contracts/legacy/random-beacon/api/IRandomBeaconConsumer.sol new file mode 100644 index 0000000000..fde2f6052a --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/random-beacon/api/IRandomBeaconConsumer.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-3.0-only +// +// ▓▓▌ ▓▓ ▐▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▄ +// ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ +// ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓ ▐▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓ +// ▓▓▓▓▓▓▄▄▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▄▄▄▄ ▓▓▓▓▓▓▄▄▄▄ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓ +// ▓▓▓▓▓▓▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ +// ▓▓▓▓▓▓▀▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓▀▀▀▀ ▓▓▓▓▓▓▀▀▀▀ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀ +// ▓▓▓▓▓▓ ▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ +// ▓▓▓▓▓▓▓▓▓▓ █▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ +// ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ +// +// Trust math, not hardware. + +pragma solidity 0.8.17; + +interface IRandomBeaconConsumer { + /// @notice Receives relay entry produced by Keep Random Beacon. This function + /// should be called only by Keep Random Beacon. + /// + /// @param relayEntry Relay entry (random number) produced by Keep Random + /// Beacon. + /// @param blockNumber Block number at which the relay entry was submitted + /// to the chain. + function __beaconCallback(uint256 relayEntry, uint256 blockNumber) external; +} diff --git a/solidity/ecdsa/contracts/legacy/random-beacon/libraries/BytesLib.sol b/solidity/ecdsa/contracts/legacy/random-beacon/libraries/BytesLib.sol new file mode 100644 index 0000000000..9d9f975c82 --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/random-beacon/libraries/BytesLib.sol @@ -0,0 +1,505 @@ +// SPDX-License-Identifier: GPL-3.0-only +// +// ▓▓▌ ▓▓ ▐▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▄ +// ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ +// ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓ ▐▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓ +// ▓▓▓▓▓▓▄▄▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▄▄▄▄ ▓▓▓▓▓▓▄▄▄▄ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓ +// ▓▓▓▓▓▓▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ +// ▓▓▓▓▓▓▀▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓▀▀▀▀ ▓▓▓▓▓▓▀▀▀▀ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀ +// ▓▓▓▓▓▓ ▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ +// ▓▓▓▓▓▓▓▓▓▓ █▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ +// ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ +// +// + +pragma solidity 0.8.17; + +/* +Version pulled from keep-core v1: +https://github.com/keep-network/keep-core/blob/f297202db00c027978ad8e7103a356503de5773c/solidity-v1/contracts/utils/BytesLib.sol + +To compile it with solidity 0.8 `_preBytes_slot` was replaced with `_preBytes.slot`. +*/ + +/* +https://github.com/GNSPS/solidity-bytes-utils/ +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. +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 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. +For more information, please refer to +*/ + +/** @title BytesLib **/ +/** @author https://github.com/GNSPS **/ + +library BytesLib { + function concatStorage(bytes storage _preBytes, bytes memory _postBytes) + internal + { + assembly { + // Read the first 32 bytes of _preBytes storage, which is the length + // of the array. (We don't need to use the offset into the slot + // because arrays use the entire slot.) + let fslot := sload(_preBytes.slot) + // Arrays of 31 bytes or less have an even value in their slot, + // while longer arrays have an odd value. The actual length is + // the slot divided by two for odd values, and the lowest order + // byte divided by two for even values. + // If the slot is even, bitwise and the slot with 255 and divide by + // two to get the length. If the slot is odd, bitwise and the slot + // with -1 and divide by two. + let slength := div( + and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), + 2 + ) + let mlength := mload(_postBytes) + let newlength := add(slength, mlength) + // slength can contain both the length and contents of the array + // if length < 32 bytes so let's prepare for that + // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage + switch add(lt(slength, 32), lt(newlength, 32)) + case 2 { + // Since the new array still fits in the slot, we just need to + // update the contents of the slot. + // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length + sstore( + _preBytes.slot, + // all the modifications to the slot are inside this + // next block + add( + // we can just add to the slot contents because the + // bytes we want to change are the LSBs + fslot, + add( + mul( + div( + // load the bytes from memory + mload(add(_postBytes, 0x20)), + // zero all bytes to the right + exp(0x100, sub(32, mlength)) + ), + // and now shift left the number of bytes to + // leave space for the length in the slot + exp(0x100, sub(32, newlength)) + ), + // increase length by the double of the memory + // bytes length + mul(mlength, 2) + ) + ) + ) + } + case 1 { + // The stored value fits in the slot, but the combined value + // will exceed it. + // get the keccak hash to get the contents of the array + mstore(0x0, _preBytes.slot) + let sc := add(keccak256(0x0, 0x20), div(slength, 32)) + + // save new length + sstore(_preBytes.slot, add(mul(newlength, 2), 1)) + + // The contents of the _postBytes array start 32 bytes into + // the structure. Our first read should obtain the `submod` + // bytes that can fit into the unused space in the last word + // of the stored array. To get this, we read 32 bytes starting + // from `submod`, so the data we read overlaps with the array + // contents by `submod` bytes. Masking the lowest-order + // `submod` bytes allows us to add that value directly to the + // stored value. + + let submod := sub(32, slength) + let mc := add(_postBytes, submod) + let end := add(_postBytes, mlength) + let mask := sub(exp(0x100, submod), 1) + + sstore( + sc, + add( + and( + fslot, + 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 + ), + and(mload(mc), mask) + ) + ) + + for { + mc := add(mc, 0x20) + sc := add(sc, 1) + } lt(mc, end) { + sc := add(sc, 1) + mc := add(mc, 0x20) + } { + sstore(sc, mload(mc)) + } + + mask := exp(0x100, sub(mc, end)) + + sstore(sc, mul(div(mload(mc), mask), mask)) + } + default { + // get the keccak hash to get the contents of the array + mstore(0x0, _preBytes.slot) + // Start copying to the last used word of the stored array. + let sc := add(keccak256(0x0, 0x20), div(slength, 32)) + + // save new length + sstore(_preBytes.slot, add(mul(newlength, 2), 1)) + + // Copy over the first `submod` bytes of the new data as in + // case 1 above. + let slengthmod := mod(slength, 32) + let submod := sub(32, slengthmod) + let mc := add(_postBytes, submod) + let end := add(_postBytes, mlength) + let mask := sub(exp(0x100, submod), 1) + + sstore(sc, add(sload(sc), and(mload(mc), mask))) + + for { + sc := add(sc, 1) + mc := add(mc, 0x20) + } lt(mc, end) { + sc := add(sc, 1) + mc := add(mc, 0x20) + } { + sstore(sc, mload(mc)) + } + + mask := exp(0x100, sub(mc, end)) + + sstore(sc, mul(div(mload(mc), mask), mask)) + } + } + } + + function equalStorage(bytes storage _preBytes, bytes memory _postBytes) + internal + view + returns (bool) + { + bool success = true; + + assembly { + // we know _preBytes_offset is 0 + let fslot := sload(_preBytes.slot) + // Decode the length of the stored array like in concatStorage(). + let slength := div( + and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), + 2 + ) + let mlength := mload(_postBytes) + + // if lengths don't match the arrays are not equal + switch eq(slength, mlength) + case 1 { + // slength can contain both the length and contents of the array + // if length < 32 bytes so let's prepare for that + // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage + if iszero(iszero(slength)) { + switch lt(slength, 32) + case 1 { + // blank the last byte which is the length + fslot := mul(div(fslot, 0x100), 0x100) + + if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { + // unsuccess: + success := 0 + } + } + default { + // cb is a circuit breaker in the for loop since there's + // no said feature for inline assembly loops + // cb = 1 - don't breaker + // cb = 0 - break + let cb := 1 + + // get the keccak hash to get the contents of the array + mstore(0x0, _preBytes.slot) + let sc := keccak256(0x0, 0x20) + + let mc := add(_postBytes, 0x20) + let end := add(mc, mlength) + + // the next line is the loop condition: + // while(uint(mc < end) + cb == 2) + for { + + } eq(add(lt(mc, end), cb), 2) { + sc := add(sc, 1) + mc := add(mc, 0x20) + } { + if iszero(eq(sload(sc), mload(mc))) { + // unsuccess: + success := 0 + cb := 0 + } + } + } + } + } + default { + // unsuccess: + success := 0 + } + } + + return success; + } + + function concat(bytes memory _preBytes, bytes memory _postBytes) + internal + pure + returns (bytes memory) + { + bytes memory tempBytes; + + assembly { + // Get a location of some free memory and store it in tempBytes as + // Solidity does for memory variables. + tempBytes := mload(0x40) + + // Store the length of the first bytes array at the beginning of + // the memory for tempBytes. + let length := mload(_preBytes) + mstore(tempBytes, length) + + // Maintain a memory counter for the current write location in the + // temp bytes array by adding the 32 bytes for the array length to + // the starting location. + let mc := add(tempBytes, 0x20) + // Stop copying when the memory counter reaches the length of the + // first bytes array. + let end := add(mc, length) + + for { + // Initialize a copy counter to the start of the _preBytes data, + // 32 bytes into its memory. + let cc := add(_preBytes, 0x20) + } lt(mc, end) { + // Increase both counters by 32 bytes each iteration. + mc := add(mc, 0x20) + cc := add(cc, 0x20) + } { + // Write the _preBytes data into the tempBytes memory 32 bytes + // at a time. + mstore(mc, mload(cc)) + } + + // Add the length of _postBytes to the current length of tempBytes + // and store it as the new length in the first 32 bytes of the + // tempBytes memory. + length := mload(_postBytes) + mstore(tempBytes, add(length, mload(tempBytes))) + + // Move the memory counter back from a multiple of 0x20 to the + // actual end of the _preBytes data. + mc := end + // Stop copying when the memory counter reaches the new combined + // length of the arrays. + end := add(mc, length) + + for { + let cc := add(_postBytes, 0x20) + } lt(mc, end) { + mc := add(mc, 0x20) + cc := add(cc, 0x20) + } { + mstore(mc, mload(cc)) + } + + // Update the free-memory pointer by padding our last write location + // to 32 bytes: add 31 bytes to the end of tempBytes to move to the + // next 32 byte block, then round down to the nearest multiple of + // 32. If the sum of the length of the two arrays is zero then add + // one before rounding down to leave a blank 32 bytes (the length block with 0). + mstore( + 0x40, + and( + add(add(end, iszero(add(length, mload(_preBytes)))), 31), + not(31) // Round down to the nearest 32 bytes. + ) + ) + } + + return tempBytes; + } + + function slice( + bytes memory _bytes, + uint256 _start, + uint256 _length + ) internal pure returns (bytes memory res) { + uint256 _end = _start + _length; + require(_end > _start && _bytes.length >= _end, "Slice out of bounds"); + + assembly { + // Alloc bytes array with additional 32 bytes afterspace and assign it's size + res := mload(0x40) + mstore(0x40, add(add(res, 64), _length)) + mstore(res, _length) + + // Compute distance between source and destination pointers + let diff := sub(res, add(_bytes, _start)) + + for { + let src := add(add(_bytes, 32), _start) + let end := add(src, _length) + } lt(src, end) { + src := add(src, 32) + } { + mstore(add(src, diff), mload(src)) + } + } + } + + function toAddress(bytes memory _bytes, uint256 _start) + internal + pure + returns (address) + { + uint256 _totalLen = _start + 20; + require( + _totalLen > _start && _bytes.length >= _totalLen, + "Address conversion out of bounds." + ); + address tempAddress; + + assembly { + tempAddress := div( + mload(add(add(_bytes, 0x20), _start)), + 0x1000000000000000000000000 + ) + } + + return tempAddress; + } + + function toUint8(bytes memory _bytes, uint256 _start) + internal + pure + returns (uint8) + { + require( + _bytes.length >= (_start + 1), + "Uint8 conversion out of bounds." + ); + uint8 tempUint; + + assembly { + tempUint := mload(add(add(_bytes, 0x1), _start)) + } + + return tempUint; + } + + function toUint(bytes memory _bytes, uint256 _start) + internal + pure + returns (uint256) + { + uint256 _totalLen = _start + 32; + require( + _totalLen > _start && _bytes.length >= _totalLen, + "Uint conversion out of bounds." + ); + uint256 tempUint; + + assembly { + tempUint := mload(add(add(_bytes, 0x20), _start)) + } + + return tempUint; + } + + function equal(bytes memory _preBytes, bytes memory _postBytes) + internal + pure + returns (bool) + { + bool success = true; + + assembly { + let length := mload(_preBytes) + + // if lengths don't match the arrays are not equal + switch eq(length, mload(_postBytes)) + case 1 { + // cb is a circuit breaker in the for loop since there's + // no said feature for inline assembly loops + // cb = 1 - don't breaker + // cb = 0 - break + let cb := 1 + + let mc := add(_preBytes, 0x20) + let end := add(mc, length) + + for { + let cc := add(_postBytes, 0x20) + // the next line is the loop condition: + // while(uint(mc < end) + cb == 2) + } eq(add(lt(mc, end), cb), 2) { + mc := add(mc, 0x20) + cc := add(cc, 0x20) + } { + // if any of these checks fails then arrays are not equal + if iszero(eq(mload(mc), mload(cc))) { + // unsuccess: + success := 0 + cb := 0 + } + } + } + default { + // unsuccess: + success := 0 + } + } + + return success; + } + + function toBytes32(bytes memory _source) + internal + pure + returns (bytes32 result) + { + if (_source.length == 0) { + return 0x0; + } + + assembly { + result := mload(add(_source, 32)) + } + } + + function keccak256Slice( + bytes memory _bytes, + uint256 _start, + uint256 _length + ) internal pure returns (bytes32 result) { + uint256 _end = _start + _length; + require(_end > _start && _bytes.length >= _end, "Slice out of bounds"); + + assembly { + result := keccak256(add(add(_bytes, 32), _start), _length) + } + } +} diff --git a/solidity/ecdsa/contracts/legacy/random-beacon/libraries/Callback.sol b/solidity/ecdsa/contracts/legacy/random-beacon/libraries/Callback.sol new file mode 100644 index 0000000000..b5eaa7ed50 --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/random-beacon/libraries/Callback.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-3.0-only +// +// ▓▓▌ ▓▓ ▐▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▄ +// ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ +// ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓ ▐▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓ +// ▓▓▓▓▓▓▄▄▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▄▄▄▄ ▓▓▓▓▓▓▄▄▄▄ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓ +// ▓▓▓▓▓▓▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ +// ▓▓▓▓▓▓▀▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓▀▀▀▀ ▓▓▓▓▓▓▀▀▀▀ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀ +// ▓▓▓▓▓▓ ▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ +// ▓▓▓▓▓▓▓▓▓▓ █▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ +// ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ +// +// + +pragma solidity 0.8.17; + +import "../api/IRandomBeaconConsumer.sol"; + +/// @title Callback library +/// @dev Library for handling calls to random beacon consumer. +library Callback { + struct Data { + IRandomBeaconConsumer callbackContract; + } + + event CallbackFailed(uint256 entry, uint256 entrySubmittedBlock); + + /// @notice Sets callback contract. + /// @param callbackContract Callback contract. + function setCallbackContract( + Data storage self, + IRandomBeaconConsumer callbackContract + ) internal { + self.callbackContract = callbackContract; + } + + /// @notice Executes consumer specified callback for the relay entry request. + /// @param entry The generated random number. + /// @param callbackGasLimit Callback gas limit. + function executeCallback( + Data storage self, + uint256 entry, + uint256 callbackGasLimit + ) internal { + if (address(self.callbackContract) != address(0)) { + try + self.callbackContract.__beaconCallback{gas: callbackGasLimit}( + entry, + block.number + ) + {} catch { + // slither-disable-next-line reentrancy-events + emit CallbackFailed(entry, block.number); + } + } + } +} diff --git a/solidity/ecdsa/contracts/legacy/sortition/Branch.sol b/solidity/ecdsa/contracts/legacy/sortition/Branch.sol new file mode 100644 index 0000000000..5f0178222c --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/sortition/Branch.sol @@ -0,0 +1,141 @@ +pragma solidity 0.8.17; + +import "./Constants.sol"; + +/// @notice The implicit 8-ary trees of the sortition pool +/// rely on packing 8 "slots" of 32-bit values into each uint256. +/// The Branch library permits efficient calculations on these slots. +library Branch { + /// @notice Calculate the right shift required + /// to make the 32 least significant bits of an uint256 + /// be the bits of the `position`th slot + /// when treating the uint256 as a uint32[8]. + /// + /// @dev Not used for efficiency reasons, + /// but left to illustrate the meaning of a common pattern. + /// I wish solidity had macros, even C macros. + function slotShift(uint256 position) internal pure returns (uint256) { + unchecked { + return position * Constants.SLOT_WIDTH; + } + } + + /// @notice Return the `position`th slot of the `node`, + /// treating `node` as a uint32[32]. + function getSlot(uint256 node, uint256 position) + internal + pure + returns (uint256) + { + unchecked { + uint256 shiftBits = position * Constants.SLOT_WIDTH; + // Doing a bitwise AND with `SLOT_MAX` + // clears all but the 32 least significant bits. + // Because of the right shift by `slotShift(position)` bits, + // those 32 bits contain the 32 bits in the `position`th slot of `node`. + return (node >> shiftBits) & Constants.SLOT_MAX; + } + } + + /// @notice Return `node` with the `position`th slot set to zero. + function clearSlot(uint256 node, uint256 position) + internal + pure + returns (uint256) + { + unchecked { + uint256 shiftBits = position * Constants.SLOT_WIDTH; + // Shifting `SLOT_MAX` left by `slotShift(position)` bits + // gives us a number where all bits of the `position`th slot are set, + // and all other bits are unset. + // + // Using a bitwise NOT on this number, + // we get a uint256 where all bits are set + // except for those of the `position`th slot. + // + // Bitwise ANDing the original `node` with this number + // sets the bits of `position`th slot to zero, + // leaving all other bits unchanged. + return node & ~(Constants.SLOT_MAX << shiftBits); + } + } + + /// @notice Return `node` with the `position`th slot set to `weight`. + /// + /// @param weight The weight of of the node. + /// Safely truncated to a 32-bit number, + /// but this should never be called with an overflowing weight regardless. + function setSlot( + uint256 node, + uint256 position, + uint256 weight + ) internal pure returns (uint256) { + unchecked { + uint256 shiftBits = position * Constants.SLOT_WIDTH; + // Clear the `position`th slot like in `clearSlot()`. + uint256 clearedNode = node & ~(Constants.SLOT_MAX << shiftBits); + // Bitwise AND `weight` with `SLOT_MAX` + // to clear all but the 32 least significant bits. + // + // Shift this left by `slotShift(position)` bits + // to obtain a uint256 with all bits unset + // except in the `position`th slot + // which contains the 32-bit value of `weight`. + uint256 shiftedWeight = (weight & Constants.SLOT_MAX) << shiftBits; + // When we bitwise OR these together, + // all other slots except the `position`th one come from the left argument, + // and the `position`th gets filled with `weight` from the right argument. + return clearedNode | shiftedWeight; + } + } + + /// @notice Calculate the summed weight of all slots in the `node`. + function sumWeight(uint256 node) internal pure returns (uint256 sum) { + unchecked { + sum = node & Constants.SLOT_MAX; + // Iterate through each slot + // by shifting `node` right in increments of 32 bits, + // and adding the 32 least significant bits to the `sum`. + uint256 newNode = node >> Constants.SLOT_WIDTH; + while (newNode > 0) { + sum += (newNode & Constants.SLOT_MAX); + newNode = newNode >> Constants.SLOT_WIDTH; + } + return sum; + } + } + + /// @notice Pick a slot in `node` that corresponds to `index`. + /// Treats the node like an array of virtual stakers, + /// the number of virtual stakers in each slot corresponding to its weight, + /// and picks which slot contains the `index`th virtual staker. + /// + /// @dev Requires that `index` be lower than `sumWeight(node)`. + /// However, this is not enforced for performance reasons. + /// If `index` exceeds the permitted range, + /// `pickWeightedSlot()` returns the rightmost slot + /// and an excessively high `newIndex`. + /// + /// @return slot The slot of `node` containing the `index`th virtual staker. + /// + /// @return newIndex The index of the `index`th virtual staker of `node` + /// within the returned slot. + function pickWeightedSlot(uint256 node, uint256 index) + internal + pure + returns (uint256 slot, uint256 newIndex) + { + unchecked { + newIndex = index; + uint256 newNode = node; + uint256 currentSlotWeight = newNode & Constants.SLOT_MAX; + while (newIndex >= currentSlotWeight) { + newIndex -= currentSlotWeight; + slot++; + newNode = newNode >> Constants.SLOT_WIDTH; + currentSlotWeight = newNode & Constants.SLOT_MAX; + } + return (slot, newIndex); + } + } +} diff --git a/solidity/ecdsa/contracts/legacy/sortition/Chaosnet.sol b/solidity/ecdsa/contracts/legacy/sortition/Chaosnet.sol new file mode 100644 index 0000000000..237e88ce07 --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/sortition/Chaosnet.sol @@ -0,0 +1,84 @@ +pragma solidity 0.8.17; + +/// @title Chaosnet +/// @notice This is a beta staker program for stakers willing to go the extra +/// mile with monitoring, share their logs with the dev team, and allow to more +/// carefully monitor the bootstrapping network. As the network matures, the +/// beta program will be ended. +contract Chaosnet { + /// @notice Indicates if the chaosnet is active. The chaosnet is active + /// after the contract deployment and can be ended with a call to + /// `deactivateChaosnet()`. Once deactivated chaosnet can not be activated + /// again. + bool public isChaosnetActive; + + /// @notice Indicates if the given operator is a beta operator for chaosnet. + mapping(address => bool) public isBetaOperator; + + /// @notice Address controlling chaosnet status and beta operator addresses. + address public chaosnetOwner; + + event BetaOperatorsAdded(address[] operators); + + event ChaosnetOwnerRoleTransferred( + address oldChaosnetOwner, + address newChaosnetOwner + ); + + event ChaosnetDeactivated(); + + constructor() { + _transferChaosnetOwner(msg.sender); + isChaosnetActive = true; + } + + modifier onlyChaosnetOwner() { + require(msg.sender == chaosnetOwner, "Not the chaosnet owner"); + _; + } + + modifier onlyOnChaosnet() { + require(isChaosnetActive, "Chaosnet is not active"); + _; + } + + /// @notice Adds beta operator to chaosnet. Can be called only by the + /// chaosnet owner when the chaosnet is active. Once the operator is added + /// as a beta operator, it can not be removed. + function addBetaOperators(address[] calldata operators) + public + onlyOnChaosnet + onlyChaosnetOwner + { + for (uint256 i = 0; i < operators.length; i++) { + isBetaOperator[operators[i]] = true; + } + + emit BetaOperatorsAdded(operators); + } + + /// @notice Deactivates the chaosnet. Can be called only by the chaosnet + /// owner. Once deactivated chaosnet can not be activated again. + function deactivateChaosnet() public onlyOnChaosnet onlyChaosnetOwner { + isChaosnetActive = false; + emit ChaosnetDeactivated(); + } + + /// @notice Transfers the chaosnet owner role to another non-zero address. + function transferChaosnetOwnerRole(address newChaosnetOwner) + public + onlyChaosnetOwner + { + require( + newChaosnetOwner != address(0), + "New chaosnet owner must not be zero address" + ); + _transferChaosnetOwner(newChaosnetOwner); + } + + function _transferChaosnetOwner(address newChaosnetOwner) internal { + address oldChaosnetOwner = chaosnetOwner; + chaosnetOwner = newChaosnetOwner; + emit ChaosnetOwnerRoleTransferred(oldChaosnetOwner, newChaosnetOwner); + } +} diff --git a/solidity/ecdsa/contracts/legacy/sortition/Constants.sol b/solidity/ecdsa/contracts/legacy/sortition/Constants.sol new file mode 100644 index 0000000000..ce1ba7dacc --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/sortition/Constants.sol @@ -0,0 +1,32 @@ +pragma solidity 0.8.17; + +library Constants { + //////////////////////////////////////////////////////////////////////////// + // Parameters for configuration + + // How many bits a position uses per level of the tree; + // each branch of the tree contains 2**SLOT_BITS slots. + uint256 constant SLOT_BITS = 3; + uint256 constant LEVELS = 7; + //////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////// + // Derived constants, do not touch + uint256 constant SLOT_COUNT = 2**SLOT_BITS; + uint256 constant SLOT_WIDTH = 256 / SLOT_COUNT; + uint256 constant LAST_SLOT = SLOT_COUNT - 1; + uint256 constant SLOT_MAX = (2**SLOT_WIDTH) - 1; + uint256 constant POOL_CAPACITY = SLOT_COUNT**LEVELS; + + uint256 constant ID_WIDTH = SLOT_WIDTH; + uint256 constant ID_MAX = SLOT_MAX; + + uint256 constant BLOCKHEIGHT_WIDTH = 96 - ID_WIDTH; + uint256 constant BLOCKHEIGHT_MAX = (2**BLOCKHEIGHT_WIDTH) - 1; + + uint256 constant SLOT_POINTER_MAX = (2**SLOT_BITS) - 1; + uint256 constant LEAF_FLAG = 1 << 255; + + uint256 constant WEIGHT_WIDTH = 256 / SLOT_COUNT; + //////////////////////////////////////////////////////////////////////////// +} diff --git a/solidity/ecdsa/contracts/legacy/sortition/LICENSE b/solidity/ecdsa/contracts/legacy/sortition/LICENSE new file mode 100644 index 0000000000..3e7efefd1d --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/sortition/LICENSE @@ -0,0 +1,17 @@ +ISC License + +The upstream @keep-network/sortition-pools package declares the ISC license. +It distributes no separate copyright notice or license file. The original +package manifest and source provenance are recorded in VENDOR.json. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/solidity/ecdsa/contracts/legacy/sortition/Leaf.sol b/solidity/ecdsa/contracts/legacy/sortition/Leaf.sol new file mode 100644 index 0000000000..4b15a72a7b --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/sortition/Leaf.sol @@ -0,0 +1,44 @@ +pragma solidity 0.8.17; + +import "./Constants.sol"; + +library Leaf { + function make( + address _operator, + uint256 _creationBlock, + uint256 _id + ) internal pure returns (uint256) { + assert(_creationBlock <= type(uint64).max); + assert(_id <= type(uint32).max); + // Converting a bytesX type into a larger type + // adds zero bytes on the right. + uint256 op = uint256(bytes32(bytes20(_operator))); + // Bitwise AND the id to erase + // all but the 32 least significant bits + uint256 uid = _id & Constants.ID_MAX; + // Erase all but the 64 least significant bits, + // then shift left by 32 bits to make room for the id + uint256 cb = (_creationBlock & Constants.BLOCKHEIGHT_MAX) << + Constants.ID_WIDTH; + // Bitwise OR them all together to get + // [address operator || uint64 creationBlock || uint32 id] + return (op | cb | uid); + } + + function operator(uint256 leaf) internal pure returns (address) { + // Converting a bytesX type into a smaller type + // truncates it on the right. + return address(bytes20(bytes32(leaf))); + } + + /// @notice Return the block number the leaf was created in. + function creationBlock(uint256 leaf) internal pure returns (uint256) { + return ((leaf >> Constants.ID_WIDTH) & Constants.BLOCKHEIGHT_MAX); + } + + function id(uint256 leaf) internal pure returns (uint32) { + // Id is stored in the 32 least significant bits. + // Bitwise AND ensures that we only get the contents of those bits. + return uint32(leaf & Constants.ID_MAX); + } +} diff --git a/solidity/ecdsa/contracts/legacy/sortition/Position.sol b/solidity/ecdsa/contracts/legacy/sortition/Position.sol new file mode 100644 index 0000000000..0985a3777d --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/sortition/Position.sol @@ -0,0 +1,39 @@ +pragma solidity 0.8.17; + +import "./Constants.sol"; + +library Position { + // Return the last 3 bits of a position number, + // corresponding to its slot in its parent + function slot(uint256 a) internal pure returns (uint256) { + return a & Constants.SLOT_POINTER_MAX; + } + + // Return the parent of a position number + function parent(uint256 a) internal pure returns (uint256) { + return a >> Constants.SLOT_BITS; + } + + // Return the location of the child of a at the given slot + function child(uint256 a, uint256 s) internal pure returns (uint256) { + return (a << Constants.SLOT_BITS) | (s & Constants.SLOT_POINTER_MAX); // slot(s) + } + + // Return the uint p as a flagged position uint: + // the least significant 21 bits contain the position + // and the 22nd bit is set as a flag + // to distinguish the position 0x000000 from an empty field. + function setFlag(uint256 p) internal pure returns (uint256) { + return p | Constants.LEAF_FLAG; + } + + // Turn a flagged position into an unflagged position + // by removing the flag at the 22nd least significant bit. + // + // We shouldn't _actually_ need this + // as all position-manipulating code should ignore non-position bits anyway + // but it's cheap to call so might as well do it. + function unsetFlag(uint256 p) internal pure returns (uint256) { + return p & (~Constants.LEAF_FLAG); + } +} diff --git a/solidity/ecdsa/contracts/legacy/sortition/README.md b/solidity/ecdsa/contracts/legacy/sortition/README.md new file mode 100644 index 0000000000..e1568d73f5 --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/sortition/README.md @@ -0,0 +1,17 @@ +# Legacy sortition compatibility + +These are the frozen runtime sources from `@keep-network/sortition-pools@2.0.0`. +The runtime files are byte-identical in `2.0.0-pre.16`, previously locked by +Random Beacon. Only the two imports in SortitionPool point to local copies of +the Thesis interfaces; their transitive IApproveAndCall interface is retained too. +`VENDOR.json` records the source revision, package manifest, and original hashes. +Licenses and notices are retained alongside the components. + +The current source still needs this implementation for legacy ABI compatibility, +fixtures, and deployment replay. Its presence is not a statement about live +operator selection. Do not add new protocol features here or refresh from an +upstream branch. Retiring the implementation itself is a separate contract and +historical-deployment migration. + +Frozen legacy sources retain their prior dependency treatment in lint and Slither +filters; the original files were excluded under `node_modules/`. diff --git a/solidity/ecdsa/contracts/legacy/sortition/RNG.sol b/solidity/ecdsa/contracts/legacy/sortition/RNG.sol new file mode 100644 index 0000000000..3e02b4b9e0 --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/sortition/RNG.sol @@ -0,0 +1,94 @@ +pragma solidity 0.8.17; + +import "./Leaf.sol"; +import "./Constants.sol"; + +library RNG { + /// @notice Get an index in the range `[0 .. range-1]` + /// and the new state of the RNG, + /// using the provided `state` of the RNG. + /// + /// @param range The upper bound of the index, exclusive. + /// + /// @param state The previous state of the RNG. + /// The initial state needs to be obtained + /// from a trusted randomness oracle (the random beacon), + /// or from a chain of earlier calls to `RNG.getIndex()` + /// on an originally trusted seed. + /// + /// @dev Calculates the number of bits required for the desired range, + /// takes the least significant bits of `state` + /// and checks if the obtained index is within the desired range. + /// The original state is hashed with `keccak256` to get a new state. + /// If the index is outside the range, + /// the function retries until it gets a suitable index. + /// + /// @return index A random integer between `0` and `range - 1`, inclusive. + /// + /// @return newState The new state of the RNG. + /// When `getIndex()` is called one or more times, + /// care must be taken to always use the output `state` + /// of the most recent call as the input `state` of a subsequent call. + /// At the end of a transaction calling `RNG.getIndex()`, + /// the previous stored state must be overwritten with the latest output. + function getIndex( + uint256 range, + bytes32 state, + uint256 bits + ) internal view returns (uint256, bytes32) { + bool found = false; + uint256 index = 0; + bytes32 newState = state; + while (!found) { + index = truncate(bits, uint256(newState)); + newState = keccak256(abi.encodePacked(newState, address(this))); + if (index < range) { + found = true; + } + } + return (index, newState); + } + + /// @notice Calculate how many bits are required + /// for an index in the range `[0 .. range-1]`. + /// + /// @param range The upper bound of the desired range, exclusive. + /// + /// @return uint The smallest number of bits + /// that can contain the number `range-1`. + function bitsRequired(uint256 range) internal pure returns (uint256) { + unchecked { + if (range == 1) { + return 0; + } + + uint256 bits = Constants.WEIGHT_WIDTH - 1; + + // Left shift by `bits`, + // so we have a 1 in the (bits + 1)th least significant bit + // and 0 in other bits. + // If this number is equal or greater than `range`, + // the range [0, range-1] fits in `bits` bits. + // + // Because we loop from high bits to low bits, + // we find the highest number of bits that doesn't fit the range, + // and return that number + 1. + while (1 << bits >= range) { + bits--; + } + + return bits + 1; + } + } + + /// @notice Truncate `input` to the `bits` least significant bits. + function truncate(uint256 bits, uint256 input) + internal + pure + returns (uint256) + { + unchecked { + return input & ((1 << bits) - 1); + } + } +} diff --git a/solidity/ecdsa/contracts/legacy/sortition/Rewards.sol b/solidity/ecdsa/contracts/legacy/sortition/Rewards.sol new file mode 100644 index 0000000000..2583e364aa --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/sortition/Rewards.sol @@ -0,0 +1,218 @@ +pragma solidity 0.8.17; + +/// @title Rewards +/// @notice Rewards are allocated proportionally to operators +/// present in the pool at payout based on their weight in the pool. +/// +/// To facilitate this, we use a global accumulator value +/// to track the total rewards one unit of weight would've earned +/// since the creation of the pool. +/// +/// Whenever a reward is paid, the accumulator is increased +/// by the size of the reward divided by the total weight +/// of all eligible operators in the pool. +/// +/// Each operator has an individual accumulator value, +/// set to equal the global accumulator when the operator joins the pool. +/// This accumulator reflects the amount of rewards +/// that have already been accounted for with that operator. +/// +/// Whenever an operator's weight in the pool changes, +/// we can update the amount of rewards the operator has earned +/// by subtracting the operator's accumulator from the global accumulator. +/// This gives us the amount of rewards one unit of weight has earned +/// since the last time the operator's rewards have been updated. +/// Then we multiply that by the operator's previous (pre-change) weight +/// to determine how much rewards in total the operator has earned, +/// and add this to the operator's earned rewards. +/// Finally, we set the operator's accumulator to the global accumulator value. +contract Rewards { + struct OperatorRewards { + // The state of the global accumulator + // when the operator's rewards were last updated + uint96 accumulated; + // The amount of rewards collected by the operator after the latest update. + // The amount the operator could withdraw may equal `available` + // or it may be greater, if more rewards have been paid in since then. + // To evaulate the most recent amount including rewards potentially paid + // since the last update, use `availableRewards` function. + uint96 available; + // If nonzero, the operator is ineligible for rewards + // and may only re-enable rewards after the specified timestamp. + // XXX: unsigned 32-bit integer unix seconds, will break around 2106 + uint32 ineligibleUntil; + // Locally cached weight of the operator, + // used to reduce the cost of setting operators ineligible. + uint32 weight; + } + + // The global accumulator of how much rewards + // a hypothetical operator of weight 1 would have earned + // since the creation of the pool. + uint96 internal globalRewardAccumulator; + // If the amount of reward tokens paid in + // does not divide cleanly by pool weight, + // the difference is recorded as rounding dust + // and added to the next reward. + uint96 internal rewardRoundingDust; + + // The amount of rewards that would've been earned by ineligible operators + // had they not been ineligible. + uint96 public ineligibleEarnedRewards; + + // Ineligibility times are calculated from this offset, + // set at contract creation. + uint256 internal immutable ineligibleOffsetStart; + + mapping(uint32 => OperatorRewards) internal operatorRewards; + + constructor() { + // solhint-disable-next-line not-rely-on-time + ineligibleOffsetStart = block.timestamp; + } + + /// @notice Return whether the operator is eligible for rewards or not. + function isEligibleForRewards(uint32 operator) internal view returns (bool) { + return operatorRewards[operator].ineligibleUntil == 0; + } + + /// @notice Return the time the operator's reward eligibility can be restored. + function rewardsEligibilityRestorableAt(uint32 operator) + internal + view + returns (uint256) + { + uint32 until = operatorRewards[operator].ineligibleUntil; + require(until != 0, "Operator already eligible"); + return (uint256(until) + ineligibleOffsetStart); + } + + /// @notice Return whether the operator is able to restore their eligibility + /// for rewards right away. + function canRestoreRewardEligibility(uint32 operator) + internal + view + returns (bool) + { + // solhint-disable-next-line not-rely-on-time + return rewardsEligibilityRestorableAt(operator) <= block.timestamp; + } + + /// @notice Internal function for updating the global state of rewards. + function addRewards(uint96 rewardAmount, uint32 currentPoolWeight) internal { + require(currentPoolWeight > 0, "No recipients in pool"); + + uint96 totalAmount = rewardAmount + rewardRoundingDust; + uint96 perWeightReward = totalAmount / currentPoolWeight; + uint96 newRoundingDust = totalAmount % currentPoolWeight; + + globalRewardAccumulator += perWeightReward; + rewardRoundingDust = newRoundingDust; + } + + /// @notice Internal function for updating the operator's reward state. + function updateOperatorRewards(uint32 operator, uint32 newWeight) internal { + uint96 acc = globalRewardAccumulator; + OperatorRewards memory o = operatorRewards[operator]; + uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight); + if (o.ineligibleUntil == 0) { + // If operator is not ineligible, update their earned rewards + o.available += accruedRewards; + } else { + // If ineligible, put the rewards into the ineligible pot + ineligibleEarnedRewards += accruedRewards; + } + // In any case, update their accumulator and weight + o.accumulated = acc; + o.weight = newWeight; + operatorRewards[operator] = o; + } + + /// @notice Set the amount of withdrawable tokens to zero + /// and return the previous withdrawable amount. + /// @dev Does not update the withdrawable amount, + /// but should usually be accompanied by an update. + function withdrawOperatorRewards(uint32 operator) + internal + returns (uint96 withdrawable) + { + OperatorRewards storage o = operatorRewards[operator]; + withdrawable = o.available; + o.available = 0; + } + + /// @notice Set the amount of ineligible-earned tokens to zero + /// and return the previous amount. + function withdrawIneligibleRewards() internal returns (uint96 withdrawable) { + withdrawable = ineligibleEarnedRewards; + ineligibleEarnedRewards = 0; + } + + /// @notice Set the given operators as ineligible for rewards. + /// The operators can restore their eligibility at the given time. + function setIneligible(uint32[] memory operators, uint256 until) internal { + OperatorRewards memory o = OperatorRewards(0, 0, 0, 0); + uint96 globalAcc = globalRewardAccumulator; + uint96 accrued = 0; + // Record ineligibility as seconds after contract creation + uint32 _until = uint32(until - ineligibleOffsetStart); + + for (uint256 i = 0; i < operators.length; i++) { + uint32 operator = operators[i]; + OperatorRewards storage r = operatorRewards[operator]; + o.available = r.available; + o.accumulated = r.accumulated; + o.ineligibleUntil = r.ineligibleUntil; + o.weight = r.weight; + + if (o.ineligibleUntil != 0) { + // If operator is already ineligible, + // don't earn rewards or shorten its ineligibility + if (o.ineligibleUntil < _until) { + o.ineligibleUntil = _until; + } + } else { + // The operator becomes ineligible -> earn rewards + o.ineligibleUntil = _until; + accrued = (globalAcc - o.accumulated) * uint96(o.weight); + o.available += accrued; + } + o.accumulated = globalAcc; + + r.available = o.available; + r.accumulated = o.accumulated; + r.ineligibleUntil = o.ineligibleUntil; + r.weight = o.weight; + } + } + + /// @notice Restore the given operator's eligibility for rewards. + function restoreEligibility(uint32 operator) internal { + // solhint-disable-next-line not-rely-on-time + require(canRestoreRewardEligibility(operator), "Operator still ineligible"); + uint96 acc = globalRewardAccumulator; + OperatorRewards memory o = operatorRewards[operator]; + uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight); + ineligibleEarnedRewards += accruedRewards; + o.accumulated = acc; + o.ineligibleUntil = 0; + operatorRewards[operator] = o; + } + + /// @notice Returns the amount of rewards currently available for withdrawal + /// for the given operator. + function availableRewards(uint32 operator) internal view returns (uint96) { + uint96 acc = globalRewardAccumulator; + OperatorRewards memory o = operatorRewards[operator]; + if (o.ineligibleUntil == 0) { + // If operator is not ineligible, calculate newly accrued rewards and add + // them to the available ones, calculated during the last update. + uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight); + return o.available + accruedRewards; + } else { + // If ineligible, return only the rewards calculated during the last + // update. + return o.available; + } + } +} diff --git a/solidity/ecdsa/contracts/legacy/sortition/SortitionPool.sol b/solidity/ecdsa/contracts/legacy/sortition/SortitionPool.sol new file mode 100644 index 0000000000..fd35bc942b --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/sortition/SortitionPool.sol @@ -0,0 +1,269 @@ +pragma solidity 0.8.17; + +import "./interfaces/IERC20WithPermit.sol"; +import "./interfaces/IReceiveApproval.sol"; + +import "@openzeppelin/contracts/access/Ownable.sol"; + +import "./RNG.sol"; +import "./SortitionTree.sol"; +import "./Rewards.sol"; +import "./Chaosnet.sol"; + +/// @title Sortition Pool +/// @notice A logarithmic data structure used to store the pool of eligible +/// operators weighted by their stakes. It allows to select a group of operators +/// based on the provided pseudo-random seed. +contract SortitionPool is + SortitionTree, + Rewards, + Ownable, + Chaosnet, + IReceiveApproval +{ + using Branch for uint256; + using Leaf for uint256; + using Position for uint256; + + IERC20WithPermit public immutable rewardToken; + + uint256 public immutable poolWeightDivisor; + + bool public isLocked; + + event IneligibleForRewards(uint32[] ids, uint256 until); + + event RewardEligibilityRestored(address indexed operator, uint32 indexed id); + + /// @notice Reverts if called while pool is locked. + modifier onlyUnlocked() { + require(!isLocked, "Sortition pool locked"); + _; + } + + /// @notice Reverts if called while pool is unlocked. + modifier onlyLocked() { + require(isLocked, "Sortition pool unlocked"); + _; + } + + constructor(IERC20WithPermit _rewardToken, uint256 _poolWeightDivisor) { + rewardToken = _rewardToken; + poolWeightDivisor = _poolWeightDivisor; + } + + function receiveApproval( + address sender, + uint256 amount, + address token, + bytes calldata + ) external override { + require(token == address(rewardToken), "Unsupported token"); + rewardToken.transferFrom(sender, address(this), amount); + Rewards.addRewards(uint96(amount), uint32(root.sumWeight())); + } + + /// @notice Withdraws all available rewards for the given operator to the + /// given beneficiary. + /// @dev Can be called only be the owner. Does not validate if the provided + /// beneficiary is associated with the provided operator - this needs to + /// be done by the owner calling this function. + /// @return The amount of rewards withdrawn in this call. + function withdrawRewards(address operator, address beneficiary) + public + onlyOwner + returns (uint96) + { + uint32 id = getOperatorID(operator); + Rewards.updateOperatorRewards(id, uint32(getPoolWeight(operator))); + uint96 earned = Rewards.withdrawOperatorRewards(id); + rewardToken.transfer(beneficiary, uint256(earned)); + return earned; + } + + /// @notice Withdraws rewards not allocated to operators marked as ineligible + /// to the given recipient address. + /// @dev Can be called only by the owner. + function withdrawIneligible(address recipient) public onlyOwner { + uint96 earned = Rewards.withdrawIneligibleRewards(); + rewardToken.transfer(recipient, uint256(earned)); + } + + /// @notice Locks the sortition pool. In locked state, members cannot be + /// inserted and removed from the pool. Members statuses cannot + /// be updated as well. + /// @dev Can be called only by the contract owner. + function lock() public onlyOwner { + isLocked = true; + } + + /// @notice Unlocks the sortition pool. Removes all restrictions set by + /// the `lock` method. + /// @dev Can be called only by the contract owner. + function unlock() public onlyOwner { + isLocked = false; + } + + /// @notice Inserts an operator to the pool. Reverts if the operator is + /// already present. Reverts if the operator is not eligible because of their + /// authorized stake. Reverts if the chaosnet is active and the operator is + /// not a beta operator. + /// @dev Can be called only by the contract owner. + /// @param operator Address of the inserted operator. + /// @param authorizedStake Inserted operator's authorized stake for the application. + function insertOperator(address operator, uint256 authorizedStake) + public + onlyOwner + onlyUnlocked + { + uint256 weight = getWeight(authorizedStake); + require(weight > 0, "Operator not eligible"); + + if (isChaosnetActive) { + require(isBetaOperator[operator], "Not beta operator for chaosnet"); + } + + _insertOperator(operator, weight); + uint32 id = getOperatorID(operator); + Rewards.updateOperatorRewards(id, uint32(weight)); + } + + /// @notice Update the operator's weight if present and eligible, + /// or remove from the pool if present and ineligible. + /// @dev Can be called only by the contract owner. + /// @param operator Address of the updated operator. + /// @param authorizedStake Operator's authorized stake for the application. + function updateOperatorStatus(address operator, uint256 authorizedStake) + public + onlyOwner + onlyUnlocked + { + uint256 weight = getWeight(authorizedStake); + + uint32 id = getOperatorID(operator); + Rewards.updateOperatorRewards(id, uint32(weight)); + + if (weight == 0) { + _removeOperator(operator); + } else { + updateOperator(operator, weight); + } + } + + /// @notice Set the given operators as ineligible for rewards. + /// The operators can restore their eligibility at the given time. + function setRewardIneligibility(uint32[] calldata operators, uint256 until) + public + onlyOwner + { + Rewards.setIneligible(operators, until); + emit IneligibleForRewards(operators, until); + } + + /// @notice Restores reward eligibility for the operator. + function restoreRewardEligibility(address operator) public { + uint32 id = getOperatorID(operator); + Rewards.restoreEligibility(id); + emit RewardEligibilityRestored(operator, id); + } + + /// @notice Returns whether the operator is eligible for rewards or not. + function isEligibleForRewards(address operator) public view returns (bool) { + uint32 id = getOperatorID(operator); + return Rewards.isEligibleForRewards(id); + } + + /// @notice Returns the time the operator's reward eligibility can be restored. + function rewardsEligibilityRestorableAt(address operator) + public + view + returns (uint256) + { + uint32 id = getOperatorID(operator); + return Rewards.rewardsEligibilityRestorableAt(id); + } + + /// @notice Returns whether the operator is able to restore their eligibility + /// for rewards right away. + function canRestoreRewardEligibility(address operator) + public + view + returns (bool) + { + uint32 id = getOperatorID(operator); + return Rewards.canRestoreRewardEligibility(id); + } + + /// @notice Returns the amount of rewards withdrawable for the given operator. + function getAvailableRewards(address operator) public view returns (uint96) { + uint32 id = getOperatorID(operator); + return availableRewards(id); + } + + /// @notice Return whether the operator is present in the pool. + function isOperatorInPool(address operator) public view returns (bool) { + return getFlaggedLeafPosition(operator) != 0; + } + + /// @notice Return whether the operator's weight in the pool + /// matches their eligible weight. + function isOperatorUpToDate(address operator, uint256 authorizedStake) + public + view + returns (bool) + { + return getWeight(authorizedStake) == getPoolWeight(operator); + } + + /// @notice Return the weight of the operator in the pool, + /// which may or may not be out of date. + function getPoolWeight(address operator) public view returns (uint256) { + uint256 flaggedPosition = getFlaggedLeafPosition(operator); + if (flaggedPosition == 0) { + return 0; + } else { + uint256 leafPosition = flaggedPosition.unsetFlag(); + uint256 leafWeight = getLeafWeight(leafPosition); + return leafWeight; + } + } + + /// @notice Selects a new group of operators of the provided size based on + /// the provided pseudo-random seed. At least one operator has to be + /// registered in the pool, otherwise the function fails reverting the + /// transaction. + /// @param groupSize Size of the requested group + /// @param seed Pseudo-random number used to select operators to group + /// @return selected Members of the selected group + function selectGroup(uint256 groupSize, bytes32 seed) + public + view + onlyLocked + returns (uint32[] memory) + { + uint256 _root = root; + + bytes32 rngState = seed; + uint256 rngRange = _root.sumWeight(); + require(rngRange > 0, "Not enough operators in pool"); + uint256 currentIndex; + + uint256 bits = RNG.bitsRequired(rngRange); + + uint32[] memory selected = new uint32[](groupSize); + + for (uint256 i = 0; i < groupSize; i++) { + (currentIndex, rngState) = RNG.getIndex(rngRange, rngState, bits); + + uint256 leafPosition = pickWeightedLeaf(currentIndex, _root); + + uint256 leaf = leaves[leafPosition]; + selected[i] = leaf.id(); + } + return selected; + } + + function getWeight(uint256 authorization) internal view returns (uint256) { + return authorization / poolWeightDivisor; + } +} diff --git a/solidity/ecdsa/contracts/legacy/sortition/SortitionTree.sol b/solidity/ecdsa/contracts/legacy/sortition/SortitionTree.sol new file mode 100644 index 0000000000..a4247b2821 --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/sortition/SortitionTree.sol @@ -0,0 +1,368 @@ +pragma solidity 0.8.17; + +import "./Branch.sol"; +import "./Position.sol"; +import "./Leaf.sol"; +import "./Constants.sol"; + +contract SortitionTree { + using Branch for uint256; + using Position for uint256; + using Leaf for uint256; + + // implicit tree + // root 8 + // level2 64 + // level3 512 + // level4 4k + // level5 32k + // level6 256k + // level7 2M + uint256 internal root; + + // A 2-index mapping from layer => (index (0-index) => branch). For example, + // to access the 6th branch in the 2nd layer (right below the root node; the + // first branch layer), call branches[2][5]. Mappings are used in place of + // arrays for efficiency. The root is the first layer, the branches occupy + // layers 2 through 7, and layer 8 is for the leaves. Following this + // convention, the first index in `branches` is `2`, and the last index is + // `7`. + mapping(uint256 => mapping(uint256 => uint256)) internal branches; + + // A 0-index mapping from index => leaf, acting as an array. For example, to + // access the 42nd leaf, call leaves[41]. + mapping(uint256 => uint256) internal leaves; + + // the flagged (see setFlag() and unsetFlag() in Position.sol) positions + // of all operators present in the pool + mapping(address => uint256) internal flaggedLeafPosition; + + // the leaf after the rightmost occupied leaf of each stack + uint256 internal rightmostLeaf; + + // the empty leaves in each stack + // between 0 and the rightmost occupied leaf + uint256[] internal emptyLeaves; + + // Each operator has an uint32 ID number + // which is allocated when they first join the pool + // and remains unchanged even if they leave and rejoin the pool. + mapping(address => uint32) internal operatorID; + + // The idAddress array records the address corresponding to each ID number. + // The ID number 0 is initialized with a zero address and is not used. + address[] internal idAddress; + + constructor() { + root = 0; + rightmostLeaf = 0; + idAddress.push(); + } + + /// @notice Return the ID number of the given operator address. An ID number + /// of 0 means the operator has not been allocated an ID number yet. + /// @param operator Address of the operator. + /// @return the ID number of the given operator address + function getOperatorID(address operator) public view returns (uint32) { + return operatorID[operator]; + } + + /// @notice Get the operator address corresponding to the given ID number. A + /// zero address means the ID number has not been allocated yet. + /// @param id ID of the operator + /// @return the address of the operator + function getIDOperator(uint32 id) public view returns (address) { + return idAddress.length > id ? idAddress[id] : address(0); + } + + /// @notice Gets the operator addresses corresponding to the given ID + /// numbers. A zero address means the ID number has not been allocated yet. + /// This function works just like getIDOperator except that it allows to fetch + /// operator addresses for multiple IDs in one call. + /// @param ids the array of the operator ids + /// @return an array of the associated operator addresses + function getIDOperators(uint32[] calldata ids) + public + view + returns (address[] memory) + { + uint256 idCount = idAddress.length; + + address[] memory operators = new address[](ids.length); + for (uint256 i = 0; i < ids.length; i++) { + uint32 id = ids[i]; + operators[i] = idCount > id ? idAddress[id] : address(0); + } + return operators; + } + + /// @notice Checks if operator is already registered in the pool. + /// @param operator the address of the operator + /// @return whether or not the operator is already registered in the pool + function isOperatorRegistered(address operator) public view returns (bool) { + return getFlaggedLeafPosition(operator) != 0; + } + + /// @notice Sum the number of operators in each trunk. + /// @return the number of operators in the pool + function operatorsInPool() public view returns (uint256) { + // Get the number of leaves that might be occupied; + // if `rightmostLeaf` equals `firstLeaf()` the tree must be empty, + // otherwise the difference between these numbers + // gives the number of leaves that may be occupied. + uint256 nPossiblyUsedLeaves = rightmostLeaf; + // Get the number of empty leaves + // not accounted for by the `rightmostLeaf` + uint256 nEmptyLeaves = emptyLeaves.length; + + return (nPossiblyUsedLeaves - nEmptyLeaves); + } + + /// @notice Convenience method to return the total weight of the pool + /// @return the total weight of the pool + function totalWeight() public view returns (uint256) { + return root.sumWeight(); + } + + /// @notice Give the operator a new ID number. + /// Does not check if the operator already has an ID number. + /// @param operator the address of the operator + /// @return a new ID for that operator + function allocateOperatorID(address operator) internal returns (uint256) { + uint256 id = idAddress.length; + + require(id <= type(uint32).max, "Pool capacity exceeded"); + + operatorID[operator] = uint32(id); + idAddress.push(operator); + return id; + } + + /// @notice Inserts an operator into the sortition pool + /// @param operator the address of an operator to insert + /// @param weight how much weight that operator has in the pool + function _insertOperator(address operator, uint256 weight) internal { + require( + !isOperatorRegistered(operator), + "Operator is already registered in the pool" + ); + + // Fetch the operator's ID, and if they don't have one, allocate them one. + uint256 id = getOperatorID(operator); + if (id == 0) { + id = allocateOperatorID(operator); + } + + // Determine which leaf to insert them into + uint256 position = getEmptyLeafPosition(); + // Record the block the operator was inserted in + uint256 theLeaf = Leaf.make(operator, block.number, id); + + // Update the leaf, and propagate the weight changes all the way up to the + // root. + root = setLeaf(position, theLeaf, weight, root); + + // Without position flags, + // the position 0x000000 would be treated as empty + flaggedLeafPosition[operator] = position.setFlag(); + } + + /// @notice Remove an operator (and their weight) from the pool. + /// @param operator the address of the operator to remove + function _removeOperator(address operator) internal { + uint256 flaggedPosition = getFlaggedLeafPosition(operator); + require(flaggedPosition != 0, "Operator is not registered in the pool"); + uint256 unflaggedPosition = flaggedPosition.unsetFlag(); + + // Update the leaf, and propagate the weight changes all the way up to the + // root. + root = removeLeaf(unflaggedPosition, root); + removeLeafPositionRecord(operator); + } + + /// @notice Update an operator's weight in the pool. + /// @param operator the address of the operator to update + /// @param weight the new weight + function updateOperator(address operator, uint256 weight) internal { + require( + isOperatorRegistered(operator), + "Operator is not registered in the pool" + ); + + uint256 flaggedPosition = getFlaggedLeafPosition(operator); + uint256 unflaggedPosition = flaggedPosition.unsetFlag(); + root = updateLeaf(unflaggedPosition, weight, root); + } + + /// @notice Helper method to remove a leaf position record for an operator. + /// @param operator the address of the operator to remove the record for + function removeLeafPositionRecord(address operator) internal { + flaggedLeafPosition[operator] = 0; + } + + /// @notice Removes the data and weight from a particular leaf. + /// @param position the leaf index to remove + /// @param _root the root node containing the leaf + /// @return the updated root node + function removeLeaf(uint256 position, uint256 _root) + internal + returns (uint256) + { + uint256 rightmostSubOne = rightmostLeaf - 1; + bool isRightmost = position == rightmostSubOne; + + // Clears out the data in the leaf node, and then propagates the weight + // changes all the way up to the root. + uint256 newRoot = setLeaf(position, 0, 0, _root); + + // Infer if need to fall back on emptyLeaves yet + if (isRightmost) { + rightmostLeaf = rightmostSubOne; + } else { + emptyLeaves.push(position); + } + return newRoot; + } + + /// @notice Updates the tree to give a particular leaf a new weight. + /// @param position the index of the leaf to update + /// @param weight the new weight + /// @param _root the root node containing the leaf + /// @return the updated root node + function updateLeaf( + uint256 position, + uint256 weight, + uint256 _root + ) internal returns (uint256) { + if (getLeafWeight(position) != weight) { + return updateTree(position, weight, _root); + } else { + return _root; + } + } + + /// @notice Places a leaf into a particular position, with a given weight and + /// propagates that change. + /// @param position the index to place the leaf in + /// @param theLeaf the new leaf to place in the position + /// @param leafWeight the weight of the leaf + /// @param _root the root containing the new leaf + /// @return the updated root node + function setLeaf( + uint256 position, + uint256 theLeaf, + uint256 leafWeight, + uint256 _root + ) internal returns (uint256) { + // set leaf + leaves[position] = theLeaf; + + return (updateTree(position, leafWeight, _root)); + } + + /// @notice Propagates a weight change at a position through the tree, + /// eventually returning the updated root. + /// @param position the index of leaf to update + /// @param weight the new weight of the leaf + /// @param _root the root node containing the leaf + /// @return the updated root node + function updateTree( + uint256 position, + uint256 weight, + uint256 _root + ) internal returns (uint256) { + uint256 childSlot; + uint256 treeNode; + uint256 newNode; + uint256 nodeWeight = weight; + + uint256 parent = position; + // set levels 7 to 2 + for (uint256 level = Constants.LEVELS; level >= 2; level--) { + childSlot = parent.slot(); + parent = parent.parent(); + treeNode = branches[level][parent]; + newNode = treeNode.setSlot(childSlot, nodeWeight); + branches[level][parent] = newNode; + nodeWeight = newNode.sumWeight(); + } + + // set level Root + childSlot = parent.slot(); + return _root.setSlot(childSlot, nodeWeight); + } + + /// @notice Retrieves the next available empty leaf position. Tries to fill + /// left to right first, ignoring leaf removals, and then fills + /// most-recent-removals first. + /// @return the position of the empty leaf + function getEmptyLeafPosition() internal returns (uint256) { + uint256 rLeaf = rightmostLeaf; + bool spaceOnRight = (rLeaf + 1) < Constants.POOL_CAPACITY; + if (spaceOnRight) { + rightmostLeaf = rLeaf + 1; + return rLeaf; + } else { + uint256 emptyLeafCount = emptyLeaves.length; + require(emptyLeafCount > 0, "Pool is full"); + uint256 emptyLeaf = emptyLeaves[emptyLeafCount - 1]; + emptyLeaves.pop(); + return emptyLeaf; + } + } + + /// @notice Gets the flagged leaf position for an operator. + /// @param operator the address of the operator + /// @return the leaf position of that operator + function getFlaggedLeafPosition(address operator) + internal + view + returns (uint256) + { + return flaggedLeafPosition[operator]; + } + + /// @notice Gets the weight of a leaf at a particular position. + /// @param position the index of the leaf + /// @return the weight of the leaf at that position + function getLeafWeight(uint256 position) internal view returns (uint256) { + uint256 slot = position.slot(); + uint256 parent = position.parent(); + + // A leaf's weight information is stored a 32-bit slot in the branch layer + // directly above the leaf layer. To access it, we calculate that slot and + // parent position, and always know the hard-coded layer index. + uint256 node = branches[Constants.LEVELS][parent]; + return node.getSlot(slot); + } + + /// @notice Picks a leaf given a random index. + /// @param index a number in `[0, _root.totalWeight())` used to decide + /// between leaves + /// @param _root the root of the tree + function pickWeightedLeaf(uint256 index, uint256 _root) + internal + view + returns (uint256 leafPosition) + { + uint256 currentIndex = index; + uint256 currentNode = _root; + uint256 currentPosition = 0; + uint256 currentSlot; + + require(index < currentNode.sumWeight(), "Index exceeds weight"); + + // get root slot + (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex); + + // get slots from levels 2 to 7 + for (uint256 level = 2; level <= Constants.LEVELS; level++) { + currentPosition = currentPosition.child(currentSlot); + currentNode = branches[level][currentPosition]; + (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex); + } + + // get leaf position + leafPosition = currentPosition.child(currentSlot); + } +} diff --git a/solidity/ecdsa/contracts/legacy/sortition/VENDOR.json b/solidity/ecdsa/contracts/legacy/sortition/VENDOR.json new file mode 100644 index 0000000000..6aa1aa0d58 --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/sortition/VENDOR.json @@ -0,0 +1,101 @@ +{ + "package": "@keep-network/sortition-pools", + "version": "2.0.0", + "upstreamCommit": "8048806a05826785075a926485e0320a7bb75745", + "upstreamPackageManifest": { + "name": "@keep-network/sortition-pools", + "version": "2.0.0", + "description": "", + "main": "truffle-config.js", + "directories": { + "test": "test" + }, + "files": [ + "contracts/**/*.sol", + "migrations/scripts" + ], + "scripts": { + "build": "hardhat compile", + "ganache": "echo 'GANACHE IS NO LONGER USED; use buidler-vm script instead'", + "test": "hardhat test", + "lint": "npm run lint:js && npm run lint:sol", + "lint:fix": "npm run lint:fix:js && npm run lint:fix:sol", + "lint:js": "eslint ${npm_package_config_eslintPaths}", + "lint:fix:js": "eslint --fix ${npm_package_config_eslintPaths}", + "lint:sol": "solhint 'contracts/**/*.sol' && prettier --list-different **/*.sol", + "lint:fix:sol": "solhint 'contracts/**/*.sol' --fix && prettier --write **/*.sol" + }, + "config": { + "eslintPaths": "test/ migrations/" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/keep-network/sortition-pools.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/keep-network/sortition-pools/issues" + }, + "homepage": "https://github.com/keep-network/sortition-pools#readme", + "dependencies": { + "@openzeppelin/contracts": "^4.3.2", + "@thesis/solidity-contracts": "github:thesis/solidity-contracts#4985bcf" + }, + "devDependencies": { + "@keep-network/hardhat-helpers": "^0.2.0-pre", + "@keep-network/hardhat-local-networks-config": "0.1.0-pre.0", + "@keep-network/prettier-config-keep": "github:keep-network/prettier-config-keep#d6ec02e", + "@nomiclabs/hardhat-ethers": "^2.0.2", + "@nomiclabs/hardhat-etherscan": "^2.1.6", + "@nomiclabs/hardhat-waffle": "^2.0.1", + "@nomiclabs/buidler": "^1.4.5", + "@openzeppelin/test-helpers": "^0.5.4", + "@types/chai": "^4.2.20", + "@types/mocha": "^8.2.3", + "@types/node": "^16.0.1", + "bn-chai": "^1.0.1", + "chai": "^4.2.0", + "eslint": "^6.8.0", + "eslint-config-keep": "github:keep-network/eslint-config-keep#0.3.0", + "ethereum-waffle": "^3.4.0", + "ethers": "^5.0.32", + "ethlint": "^1.2.5", + "hardhat": "^2.6.4", + "hardhat-deploy": "^0.9.1", + "hardhat-gas-reporter": "^1.0.8", + "prettier": "^2.3.2", + "prettier-plugin-solidity": "^1.0.0-beta.14", + "solc": "0.8.6", + "solhint": "^3.3.6", + "solhint-config-keep": "github:keep-network/solhint-config-keep", + "truffle": "^5.4.14", + "ts-node": "^10.0.0", + "typescript": "^4.3.5" + } + }, + "sourceSha256": { + "package/contracts/Branch.sol": "0aec2214f3ff1f8c4494baa95eba565644ab1eb6b6688ac20c55ca5da0ef1363", + "package/contracts/Chaosnet.sol": "5400c070de2b775d222ebf0a8633a05d237509b050399ad3468d853f7de2c750", + "package/contracts/Constants.sol": "1e7897b3beaff2b6ae99a214c363d6844e90aff6ef6fdf752b5ed3f6f294e9d1", + "package/contracts/Leaf.sol": "362f02f24d0a4429bea86051b881fe34ae75d6fbb7af29322cc87e324397a659", + "package/contracts/Position.sol": "8bb4ad218deb3a3faafeddc63e4186a27cc550c1c527a3b62751685fd0b97cf6", + "package/contracts/Rewards.sol": "6068ce09b1831411a47b3c25a0ac91725d44057b7c3cb3c5689b6627c191a6d8", + "package/contracts/RNG.sol": "005d1a3beab5b49083ad8dfad1f85baea08cd7119512977d91187bc42b9b22f5", + "package/contracts/SortitionPool.sol": "d81d8cad798e53745bec0b71c0bfd0b2a32c0f8678165048eb9142d9c8114221", + "package/contracts/SortitionTree.sol": "ca43b3e7c8ee362d787f0d12262d397fe916973d9015d738e534751fb1025521" + }, + "interfaceSha256": { + "IApproveAndCall.sol": "211e50c2984546d5ad4ff78991beb2ce344c0573d203fb505132903715991597", + "IERC20WithPermit.sol": "8fa746c4fa1820230c91eec5689c1026bb6369e0ec9ed01976be1b8cdf09bb47", + "IReceiveApproval.sol": "158a8fe35674f1edf2e58223ae9dc7da58b317cc2be3f4cf8e7996ccfcafad6e" + }, + "changes": [ + "Only the two Thesis interface import paths were made local." + ], + "interfaces": { + "repository": "https://github.com/thesis/solidity-contracts", + "revision": "4985bcf" + }, + "compatibility": "Runtime Solidity sources are identical in 2.0.0 and 2.0.0-pre.16." +} diff --git a/solidity/ecdsa/contracts/legacy/sortition/interfaces/IApproveAndCall.sol b/solidity/ecdsa/contracts/legacy/sortition/interfaces/IApproveAndCall.sol new file mode 100644 index 0000000000..bccb1ac658 --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/sortition/interfaces/IApproveAndCall.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.4; + +/// @notice An interface that should be implemented by tokens supporting +/// `approveAndCall`/`receiveApproval` pattern. +interface IApproveAndCall { + /// @notice Executes `receiveApproval` function on spender as specified in + /// `IReceiveApproval` interface. Approves spender to withdraw from + /// the caller multiple times, up to the `amount`. If this + /// function is called again, it overwrites the current allowance + /// with `amount`. Reverts if the approval reverted or if + /// `receiveApproval` call on the spender reverted. + function approveAndCall( + address spender, + uint256 amount, + bytes memory extraData + ) external returns (bool); +} diff --git a/solidity/ecdsa/contracts/legacy/sortition/interfaces/IERC20WithPermit.sol b/solidity/ecdsa/contracts/legacy/sortition/interfaces/IERC20WithPermit.sol new file mode 100644 index 0000000000..80693f9543 --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/sortition/interfaces/IERC20WithPermit.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.4; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; + +import "./IApproveAndCall.sol"; + +/// @title IERC20WithPermit +/// @notice Burnable ERC20 token with EIP2612 permit functionality. User can +/// authorize a transfer of their token with a signature conforming +/// EIP712 standard instead of an on-chain transaction from their +/// address. Anyone can submit this signature on the user's behalf by +/// calling the permit function, as specified in EIP2612 standard, +/// paying gas fees, and possibly performing other actions in the same +/// transaction. +interface IERC20WithPermit is IERC20, IERC20Metadata, IApproveAndCall { + /// @notice EIP2612 approval made with secp256k1 signature. + /// Users can authorize a transfer of their tokens with a signature + /// conforming EIP712 standard, rather than an on-chain transaction + /// from their address. Anyone can submit this signature on the + /// user's behalf by calling the permit function, paying gas fees, + /// and possibly performing other actions in the same transaction. + /// @dev The deadline argument can be set to `type(uint256).max to create + /// permits that effectively never expire. + function permit( + address owner, + address spender, + uint256 amount, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + /// @notice Destroys `amount` tokens from the caller. + function burn(uint256 amount) external; + + /// @notice Destroys `amount` of tokens from `account`, deducting the amount + /// from caller's allowance. + function burnFrom(address account, uint256 amount) external; + + /// @notice Returns hash of EIP712 Domain struct with the token name as + /// a signing domain and token contract as a verifying contract. + /// Used to construct EIP2612 signature provided to `permit` + /// function. + /* solhint-disable-next-line func-name-mixedcase */ + function DOMAIN_SEPARATOR() external view returns (bytes32); + + /// @notice Returns the current nonce for EIP2612 permission for the + /// provided token owner for a replay protection. Used to construct + /// EIP2612 signature provided to `permit` function. + function nonce(address owner) external view returns (uint256); + + /// @notice Returns EIP2612 Permit message hash. Used to construct EIP2612 + /// signature provided to `permit` function. + /* solhint-disable-next-line func-name-mixedcase */ + function PERMIT_TYPEHASH() external pure returns (bytes32); +} diff --git a/solidity/ecdsa/contracts/legacy/sortition/interfaces/IReceiveApproval.sol b/solidity/ecdsa/contracts/legacy/sortition/interfaces/IReceiveApproval.sol new file mode 100644 index 0000000000..0aa4c01d1b --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/sortition/interfaces/IReceiveApproval.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.4; + +/// @notice An interface that should be implemented by contracts supporting +/// `approveAndCall`/`receiveApproval` pattern. +interface IReceiveApproval { + /// @notice Receives approval to spend tokens. Called as a result of + /// `approveAndCall` call on the token. + function receiveApproval( + address from, + uint256 amount, + address token, + bytes calldata extraData + ) external; +} diff --git a/solidity/ecdsa/contracts/legacy/sortition/interfaces/LICENSE b/solidity/ecdsa/contracts/legacy/sortition/interfaces/LICENSE new file mode 100644 index 0000000000..e1cd72518a --- /dev/null +++ b/solidity/ecdsa/contracts/legacy/sortition/interfaces/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Thesis + +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/solidity/ecdsa/contracts/libraries/EcdsaAuthorization.sol b/solidity/ecdsa/contracts/libraries/EcdsaAuthorization.sol index 49f5ed0ef8..4ed54aee56 100644 --- a/solidity/ecdsa/contracts/libraries/EcdsaAuthorization.sol +++ b/solidity/ecdsa/contracts/libraries/EcdsaAuthorization.sol @@ -14,7 +14,7 @@ pragma solidity 0.8.17; -import "@keep-network/sortition-pools/contracts/SortitionPool.sol"; +import "../legacy/sortition/SortitionPool.sol"; import "@threshold-network/solidity-contracts/contracts/staking/IStaking.sol"; /// @notice Library managing the state of stake authorizations for ECDSA @@ -149,9 +149,8 @@ library EcdsaAuthorization { Data storage self, uint64 _authorizationDecreaseDelay ) internal { - self - .parameters - .authorizationDecreaseDelay = _authorizationDecreaseDelay; + self.parameters.authorizationDecreaseDelay = + _authorizationDecreaseDelay; } /// @notice Sets the authorization decrease change period. It is the time @@ -162,9 +161,8 @@ library EcdsaAuthorization { Data storage self, uint64 _authorizationDecreaseChangePeriod ) internal { - self - .parameters - .authorizationDecreaseChangePeriod = _authorizationDecreaseChangePeriod; + self.parameters.authorizationDecreaseChangePeriod = + _authorizationDecreaseChangePeriod; } /// @notice Used by staking provider to set operator address that will @@ -622,9 +620,8 @@ library EcdsaAuthorization { address(this) ); - uint96 _eligibleStake = authorizedStake > decreasingBy - ? authorizedStake - decreasingBy - : 0; + uint96 _eligibleStake = + authorizedStake > decreasingBy ? authorizedStake - decreasingBy : 0; if (_eligibleStake < self.parameters.minimumAuthorization) { return 0; diff --git a/solidity/ecdsa/contracts/libraries/EcdsaDkg.sol b/solidity/ecdsa/contracts/libraries/EcdsaDkg.sol index ade4ced153..a817e167df 100644 --- a/solidity/ecdsa/contracts/libraries/EcdsaDkg.sol +++ b/solidity/ecdsa/contracts/libraries/EcdsaDkg.sol @@ -25,8 +25,8 @@ pragma solidity 0.8.17; import "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol"; -import "@keep-network/sortition-pools/contracts/SortitionPool.sol"; -import "@keep-network/random-beacon/contracts/libraries/BytesLib.sol"; +import "../legacy/sortition/SortitionPool.sol"; +import "../legacy/random-beacon/libraries/BytesLib.sol"; import "../EcdsaDkgValidator.sol"; library EcdsaDkg { @@ -192,11 +192,9 @@ library EcdsaDkg { /// @notice Determines the current state of group creation. It doesn't take /// timeouts into consideration. The timeouts should be tracked and /// notified separately. - function currentState(Data storage self) - internal - view - returns (State state) - { + function currentState( + Data storage self + ) internal view returns (State state) { state = State.IDLE; if (self.sortitionPool.isLocked()) { @@ -290,9 +288,9 @@ library EcdsaDkg { return currentState(self) == State.AWAITING_RESULT && block.number > - (self.startBlock + - self.resultSubmissionStartBlockOffset + - self.parameters.resultSubmissionTimeout); + (self.startBlock + + self.resultSubmissionStartBlockOffset + + self.parameters.resultSubmissionTimeout); } /// @notice Notifies about the seed was not delivered and restores the @@ -324,17 +322,18 @@ library EcdsaDkg { /// @param result Result to approve. Must match the submitted result stored /// during `submitResult`. /// @return misbehavedMembers Identifiers of members who misbehaved during DKG. - function approveResult(Data storage self, Result calldata result) - internal - returns (uint32[] memory misbehavedMembers) - { + function approveResult( + Data storage self, + Result calldata result + ) internal returns (uint32[] memory misbehavedMembers) { require( currentState(self) == State.CHALLENGE, "Current state is not CHALLENGE" ); - uint256 challengePeriodEnd = self.submittedResultBlock + - self.parameters.resultChallengePeriodLength; + uint256 challengePeriodEnd = + self.submittedResultBlock + + self.parameters.resultChallengePeriodLength; require( block.number > challengePeriodEnd, @@ -356,8 +355,8 @@ library EcdsaDkg { require( msg.sender == submitterMember || block.number > - challengePeriodEnd + - self.parameters.submitterPrecedencePeriodLength, + challengePeriodEnd + + self.parameters.submitterPrecedencePeriodLength, "Only submitter can approve now" ); @@ -385,7 +384,10 @@ library EcdsaDkg { /// stored during `submitResult`. /// @return maliciousResultHash Hash of the malicious result. /// @return maliciousSubmitter Identifier of the malicious submitter. - function challengeResult(Data storage self, Result calldata result) + function challengeResult( + Data storage self, + Result calldata result + ) internal returns (bytes32 maliciousResultHash, uint32 maliciousSubmitter) { @@ -451,11 +453,10 @@ library EcdsaDkg { /// @param result DKG result. /// @return True if the result is valid. If the result is invalid it returns /// false and an error message. - function isResultValid(Data storage self, Result calldata result) - internal - view - returns (bool, string memory) - { + function isResultValid( + Data storage self, + Result calldata result + ) internal view returns (bool, string memory) { require(self.startBlock > 0, "DKG has not been started"); return self.dkgValidator.validate(result, self.seed, self.startBlock); @@ -464,9 +465,10 @@ library EcdsaDkg { /// @notice Set setSeedTimeout parameter. /// @dev State validation is performed by the caller to reduce bytecode size /// by eliminating redundant checks across multiple setter functions. - function setSeedTimeout(Data storage self, uint256 newSeedTimeout) - internal - { + function setSeedTimeout( + Data storage self, + uint256 newSeedTimeout + ) internal { require(newSeedTimeout > 0, "Value must be greater than zero"); self.parameters.seedTimeout = newSeedTimeout; @@ -484,9 +486,8 @@ library EcdsaDkg { "Value must be greater than zero" ); - self - .parameters - .resultChallengePeriodLength = newResultChallengePeriodLength; + self.parameters.resultChallengePeriodLength = + newResultChallengePeriodLength; } /// @notice Set resultChallengeExtraGas parameter. @@ -529,9 +530,8 @@ library EcdsaDkg { "Value exceeds result submission timeout" ); - self - .parameters - .submitterPrecedencePeriodLength = newSubmitterPrecedencePeriodLength; + self.parameters.submitterPrecedencePeriodLength = + newSubmitterPrecedencePeriodLength; } /// @notice Completes DKG by cleaning up state. diff --git a/solidity/ecdsa/contracts/libraries/EcdsaInactivity.sol b/solidity/ecdsa/contracts/libraries/EcdsaInactivity.sol index d72f3825fa..e33ec04482 100644 --- a/solidity/ecdsa/contracts/libraries/EcdsaInactivity.sol +++ b/solidity/ecdsa/contracts/libraries/EcdsaInactivity.sol @@ -16,8 +16,8 @@ pragma solidity 0.8.17; import "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol"; -import "@keep-network/random-beacon/contracts/libraries/BytesLib.sol"; -import "@keep-network/sortition-pools/contracts/SortitionPool.sol"; +import "../legacy/random-beacon/libraries/BytesLib.sol"; +import "../legacy/sortition/SortitionPool.sol"; import "./Wallets.sol"; diff --git a/solidity/ecdsa/contracts/libraries/Wallets.sol b/solidity/ecdsa/contracts/libraries/Wallets.sol index f0fe5e8ece..e1378f8ee0 100644 --- a/solidity/ecdsa/contracts/libraries/Wallets.sol +++ b/solidity/ecdsa/contracts/libraries/Wallets.sol @@ -43,10 +43,10 @@ library Wallets { /// must be called first for a public key of a wallet added with /// `addWallet` function. /// @param publicKey Uncompressed public key of a new wallet. - function validatePublicKey(Data storage self, bytes calldata publicKey) - internal - view - { + function validatePublicKey( + Data storage self, + bytes calldata publicKey + ) internal view { require(publicKey.length == 64, "Invalid length of the public key"); bytes32 walletID = keccak256(publicKey); @@ -74,11 +74,7 @@ library Wallets { bytes calldata publicKey ) internal - returns ( - bytes32 walletID, - bytes32 publicKeyX, - bytes32 publicKeyY - ) + returns (bytes32 walletID, bytes32 publicKeyX, bytes32 publicKeyY) { walletID = keccak256(publicKey); @@ -105,11 +101,10 @@ library Wallets { /// @notice Checks if a wallet with the given ID is registered. /// @param walletID Wallet's ID /// @return True if a wallet is registered, false otherwise - function isWalletRegistered(Data storage self, bytes32 walletID) - internal - view - returns (bool) - { + function isWalletRegistered( + Data storage self, + bytes32 walletID + ) internal view returns (bool) { return self.registry[walletID].publicKeyX != bytes32(0); } @@ -119,11 +114,10 @@ library Wallets { /// Reverts if wallet with the given ID is not registered. /// @param walletID ID of the wallet /// @return Wallet signing group members hash - function getWalletMembersIdsHash(Data storage self, bytes32 walletID) - internal - view - returns (bytes32) - { + function getWalletMembersIdsHash( + Data storage self, + bytes32 walletID + ) internal view returns (bytes32) { require( isWalletRegistered(self, walletID), "Wallet with the given ID has not been registered" @@ -138,11 +132,10 @@ library Wallets { /// @param walletID ID of the wallet /// @return x Public key X coordinate /// @return y Public key Y coordinate - function getWalletPublicKeyCoordinates(Data storage self, bytes32 walletID) - internal - view - returns (bytes32 x, bytes32 y) - { + function getWalletPublicKeyCoordinates( + Data storage self, + bytes32 walletID + ) internal view returns (bytes32 x, bytes32 y) { require( isWalletRegistered(self, walletID), "Wallet with the given ID has not been registered" @@ -159,11 +152,10 @@ library Wallets { /// Reverts if wallet with the given ID is not registered. /// @param walletID ID of the wallet /// @return Uncompressed public key of the wallet - function getWalletPublicKey(Data storage self, bytes32 walletID) - internal - view - returns (bytes memory) - { + function getWalletPublicKey( + Data storage self, + bytes32 walletID + ) internal view returns (bytes memory) { (bytes32 x, bytes32 y) = getWalletPublicKeyCoordinates(self, walletID); return bytes.concat(x, y); } diff --git a/solidity/ecdsa/contracts/test/MockContract.sol b/solidity/ecdsa/contracts/test/MockContract.sol index 97bf06c1f9..3b5e8b3085 100644 --- a/solidity/ecdsa/contracts/test/MockContract.sol +++ b/solidity/ecdsa/contracts/test/MockContract.sol @@ -272,20 +272,18 @@ contract MockContract { /// @notice Marks selectors that must never be recorded. The helper calls /// this once with every `view` and `pure` function of the mocked /// ABI. - function __mock__setNonRecordingSelectors(bytes4[] calldata selectors) - external - { + function __mock__setNonRecordingSelectors( + bytes4[] calldata selectors + ) external { for (uint256 i = 0; i < selectors.length; i++) { _state().nonRecording[selectors[i]] = true; } } /// @notice Whether a selector is excluded from recording. - function __mock__isNonRecording(bytes4 selector) - external - view - returns (bool) - { + function __mock__isNonRecording( + bytes4 selector + ) external view returns (bool) { return _state().nonRecording[selector]; } @@ -324,20 +322,16 @@ contract MockContract { } /// @notice Raw calldata of the i-th call recorded, across all selectors. - function __mock__callAt(uint256 index) - external - view - returns (bytes memory) - { + function __mock__callAt( + uint256 index + ) external view returns (bytes memory) { return _state().receivedCalls[index]; } /// @notice Number of calls recorded for one selector. - function __mock__callCountForSelector(bytes4 selector) - external - view - returns (uint256 count) - { + function __mock__callCountForSelector( + bytes4 selector + ) external view returns (uint256 count) { uint256 total = _state().receivedCalls.length; for (uint256 i = 0; i < total; i++) { if (__mock__selectorOf(_state().receivedCalls[i]) == selector) { @@ -348,11 +342,10 @@ contract MockContract { /// @notice Raw calldata of the i-th call recorded for one selector. /// @notice msg.value of the i-th call recorded for one selector. - function __mock__callValueForSelectorAt(bytes4 selector, uint256 index) - external - view - returns (uint256) - { + function __mock__callValueForSelectorAt( + bytes4 selector, + uint256 index + ) external view returns (uint256) { uint256 seen = 0; uint256 total = _state().receivedCalls.length; @@ -368,11 +361,10 @@ contract MockContract { revert("MockContract: call index out of range"); } - function __mock__callForSelectorAt(bytes4 selector, uint256 index) - external - view - returns (bytes memory) - { + function __mock__callForSelectorAt( + bytes4 selector, + uint256 index + ) external view returns (bytes memory) { uint256 seen = 0; uint256 total = _state().receivedCalls.length; @@ -389,11 +381,9 @@ contract MockContract { } /// @dev Leading four bytes of `callData`, or zero if it is shorter. - function __mock__selectorOf(bytes memory callData) - public - pure - returns (bytes4 selector) - { + function __mock__selectorOf( + bytes memory callData + ) public pure returns (bytes4 selector) { if (callData.length < 4) { return bytes4(0); } @@ -445,11 +435,9 @@ contract MockContract { /// @dev Resolves an incoming call against the three layers, most specific /// first. Reverts here if the matched response is a configured revert. - function __mock__responseFor(bytes memory callData) - private - view - returns (bytes memory) - { + function __mock__responseFor( + bytes memory callData + ) private view returns (bytes memory) { Response storage exact = _state().responseByCalldata[ keccak256(callData) ]; @@ -499,11 +487,9 @@ contract MockContract { } } - function __mock__respond(Response storage response) - private - view - returns (bytes memory) - { + function __mock__respond( + Response storage response + ) private view returns (bytes memory) { if (response.behaviour == Behaviour.Revert) { bytes memory revertData = response.data; diff --git a/solidity/ecdsa/contracts/test/MockTargetConsumer.sol b/solidity/ecdsa/contracts/test/MockTargetConsumer.sol index 45c30efae4..eb1232ad4a 100644 --- a/solidity/ecdsa/contracts/test/MockTargetConsumer.sol +++ b/solidity/ecdsa/contracts/test/MockTargetConsumer.sol @@ -33,27 +33,21 @@ contract MockTargetConsumer { } /// @dev STATICCALL: `readValue` is `view` on the interface. - function readValueThroughStaticCall(uint256 key) - external - view - returns (uint256) - { + function readValueThroughStaticCall( + uint256 key + ) external view returns (uint256) { return target.readValue(key); } - function readInfoThroughStaticCall(uint256 key) - external - view - returns (IMockTarget.Info memory) - { + function readInfoThroughStaticCall( + uint256 key + ) external view returns (IMockTarget.Info memory) { return target.readInfo(key); } - function readPairThroughStaticCall(uint256 key) - external - view - returns (uint32, uint32) - { + function readPairThroughStaticCall( + uint256 key + ) external view returns (uint32, uint32) { return target.readPair(key); } } diff --git a/solidity/ecdsa/contracts/test/RandomBeaconStub.sol b/solidity/ecdsa/contracts/test/RandomBeaconStub.sol index cd6cdde703..95c3c5a281 100644 --- a/solidity/ecdsa/contracts/test/RandomBeaconStub.sol +++ b/solidity/ecdsa/contracts/test/RandomBeaconStub.sol @@ -3,9 +3,9 @@ pragma solidity 0.8.17; -import "@keep-network/random-beacon/contracts/api/IRandomBeacon.sol"; -import "@keep-network/random-beacon/contracts/api/IRandomBeaconConsumer.sol"; -import "@keep-network/random-beacon/contracts/libraries/Callback.sol"; +import "../legacy/random-beacon/api/IRandomBeacon.sol"; +import "../legacy/random-beacon/api/IRandomBeaconConsumer.sol"; +import "../legacy/random-beacon/libraries/Callback.sol"; // TODO: get rid of this contract; use RandomBeacon implementation instead. // This implementation is used to test callback's gas limit only. In most tests @@ -19,9 +19,9 @@ contract RandomBeaconStub is IRandomBeacon { event CallbackFailed(uint256 entry, uint256 entrySubmittedBlock); - function requestRelayEntry(IRandomBeaconConsumer _callbackContract) - external - { + function requestRelayEntry( + IRandomBeaconConsumer _callbackContract + ) external { callback.setCallbackContract(_callbackContract); } diff --git a/solidity/ecdsa/contracts/test/WalletRegistryStub.sol b/solidity/ecdsa/contracts/test/WalletRegistryStub.sol index 44b9f4cee9..0dd2d92b41 100644 --- a/solidity/ecdsa/contracts/test/WalletRegistryStub.sol +++ b/solidity/ecdsa/contracts/test/WalletRegistryStub.sol @@ -3,8 +3,8 @@ pragma solidity 0.8.17; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@keep-network/sortition-pools/contracts/SortitionPool.sol"; -import "@keep-network/random-beacon/contracts/ReimbursementPool.sol"; +import "../legacy/sortition/SortitionPool.sol"; +import "../legacy/random-beacon/ReimbursementPool.sol"; import "../WalletRegistry.sol"; import "../EcdsaDkgValidator.sol"; import "../libraries/Wallets.sol"; @@ -13,13 +13,15 @@ contract WalletRegistryStub is WalletRegistry { using Wallets for Wallets.Data; /// @custom:oz-upgrades-unsafe-allow constructor - constructor(SortitionPool _sortitionPool, IStaking _staking) - WalletRegistry(_sortitionPool, _staking) - {} + constructor( + SortitionPool _sortitionPool, + IStaking _staking + ) WalletRegistry(_sortitionPool, _staking) {} - function forceAddWallet(bytes calldata groupPubKey, bytes32 membersIdsHash) - external - { + function forceAddWallet( + bytes calldata groupPubKey, + bytes32 membersIdsHash + ) external { wallets.addWallet(membersIdsHash, groupPubKey); } diff --git a/solidity/ecdsa/contracts/test/upgrades/WalletRegistryV2.sol b/solidity/ecdsa/contracts/test/upgrades/WalletRegistryV2.sol index 08769eff52..863ea50b8b 100644 --- a/solidity/ecdsa/contracts/test/upgrades/WalletRegistryV2.sol +++ b/solidity/ecdsa/contracts/test/upgrades/WalletRegistryV2.sol @@ -25,12 +25,12 @@ import {EcdsaDkg as DKG} from "../../libraries/EcdsaDkg.sol"; import {EcdsaInactivity as Inactivity} from "../../libraries/EcdsaInactivity.sol"; import {EcdsaDkgValidator as DKGValidator} from "../../EcdsaDkgValidator.sol"; -import "@keep-network/sortition-pools/contracts/SortitionPool.sol"; -import "@keep-network/random-beacon/contracts/api/IRandomBeacon.sol"; -import "@keep-network/random-beacon/contracts/api/IRandomBeaconConsumer.sol"; -import "@keep-network/random-beacon/contracts/Reimbursable.sol"; -import "@keep-network/random-beacon/contracts/ReimbursementPool.sol"; -import "@keep-network/random-beacon/contracts/Governable.sol"; +import "../../legacy/sortition/SortitionPool.sol"; +import "../../legacy/random-beacon/api/IRandomBeacon.sol"; +import "../../legacy/random-beacon/api/IRandomBeaconConsumer.sol"; +import "../../legacy/random-beacon/Reimbursable.sol"; +import "../../legacy/random-beacon/ReimbursementPool.sol"; +import "../../legacy/random-beacon/Governable.sol"; import "@threshold-network/solidity-contracts/contracts/staking/IApplication.sol"; import "@threshold-network/solidity-contracts/contracts/staking/IStaking.sol"; @@ -294,10 +294,10 @@ contract WalletRegistryV2 is } // TEST: Added initializer for V2 - function initializeV2(IRandomBeacon _randomBeacon, string memory _newVar) - public - reinitializer(2) - { + function initializeV2( + IRandomBeacon _randomBeacon, + string memory _newVar + ) public reinitializer(2) { randomBeacon = _randomBeacon; newVar = _newVar; } @@ -321,10 +321,9 @@ contract WalletRegistryV2 is /// @dev Can be called only by the contract guvnor, which should be the /// wallet registry governance contract. /// @param recipient Recipient of withdrawn rewards. - function withdrawIneligibleRewards(address recipient) - external - onlyGovernance - { + function withdrawIneligibleRewards( + address recipient + ) external onlyGovernance { sortitionPool.withdrawIneligible(recipient); } @@ -457,10 +456,9 @@ contract WalletRegistryV2 is /// wallet registry governance contract. The caller is responsible for /// validating parameters. /// @param _randomBeacon Random Beacon address. - function upgradeRandomBeacon(IRandomBeacon _randomBeacon) - external - onlyGovernance - { + function upgradeRandomBeacon( + IRandomBeacon _randomBeacon + ) external onlyGovernance { randomBeacon = _randomBeacon; emit RandomBeaconUpgraded(address(_randomBeacon)); } @@ -471,10 +469,9 @@ contract WalletRegistryV2 is /// validating parameters. The wallet owner has to implement `IWalletOwner` /// interface. /// @param _walletOwner New wallet owner address. - function updateWalletOwner(IWalletOwner _walletOwner) - external - onlyGovernance - { + function updateWalletOwner( + IWalletOwner _walletOwner + ) external onlyGovernance { walletOwner = _walletOwner; emit WalletOwnerUpdated(address(_walletOwner)); } @@ -557,7 +554,8 @@ contract WalletRegistryV2 is uint256 maliciousDkgResultNotificationRewardMultiplier, uint256 sortitionPoolRewardsBanDuration ) external onlyGovernance { - _maliciousDkgResultNotificationRewardMultiplier = maliciousDkgResultNotificationRewardMultiplier; + _maliciousDkgResultNotificationRewardMultiplier = + maliciousDkgResultNotificationRewardMultiplier; _sortitionPoolRewardsBanDuration = sortitionPoolRewardsBanDuration; emit RewardParametersUpdated( maliciousDkgResultNotificationRewardMultiplier, @@ -571,10 +569,9 @@ contract WalletRegistryV2 is /// validating parameters. /// @param maliciousDkgResultSlashingAmount New malicious DKG result /// slashing amount. - function updateSlashingParameters(uint96 maliciousDkgResultSlashingAmount) - external - onlyGovernance - { + function updateSlashingParameters( + uint96 maliciousDkgResultSlashingAmount + ) external onlyGovernance { _maliciousDkgResultSlashingAmount = maliciousDkgResultSlashingAmount; emit SlashingParametersUpdated(maliciousDkgResultSlashingAmount); } @@ -914,11 +911,9 @@ contract WalletRegistryV2 is /// @param result DKG result. /// @return True if the result is valid. If the result is invalid it returns /// false and an error message. - function isDkgResultValid(DKG.Result calldata result) - external - view - returns (bool, string memory) - { + function isDkgResultValid( + DKG.Result calldata result + ) external view returns (bool, string memory) { return dkg.isResultValid(result); } @@ -986,11 +981,9 @@ contract WalletRegistryV2 is return dkg.hasDkgTimedOut(); } - function getWallet(bytes32 walletID) - external - view - returns (Wallets.Wallet memory) - { + function getWallet( + bytes32 walletID + ) external view returns (Wallets.Wallet memory) { return wallets.registry[walletID]; } @@ -999,11 +992,9 @@ contract WalletRegistryV2 is /// concatenation of X and Y coordinates. /// @param walletID ID of the wallet. /// @return Uncompressed public key of the wallet. - function getWalletPublicKey(bytes32 walletID) - external - view - returns (bytes memory) - { + function getWalletPublicKey( + bytes32 walletID + ) external view returns (bytes memory) { return wallets.getWalletPublicKey(walletID); } @@ -1026,22 +1017,18 @@ contract WalletRegistryV2 is /// is what is used for operator's weight in the sortition pool. /// If the authorized stake minus the pending authorization decrease /// is below the minimum authorization, eligible stake is 0. - function eligibleStake(address stakingProvider) - external - view - returns (uint96) - { + function eligibleStake( + address stakingProvider + ) external view returns (uint96) { return authorization.eligibleStake(staking, stakingProvider); } /// @notice Returns the amount of rewards available for withdrawal for the /// given staking provider. Reverts if staking provider has not /// registered the operator address. - function availableRewards(address stakingProvider) - external - view - returns (uint96) - { + function availableRewards( + address stakingProvider + ) external view returns (uint96) { address operator = stakingProviderToOperator(stakingProvider); require(operator != address(0), "Unknown operator"); return sortitionPool.getAvailableRewards(operator); @@ -1050,11 +1037,9 @@ contract WalletRegistryV2 is /// @notice Returns the amount of stake that is pending authorization /// decrease for the given staking provider. If no authorization /// decrease has been requested, returns zero. - function pendingAuthorizationDecrease(address stakingProvider) - external - view - returns (uint96) - { + function pendingAuthorizationDecrease( + address stakingProvider + ) external view returns (uint96) { return authorization.pendingAuthorizationDecrease(stakingProvider); } @@ -1063,30 +1048,24 @@ contract WalletRegistryV2 is /// If the sortition pool state was not updated yet by the operator /// after requesting the authorization decrease, returns /// `type(uint64).max`. - function remainingAuthorizationDecreaseDelay(address stakingProvider) - external - view - returns (uint64) - { + function remainingAuthorizationDecreaseDelay( + address stakingProvider + ) external view returns (uint64) { return authorization.remainingAuthorizationDecreaseDelay(stakingProvider); } /// @notice Returns operator registered for the given staking provider. - function stakingProviderToOperator(address stakingProvider) - public - view - returns (address) - { + function stakingProviderToOperator( + address stakingProvider + ) public view returns (address) { return authorization.stakingProviderToOperator[stakingProvider]; } /// @notice Returns staking provider of the given operator. - function operatorToStakingProvider(address operator) - public - view - returns (address) - { + function operatorToStakingProvider( + address operator + ) public view returns (address) { return authorization.operatorToStakingProvider[operator]; } diff --git a/solidity/ecdsa/contracts/test/upgrades/WalletRegistryV2MisplacedNewSlot.sol b/solidity/ecdsa/contracts/test/upgrades/WalletRegistryV2MisplacedNewSlot.sol index 8a06925e01..d1ad3ba9e2 100644 --- a/solidity/ecdsa/contracts/test/upgrades/WalletRegistryV2MisplacedNewSlot.sol +++ b/solidity/ecdsa/contracts/test/upgrades/WalletRegistryV2MisplacedNewSlot.sol @@ -25,12 +25,12 @@ import {EcdsaDkg as DKG} from "../../libraries/EcdsaDkg.sol"; import {EcdsaInactivity as Inactivity} from "../../libraries/EcdsaInactivity.sol"; import {EcdsaDkgValidator as DKGValidator} from "../../EcdsaDkgValidator.sol"; -import "@keep-network/sortition-pools/contracts/SortitionPool.sol"; -import "@keep-network/random-beacon/contracts/api/IRandomBeacon.sol"; -import "@keep-network/random-beacon/contracts/api/IRandomBeaconConsumer.sol"; -import "@keep-network/random-beacon/contracts/Reimbursable.sol"; -import "@keep-network/random-beacon/contracts/ReimbursementPool.sol"; -import "@keep-network/random-beacon/contracts/Governable.sol"; +import "../../legacy/sortition/SortitionPool.sol"; +import "../../legacy/random-beacon/api/IRandomBeacon.sol"; +import "../../legacy/random-beacon/api/IRandomBeaconConsumer.sol"; +import "../../legacy/random-beacon/Reimbursable.sol"; +import "../../legacy/random-beacon/ReimbursementPool.sol"; +import "../../legacy/random-beacon/Governable.sol"; import "@threshold-network/solidity-contracts/contracts/staking/IApplication.sol"; import "@threshold-network/solidity-contracts/contracts/staking/IStaking.sol"; @@ -292,10 +292,10 @@ contract WalletRegistryV2MisplacedNewSlot is } // TEST: Added initializer for V2 - function initializeV2(IRandomBeacon _randomBeacon, string memory _newVar) - public - reinitializer(2) - { + function initializeV2( + IRandomBeacon _randomBeacon, + string memory _newVar + ) public reinitializer(2) { randomBeacon = _randomBeacon; newVar = _newVar; } @@ -319,10 +319,9 @@ contract WalletRegistryV2MisplacedNewSlot is /// @dev Can be called only by the contract guvnor, which should be the /// wallet registry governance contract. /// @param recipient Recipient of withdrawn rewards. - function withdrawIneligibleRewards(address recipient) - external - onlyGovernance - { + function withdrawIneligibleRewards( + address recipient + ) external onlyGovernance { sortitionPool.withdrawIneligible(recipient); } @@ -455,10 +454,9 @@ contract WalletRegistryV2MisplacedNewSlot is /// wallet registry governance contract. The caller is responsible for /// validating parameters. /// @param _randomBeacon Random Beacon address. - function upgradeRandomBeacon(IRandomBeacon _randomBeacon) - external - onlyGovernance - { + function upgradeRandomBeacon( + IRandomBeacon _randomBeacon + ) external onlyGovernance { randomBeacon = _randomBeacon; emit RandomBeaconUpgraded(address(_randomBeacon)); } @@ -469,10 +467,9 @@ contract WalletRegistryV2MisplacedNewSlot is /// validating parameters. The wallet owner has to implement `IWalletOwner` /// interface. /// @param _walletOwner New wallet owner address. - function updateWalletOwner(IWalletOwner _walletOwner) - external - onlyGovernance - { + function updateWalletOwner( + IWalletOwner _walletOwner + ) external onlyGovernance { walletOwner = _walletOwner; emit WalletOwnerUpdated(address(_walletOwner)); } @@ -555,7 +552,8 @@ contract WalletRegistryV2MisplacedNewSlot is uint256 maliciousDkgResultNotificationRewardMultiplier, uint256 sortitionPoolRewardsBanDuration ) external onlyGovernance { - _maliciousDkgResultNotificationRewardMultiplier = maliciousDkgResultNotificationRewardMultiplier; + _maliciousDkgResultNotificationRewardMultiplier = + maliciousDkgResultNotificationRewardMultiplier; _sortitionPoolRewardsBanDuration = sortitionPoolRewardsBanDuration; emit RewardParametersUpdated( maliciousDkgResultNotificationRewardMultiplier, @@ -569,10 +567,9 @@ contract WalletRegistryV2MisplacedNewSlot is /// validating parameters. /// @param maliciousDkgResultSlashingAmount New malicious DKG result /// slashing amount. - function updateSlashingParameters(uint96 maliciousDkgResultSlashingAmount) - external - onlyGovernance - { + function updateSlashingParameters( + uint96 maliciousDkgResultSlashingAmount + ) external onlyGovernance { _maliciousDkgResultSlashingAmount = maliciousDkgResultSlashingAmount; emit SlashingParametersUpdated(maliciousDkgResultSlashingAmount); } @@ -927,11 +924,9 @@ contract WalletRegistryV2MisplacedNewSlot is /// @param result DKG result. /// @return True if the result is valid. If the result is invalid it returns /// false and an error message. - function isDkgResultValid(DKG.Result calldata result) - external - view - returns (bool, string memory) - { + function isDkgResultValid( + DKG.Result calldata result + ) external view returns (bool, string memory) { return dkg.isResultValid(result); } @@ -999,11 +994,9 @@ contract WalletRegistryV2MisplacedNewSlot is return dkg.hasDkgTimedOut(); } - function getWallet(bytes32 walletID) - external - view - returns (Wallets.Wallet memory) - { + function getWallet( + bytes32 walletID + ) external view returns (Wallets.Wallet memory) { return wallets.registry[walletID]; } @@ -1012,11 +1005,9 @@ contract WalletRegistryV2MisplacedNewSlot is /// concatenation of X and Y coordinates. /// @param walletID ID of the wallet. /// @return Uncompressed public key of the wallet. - function getWalletPublicKey(bytes32 walletID) - external - view - returns (bytes memory) - { + function getWalletPublicKey( + bytes32 walletID + ) external view returns (bytes memory) { return wallets.getWalletPublicKey(walletID); } @@ -1039,22 +1030,18 @@ contract WalletRegistryV2MisplacedNewSlot is /// is what is used for operator's weight in the sortition pool. /// If the authorized stake minus the pending authorization decrease /// is below the minimum authorization, eligible stake is 0. - function eligibleStake(address stakingProvider) - external - view - returns (uint96) - { + function eligibleStake( + address stakingProvider + ) external view returns (uint96) { return authorization.eligibleStake(staking, stakingProvider); } /// @notice Returns the amount of rewards available for withdrawal for the /// given staking provider. Reverts if staking provider has not /// registered the operator address. - function availableRewards(address stakingProvider) - external - view - returns (uint96) - { + function availableRewards( + address stakingProvider + ) external view returns (uint96) { address operator = stakingProviderToOperator(stakingProvider); require(operator != address(0), "Unknown operator"); return sortitionPool.getAvailableRewards(operator); @@ -1063,11 +1050,9 @@ contract WalletRegistryV2MisplacedNewSlot is /// @notice Returns the amount of stake that is pending authorization /// decrease for the given staking provider. If no authorization /// decrease has been requested, returns zero. - function pendingAuthorizationDecrease(address stakingProvider) - external - view - returns (uint96) - { + function pendingAuthorizationDecrease( + address stakingProvider + ) external view returns (uint96) { return authorization.pendingAuthorizationDecrease(stakingProvider); } @@ -1076,30 +1061,24 @@ contract WalletRegistryV2MisplacedNewSlot is /// If the sortition pool state was not updated yet by the operator /// after requesting the authorization decrease, returns /// `type(uint64).max`. - function remainingAuthorizationDecreaseDelay(address stakingProvider) - external - view - returns (uint64) - { + function remainingAuthorizationDecreaseDelay( + address stakingProvider + ) external view returns (uint64) { return authorization.remainingAuthorizationDecreaseDelay(stakingProvider); } /// @notice Returns operator registered for the given staking provider. - function stakingProviderToOperator(address stakingProvider) - public - view - returns (address) - { + function stakingProviderToOperator( + address stakingProvider + ) public view returns (address) { return authorization.stakingProviderToOperator[stakingProvider]; } /// @notice Returns staking provider of the given operator. - function operatorToStakingProvider(address operator) - public - view - returns (address) - { + function operatorToStakingProvider( + address operator + ) public view returns (address) { return authorization.operatorToStakingProvider[operator]; } diff --git a/solidity/ecdsa/contracts/test/upgrades/WalletRegistryV2MissingSlot.sol b/solidity/ecdsa/contracts/test/upgrades/WalletRegistryV2MissingSlot.sol index 4e61f4a57c..c61fc6ba4c 100644 --- a/solidity/ecdsa/contracts/test/upgrades/WalletRegistryV2MissingSlot.sol +++ b/solidity/ecdsa/contracts/test/upgrades/WalletRegistryV2MissingSlot.sol @@ -25,12 +25,12 @@ import {EcdsaDkg as DKG} from "../../libraries/EcdsaDkg.sol"; import {EcdsaInactivity as Inactivity} from "../../libraries/EcdsaInactivity.sol"; import {EcdsaDkgValidator as DKGValidator} from "../../EcdsaDkgValidator.sol"; -import "@keep-network/sortition-pools/contracts/SortitionPool.sol"; -import "@keep-network/random-beacon/contracts/api/IRandomBeacon.sol"; -import "@keep-network/random-beacon/contracts/api/IRandomBeaconConsumer.sol"; -import "@keep-network/random-beacon/contracts/Reimbursable.sol"; -import "@keep-network/random-beacon/contracts/ReimbursementPool.sol"; -import "@keep-network/random-beacon/contracts/Governable.sol"; +import "../../legacy/sortition/SortitionPool.sol"; +import "../../legacy/random-beacon/api/IRandomBeacon.sol"; +import "../../legacy/random-beacon/api/IRandomBeaconConsumer.sol"; +import "../../legacy/random-beacon/Reimbursable.sol"; +import "../../legacy/random-beacon/ReimbursementPool.sol"; +import "../../legacy/random-beacon/Governable.sol"; import "@threshold-network/solidity-contracts/contracts/staking/IApplication.sol"; import "@threshold-network/solidity-contracts/contracts/staking/IStaking.sol"; @@ -290,10 +290,10 @@ contract WalletRegistryV2MissingSlot is } // TEST: Added initializer for V2 - function initializeV2(IRandomBeacon _randomBeacon, string memory _newVar) - public - reinitializer(2) - { + function initializeV2( + IRandomBeacon _randomBeacon, + string memory _newVar + ) public reinitializer(2) { randomBeacon = _randomBeacon; _newVar; } @@ -317,10 +317,9 @@ contract WalletRegistryV2MissingSlot is /// @dev Can be called only by the contract guvnor, which should be the /// wallet registry governance contract. /// @param recipient Recipient of withdrawn rewards. - function withdrawIneligibleRewards(address recipient) - external - onlyGovernance - { + function withdrawIneligibleRewards( + address recipient + ) external onlyGovernance { sortitionPool.withdrawIneligible(recipient); } @@ -453,10 +452,9 @@ contract WalletRegistryV2MissingSlot is /// wallet registry governance contract. The caller is responsible for /// validating parameters. /// @param _randomBeacon Random Beacon address. - function upgradeRandomBeacon(IRandomBeacon _randomBeacon) - external - onlyGovernance - { + function upgradeRandomBeacon( + IRandomBeacon _randomBeacon + ) external onlyGovernance { randomBeacon = _randomBeacon; emit RandomBeaconUpgraded(address(_randomBeacon)); } @@ -467,10 +465,9 @@ contract WalletRegistryV2MissingSlot is /// validating parameters. The wallet owner has to implement `IWalletOwner` /// interface. /// @param _walletOwner New wallet owner address. - function updateWalletOwner(IWalletOwner _walletOwner) - external - onlyGovernance - { + function updateWalletOwner( + IWalletOwner _walletOwner + ) external onlyGovernance { walletOwner = _walletOwner; emit WalletOwnerUpdated(address(_walletOwner)); } @@ -568,10 +565,9 @@ contract WalletRegistryV2MissingSlot is /// validating parameters. /// @param maliciousDkgResultSlashingAmount New malicious DKG result /// slashing amount. - function updateSlashingParameters(uint96 maliciousDkgResultSlashingAmount) - external - onlyGovernance - { + function updateSlashingParameters( + uint96 maliciousDkgResultSlashingAmount + ) external onlyGovernance { _maliciousDkgResultSlashingAmount = maliciousDkgResultSlashingAmount; emit SlashingParametersUpdated(maliciousDkgResultSlashingAmount); } @@ -926,11 +922,9 @@ contract WalletRegistryV2MissingSlot is /// @param result DKG result. /// @return True if the result is valid. If the result is invalid it returns /// false and an error message. - function isDkgResultValid(DKG.Result calldata result) - external - view - returns (bool, string memory) - { + function isDkgResultValid( + DKG.Result calldata result + ) external view returns (bool, string memory) { return dkg.isResultValid(result); } @@ -998,11 +992,9 @@ contract WalletRegistryV2MissingSlot is return dkg.hasDkgTimedOut(); } - function getWallet(bytes32 walletID) - external - view - returns (Wallets.Wallet memory) - { + function getWallet( + bytes32 walletID + ) external view returns (Wallets.Wallet memory) { return wallets.registry[walletID]; } @@ -1011,11 +1003,9 @@ contract WalletRegistryV2MissingSlot is /// concatenation of X and Y coordinates. /// @param walletID ID of the wallet. /// @return Uncompressed public key of the wallet. - function getWalletPublicKey(bytes32 walletID) - external - view - returns (bytes memory) - { + function getWalletPublicKey( + bytes32 walletID + ) external view returns (bytes memory) { return wallets.getWalletPublicKey(walletID); } @@ -1038,22 +1028,18 @@ contract WalletRegistryV2MissingSlot is /// is what is used for operator's weight in the sortition pool. /// If the authorized stake minus the pending authorization decrease /// is below the minimum authorization, eligible stake is 0. - function eligibleStake(address stakingProvider) - external - view - returns (uint96) - { + function eligibleStake( + address stakingProvider + ) external view returns (uint96) { return authorization.eligibleStake(staking, stakingProvider); } /// @notice Returns the amount of rewards available for withdrawal for the /// given staking provider. Reverts if staking provider has not /// registered the operator address. - function availableRewards(address stakingProvider) - external - view - returns (uint96) - { + function availableRewards( + address stakingProvider + ) external view returns (uint96) { address operator = stakingProviderToOperator(stakingProvider); require(operator != address(0), "Unknown operator"); return sortitionPool.getAvailableRewards(operator); @@ -1062,11 +1048,9 @@ contract WalletRegistryV2MissingSlot is /// @notice Returns the amount of stake that is pending authorization /// decrease for the given staking provider. If no authorization /// decrease has been requested, returns zero. - function pendingAuthorizationDecrease(address stakingProvider) - external - view - returns (uint96) - { + function pendingAuthorizationDecrease( + address stakingProvider + ) external view returns (uint96) { return authorization.pendingAuthorizationDecrease(stakingProvider); } @@ -1075,30 +1059,24 @@ contract WalletRegistryV2MissingSlot is /// If the sortition pool state was not updated yet by the operator /// after requesting the authorization decrease, returns /// `type(uint64).max`. - function remainingAuthorizationDecreaseDelay(address stakingProvider) - external - view - returns (uint64) - { + function remainingAuthorizationDecreaseDelay( + address stakingProvider + ) external view returns (uint64) { return authorization.remainingAuthorizationDecreaseDelay(stakingProvider); } /// @notice Returns operator registered for the given staking provider. - function stakingProviderToOperator(address stakingProvider) - public - view - returns (address) - { + function stakingProviderToOperator( + address stakingProvider + ) public view returns (address) { return authorization.stakingProviderToOperator[stakingProvider]; } /// @notice Returns staking provider of the given operator. - function operatorToStakingProvider(address operator) - public - view - returns (address) - { + function operatorToStakingProvider( + address operator + ) public view returns (address) { return authorization.operatorToStakingProvider[operator]; } diff --git a/solidity/ecdsa/deploy/00_log_external_deployments.ts b/solidity/ecdsa/deploy/00_log_external_deployments.ts index 1b444a6fc6..d35b4a8c64 100644 --- a/solidity/ecdsa/deploy/00_log_external_deployments.ts +++ b/solidity/ecdsa/deploy/00_log_external_deployments.ts @@ -32,7 +32,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const names = Object.keys(all).sort() log( - `Deploy starting on network "${network.name}" with ${names.length} pre-resolved deployments:` + `Deploy starting on network "${network.name}" with ${names.length} pre-resolved deployments:`, ) names.forEach((name) => { log(` - ${name} @ ${all[name].address}`) @@ -40,15 +40,15 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { if (network.name === "sepolia") { const missing = EXPECTED_EXTERNAL_ON_SEPOLIA.filter( - (name) => !(name in all) + (name) => !(name in all), ) if (missing.length > 0) { throw new Error( `Sepolia deploy: expected upstream contracts missing from deployments/sepolia/: ${missing.join( - ", " + ", ", )}. ` + "external.deployments.sepolia is empty by design; the committed snapshot under " + - "deployments/sepolia/ is the sole source. Regenerate or copy the missing artifacts." + "deployments/sepolia/ is the sole source. Regenerate or copy the missing artifacts.", ) } } @@ -65,15 +65,15 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { (role) => { const addr = (named[role] || "").toLowerCase() return Boolean(deployer && addr && deployer === addr) - } + }, ) if (collisions.length > 0) { throw new Error( `Mainnet deploy refused: deployer address (${named.deployer}) collides with ` + `role(s) ${collisions.join( - ", " + ", ", )}. Each of these must be a distinct address ` + - "to preserve the separation between the deploy key and governance." + "to preserve the separation between the deploy key and governance.", ) } } diff --git a/solidity/ecdsa/deploy/00_resolve_random_beacon_chaosnet.ts b/solidity/ecdsa/deploy/00_resolve_random_beacon_chaosnet.ts index 8a3da5a538..8317a9a6dd 100644 --- a/solidity/ecdsa/deploy/00_resolve_random_beacon_chaosnet.ts +++ b/solidity/ecdsa/deploy/00_resolve_random_beacon_chaosnet.ts @@ -6,7 +6,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const { log } = deployments const RandomBeaconChaosnet = await deployments.getOrNull( - "RandomBeaconChaosnet" + "RandomBeaconChaosnet", ) if ( @@ -14,7 +14,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { helpers.address.isValid(RandomBeaconChaosnet.address) ) { log( - `using existing RandomBeaconChaosnet at ${RandomBeaconChaosnet.address}` + `using existing RandomBeaconChaosnet at ${RandomBeaconChaosnet.address}`, ) } else { throw new Error("deployed RandomBeaconChaosnet contract not found") diff --git a/solidity/ecdsa/deploy/00_resolve_reimbursement_pool.ts b/solidity/ecdsa/deploy/00_resolve_reimbursement_pool.ts index b4301aef0e..9f550a32d1 100644 --- a/solidity/ecdsa/deploy/00_resolve_reimbursement_pool.ts +++ b/solidity/ecdsa/deploy/00_resolve_reimbursement_pool.ts @@ -16,13 +16,13 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { throw new Error( `ReimbursementPool not found on "${hre.network.name}". On local networks it is expected to come from the ` + "random-beacon external deploys — set USE_EXTERNAL_DEPLOY=true (the package.json test/deploy:test scripts " + - "already do this) or pre-deploy ReimbursementPool yourself before running this script." + "already do this) or pre-deploy ReimbursementPool yourself before running this script.", ) } throw new Error( `ReimbursementPool not found on "${hre.network.name}". For Sepolia, the committed ` + "deployments/sepolia/ReimbursementPool.json is the source of truth. For mainnet, ./external/mainnet must " + - "contain ReimbursementPool.json." + "contain ReimbursementPool.json.", ) } diff --git a/solidity/ecdsa/deploy/00_resolve_token_staking.ts b/solidity/ecdsa/deploy/00_resolve_token_staking.ts index f11d517ed5..13402c0451 100644 --- a/solidity/ecdsa/deploy/00_resolve_token_staking.ts +++ b/solidity/ecdsa/deploy/00_resolve_token_staking.ts @@ -16,13 +16,13 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { throw new Error( `TokenStaking not found on "${hre.network.name}". On local networks the contract is expected to come from ` + "@threshold-network/solidity-contracts external deploys — set USE_EXTERNAL_DEPLOY=true (the package.json test/deploy:test " + - "scripts already do this) or pre-deploy TokenStaking yourself before running this script." + "scripts already do this) or pre-deploy TokenStaking yourself before running this script.", ) } throw new Error( `TokenStaking not found on "${hre.network.name}". For Sepolia, the committed deployments/sepolia/TokenStaking.json ` + "is the source of truth (external.deployments.sepolia is empty by design). For mainnet, ./external/mainnet must " + - "contain TokenStaking.json." + "contain TokenStaking.json.", ) } diff --git a/solidity/ecdsa/deploy/01_deploy_ecdsa_sortition_pool.ts b/solidity/ecdsa/deploy/01_deploy_ecdsa_sortition_pool.ts index 800bab4aa1..a8a61cbd71 100644 --- a/solidity/ecdsa/deploy/01_deploy_ecdsa_sortition_pool.ts +++ b/solidity/ecdsa/deploy/01_deploy_ecdsa_sortition_pool.ts @@ -11,12 +11,11 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const { to1e18 } = helpers.number // Skip if EcdsaSortitionPool already deployed (for existing mainnet/testnet deployments) - const existingSortitionPool = await deployments.getOrNull( - "EcdsaSortitionPool" - ) + const existingSortitionPool = + await deployments.getOrNull("EcdsaSortitionPool") if (existingSortitionPool) { console.log( - `using existing EcdsaSortitionPool at ${existingSortitionPool.address}` + `using existing EcdsaSortitionPool at ${existingSortitionPool.address}`, ) return true } @@ -37,7 +36,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { "EcdsaSortitionPool", { from: deployer, log: true, waitConfirmations: 1 }, "transferChaosnetOwnerRole", - chaosnetOwner + chaosnetOwner, ) if ( @@ -45,7 +44,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { process.env.DISABLE_HARDHAT_VERIFY !== "true" ) { await verifyOnEtherscanOrContinue(hre, () => - helpers.etherscan.verify(EcdsaSortitionPool) + helpers.etherscan.verify(EcdsaSortitionPool), ) } @@ -54,7 +53,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { hre.tenderly.verify({ name: "EcdsaSortitionPool", address: EcdsaSortitionPool.address, - }) + }), ) } diff --git a/solidity/ecdsa/deploy/02_deploy_dkg_validator.ts b/solidity/ecdsa/deploy/02_deploy_dkg_validator.ts index 901a7dfe46..603ec71f97 100644 --- a/solidity/ecdsa/deploy/02_deploy_dkg_validator.ts +++ b/solidity/ecdsa/deploy/02_deploy_dkg_validator.ts @@ -51,7 +51,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { "once-only, so a validator-only redeploy would desync " + `deployments/${hre.network.name}/EcdsaDkgValidator.json from the ` + "on-chain binding. Wipe and redeploy the WalletRegistry in the same " + - "run (e.g. full-redeploy-sepolia-stack.sh) before redeploying the validator." + "run (e.g. full-redeploy-sepolia-stack.sh) before redeploying the validator.", ) } } @@ -69,7 +69,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { process.env.DISABLE_HARDHAT_VERIFY !== "true" ) { await verifyOnEtherscanOrContinue(hre, () => - helpers.etherscan.verify(EcdsaDkgValidator) + helpers.etherscan.verify(EcdsaDkgValidator), ) } @@ -78,7 +78,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { hre.tenderly.verify({ name: "EcdsaDkgValidator", address: EcdsaDkgValidator.address, - }) + }), ) } diff --git a/solidity/ecdsa/deploy/03_deploy_wallet_registry.ts b/solidity/ecdsa/deploy/03_deploy_wallet_registry.ts index 49d513f794..ab479db2b9 100644 --- a/solidity/ecdsa/deploy/03_deploy_wallet_registry.ts +++ b/solidity/ecdsa/deploy/03_deploy_wallet_registry.ts @@ -12,7 +12,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const existingWalletRegistry = await deployments.getOrNull("WalletRegistry") if (existingWalletRegistry) { console.log( - `using existing WalletRegistry at ${existingWalletRegistry.address}` + `using existing WalletRegistry at ${existingWalletRegistry.address}`, ) return true } @@ -52,13 +52,13 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { unsafeAllow: ["external-library-linking"], kind: "transparent", }, - } + }, ) await helpers.ownable.transferOwnership( "EcdsaSortitionPool", - walletRegistry.address, - deployer + await walletRegistry.getAddress(), + deployer, ) if ( @@ -79,11 +79,11 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { } if (hre.network.tags.tenderly) { - await verifyOnTenderlyOrContinue(hre, () => + await verifyOnTenderlyOrContinue(hre, async () => hre.tenderly.verify({ name: "WalletRegistry", - address: walletRegistry.address, - }) + address: await walletRegistry.getAddress(), + }), ) } diff --git a/solidity/ecdsa/deploy/04_upgrade_random_beacon_chaosnet.ts b/solidity/ecdsa/deploy/04_upgrade_random_beacon_chaosnet.ts index 216d0862d7..808993730c 100644 --- a/solidity/ecdsa/deploy/04_upgrade_random_beacon_chaosnet.ts +++ b/solidity/ecdsa/deploy/04_upgrade_random_beacon_chaosnet.ts @@ -16,7 +16,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { "WalletRegistry", { from: deployer, log: true, waitConfirmations: 1 }, "upgradeRandomBeacon", - RandomBeaconChaosnet.address + RandomBeaconChaosnet.address, ) } diff --git a/solidity/ecdsa/deploy/05_authorize_in_random_beacon_chaosnet.ts b/solidity/ecdsa/deploy/05_authorize_in_random_beacon_chaosnet.ts index 9f265595df..7b109d84c0 100644 --- a/solidity/ecdsa/deploy/05_authorize_in_random_beacon_chaosnet.ts +++ b/solidity/ecdsa/deploy/05_authorize_in_random_beacon_chaosnet.ts @@ -13,7 +13,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { { from: deployer, log: true, waitConfirmations: 1 }, "setRequesterAuthorization", WalletRegistry.address, - true + true, ) } diff --git a/solidity/ecdsa/deploy/06_transfer_ownership_random_beacon_chaosnet.ts b/solidity/ecdsa/deploy/06_transfer_ownership_random_beacon_chaosnet.ts index 4972f0ee36..810e71c8e7 100644 --- a/solidity/ecdsa/deploy/06_transfer_ownership_random_beacon_chaosnet.ts +++ b/solidity/ecdsa/deploy/06_transfer_ownership_random_beacon_chaosnet.ts @@ -8,7 +8,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { await helpers.ownable.transferOwnership( "RandomBeaconChaosnet", governance, - deployer + deployer, ) } diff --git a/solidity/ecdsa/deploy/07_approve_wallet_registry.ts b/solidity/ecdsa/deploy/07_approve_wallet_registry.ts index 8901e153af..618da0ba67 100644 --- a/solidity/ecdsa/deploy/07_approve_wallet_registry.ts +++ b/solidity/ecdsa/deploy/07_approve_wallet_registry.ts @@ -1,11 +1,10 @@ import type { HardhatRuntimeEnvironment } from "hardhat/types" import type { DeployFunction } from "hardhat-deploy/types" -import type { utils } from "ethers" +import type { Interface } from "ethers" -function ifaceHasFunction(iface: utils.Interface, name: string): boolean { +function ifaceHasFunction(iface: Interface, name: string): boolean { try { - iface.getFunction(name) - return true + return iface.getFunction(name) !== null } catch { return false } @@ -19,10 +18,10 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const WalletRegistry = await deployments.get("WalletRegistry") const TokenStaking = await get("TokenStaking") - const iface = new ethers.utils.Interface(TokenStaking.abi) + const iface = new ethers.Interface(TokenStaking.abi) if (!ifaceHasFunction(iface, "approveApplication")) { hre.deployments.log( - "TokenStaking does not have approveApplication (Threshold TokenStaking); skipping WalletRegistry approval" + "TokenStaking does not have approveApplication (Threshold TokenStaking); skipping WalletRegistry approval", ) return } @@ -31,7 +30,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { "TokenStaking", { from: deployer, log: true, waitConfirmations: 1 }, "approveApplication", - WalletRegistry.address + WalletRegistry.address, ) } diff --git a/solidity/ecdsa/deploy/08_authorize_wallet_registry.ts b/solidity/ecdsa/deploy/08_authorize_wallet_registry.ts index 4d2b18c9e5..3cc793636f 100644 --- a/solidity/ecdsa/deploy/08_authorize_wallet_registry.ts +++ b/solidity/ecdsa/deploy/08_authorize_wallet_registry.ts @@ -12,7 +12,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { "ReimbursementPool", { from: deployer, log: true, waitConfirmations: 1 }, "authorize", - WalletRegistry.address + WalletRegistry.address, ) } diff --git a/solidity/ecdsa/deploy/09_deploy_wallet_registry_governance.ts b/solidity/ecdsa/deploy/09_deploy_wallet_registry_governance.ts index 09a9831e3a..e2c119cf55 100644 --- a/solidity/ecdsa/deploy/09_deploy_wallet_registry_governance.ts +++ b/solidity/ecdsa/deploy/09_deploy_wallet_registry_governance.ts @@ -20,7 +20,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { args: [WalletRegistry.address, GOVERNANCE_DELAY], log: true, waitConfirmations: 1, - } + }, ) if ( @@ -28,7 +28,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { process.env.DISABLE_HARDHAT_VERIFY !== "true" ) { await verifyOnEtherscanOrContinue(hre, () => - helpers.etherscan.verify(WalletRegistryGovernance) + helpers.etherscan.verify(WalletRegistryGovernance), ) } @@ -37,7 +37,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { hre.tenderly.verify({ name: "WalletRegistryGovernance", address: WalletRegistryGovernance.address, - }) + }), ) } } diff --git a/solidity/ecdsa/deploy/10_transfer_governance.ts b/solidity/ecdsa/deploy/10_transfer_governance.ts index 1b2b0824b9..741b3ebf03 100644 --- a/solidity/ecdsa/deploy/10_transfer_governance.ts +++ b/solidity/ecdsa/deploy/10_transfer_governance.ts @@ -6,20 +6,20 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const { deployer, governance } = await getNamedAccounts() const WalletRegistryGovernance = await deployments.get( - "WalletRegistryGovernance" + "WalletRegistryGovernance", ) await helpers.ownable.transferOwnership( "WalletRegistryGovernance", governance, - deployer + deployer, ) await deployments.execute( "WalletRegistry", { from: deployer, log: true, waitConfirmations: 1 }, "transferGovernance", - WalletRegistryGovernance.address + WalletRegistryGovernance.address, ) } diff --git a/solidity/ecdsa/deploy/11_transfer_proxy_admin_ownership.ts b/solidity/ecdsa/deploy/11_transfer_proxy_admin_ownership.ts index 9b022cc8f1..d6270f17bf 100644 --- a/solidity/ecdsa/deploy/11_transfer_proxy_admin_ownership.ts +++ b/solidity/ecdsa/deploy/11_transfer_proxy_admin_ownership.ts @@ -21,7 +21,9 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { if (!helpers.address.equal(currentOwner, newProxyAdminOwner)) { log(`transferring ownership of ProxyAdmin to ${newProxyAdminOwner}`) await ( - await proxyAdmin.connect(deployer).transferOwnership(newProxyAdminOwner) + await proxyAdmin.connect(deployer).getFunction("transferOwnership")( + newProxyAdminOwner, + ) ).wait() } } diff --git a/solidity/ecdsa/deploy/12_deploy_proxy_admin_with_deputy.ts b/solidity/ecdsa/deploy/12_deploy_proxy_admin_with_deputy.ts index 7537fcb4b1..02ff72cb68 100644 --- a/solidity/ecdsa/deploy/12_deploy_proxy_admin_with_deputy.ts +++ b/solidity/ecdsa/deploy/12_deploy_proxy_admin_with_deputy.ts @@ -13,7 +13,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { args: [dao, esdm], log: true, waitConfirmations: 1, - } + }, ) const WalletRegistry = await deployments.get("WalletRegistry") @@ -23,10 +23,10 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { await ( await proxyAdmin .connect(await ethers.getSigner(esdm)) - .changeProxyAdmin( - WalletRegistry.address, - WalletRegistryProxyAdminWithDeputy.address - ) + .getFunction("changeProxyAdmin")( + WalletRegistry.address, + WalletRegistryProxyAdminWithDeputy.address, + ) ).wait() } diff --git a/solidity/ecdsa/deploy/13_authorize_in_random_beacon.ts b/solidity/ecdsa/deploy/13_authorize_in_random_beacon.ts index 06f5da031f..70a71b2e8b 100644 --- a/solidity/ecdsa/deploy/13_authorize_in_random_beacon.ts +++ b/solidity/ecdsa/deploy/13_authorize_in_random_beacon.ts @@ -19,7 +19,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { { from, log: true, waitConfirmations: 1 }, "setRequesterAuthorization", WalletRegistry.address, - true + true, ) } diff --git a/solidity/ecdsa/deploy/14_transfer_reimbursement_pool_ownerhsip.ts b/solidity/ecdsa/deploy/14_transfer_reimbursement_pool_ownerhsip.ts index 289989a59f..b1adde453b 100644 --- a/solidity/ecdsa/deploy/14_transfer_reimbursement_pool_ownerhsip.ts +++ b/solidity/ecdsa/deploy/14_transfer_reimbursement_pool_ownerhsip.ts @@ -8,7 +8,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { await helpers.ownable.transferOwnership( "ReimbursementPool", governance, - deployer + deployer, ) } diff --git a/solidity/ecdsa/deploy/15_deploy_allowlist.ts b/solidity/ecdsa/deploy/15_deploy_allowlist.ts index 3a93b269be..1e187f6f87 100644 --- a/solidity/ecdsa/deploy/15_deploy_allowlist.ts +++ b/solidity/ecdsa/deploy/15_deploy_allowlist.ts @@ -21,7 +21,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { proxyOpts: { kind: "transparent", }, - } + }, ) // IMPORTANT: Do NOT transfer ownership here! @@ -37,14 +37,12 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { // Ownership transfer is handled at the END of script 16 after weights are set. // Log deployment information - console.log(`Allowlist deployed at: ${allowlist.address}`) - console.log( - `Allowlist proxy admin: ${proxyDeployment.receipt.contractAddress}` - ) + console.log(`Allowlist deployed at: ${await allowlist.getAddress()}`) + console.log(`Allowlist proxy deployed at: ${proxyDeployment.address}`) console.log(`Allowlist owner: ${await allowlist.owner()} (deployer)`) if (governance && governance !== deployer) { console.log( - `Ownership will be transferred to governance (${governance}) after weights initialization` + `Ownership will be transferred to governance (${governance}) after weights initialization`, ) } @@ -63,7 +61,7 @@ func.skip = async (hre: HardhatRuntimeEnvironment) => { const existingAllowlist = await deployments.getOrNull("Allowlist") if (existingAllowlist) { console.log( - `Skipping Allowlist deployment - already deployed at ${existingAllowlist.address}` + `Skipping Allowlist deployment - already deployed at ${existingAllowlist.address}`, ) return true } diff --git a/solidity/ecdsa/deploy/16_initialize_allowlist_weights.ts b/solidity/ecdsa/deploy/16_initialize_allowlist_weights.ts index 7a4a5920fa..485eddac23 100644 --- a/solidity/ecdsa/deploy/16_initialize_allowlist_weights.ts +++ b/solidity/ecdsa/deploy/16_initialize_allowlist_weights.ts @@ -50,11 +50,11 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { // Use network-specific file if available const networkSpecificPath = path.join( __dirname, - `../deploy-data/allowlist-weights-${hre.network.name}.json` + `../deploy-data/allowlist-weights-${hre.network.name}.json`, ) const defaultPath = path.join( __dirname, - "../deploy-data/allowlist-weights.json" + "../deploy-data/allowlist-weights.json", ) const weightsPath = fs.existsSync(networkSpecificPath) ? networkSpecificPath @@ -63,12 +63,12 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { if (!fs.existsSync(weightsPath)) { throw new Error( `Weights file not found at ${weightsPath}. ` + - "Please ensure allowlist-weights.json exists in deploy-data/" + "Please ensure allowlist-weights.json exists in deploy-data/", ) } const weightsData: WeightsData = JSON.parse( - fs.readFileSync(weightsPath, "utf8") + fs.readFileSync(weightsPath, "utf8"), ) console.log("=== ALLOWLIST INITIALIZATION ===") @@ -83,11 +83,11 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const allowlist = await ethers.getContractAt( "Allowlist", - allowlistDeployment.address + allowlistDeployment.address, ) const walletRegistry = await ethers.getContractAt( "WalletRegistry", - walletRegistryDeployment.address + walletRegistryDeployment.address, ) // Get the actual owner of Allowlist (should be deployer at this point) @@ -97,8 +97,8 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const currentOwner = await allowlist.owner() const ownerSigner = await ethers.getSigner(currentOwner) - console.log(`Allowlist address: ${allowlist.address}`) - console.log(`WalletRegistry address: ${walletRegistry.address}`) + console.log(`Allowlist address: ${await allowlist.getAddress()}`) + console.log(`WalletRegistry address: ${await walletRegistry.getAddress()}`) console.log(`Allowlist owner: ${currentOwner}`) console.log(`Owner signer: ${await ownerSigner.getAddress()}`) console.log() @@ -110,7 +110,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { console.log( `${consolidation.providerGroup}: ` + `${consolidation.consolidatedOperators} operators -> 1 ` + - `(accumulated: ${consolidation.accumulatedStake.toLocaleString()} T)` + `(accumulated: ${consolidation.accumulatedStake.toLocaleString()} T)`, ) } console.log() @@ -136,15 +136,15 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { // eslint-disable-next-line no-await-in-loop const existingWeight = await allowlist.authorizedStake( op.stakingProvider, - ethers.constants.AddressZero + ethers.ZeroAddress, ) - if (existingWeight.gt(0)) { + if (existingWeight > 0n) { console.log( `Skipping ${op.identification} (${op.stakingProvider.slice( 0, - 10 - )}...) - already in Allowlist` + 10, + )}...) - already in Allowlist`, ) migrationResults.push({ stakingProvider: op.stakingProvider, @@ -168,7 +168,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { // eslint-disable-next-line no-await-in-loop const tx = await allowlist .connect(ownerSigner) - .addStakingProvider(op.stakingProvider, op.weight) + .getFunction("addStakingProvider")(op.stakingProvider, op.weight) // eslint-disable-next-line no-await-in-loop const receipt = await tx.wait() @@ -204,31 +204,34 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const currentAllowlist = await walletRegistry.allowlist() - if (currentAllowlist === ethers.constants.AddressZero) { + if (currentAllowlist === ethers.ZeroAddress) { console.error("ERROR: WalletRegistry V2 is not initialized!") console.error() console.error("Please run the upgrade script first:") console.error( - " UPGRADE_WALLET_REGISTRY_V2=true npx hardhat deploy --tags UpgradeWalletRegistryV2" + " UPGRADE_WALLET_REGISTRY_V2=true npx hardhat deploy --tags UpgradeWalletRegistryV2", ) console.error() console.error( - "The upgrade script atomically upgrades WalletRegistry and calls initializeV2." + "The upgrade script atomically upgrades WalletRegistry and calls initializeV2.", ) return false } - if (currentAllowlist.toLowerCase() !== allowlist.address.toLowerCase()) { + if ( + currentAllowlist.toLowerCase() !== + (await allowlist.getAddress()).toLowerCase() + ) { console.error( - "ERROR: WalletRegistry is initialized with a different Allowlist!" + "ERROR: WalletRegistry is initialized with a different Allowlist!", ) console.error(` Current: ${currentAllowlist}`) - console.error(` Expected: ${allowlist.address}`) + console.error(` Expected: ${await allowlist.getAddress()}`) return false } console.log( - `WalletRegistry V2 initialized with Allowlist: ${currentAllowlist}` + `WalletRegistry V2 initialized with Allowlist: ${currentAllowlist}`, ) console.log("Verification: PASSED") @@ -237,13 +240,13 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { console.log("=== MIGRATION SUMMARY ===") const successful = migrationResults.filter( - (r) => r.status === "success" + (r) => r.status === "success", ).length const failed = migrationResults.filter((r) => - r.status.startsWith("failed") + r.status.startsWith("failed"), ).length const skipped = migrationResults.filter((r) => - r.status.startsWith("skipped") + r.status.startsWith("skipped"), ).length console.log(`Total operators processed: ${migrationResults.length}`) @@ -252,10 +255,10 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { console.log(`Failed: ${failed}`) console.log() console.log( - `Total accumulated stake: ${weightsData.summary.totalAccumulatedTStake.toLocaleString()} T` + `Total accumulated stake: ${weightsData.summary.totalAccumulatedTStake.toLocaleString()} T`, ) console.log( - `Stake increase from consolidation: +${weightsData.summary.stakeIncreaseFromConsolidation.toLocaleString()} T` + `Stake increase from consolidation: +${weightsData.summary.stakeIncreaseFromConsolidation.toLocaleString()} T`, ) // Save migration results @@ -266,8 +269,8 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { { timestamp: new Date().toISOString(), network: hre.network.name, - allowlistAddress: allowlist.address, - walletRegistryAddress: walletRegistry.address, + allowlistAddress: await allowlist.getAddress(), + walletRegistryAddress: await walletRegistry.getAddress(), weightsSource: weightsData.metadata.source, weightsGeneratedAt: weightsData.metadata.generatedAt, summary: { @@ -283,8 +286,8 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { results: migrationResults, }, null, - 2 - ) + 2, + ), ) console.log() @@ -307,18 +310,18 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { console.log("Allowlist uses Ownable2StepUpgradeable (two-step transfer):") console.log(" Step 1: transferOwnership(governance) - sets pendingOwner") console.log( - " Step 2: governance calls acceptOwnership() - completes transfer" + " Step 2: governance calls acceptOwnership() - completes transfer", ) console.log() try { console.log( - `Initiating transfer from ${currentOwner} to ${governance}...` + `Initiating transfer from ${currentOwner} to ${governance}...`, ) const tx = await allowlist .connect(ownerSigner) - .transferOwnership(governance) + .getFunction("transferOwnership")(governance) await tx.wait() @@ -330,27 +333,27 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { console.log(`Pending owner set to: ${pendingOwner}`) console.log() console.log( - "IMPORTANT: Governance must call Allowlist.acceptOwnership() to complete the transfer!" + "IMPORTANT: Governance must call Allowlist.acceptOwnership() to complete the transfer!", ) console.log( - `Until then, the current owner remains: ${await allowlist.owner()}` + `Until then, the current owner remains: ${await allowlist.owner()}`, ) } catch (error: any) { console.error(` FAILED: ${error.message}`) console.log() console.warn( - "WARNING: Ownership transfer failed. Manual intervention required." + "WARNING: Ownership transfer failed. Manual intervention required.", ) throw new Error( `Ownership transfer failed; manual intervention required: ${ error instanceof Error ? error.message : String(error) - }` + }`, ) } } else { console.log() console.log( - "Ownership transfer not needed (owner is already governance or same account)." + "Ownership transfer not needed (owner is already governance or same account).", ) } diff --git a/solidity/ecdsa/deploy/17_upgrade_wallet_registry_v2.ts b/solidity/ecdsa/deploy/17_upgrade_wallet_registry_v2.ts index 9ca18939b1..af353f1569 100644 --- a/solidity/ecdsa/deploy/17_upgrade_wallet_registry_v2.ts +++ b/solidity/ecdsa/deploy/17_upgrade_wallet_registry_v2.ts @@ -48,7 +48,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const walletRegistryDeployment = await deployments.get("WalletRegistry") const walletRegistryBefore = await ethers.getContractAt( "WalletRegistry", - walletRegistryDeployment.address + walletRegistryDeployment.address, ) console.log("Current WalletRegistry state:") @@ -56,10 +56,10 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { // Check if already upgraded (allowlist is set) // Note: V1 doesn't have allowlist() function, so we need to handle that case - let currentAllowlist = ethers.constants.AddressZero + let currentAllowlist = ethers.ZeroAddress try { currentAllowlist = await walletRegistryBefore.allowlist() - if (currentAllowlist !== ethers.constants.AddressZero) { + if (currentAllowlist !== ethers.ZeroAddress) { console.log(` Allowlist: ${currentAllowlist}`) console.log() console.log("WalletRegistry is already upgraded to V2!") @@ -81,23 +81,21 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { // Get ProxyAdmin address from EIP-1967 slot const ADMIN_SLOT = "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103" - const proxyAdminSlot = await ethers.provider.getStorageAt( + const proxyAdminSlot = await ethers.provider.getStorage( walletRegistryDeployment.address, - ADMIN_SLOT - ) - const proxyAdminAddress = ethers.utils.getAddress( - `0x${proxyAdminSlot.slice(-40)}` + ADMIN_SLOT, ) + const proxyAdminAddress = ethers.getAddress(`0x${proxyAdminSlot.slice(-40)}`) console.log(` ProxyAdmin: ${proxyAdminAddress}`) // Get current implementation const IMPL_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc" - const implSlot = await ethers.provider.getStorageAt( + const implSlot = await ethers.provider.getStorage( walletRegistryDeployment.address, - IMPL_SLOT + IMPL_SLOT, ) - const currentImpl = ethers.utils.getAddress(`0x${implSlot.slice(-40)}`) + const currentImpl = ethers.getAddress(`0x${implSlot.slice(-40)}`) console.log(` Current Implementation: ${currentImpl}`) // Verify governance state is preserved @@ -116,35 +114,44 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { libraries: { EcdsaInactivity: EcdsaInactivity.address, }, - } + }, ) // Deploy implementation with constructor args (immutable variables) const newImplementation = await WalletRegistryFactory.deploy( EcdsaSortitionPool.address, - TokenStaking.address + TokenStaking.address, ) - await newImplementation.deployed() + await newImplementation.waitForDeployment() - console.log(`New implementation deployed: ${newImplementation.address}`) - console.log(` TX: ${newImplementation.deployTransaction.hash}`) + const deploymentTransaction = newImplementation.deploymentTransaction() + if (!deploymentTransaction) { + throw new Error( + "WalletRegistry implementation deployment has no transaction", + ) + } + + console.log( + `New implementation deployed: ${await newImplementation.getAddress()}`, + ) + console.log(` TX: ${deploymentTransaction.hash}`) console.log() // Save deployment artifact await deployments.save("WalletRegistryV2Implementation", { - address: newImplementation.address, - abi: WalletRegistryFactory.interface.format("json") as any, - transactionHash: newImplementation.deployTransaction.hash, + address: await newImplementation.getAddress(), + abi: JSON.parse(WalletRegistryFactory.interface.formatJson()), + transactionHash: deploymentTransaction.hash, }) // Encode initializeV2 call const initializeV2Data = WalletRegistryFactory.interface.encodeFunctionData( "initializeV2", - [Allowlist.address] + [Allowlist.address], ) // Encode upgradeAndCall for ProxyAdmin - const proxyAdminInterface = new ethers.utils.Interface([ + const proxyAdminInterface = new ethers.Interface([ "function upgradeAndCall(address proxy, address implementation, bytes calldata data) external payable", "function owner() external view returns (address)", ]) @@ -153,15 +160,15 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { "upgradeAndCall", [ walletRegistryDeployment.address, - newImplementation.address, + await newImplementation.getAddress(), initializeV2Data, - ] + ], ) // Get ProxyAdmin owner const proxyAdmin = await ethers.getContractAt( ["function owner() view returns (address)"], - proxyAdminAddress + proxyAdminAddress, ) const proxyAdminOwner = await proxyAdmin.owner() console.log(`ProxyAdmin owner: ${proxyAdminOwner}`) @@ -172,7 +179,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { console.log("=== MAINNET GOVERNANCE PROPOSAL ===") console.log() console.log( - "The upgrade must be executed through the Timelock (24h delay)." + "The upgrade must be executed through the Timelock (24h delay).", ) console.log() console.log("Step 1: Schedule the upgrade via Timelock") @@ -189,7 +196,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { // prettier-ignore console.log(" \"upgradeAndCall(address,address,bytes)\" \\") console.log(` ${walletRegistryDeployment.address} \\`) - console.log(` ${newImplementation.address} \\`) + console.log(` ${await newImplementation.getAddress()} \\`) console.log(` ${initializeV2Data} \\`) console.log(" --rpc-url $CHAIN_API_URL \\") console.log(" --private-key ") @@ -210,7 +217,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { network: network.name, timestamp: new Date().toISOString(), description: "Upgrade WalletRegistry to V2 with Allowlist integration", - newImplementation: newImplementation.address, + newImplementation: await newImplementation.getAddress(), proxy: walletRegistryDeployment.address, proxyAdmin: proxyAdminAddress, proxyAdminOwner, @@ -233,7 +240,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const proposalPath = path.join( __dirname, - "../upgrade-proposal-mainnet.json" + "../upgrade-proposal-mainnet.json", ) fs.writeFileSync(proposalPath, JSON.stringify(proposalData, null, 2)) console.log(`Proposal data saved to: ${proposalPath}`) @@ -256,7 +263,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { // prettier-ignore console.log(" \"upgradeAndCall(address,address,bytes)\" \\") console.log(` ${walletRegistryDeployment.address} \\`) - console.log(` ${newImplementation.address} \\`) + console.log(` ${await newImplementation.getAddress()} \\`) console.log(` "${initializeV2Data}" \\`) console.log(" --rpc-url $CHAIN_API_URL \\") console.log(" --private-key ") @@ -270,14 +277,14 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { "function upgradeAndCall(address proxy, address implementation, bytes calldata data) external payable", ], proxyAdminAddress, - esdm + esdm, ) console.log("Calling ProxyAdmin.upgradeAndCall()...") const tx = await proxyAdminContract.upgradeAndCall( walletRegistryDeployment.address, - newImplementation.address, - initializeV2Data + await newImplementation.getAddress(), + initializeV2Data, ) console.log(`TX: ${tx.hash}`) @@ -291,7 +298,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const walletRegistryV2 = await ethers.getContractAt( "WalletRegistry", - walletRegistryDeployment.address + walletRegistryDeployment.address, ) const newAllowlist = await walletRegistryV2.allowlist() @@ -317,7 +324,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { // prettier-ignore console.log(" \"upgradeAndCall(address,address,bytes)\" \\") console.log(` ${walletRegistryDeployment.address} \\`) - console.log(` ${newImplementation.address} \\`) + console.log(` ${await newImplementation.getAddress()} \\`) console.log(` "${initializeV2Data}" \\`) console.log(" --rpc-url $CHAIN_API_URL \\") console.log(" --private-key ") diff --git a/solidity/ecdsa/deploy/etherscanVerification.ts b/solidity/ecdsa/deploy/etherscanVerification.ts index 5a561ec283..e46d03e3d2 100644 --- a/solidity/ecdsa/deploy/etherscanVerification.ts +++ b/solidity/ecdsa/deploy/etherscanVerification.ts @@ -17,7 +17,7 @@ import type { HardhatRuntimeEnvironment } from "hardhat/types" */ export default async function verifyOnEtherscanOrContinue( hre: HardhatRuntimeEnvironment, - verify: () => Promise + verify: () => Promise, ): Promise { try { await verify() @@ -26,7 +26,7 @@ export default async function verifyOnEtherscanOrContinue( throw err } hre.deployments.log( - `Etherscan verification skipped (deploy continues): ${err}` + `Etherscan verification skipped (deploy continues): ${err}`, ) } } diff --git a/solidity/ecdsa/deploy/tenderlyVerification.ts b/solidity/ecdsa/deploy/tenderlyVerification.ts index d3c5283fd8..bf8e90c527 100644 --- a/solidity/ecdsa/deploy/tenderlyVerification.ts +++ b/solidity/ecdsa/deploy/tenderlyVerification.ts @@ -15,7 +15,7 @@ import type { HardhatRuntimeEnvironment } from "hardhat/types" */ export default async function verifyOnTenderlyOrContinue( hre: HardhatRuntimeEnvironment, - verify: () => Promise + verify: () => Promise, ): Promise { try { await verify() @@ -24,7 +24,7 @@ export default async function verifyOnTenderlyOrContinue( throw err } hre.deployments.log( - `Tenderly verification skipped (deploy continues): ${err}` + `Tenderly verification skipped (deploy continues): ${err}`, ) } } diff --git a/solidity/ecdsa/eslint.config.mjs b/solidity/ecdsa/eslint.config.mjs new file mode 100644 index 0000000000..2a0cb7e9fb --- /dev/null +++ b/solidity/ecdsa/eslint.config.mjs @@ -0,0 +1,546 @@ +// Preserve the active non-React rules from the former Thesis/Airbnb config. +// Formatting is checked by Prettier; generated code is excluded below. +import tseslint from "typescript-eslint" +import importPlugin from "eslint-plugin-import-x" +import noOnlyTests from "eslint-plugin-no-only-tests" +import stylistic from "@stylistic/eslint-plugin" +import globals from "globals" + +export default [ + { + ignores: [ + "**/.hardhat/**", + "**/artifacts/**", + "**/build/**", + "**/cache/**", + "**/deployments/**", + "**/export/**", + "**/external/**", + "**/hardhat-dependency-compiler/**", + "**/tasks/legacy-random-beacon/**", + "**/typechain/**", + "**/export.json", + ], + }, + { + files: ["**/*.{js,cjs,mjs,ts}"], + languageOptions: { ecmaVersion: "latest", globals: globals.node }, + plugins: { + import: importPlugin, + "no-only-tests": noOnlyTests, + "@stylistic": stylistic, + }, + settings: { + "import-x/resolver": { + typescript: { project: "./tsconfig.json" }, + node: true, + }, + "import-x/parsers": { "@typescript-eslint/parser": [".ts"] }, + }, + rules: { + "import/no-extraneous-dependencies": [ + "error", + { + devDependencies: [ + "test/**/*.ts", + "tasks/**/*.ts", + "hardhat.config.ts", + "*.config.mjs", + ".prettierrc.js", + ], + }, + ], + "no-plusplus": [ + "error", + { + allowForLoopAfterthoughts: true, + }, + ], + "import/order": [ + "warn", + { + groups: ["builtin", "external", "parent", "sibling", "index", "type"], + "newlines-between": "always", + warnOnUnassignedImports: false, + }, + ], + "no-param-reassign": [ + "error", + { + props: true, + ignorePropertyModificationsFor: [ + "acc", + "accumulator", + "e", + "ctx", + "context", + "req", + "request", + "res", + "response", + "$scope", + "staticContext", + ], + ignorePropertyModificationsForRegex: ["^immer"], + }, + ], + "no-var": ["error"], + "prefer-const": [ + "error", + { + destructuring: "any", + ignoreReadBeforeAssign: true, + }, + ], + "prefer-rest-params": ["error"], + "prefer-spread": ["error"], + "import/no-unresolved": [ + "error", + { + commonjs: true, + caseSensitive: true, + }, + ], + "import/namespace": ["error"], + "import/default": ["error"], + "import/export": ["error"], + "import/no-named-as-default": ["warn"], + "import/no-named-as-default-member": ["warn"], + "import/no-duplicates": ["warn"], + "import/extensions": [ + "error", + "ignorePackages", + { + js: "never", + mjs: "never", + jsx: "never", + ts: "never", + tsx: "never", + }, + ], + "no-underscore-dangle": [ + "error", + { + allow: ["__REDUX_DEVTOOLS_EXTENSION_COMPOSE__"], + allowAfterThis: false, + allowAfterSuper: false, + enforceInMethodNames: true, + allowAfterThisConstructor: false, + allowFunctionParams: true, + }, + ], + "class-methods-use-this": ["error"], + strict: ["error", "never"], + "import/no-mutable-exports": ["error"], + "import/no-amd": ["error"], + "import/first": ["error"], + "import/newline-after-import": ["error"], + "import/prefer-default-export": ["error"], + "import/no-absolute-path": ["error"], + "import/no-dynamic-require": ["error"], + "import/no-webpack-loader-syntax": ["error"], + "import/no-named-default": ["error"], + "import/no-self-import": ["error"], + "import/no-cycle": [ + "error", + { + ignoreExternal: false, + }, + ], + "import/no-useless-path-segments": [ + "error", + { + commonjs: true, + }, + ], + "arrow-body-style": [ + "error", + "as-needed", + { + requireReturnForObjectLiteral: false, + }, + ], + "no-class-assign": ["error"], + "no-useless-computed-key": ["error"], + "no-useless-rename": [ + "error", + { + ignoreDestructuring: false, + ignoreImport: false, + ignoreExport: false, + }, + ], + "object-shorthand": [ + "error", + "always", + { + ignoreConstructors: false, + avoidQuotes: true, + }, + ], + "prefer-arrow-callback": [ + "error", + { + allowNamedFunctions: false, + allowUnboundThis: true, + }, + ], + "prefer-destructuring": [ + "error", + { + VariableDeclarator: { + array: false, + object: true, + }, + AssignmentExpression: { + array: true, + object: false, + }, + }, + { + enforceForRenamedProperties: false, + }, + ], + "prefer-numeric-literals": ["error"], + "prefer-template": ["error"], + "require-yield": ["error"], + "symbol-description": ["error"], + "no-delete-var": ["error"], + "no-label-var": ["error"], + "no-restricted-globals": ["error", "isFinite", "isNaN"], + "no-shadow-restricted-names": ["error"], + "no-undef-init": ["error"], + "func-names": ["warn"], + "new-cap": [ + "error", + { + newIsCap: true, + newIsCapExceptions: [], + capIsNew: false, + capIsNewExceptions: [ + "Immutable.Map", + "Immutable.Set", + "Immutable.List", + ], + properties: true, + }, + ], + "no-bitwise": ["error"], + "no-continue": ["error"], + "no-lonely-if": ["error"], + "no-multi-assign": ["error"], + "no-nested-ternary": ["error"], + "no-restricted-syntax": [ + "error", + { + selector: "ForInStatement", + }, + { + selector: "ForOfStatement", + }, + { + selector: "LabeledStatement", + }, + { + selector: "WithStatement", + }, + ], + "no-unneeded-ternary": [ + "error", + { + defaultAssignment: false, + }, + ], + "one-var": ["error", "never"], + "operator-assignment": ["error", "always"], + "prefer-object-spread": ["error"], + "global-require": ["error"], + "no-buffer-constructor": ["error"], + "no-new-require": ["error"], + "no-path-concat": ["error"], + "for-direction": ["error"], + "no-async-promise-executor": ["error"], + "no-await-in-loop": ["error"], + "no-new-func": ["error"], + "no-promise-executor-return": ["error"], + "no-unreachable-loop": ["error"], + "no-dupe-else-if": ["error"], + "no-unsafe-optional-chaining": [ + "error", + { disallowArithmeticOperators: true }, + ], + "no-useless-backreference": ["error"], + "no-constructor-return": ["error"], + "grouped-accessor-pairs": ["error"], + "no-compare-neg-zero": ["error"], + "no-cond-assign": ["error", "always"], + "no-console": ["warn"], + "no-constant-condition": ["warn"], + "no-control-regex": ["error"], + "no-debugger": ["error"], + "no-duplicate-case": ["error"], + "no-empty": ["error"], + "no-empty-character-class": ["error"], + "no-ex-assign": ["error"], + "no-extra-boolean-cast": ["error"], + "no-inner-declarations": ["error"], + "no-invalid-regexp": ["error"], + "no-irregular-whitespace": ["error"], + "no-misleading-character-class": ["error"], + "no-prototype-builtins": ["error"], + "no-regex-spaces": ["error"], + "no-sparse-arrays": ["error"], + "no-template-curly-in-string": ["error"], + "no-unsafe-finally": ["error"], + "use-isnan": ["error"], + "array-callback-return": [ + "error", + { + allowImplicit: true, + checkForEach: false, + }, + ], + "block-scoped-var": ["error"], + "consistent-return": ["error"], + "default-case": [ + "error", + { + commentPattern: "^no default$", + }, + ], + eqeqeq: [ + "error", + "always", + { + null: "ignore", + }, + ], + "guard-for-in": ["error"], + "max-classes-per-file": ["error", 1], + "no-alert": ["warn"], + "no-caller": ["error"], + "no-case-declarations": ["error"], + "no-else-return": [ + "error", + { + allowElseIf: false, + }, + ], + "no-empty-pattern": ["error"], + "no-eval": ["error"], + "no-extend-native": ["error"], + "no-extra-bind": ["error"], + "no-extra-label": ["error"], + "no-fallthrough": ["error"], + "no-global-assign": [ + "error", + { + exceptions: [], + }, + ], + "no-iterator": ["error"], + "no-labels": [ + "error", + { + allowLoop: false, + allowSwitch: false, + }, + ], + "no-lone-blocks": ["error"], + "no-multi-str": ["error"], + "no-new": ["error"], + "no-new-wrappers": ["error"], + "no-octal": ["error"], + "no-octal-escape": ["error"], + "no-proto": ["error"], + "no-restricted-properties": [ + "error", + { + object: "arguments", + property: "callee", + }, + { + object: "global", + property: "isFinite", + }, + { + object: "self", + property: "isFinite", + }, + { + object: "window", + property: "isFinite", + }, + { + object: "global", + property: "isNaN", + }, + { + object: "self", + property: "isNaN", + }, + { + object: "window", + property: "isNaN", + }, + { + property: "__defineGetter__", + }, + { + property: "__defineSetter__", + }, + { + object: "Math", + property: "pow", + }, + ], + "no-return-assign": ["error", "always"], + "no-script-url": ["error"], + "no-self-assign": [ + "error", + { + props: true, + }, + ], + "no-self-compare": ["error"], + "no-sequences": ["error"], + "no-unused-labels": ["error"], + "no-useless-catch": ["error"], + "no-useless-concat": ["error"], + "no-useless-escape": ["error"], + "no-useless-return": ["error"], + "no-void": ["error"], + "no-with": ["error"], + "prefer-promise-reject-errors": [ + "error", + { + allowEmptyReject: true, + }, + ], + radix: ["error"], + "vars-on-top": ["error"], + yoda: ["error"], + "no-object-constructor": ["error"], + "@stylistic/spaced-comment": [ + "error", + "always", + { + line: { + exceptions: ["-", "+"], + markers: ["=", "!", "/"], + }, + block: { + exceptions: ["-", "+"], + markers: ["=", "!", ":", "::"], + balanced: true, + }, + }, + ], + "@stylistic/lines-between-class-members": [ + "error", + "always", + { + exceptAfterSingleLine: false, + }, + ], + "no-only-tests/no-only-tests": ["error"], + }, + }, + { + files: ["**/*.ts"], + languageOptions: { + parser: tseslint.parser, + sourceType: "module", + parserOptions: { + project: "./.tsconfig-eslint.json", + tsconfigRootDir: import.meta.dirname, + }, + }, + plugins: { "@typescript-eslint": tseslint.plugin }, + rules: { + "@typescript-eslint/consistent-type-imports": ["warn"], + "@typescript-eslint/adjacent-overload-signatures": ["error"], + "@typescript-eslint/ban-ts-comment": ["error"], + "@typescript-eslint/explicit-module-boundary-types": ["warn"], + "@typescript-eslint/no-array-constructor": ["error"], + "@typescript-eslint/no-empty-function": [ + "error", + { + allow: ["arrowFunctions", "functions", "methods"], + }, + ], + "@typescript-eslint/no-explicit-any": ["warn"], + "@typescript-eslint/no-extra-non-null-assertion": ["error"], + "@typescript-eslint/no-inferrable-types": ["error"], + "@typescript-eslint/no-misused-new": ["error"], + "@typescript-eslint/no-namespace": ["error"], + "@typescript-eslint/no-non-null-asserted-optional-chain": ["error"], + "@typescript-eslint/no-non-null-assertion": ["warn"], + "@typescript-eslint/no-this-alias": ["error"], + "@typescript-eslint/no-unused-vars": [ + "warn", + { + vars: "all", + args: "after-used", + ignoreRestSiblings: true, + }, + ], + "@typescript-eslint/prefer-as-const": ["error"], + "@typescript-eslint/prefer-namespace-keyword": ["error"], + "@typescript-eslint/triple-slash-reference": ["error"], + "@typescript-eslint/naming-convention": [ + "error", + { + selector: "variable", + format: ["camelCase", "PascalCase", "UPPER_CASE"], + }, + { + selector: "function", + format: ["camelCase", "PascalCase"], + }, + { + selector: "typeLike", + format: ["PascalCase"], + }, + ], + "@typescript-eslint/dot-notation": [ + "error", + { + allowKeywords: true, + allowPattern: "", + allowPrivateClassPropertyAccess: false, + allowProtectedClassPropertyAccess: false, + allowIndexSignaturePropertyAccess: false, + }, + ], + "@typescript-eslint/no-dupe-class-members": ["error"], + "@typescript-eslint/no-implied-eval": ["error"], + "@typescript-eslint/no-loop-func": ["error"], + "@typescript-eslint/no-redeclare": ["error"], + "@typescript-eslint/no-shadow": ["error"], + "@typescript-eslint/no-unused-expressions": [ + "error", + { + allowShortCircuit: false, + allowTernary: false, + allowTaggedTemplates: false, + enforceForJSX: false, + }, + ], + "@typescript-eslint/no-useless-constructor": ["error"], + "@typescript-eslint/return-await": ["error"], + "@typescript-eslint/no-empty-object-type": ["error"], + "@typescript-eslint/only-throw-error": ["error"], + "@typescript-eslint/no-require-imports": [ + "error", + { allowAsImport: true }, + ], + "@typescript-eslint/no-unsafe-function-type": ["error"], + "@typescript-eslint/no-wrapper-object-types": ["error"], + "@typescript-eslint/default-param-last": ["error"], + }, + }, + { files: ["test/**/*.ts"], languageOptions: { globals: globals.mocha } }, + { files: ["**/*.{js,cjs}"], languageOptions: { sourceType: "commonjs" } }, + { files: ["deploy/**/*.ts"], rules: { "no-console": "off" } }, +] diff --git a/solidity/ecdsa/export-baseline.sha256 b/solidity/ecdsa/export-baseline.sha256 new file mode 100644 index 0000000000..7cdbaea3b5 --- /dev/null +++ b/solidity/ecdsa/export-baseline.sha256 @@ -0,0 +1,83 @@ +b2eaf938d16b07298db4065909aea576b27ac10d119e23b2b8b50078d5924a7b export.json +3a30ca326e82feebdf751526de2c7aceeeb2258d15ffc22166c1d978faffe467 export/artifacts/@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol/SafeERC20Upgradeable.json +cc7ea5794dd9b985330a3b38712bc1293e89baccc6e2fa2fe764b76de8c536a6 export/artifacts/@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol/AddressUpgradeable.json +2b1720aa85c5ba7213304c6cea97cce77bc3a75cbaa50767b108bdcb9293e1a8 export/artifacts/@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol/StringsUpgradeable.json +7aca03497740ea17aec1e2fe202c3f49cb215ccab0887162b59afec8af0ce713 export/artifacts/@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol/ECDSAUpgradeable.json +3742b00c7fc8bf16d06ed7d10438d90d8427a13e9c5b15077b72f69e47d7e572 export/artifacts/@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol/MathUpgradeable.json +a4408dd730e8a036c54d1a78ed5c9c5da544ffd1f93cb8958061632321cca586 export/artifacts/@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol/SafeCastUpgradeable.json +a0793903fe492a350daef50411bd334f73870b98bca8e612a70c4fd4de8b063b export/artifacts/@openzeppelin/contracts-upgradeable/utils/math/SignedMathUpgradeable.sol/SignedMathUpgradeable.json +1642041b7f8b65973b41f3819ce45ec840c4dc4df0550c66313c53f01270f603 export/artifacts/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol/ERC1967Proxy.json +367662db1b73cd9cb1c340b2dfdc9728c78b0c0b0175b7cd75b254aa0c0f1e66 export/artifacts/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json +18c34d25c9e72529904770309c29b8abe8ce03fea866855b2f64a5b2963ef3b3 export/artifacts/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol/SafeERC20.json +53e76b480ecc4b3708ae23f0a1b28c89e965d3413fda19e82ee29ef845f885ac export/artifacts/@openzeppelin/contracts/utils/Address.sol/Address.json +509cc9e28d7b9e0c3d75198f7000af920fbbb8b82b1ecdc941c0605ad0918851 export/artifacts/@openzeppelin/contracts/utils/StorageSlot.sol/StorageSlot.json +a350398ffa274d83bed1289d3f9abd03aadf27633ba4cafc0ed6f1fd7006d3ce export/artifacts/@openzeppelin/contracts/utils/Strings.sol/Strings.json +d18a541b173dff1bb5c37896135b1f0ed5dc5a2277f80215684af64580b00705 export/artifacts/@openzeppelin/contracts/utils/cryptography/ECDSA.sol/ECDSA.json +a4e34754e3104a3fe8b33956f36d0ea303ecfac3c25012bddc6e0d5ac77b3a18 export/artifacts/@openzeppelin/contracts/utils/math/Math.sol/Math.json +f42ed542c7ca0de045541eb6099a1dfc3fe7157be7cb429e174be9ece53edd1e export/artifacts/@openzeppelin/contracts/utils/math/SafeCast.sol/SafeCast.json +a0477d5cae6b64f72b60513eda2bdadb35dc2dfab5d801389856cc6901480982 export/artifacts/@openzeppelin/contracts/utils/math/SignedMath.sol/SignedMath.json +070203d2a2b4d31bf41f919302e0e1792be6351a9a28608139ac32f5e887284e export/artifacts/@thesis/solidity-contracts/contracts/token/ERC20WithPermit.sol/ERC20WithPermit.json +53984896508e8ddc09055d2830339a4bcad29dba3a7957747a4510e9ef24835c export/artifacts/@thesis/solidity-contracts/contracts/token/MisfundRecovery.sol/MisfundRecovery.json +3ec236d2878e8b35e3fb7cbb7ed938f51c135043cac0932a65edb2d2944ca0a1 export/artifacts/@threshold-network/solidity-contracts/contracts/staking/TokenStaking.sol/TokenStaking.json +bdcc156776934335faeadd1235fb919367bc1e5a30daa1d024cd48e393c78168 export/artifacts/@threshold-network/solidity-contracts/contracts/token/T.sol/T.json +efe500ffe2b983e9be848227c15de8e50ca98e9192f6f971d6dee8b43592f757 export/artifacts/@threshold-network/solidity-contracts/contracts/utils/PercentUtils.sol/PercentUtils.json +5d5793b0e335a8729eb9aa7809fa32ca7cb88e1af01a1e52c1220eb4de040611 export/artifacts/@threshold-network/solidity-contracts/contracts/utils/SafeTUpgradeable.sol/SafeTUpgradeable.json +73cd8616fca637d81829c49b4cd2393b3055dee62f593b7f627889af62b98302 export/artifacts/@threshold-network/solidity-contracts/contracts/vending/VendingMachine.sol/VendingMachine.json +0c3004c046f3e3ae483ac94344b800fa153f67cd10f547210abace8b75d8eb2a export/artifacts/contracts/Allowlist.sol/Allowlist.json +ee0124c2c3590e346c012d099cf6217be53dcb68cebba9b80418f989a632dda1 export/artifacts/contracts/EcdsaDkgValidator.sol/EcdsaDkgValidator.json +eef360bca99d3b6ff20f45830fa9edd5db772d6a194fe6b5f5a593c1c9e9272e export/artifacts/contracts/WalletRegistry.sol/WalletRegistry.json +80026eb1e4073dd60a9aa1e4af43a4d47712b7b892b8e159a47773281be64d5a export/artifacts/contracts/WalletRegistryGovernance.sol/WalletRegistryGovernance.json +804fa94de2d1568a9f7654ee5d1c898d388b2068b6b798f1129d01a015dce610 export/artifacts/contracts/legacy/random-beacon/ReimbursementPool.sol/ReimbursementPool.json +b5acdf8f6e752ca9c8f260d87629ae1c544760a17f6f103c41991d12021eb509 export/artifacts/contracts/legacy/random-beacon/libraries/BytesLib.sol/BytesLib.json +8683f5a6baecea727684c2634f77be191030b15abd559b5473b1650933002a71 export/artifacts/contracts/legacy/random-beacon/libraries/Callback.sol/Callback.json +aa7c3572e8f15c1409b9b75c875f28e09ebf8c4508f9b11a6f805d8ce2ac4840 export/artifacts/contracts/legacy/sortition/Branch.sol/Branch.json +ed9590ae798dab6def6824c2c8cf495da7cdc624914740f37e6eabdb097191d0 export/artifacts/contracts/legacy/sortition/Chaosnet.sol/Chaosnet.json +7ee4d2d969ea016eb93026815fed7c10d66bfa6fb05188a5554e0dd7c65a6f3d export/artifacts/contracts/legacy/sortition/Constants.sol/Constants.json +d85fc4ffe49db3193834c2d081df1f38c10bbcc2ea2429a6c3c320db14b11315 export/artifacts/contracts/legacy/sortition/Leaf.sol/Leaf.json +8760b496da15181f996690fda689ca119b4cfa8c1507583a19fe1107df084e1f export/artifacts/contracts/legacy/sortition/Position.sol/Position.json +017d50f1545182065eebcf007e399e7902800a63989ded34c649e656e0d4983f export/artifacts/contracts/legacy/sortition/RNG.sol/RNG.json +870469b2861cc8e440b87fe22afc94a3eb6f69014df5cbd6febe0d5a2325936e export/artifacts/contracts/legacy/sortition/Rewards.sol/Rewards.json +d0738cf28d144135b7566b82e78ac699733592d4b7ab8a0d710c2a6202b085f3 export/artifacts/contracts/legacy/sortition/SortitionPool.sol/SortitionPool.json +b9d82a9248f8c3c9a59024f5c648835859665bbe93a2f41abca14e801a192b85 export/artifacts/contracts/legacy/sortition/SortitionTree.sol/SortitionTree.json +984f1a5b124efed514d381c36625c6d54381ab7db17c21541301888390ffa632 export/artifacts/contracts/libraries/EcdsaAuthorization.sol/EcdsaAuthorization.json +314e1452f90176a1fa79cb5ccc767cbea7c28658782973eae1d71a3be5307996 export/artifacts/contracts/libraries/EcdsaDkg.sol/EcdsaDkg.json +9342bc8294b45649ee8e5da019c783b4c8921d840696d385c4bcde1ed7ecb688 export/artifacts/contracts/libraries/EcdsaInactivity.sol/EcdsaInactivity.json +f04da642dfb46cf55c20331756c24a33f43ab22e21707cd7bce081bd09d7f034 export/artifacts/contracts/libraries/Wallets.sol/Wallets.json +8b61d6deaff3f44da785f326bc89eea1f428ba89f26f7d6a765b0888afb213d1 export/artifacts/contracts/test/DkgChallenger.sol/DkgChallenger.json +77b07a235c39b71262bcbfce87fc1c1e260839597cfe8020a67570c69564988c export/artifacts/contracts/test/MockContract.sol/MockContract.json +e9009c33bdaaca2b053dacd1c66c4e4a375df05dafa764533f3526204309ca3f export/artifacts/contracts/test/MockTargetConsumer.sol/MockTargetConsumer.json +950ab425ce75c9a8d49c311bde22a7435d52624fb6f82e596ed4c925d74153ce export/artifacts/contracts/test/RandomBeaconStub.sol/RandomBeaconStub.json +6b0358d0d371cae7533053d4ed95d09da6065e06cfb6a2ca877c86300a314c09 export/artifacts/contracts/test/WalletRegistryStub.sol/WalletRegistryStub.json +a1e419a33ffa6800d9fb7d92f57e75cdf5bbb516b9cc4a7c416674da4e3b6978 export/artifacts/contracts/test/upgrades/WalletRegistryV2.sol/WalletRegistryV2.json +c8486f81b3d791a1ac1a745ce0afc86f51566994c05747038141ae7688537a0e export/artifacts/contracts/test/upgrades/WalletRegistryV2MisplacedNewSlot.sol/WalletRegistryV2MisplacedNewSlot.json +1f0fa4b1426548059c3e302180b30a476683c6418c916c44e36fcf7e67da7ac0 export/artifacts/contracts/test/upgrades/WalletRegistryV2MissingSlot.sol/WalletRegistryV2MissingSlot.json +cb9e043c8b367cdf3d3c8155558d2fe5ef39547e506dc9d49871c5f57019766a export/deploy/00_log_external_deployments.js +2c3ec36b25515b37882e3257122e3b3d06cd5a987cd52bb6f1777d5f38394dbe export/deploy/00_resolve_random_beacon.js +b0f64c4f26d2a22c75d0f715bc34d128d40cdb8fdfac9db8cd80a1aead05827d export/deploy/00_resolve_random_beacon_chaosnet.js +98fdb175e6abba07e214ddf7ec522d3b0526081eb796d9041fd37db0b83aa066 export/deploy/00_resolve_reimbursement_pool.js +544a4d1e45c697304f355ec42fdd3d03c8668415e3165b9796406d835be6d80c export/deploy/00_resolve_token_staking.js +8cd73af459dcea2a0c81d453e56d190f82006535d3bb730350c06393e397d97d export/deploy/01_deploy_ecdsa_sortition_pool.js +0981bb7c24be09b39b7d5f39ecc933667adfc2991cce261018ad558bc2b13740 export/deploy/02_deploy_dkg_validator.js +7823892dca4a29a90a6a9c440a737b7cd66e354d6c8835ecbd511b432f5e43d4 export/deploy/03_deploy_wallet_registry.js +dc00fb7433b97f19a13c2d32e9c66daa03592ccbfae2ed74e0cbc57f837a920c export/deploy/04_upgrade_random_beacon_chaosnet.js +39fe289554f1630cb5100bce012c1be3f0230f0bebce80547553d6a23da4aae2 export/deploy/05_authorize_in_random_beacon_chaosnet.js +3e9c8ad80dde936aee0c95705bdbb544559993d4587839a65fc7b427f6f26885 export/deploy/06_transfer_ownership_random_beacon_chaosnet.js +0909d0cdf9ebb013f16ad6a38ababb74513545e089ebd0da60321526ea8240d0 export/deploy/07_approve_wallet_registry.js +1873bde07dae765880b9608aa2e6d115dfb903e1ac112131fcfa4fffdd98c15a export/deploy/08_authorize_wallet_registry.js +861f37f05e2d1e88d07dad2a858409798161dd9b4762bb8e133d0b99aaba0da2 export/deploy/09_deploy_wallet_registry_governance.js +6706e1c643ca7dc85a772d89b7b5df1dad214adee070783ddccdcb8bfaa433e7 export/deploy/10_transfer_governance.js +a346901a794f8438815b8c5d9790fba24d28f6d72c13bcba5bdec21949e52871 export/deploy/11_transfer_proxy_admin_ownership.js +1372ae784f9aaa6819e7aa6d661ea2fa038682cb2597f5bcbed6c3bd462224b1 export/deploy/12_deploy_proxy_admin_with_deputy.js +15ac5da9a177d9c64db0f61111b5a25dc3f191abcea521775d8d30bec32cc47a export/deploy/13_authorize_in_random_beacon.js +8550c65be55299dfd72538021e27b86f39e1f98f31aa0ee878b521dc47b3489e export/deploy/14_transfer_reimbursement_pool_ownerhsip.js +97b667f5e6fe8fa0ddcccb3be3561a746bb749630a01cc6fe28bbdf0f39bcca8 export/deploy/15_deploy_allowlist.js +39dca7317dafdea5a73e2651ddfea978062a45cd746acd0c081c3af3f6e1283d export/deploy/16_initialize_allowlist_weights.js +a9be64e4aa3a3c4c5a00753ca743b0d548c3d7d286a036f89ec3b8c5b1435338 export/deploy/17_upgrade_wallet_registry_v2.js +6ca5200a0e847f77214fe81b2be9262db012ef342d3abe8973c8b8193cf1eb69 export/deploy/etherscanVerification.js +e5e4354e40f830b4e57362802a857dca9370e225a08b3737bdcc4bc0b0f71960 export/deploy/tenderlyVerification.js +2901f0bd97e1a60babbab489ac745ff73fe3b455a52fb5ea4892139fe39f270e export/hardhat.config.js +eb6c89a466ed63b60ba79a273d285aed811b1d58c3cf794079553fc544c922e3 export/tasks/index.js +8877b2c460f39736efb87f2bb83aae40553f0d5a1b44a101de10e174fd3f9125 export/tasks/initialize-wallet-owner.js +519b80b9e5494bc0bfbe14416fb285bdb3f98273943cc814e84acd2a52eb9b28 export/tasks/initialize.js +2693ed0b67840cb2a6ea036d9d8911b015e8b1b41f653bda8826d80f269779a7 export/tasks/random-beacon.js +8ffab660becb20abac9e25799130c7950a8d294f9217214449afa54b40e70b28 export/utils/random-beacon-export.js diff --git a/solidity/ecdsa/export.json b/solidity/ecdsa/export.json index f8056f600b..ce8c815c2a 100644 --- a/solidity/ecdsa/export.json +++ b/solidity/ecdsa/export.json @@ -1,80 +1,38 @@ { - "name": "mainnet", - "chainId": "1", + "name": "hardhat", + "chainId": "31337", "contracts": { - "Allowlist": { - "address": "0x5e1b4e41ea2eea6ac7656431ccdc7b204a88386f", + "NuCypherToken": { + "address": "0x8464135c8F25Da09e49BC8782676a84730C318bC", "abi": [ { "inputs": [], "stateMutability": "nonpayable", "type": "constructor" }, - { - "inputs": [], - "name": "NoDecreasePending", - "type": "error" - }, - { - "inputs": [], - "name": "NotWalletRegistry", - "type": "error" - }, - { - "inputs": [], - "name": "RequestedWeightNotBelowCurrentWeight", - "type": "error" - }, - { - "inputs": [], - "name": "StakingProviderAlreadyAdded", - "type": "error" - }, - { - "inputs": [], - "name": "StakingProviderUnknown", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroWeight", - "type": "error" - }, { "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, { - "indexed": false, + "indexed": true, "internalType": "address", - "name": "notifier", + "name": "spender", "type": "address" }, { "indexed": false, - "internalType": "address[]", - "name": "stakingProviders", - "type": "address[]" + "internalType": "uint256", + "name": "value", + "type": "uint256" } ], - "name": "MaliciousBehaviorIdentified", + "name": "Approval", "type": "event" }, { @@ -93,7 +51,7 @@ "type": "address" } ], - "name": "OwnershipTransferStarted", + "name": "OwnershipTransferred", "type": "event" }, { @@ -102,110 +60,96 @@ { "indexed": true, "internalType": "address", - "name": "previousOwner", + "name": "from", "type": "address" }, { "indexed": true, "internalType": "address", - "name": "newOwner", + "name": "to", "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" } ], - "name": "OwnershipTransferred", + "name": "Transfer", "type": "event" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [ { - "indexed": false, - "internalType": "uint96", - "name": "weight", - "type": "uint96" + "internalType": "bytes32", + "name": "", + "type": "bytes32" } ], - "name": "StakingProviderAdded", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint96", - "name": "oldWeight", - "type": "uint96" - }, + "inputs": [], + "name": "PERMIT_TYPEHASH", + "outputs": [ { - "indexed": false, - "internalType": "uint96", - "name": "newWeight", - "type": "uint96" + "internalType": "bytes32", + "name": "", + "type": "bytes32" } ], - "name": "WeightDecreaseFinalized", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": true, "internalType": "address", - "name": "stakingProvider", + "name": "", "type": "address" }, { - "indexed": false, - "internalType": "uint96", - "name": "oldWeight", - "type": "uint96" - }, + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ { - "indexed": false, - "internalType": "uint96", - "name": "newWeight", - "type": "uint96" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "WeightDecreaseRequested", - "type": "event" - }, - { - "inputs": [], - "name": "acceptOwnership", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", - "name": "stakingProvider", + "name": "spender", "type": "address" }, { - "internalType": "uint96", - "name": "weight", - "type": "uint96" + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" } ], - "name": "addStakingProvider", - "outputs": [], "stateMutability": "nonpayable", "type": "function" }, @@ -213,16 +157,26 @@ "inputs": [ { "internalType": "address", - "name": "stakingProvider", + "name": "spender", "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "extraData", + "type": "bytes" } ], - "name": "approveAuthorizationDecrease", + "name": "approveAndCall", "outputs": [ { - "internalType": "uint96", + "internalType": "bool", "name": "", - "type": "uint96" + "type": "bool" } ], "stateMutability": "nonpayable", @@ -230,49 +184,62 @@ }, { "inputs": [ - { - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, { "internalType": "address", "name": "", "type": "address" } ], - "name": "authorizedStake", + "name": "balanceOf", "outputs": [ { - "internalType": "uint96", + "internalType": "uint256", "name": "", - "type": "uint96" + "type": "uint256" } ], "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { "internalType": "address", - "name": "_walletRegistry", + "name": "account", "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], - "name": "initialize", + "name": "burnFrom", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "owner", + "name": "cachedChainId", "outputs": [ { - "internalType": "address", + "internalType": "uint256", "name": "", - "type": "address" + "type": "uint256" } ], "stateMutability": "view", @@ -280,12 +247,12 @@ }, { "inputs": [], - "name": "pendingOwner", + "name": "cachedDomainSeparator", "outputs": [ { - "internalType": "address", + "internalType": "bytes32", "name": "", - "type": "address" + "type": "bytes32" } ], "stateMutability": "view", @@ -293,53 +260,43 @@ }, { "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", - "name": "stakingProvider", + "name": "recipient", "type": "address" }, { - "internalType": "uint96", - "name": "newWeight", - "type": "uint96" + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], - "name": "requestWeightDecrease", + "name": "mint", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "stakingProvider", - "type": "address" - } - ], - "name": "rolesOf", + "inputs": [], + "name": "name", "outputs": [ { - "internalType": "address", - "name": "stakeOwner", - "type": "address" - }, - { - "internalType": "address payable", - "name": "beneficiary", - "type": "address" - }, - { - "internalType": "address", - "name": "authorizer", - "type": "address" + "internalType": "string", + "name": "", + "type": "string" } ], "stateMutability": "view", @@ -348,57 +305,32 @@ { "inputs": [ { - "internalType": "uint96", + "internalType": "address", "name": "", - "type": "uint96" - }, + "type": "address" + } + ], + "name": "nonce", + "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" - }, - { - "internalType": "address", - "name": "notifier", - "type": "address" - }, - { - "internalType": "address[]", - "name": "_stakingProviders", - "type": "address[]" } ], - "name": "seize", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "owner", + "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], - "name": "stakingProviders", - "outputs": [ - { - "internalType": "uint96", - "name": "weight", - "type": "uint96" - }, - { - "internalType": "uint96", - "name": "pendingNewWeight", - "type": "uint96" - }, - { - "internalType": "bool", - "name": "decreasePending", - "type": "bool" - } - ], "stateMutability": "view", "type": "function" }, @@ -406,78 +338,60 @@ "inputs": [ { "internalType": "address", - "name": "newOwner", + "name": "owner", "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "walletRegistry", - "outputs": [ + }, { - "internalType": "contract WalletRegistry", - "name": "", + "internalType": "address", + "name": "spender", "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - } - ] - }, - "EcdsaDkgValidator": { - "address": "0x0125c8977a02b2Fa3970b1ED9AF02f5Bedd4eF27", - "abi": [ - { - "inputs": [ + }, { - "internalType": "contract SortitionPool", - "name": "_sortitionPool", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "activeThreshold", - "outputs": [ + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, { "internalType": "uint256", - "name": "", + "name": "deadline", "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" } ], - "stateMutability": "view", + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "groupSize", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "groupThreshold", + "name": "symbol", "outputs": [ { - "internalType": "uint256", + "internalType": "string", "name": "", - "type": "uint256" + "type": "string" } ], "stateMutability": "view", @@ -485,7 +399,7 @@ }, { "inputs": [], - "name": "publicKeyByteSize", + "name": "totalSupply", "outputs": [ { "internalType": "uint256", @@ -497,362 +411,253 @@ "type": "function" }, { - "inputs": [], - "name": "signatureByteSize", - "outputs": [ + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, { "internalType": "uint256", - "name": "", + "name": "amount", "type": "uint256" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "sortitionPool", + "name": "transfer", "outputs": [ { - "internalType": "contract SortitionPool", + "internalType": "bool", "name": "", - "type": "address" + "type": "bool" } ], - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { - "components": [ - { - "internalType": "uint256", - "name": "submitterMemberIndex", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "groupPubKey", - "type": "bytes" - }, - { - "internalType": "uint8[]", - "name": "misbehavedMembersIndices", - "type": "uint8[]" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "uint256[]", - "name": "signingMembersIndices", - "type": "uint256[]" - }, - { - "internalType": "uint32[]", - "name": "members", - "type": "uint32[]" - }, - { - "internalType": "bytes32", - "name": "membersHash", - "type": "bytes32" - } - ], - "internalType": "struct EcdsaDkg.Result", - "name": "result", - "type": "tuple" + "internalType": "address", + "name": "spender", + "type": "address" }, { - "internalType": "uint256", - "name": "seed", - "type": "uint256" + "internalType": "address", + "name": "recipient", + "type": "address" }, { "internalType": "uint256", - "name": "startBlock", + "name": "amount", "type": "uint256" } ], - "name": "validate", + "name": "transferFrom", "outputs": [ { "internalType": "bool", - "name": "isValid", + "name": "", "type": "bool" - }, - { - "internalType": "string", - "name": "errorMsg", - "type": "string" } ], - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { - "components": [ - { - "internalType": "uint256", - "name": "submitterMemberIndex", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "groupPubKey", - "type": "bytes" - }, - { - "internalType": "uint8[]", - "name": "misbehavedMembersIndices", - "type": "uint8[]" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "uint256[]", - "name": "signingMembersIndices", - "type": "uint256[]" - }, - { - "internalType": "uint32[]", - "name": "members", - "type": "uint32[]" - }, - { - "internalType": "bytes32", - "name": "membersHash", - "type": "bytes32" - } - ], - "internalType": "struct EcdsaDkg.Result", - "name": "result", - "type": "tuple" + "internalType": "address", + "name": "newOwner", + "type": "address" } ], - "name": "validateFields", - "outputs": [ + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] + }, + "T": { + "address": "0x948B3c65b89DF0B4894ABE91E6D02FE579834F8F", + "abi": [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ { - "internalType": "bool", - "name": "isValid", - "type": "bool" + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" }, { - "internalType": "string", - "name": "errorMsg", - "type": "string" + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" } ], - "stateMutability": "pure", - "type": "function" + "name": "Approval", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "components": [ - { - "internalType": "uint256", - "name": "submitterMemberIndex", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "groupPubKey", - "type": "bytes" - }, - { - "internalType": "uint8[]", - "name": "misbehavedMembersIndices", - "type": "uint8[]" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "uint256[]", - "name": "signingMembersIndices", - "type": "uint256[]" - }, - { - "internalType": "uint32[]", - "name": "members", - "type": "uint32[]" - }, - { - "internalType": "bytes32", - "name": "membersHash", - "type": "bytes32" - } - ], - "internalType": "struct EcdsaDkg.Result", - "name": "result", - "type": "tuple" + "indexed": true, + "internalType": "address", + "name": "delegator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "fromDelegate", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "toDelegate", + "type": "address" + } + ], + "name": "DelegateChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "delegate", + "type": "address" }, { + "indexed": false, "internalType": "uint256", - "name": "seed", + "name": "previousBalance", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newBalance", "type": "uint256" } ], - "name": "validateGroupMembers", - "outputs": [ + "name": "DelegateVotesChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" } ], - "stateMutability": "view", - "type": "function" + "name": "OwnershipTransferred", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "components": [ - { - "internalType": "uint256", - "name": "submitterMemberIndex", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "groupPubKey", - "type": "bytes" - }, - { - "internalType": "uint8[]", - "name": "misbehavedMembersIndices", - "type": "uint8[]" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "uint256[]", - "name": "signingMembersIndices", - "type": "uint256[]" - }, - { - "internalType": "uint32[]", - "name": "members", - "type": "uint32[]" - }, - { - "internalType": "bytes32", - "name": "membersHash", - "type": "bytes32" - } - ], - "internalType": "struct EcdsaDkg.Result", - "name": "result", - "type": "tuple" + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" } ], - "name": "validateMembersHash", + "name": "Transfer", + "type": "event" + }, + { + "inputs": [], + "name": "DELEGATION_TYPEHASH", "outputs": [ { - "internalType": "bool", + "internalType": "bytes32", "name": "", - "type": "bool" + "type": "bytes32" } ], - "stateMutability": "pure", + "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "submitterMemberIndex", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "groupPubKey", - "type": "bytes" - }, - { - "internalType": "uint8[]", - "name": "misbehavedMembersIndices", - "type": "uint8[]" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "uint256[]", - "name": "signingMembersIndices", - "type": "uint256[]" - }, - { - "internalType": "uint32[]", - "name": "members", - "type": "uint32[]" - }, - { - "internalType": "bytes32", - "name": "membersHash", - "type": "bytes32" - } - ], - "internalType": "struct EcdsaDkg.Result", - "name": "result", - "type": "tuple" - }, - { - "internalType": "uint256", - "name": "startBlock", - "type": "uint256" - } - ], - "name": "validateSignatures", + "inputs": [], + "name": "DOMAIN_SEPARATOR", "outputs": [ { - "internalType": "bool", + "internalType": "bytes32", "name": "", - "type": "bool" + "type": "bytes32" } ], "stateMutability": "view", "type": "function" - } - ] - }, - "EcdsaInactivity": { - "address": "0x8263eFCb8F28246697585c89Fed0501Cd946F764", - "abi": [ + }, { "inputs": [], - "name": "groupThreshold", + "name": "PERMIT_TYPEHASH", "outputs": [ { - "internalType": "uint256", + "internalType": "bytes32", "name": "", - "type": "uint256" + "type": "bytes32" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "signatureByteSize", + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "allowance", "outputs": [ { "internalType": "uint256", @@ -866,212 +671,163 @@ { "inputs": [ { - "internalType": "contract SortitionPool", - "name": "sortitionPool", - "type": "SortitionPool" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "walletID", - "type": "bytes32" - }, - { - "internalType": "uint256[]", - "name": "inactiveMembersIndices", - "type": "uint256[]" - }, - { - "internalType": "bool", - "name": "heartbeatFailed", - "type": "bool" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "uint256[]", - "name": "signingMembersIndices", - "type": "uint256[]" - } - ], - "internalType": "struct EcdsaInactivity.Claim", - "name": "claim", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "walletPubKey", - "type": "bytes" + "internalType": "address", + "name": "spender", + "type": "address" }, { "internalType": "uint256", - "name": "nonce", + "name": "amount", "type": "uint256" - }, - { - "internalType": "uint32[]", - "name": "groupMembers", - "type": "uint32[]" } ], - "name": "verifyClaim", + "name": "approve", "outputs": [ { - "internalType": "uint32[]", - "name": "inactiveMembers", - "type": "uint32[]" + "internalType": "bool", + "name": "", + "type": "bool" } ], - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" - } - ] - }, - "EcdsaSortitionPool": { - "address": "0xc2731fb2823af3Efc2694c9bC86F444d5c5bb4Dc", - "abi": [ + }, { "inputs": [ { - "internalType": "contract IERC20WithPermit", - "name": "_rewardToken", + "internalType": "address", + "name": "spender", "type": "address" }, { "internalType": "uint256", - "name": "_poolWeightDivisor", + "name": "amount", "type": "uint256" + }, + { + "internalType": "bytes", + "name": "extraData", + "type": "bytes" } ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ + "name": "approveAndCall", + "outputs": [ { - "indexed": false, - "internalType": "address[]", - "name": "operators", - "type": "address[]" + "internalType": "bool", + "name": "", + "type": "bool" } ], - "name": "BetaOperatorsAdded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [], - "name": "ChaosnetDeactivated", - "type": "event" + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, "internalType": "address", - "name": "oldChaosnetOwner", + "name": "", "type": "address" - }, + } + ], + "name": "balanceOf", + "outputs": [ { - "indexed": false, - "internalType": "address", - "name": "newChaosnetOwner", - "type": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "ChaosnetOwnerRoleTransferred", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint32[]", - "name": "ids", - "type": "uint32[]" - }, - { - "indexed": false, "internalType": "uint256", - "name": "until", + "name": "amount", "type": "uint256" } ], - "name": "IneligibleForRewards", - "type": "event" + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": true, "internalType": "address", - "name": "previousOwner", + "name": "account", "type": "address" }, { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], - "name": "OwnershipTransferred", - "type": "event" + "name": "burnFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" - }, + "inputs": [], + "name": "cachedChainId", + "outputs": [ { - "indexed": true, - "internalType": "uint32", - "name": "id", - "type": "uint32" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "RewardEligibilityRestored", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "cachedDomainSeparator", + "outputs": [ { - "internalType": "address[]", - "name": "operators", - "type": "address[]" + "internalType": "bytes32", + "name": "", + "type": "bytes32" } ], - "name": "addBetaOperators", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", - "name": "operator", + "name": "account", "type": "address" + }, + { + "internalType": "uint32", + "name": "pos", + "type": "uint32" } ], - "name": "canRestoreRewardEligibility", + "name": "checkpoints", "outputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "components": [ + { + "internalType": "uint32", + "name": "fromBlock", + "type": "uint32" + }, + { + "internalType": "uint96", + "name": "votes", + "type": "uint96" + } + ], + "internalType": "struct Checkpoints.Checkpoint", + "name": "checkpoint", + "type": "tuple" } ], "stateMutability": "view", @@ -1079,20 +835,26 @@ }, { "inputs": [], - "name": "chaosnetOwner", + "name": "decimals", "outputs": [ { - "internalType": "address", + "internalType": "uint8", "name": "", - "type": "address" + "type": "uint8" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "deactivateChaosnet", + "inputs": [ + { + "internalType": "address", + "name": "delegatee", + "type": "address" + } + ], + "name": "delegate", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -1101,30 +863,49 @@ "inputs": [ { "internalType": "address", - "name": "operator", + "name": "signatory", "type": "address" - } - ], - "name": "getAvailableRewards", - "outputs": [ + }, { - "internalType": "uint96", - "name": "", - "type": "uint96" + "internalType": "address", + "name": "delegatee", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" } ], - "stateMutability": "view", + "name": "delegateBySig", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { - "internalType": "uint32", - "name": "id", - "type": "uint32" + "internalType": "address", + "name": "account", + "type": "address" } ], - "name": "getIDOperator", + "name": "delegates", "outputs": [ { "internalType": "address", @@ -1138,17 +919,17 @@ { "inputs": [ { - "internalType": "uint32[]", - "name": "ids", - "type": "uint32[]" + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" } ], - "name": "getIDOperators", + "name": "getPastTotalSupply", "outputs": [ { - "internalType": "address[]", + "internalType": "uint96", "name": "", - "type": "address[]" + "type": "uint96" } ], "stateMutability": "view", @@ -1158,16 +939,21 @@ "inputs": [ { "internalType": "address", - "name": "operator", + "name": "account", "type": "address" + }, + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" } ], - "name": "getOperatorID", + "name": "getPastVotes", "outputs": [ { - "internalType": "uint32", + "internalType": "uint96", "name": "", - "type": "uint32" + "type": "uint96" } ], "stateMutability": "view", @@ -1177,24 +963,11 @@ "inputs": [ { "internalType": "address", - "name": "operator", + "name": "account", "type": "address" } ], - "name": "getPoolWeight", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "ineligibleEarnedRewards", + "name": "getVotes", "outputs": [ { "internalType": "uint96", @@ -1209,47 +982,47 @@ "inputs": [ { "internalType": "address", - "name": "operator", + "name": "recipient", "type": "address" }, { "internalType": "uint256", - "name": "authorizedStake", + "name": "amount", "type": "uint256" } ], - "name": "insertOperator", + "name": "mint", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "isBetaOperator", + "inputs": [], + "name": "name", "outputs": [ { - "internalType": "bool", + "internalType": "string", "name": "", - "type": "bool" + "type": "string" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "isChaosnetActive", + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "nonce", "outputs": [ { - "internalType": "bool", + "internalType": "uint256", "name": "", - "type": "bool" + "type": "uint256" } ], "stateMutability": "view", @@ -1259,16 +1032,16 @@ "inputs": [ { "internalType": "address", - "name": "operator", + "name": "account", "type": "address" } ], - "name": "isEligibleForRewards", + "name": "numCheckpoints", "outputs": [ { - "internalType": "bool", + "internalType": "uint32", "name": "", - "type": "bool" + "type": "uint32" } ], "stateMutability": "view", @@ -1276,12 +1049,12 @@ }, { "inputs": [], - "name": "isLocked", + "name": "owner", "outputs": [ { - "internalType": "bool", + "internalType": "address", "name": "", - "type": "bool" + "type": "address" } ], "stateMutability": "view", @@ -1291,92 +1064,111 @@ "inputs": [ { "internalType": "address", - "name": "operator", + "name": "owner", "type": "address" - } - ], - "name": "isOperatorInPool", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ + }, { "internalType": "address", - "name": "operator", + "name": "spender", "type": "address" - } - ], - "name": "isOperatorRegistered", - "outputs": [ + }, { - "internalType": "bool", - "name": "", - "type": "bool" + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" } ], - "stateMutability": "view", + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { - "internalType": "address", - "name": "operator", + "internalType": "contract IERC20", + "name": "token", "type": "address" }, { - "internalType": "uint256", - "name": "authorizedStake", - "type": "uint256" - } - ], - "name": "isOperatorUpToDate", - "outputs": [ + "internalType": "address", + "name": "recipient", + "type": "address" + }, { - "internalType": "bool", - "name": "", - "type": "bool" + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "lock", + "name": "recoverERC20", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "operatorsInPool", - "outputs": [ + "inputs": [ + { + "internalType": "contract IERC721", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, { "internalType": "uint256", - "name": "", + "name": "tokenId", "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" } ], - "stateMutability": "view", + "name": "recoverERC721", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "owner", + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", "outputs": [ { - "internalType": "address", + "internalType": "string", "name": "", - "type": "address" + "type": "string" } ], "stateMutability": "view", @@ -1384,7 +1176,7 @@ }, { "inputs": [], - "name": "poolWeightDivisor", + "name": "totalSupply", "outputs": [ { "internalType": "uint256", @@ -1399,72 +1191,152 @@ "inputs": [ { "internalType": "address", - "name": "sender", + "name": "recipient", "type": "address" }, { "internalType": "uint256", "name": "amount", "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" }, { "internalType": "address", - "name": "token", + "name": "recipient", "type": "address" }, { - "internalType": "bytes", + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", "name": "", - "type": "bytes" + "type": "bool" } ], - "name": "receiveApproval", - "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "renounceOwnership", + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" - }, + } + ] + }, + "VendingMachineNuCypher": { + "address": "0xbCF26943C0197d2eE0E5D05c716Be60cc2761508", + "abi": [ { "inputs": [ { - "internalType": "address", - "name": "operator", + "internalType": "contract IERC20", + "name": "_wrappedToken", + "type": "address" + }, + { + "internalType": "contract T", + "name": "_tToken", "type": "address" + }, + { + "internalType": "uint96", + "name": "_wrappedTokenAllocation", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "_tTokenAllocation", + "type": "uint96" } ], - "name": "restoreRewardEligibility", - "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "constructor" }, { - "inputs": [], - "name": "rewardToken", - "outputs": [ + "anonymous": false, + "inputs": [ { - "internalType": "contract IERC20WithPermit", - "name": "", + "indexed": true, + "internalType": "address", + "name": "recipient", "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tTokenAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "wrappedTokenAmount", + "type": "uint256" } ], - "stateMutability": "view", - "type": "function" + "name": "Unwrapped", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": true, "internalType": "address", - "name": "operator", + "name": "recipient", "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "wrappedTokenAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tTokenAmount", + "type": "uint256" } ], - "name": "rewardsEligibilityRestorableAt", + "name": "Wrapped", + "type": "event" + }, + { + "inputs": [], + "name": "FLOATING_POINT_DIVISOR", "outputs": [ { "internalType": "uint256", @@ -1476,24 +1348,37 @@ "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "WRAPPED_TOKEN_CONVERSION_PRECISION", + "outputs": [ { "internalType": "uint256", - "name": "groupSize", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ { - "internalType": "bytes32", - "name": "seed", - "type": "bytes32" + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], - "name": "selectGroup", + "name": "conversionFromT", "outputs": [ { - "internalType": "uint32[]", - "name": "", - "type": "uint32[]" + "internalType": "uint256", + "name": "wrappedAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tRemainder", + "type": "uint256" } ], "stateMutability": "view", @@ -1502,24 +1387,30 @@ { "inputs": [ { - "internalType": "uint32[]", - "name": "operators", - "type": "uint32[]" + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "conversionToT", + "outputs": [ + { + "internalType": "uint256", + "name": "tAmount", + "type": "uint256" }, { "internalType": "uint256", - "name": "until", + "name": "wrappedRemainder", "type": "uint256" } ], - "name": "setRewardIneligibility", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [], - "name": "totalWeight", + "name": "ratio", "outputs": [ { "internalType": "uint256", @@ -1534,49 +1425,52 @@ "inputs": [ { "internalType": "address", - "name": "newChaosnetOwner", + "name": "from", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "token", "type": "address" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" } ], - "name": "transferChaosnetOwnerRole", + "name": "receiveApproval", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "tToken", + "outputs": [ { - "internalType": "address", - "name": "newOwner", + "internalType": "contract T", + "name": "", "type": "address" } ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "unlock", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - }, { "internalType": "uint256", - "name": "authorizedStake", + "name": "amount", "type": "uint256" } ], - "name": "updateOperatorStatus", + "name": "unwrap", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -1584,12 +1478,12 @@ { "inputs": [ { - "internalType": "address", - "name": "recipient", - "type": "address" + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], - "name": "withdrawIneligible", + "name": "wrap", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -1598,41 +1492,44 @@ "inputs": [ { "internalType": "address", - "name": "operator", + "name": "", "type": "address" - }, + } + ], + "name": "wrappedBalance", + "outputs": [ { - "internalType": "address", - "name": "beneficiary", - "type": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "withdrawRewards", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "wrappedToken", "outputs": [ { - "internalType": "uint96", + "internalType": "contract IERC20", "name": "", - "type": "uint96" + "type": "address" } ], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" } ] }, - "WalletRegistry": { - "address": "0x46d52E41C2F300BC82217Ce22b920c34995204eb", + "TokenStaking": { + "address": "0xC6bA8C3233eCF65B761049ef63466945c362EdD2", "abi": [ { "inputs": [ { - "internalType": "contract SortitionPool", - "name": "_sortitionPool", - "type": "address" - }, - { - "internalType": "contract IStaking", - "name": "_staking", + "internalType": "contract T", + "name": "_token", "type": "address" } ], @@ -1645,11 +1542,30 @@ { "indexed": true, "internalType": "address", - "name": "stakingProvider", + "name": "application", "type": "address" + }, + { + "indexed": true, + "internalType": "enum TokenStaking.ApplicationStatus", + "name": "newStatus", + "type": "uint8" } ], - "name": "AuthorizationDecreaseApproved", + "name": "ApplicationStatusChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "ceiling", + "type": "uint256" + } + ], + "name": "AuthorizationCeilingSet", "type": "event" }, { @@ -1664,7 +1580,7 @@ { "indexed": true, "internalType": "address", - "name": "operator", + "name": "application", "type": "address" }, { @@ -1678,12 +1594,37 @@ "internalType": "uint96", "name": "toAmount", "type": "uint96" + } + ], + "name": "AuthorizationDecreaseApproved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "application", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" }, { "indexed": false, - "internalType": "uint64", - "name": "decreasingAt", - "type": "uint64" + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" } ], "name": "AuthorizationDecreaseRequested", @@ -1701,7 +1642,7 @@ { "indexed": true, "internalType": "address", - "name": "operator", + "name": "application", "type": "address" }, { @@ -1723,26 +1664,38 @@ { "anonymous": false, "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "application", + "type": "address" + }, { "indexed": false, "internalType": "uint96", - "name": "minimumAuthorization", + "name": "fromAmount", "type": "uint96" }, { "indexed": false, - "internalType": "uint64", - "name": "authorizationDecreaseDelay", - "type": "uint64" + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" }, { - "indexed": false, - "internalType": "uint64", - "name": "authorizationDecreaseChangePeriod", - "type": "uint64" + "indexed": true, + "internalType": "bool", + "name": "successfulCall", + "type": "bool" } ], - "name": "AuthorizationParametersUpdated", + "name": "AuthorizationInvoluntaryDecreased", "type": "event" }, { @@ -1750,24 +1703,18 @@ "inputs": [ { "indexed": true, - "internalType": "bytes32", - "name": "resultHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "slashingAmount", - "type": "uint256" + "internalType": "address", + "name": "stakingProvider", + "type": "address" }, { "indexed": false, - "internalType": "address", - "name": "maliciousSubmitter", - "type": "address" + "internalType": "bool", + "name": "autoIncrease", + "type": "bool" } ], - "name": "DkgMaliciousResultSlashed", + "name": "AutoIncreaseToggled", "type": "event" }, { @@ -1775,254 +1722,164 @@ "inputs": [ { "indexed": true, - "internalType": "bytes32", - "name": "resultHash", - "type": "bytes32" + "internalType": "address", + "name": "delegator", + "type": "address" }, { - "indexed": false, - "internalType": "uint256", - "name": "slashingAmount", - "type": "uint256" + "indexed": true, + "internalType": "address", + "name": "fromDelegate", + "type": "address" }, { - "indexed": false, + "indexed": true, "internalType": "address", - "name": "maliciousSubmitter", + "name": "toDelegate", "type": "address" } ], - "name": "DkgMaliciousResultSlashingFailed", + "name": "DelegateChanged", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "seedTimeout", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "resultChallengePeriodLength", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "resultChallengeExtraGas", - "type": "uint256" + "indexed": true, + "internalType": "address", + "name": "delegate", + "type": "address" }, { "indexed": false, "internalType": "uint256", - "name": "resultSubmissionTimeout", + "name": "previousBalance", "type": "uint256" }, { "indexed": false, "internalType": "uint256", - "name": "resultSubmitterPrecedencePeriodLength", + "name": "newBalance", "type": "uint256" } ], - "name": "DkgParametersUpdated", + "name": "DelegateVotesChanged", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "resultHash", - "type": "bytes32" + "indexed": false, + "internalType": "address", + "name": "oldGovernance", + "type": "address" }, { - "indexed": true, + "indexed": false, "internalType": "address", - "name": "approver", + "name": "newGovernance", "type": "address" } ], - "name": "DkgResultApproved", + "name": "GovernanceTransferred", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "resultHash", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "challenger", - "type": "address" - }, + "indexed": false, + "internalType": "uint96", + "name": "amount", + "type": "uint96" + } + ], + "name": "MinimumStakeAmountSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ { "indexed": false, - "internalType": "string", - "name": "reason", - "type": "string" + "internalType": "uint96", + "name": "reward", + "type": "uint96" } ], - "name": "DkgResultChallenged", + "name": "NotificationRewardPushed", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "resultHash", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "seed", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "submitterMemberIndex", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "groupPubKey", - "type": "bytes" - }, - { - "internalType": "uint8[]", - "name": "misbehavedMembersIndices", - "type": "uint8[]" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "uint256[]", - "name": "signingMembersIndices", - "type": "uint256[]" - }, - { - "internalType": "uint32[]", - "name": "members", - "type": "uint32[]" - }, - { - "internalType": "bytes32", - "name": "membersHash", - "type": "bytes32" - } - ], "indexed": false, - "internalType": "struct EcdsaDkg.Result", - "name": "result", - "type": "tuple" + "internalType": "uint96", + "name": "reward", + "type": "uint96" } ], - "name": "DkgResultSubmitted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [], - "name": "DkgSeedTimedOut", + "name": "NotificationRewardSet", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "uint256", - "name": "seed", - "type": "uint256" + "indexed": false, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "amount", + "type": "uint96" } ], - "name": "DkgStarted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [], - "name": "DkgStateLocked", - "type": "event" - }, - { - "anonymous": false, - "inputs": [], - "name": "DkgTimedOut", + "name": "NotificationRewardWithdrawn", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "dkgResultSubmissionGas", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "dkgResultApprovalGasOffset", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "notifyOperatorInactivityGasOffset", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "notifySeedTimeoutGasOffset", - "type": "uint256" + "indexed": true, + "internalType": "address", + "name": "notifier", + "type": "address" }, { "indexed": false, "internalType": "uint256", - "name": "notifyDkgTimeoutNegativeGasOffset", + "name": "amount", "type": "uint256" } ], - "name": "GasParametersUpdated", + "name": "NotifierRewarded", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": false, + "indexed": true, "internalType": "address", - "name": "oldGovernance", + "name": "application", "type": "address" }, { - "indexed": false, + "indexed": true, "internalType": "address", - "name": "newGovernance", + "name": "panicButton", "type": "address" } ], - "name": "GovernanceTransferred", + "name": "PanicButtonSet", "type": "event" }, { @@ -2030,68 +1887,67 @@ "inputs": [ { "indexed": true, - "internalType": "bytes32", - "name": "walletID", - "type": "bytes32" + "internalType": "address", + "name": "caller", + "type": "address" }, { "indexed": false, "internalType": "uint256", - "name": "nonce", + "name": "count", "type": "uint256" }, { "indexed": false, - "internalType": "address", - "name": "notifier", - "type": "address" + "internalType": "uint256", + "name": "tAmount", + "type": "uint256" } ], - "name": "InactivityClaimed", + "name": "SlashingProcessed", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint8", - "name": "version", + "indexed": true, + "internalType": "enum TokenStaking.StakeType", + "name": "stakeType", "type": "uint8" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + }, { "indexed": true, "internalType": "address", - "name": "stakingProvider", + "name": "owner", "type": "address" }, { "indexed": true, "internalType": "address", - "name": "operator", + "name": "stakingProvider", "type": "address" }, { "indexed": false, - "internalType": "uint96", - "name": "fromAmount", - "type": "uint96" + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "authorizer", + "type": "address" }, { "indexed": false, "internalType": "uint96", - "name": "toAmount", + "name": "amount", "type": "uint96" } ], - "name": "InvoluntaryAuthorizationDecreaseFailed", + "name": "Staked", "type": "event" }, { @@ -2103,14 +1959,20 @@ "name": "stakingProvider", "type": "address" }, + { + "indexed": false, + "internalType": "uint96", + "name": "amount", + "type": "uint96" + }, { "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" + "internalType": "bool", + "name": "discrepancy", + "type": "bool" } ], - "name": "OperatorJoinedSortitionPool", + "name": "TokensSeized", "type": "event" }, { @@ -2123,13 +1985,13 @@ "type": "address" }, { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" + "indexed": false, + "internalType": "uint96", + "name": "amount", + "type": "uint96" } ], - "name": "OperatorRegistered", + "name": "ToppedUp", "type": "event" }, { @@ -2142,216 +2004,161 @@ "type": "address" }, { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" + "indexed": false, + "internalType": "uint96", + "name": "amount", + "type": "uint96" } ], - "name": "OperatorStatusUpdated", + "name": "Unstaked", "type": "event" }, { - "anonymous": false, "inputs": [ { - "indexed": false, "internalType": "address", - "name": "randomBeacon", + "name": "", "type": "address" } ], - "name": "RandomBeaconUpgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "name": "applicationInfo", + "outputs": [ + { + "internalType": "enum TokenStaking.ApplicationStatus", + "name": "status", + "type": "uint8" + }, { - "indexed": false, "internalType": "address", - "name": "newReimbursementPool", + "name": "panicButton", "type": "address" } ], - "name": "ReimbursementPoolUpdated", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "maliciousDkgResultNotificationRewardMultiplier", - "type": "uint256" - }, - { - "indexed": false, "internalType": "uint256", - "name": "sortitionPoolRewardsBanDuration", + "name": "", "type": "uint256" } ], - "name": "RewardParametersUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "name": "applications", + "outputs": [ { - "indexed": true, "internalType": "address", - "name": "stakingProvider", + "name": "", "type": "address" - }, - { - "indexed": false, - "internalType": "uint96", - "name": "amount", - "type": "uint96" } ], - "name": "RewardsWithdrawn", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "maliciousDkgResultSlashingAmount", - "type": "uint256" + "internalType": "address", + "name": "application", + "type": "address" } ], - "name": "SlashingParametersUpdated", - "type": "event" + "name": "approveApplication", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "walletID", - "type": "bytes32" + "internalType": "address", + "name": "stakingProvider", + "type": "address" } ], - "name": "WalletClosed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "walletID", - "type": "bytes32" - }, + "name": "approveAuthorizationDecrease", + "outputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "dkgResultHash", - "type": "bytes32" + "internalType": "uint96", + "name": "", + "type": "uint96" } ], - "name": "WalletCreated", - "type": "event" + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "authorizationCeiling", + "outputs": [ { - "indexed": false, - "internalType": "address", - "name": "walletOwner", - "type": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "WalletOwnerUpdated", - "type": "event" + "stateMutability": "view", + "type": "function" }, { "inputs": [ { - "internalType": "uint256", - "name": "relayEntry", - "type": "uint256" + "internalType": "address", + "name": "stakingProvider", + "type": "address" }, { - "internalType": "uint256", + "internalType": "address", + "name": "application", + "type": "address" + } + ], + "name": "authorizedStake", + "outputs": [ + { + "internalType": "uint96", "name": "", - "type": "uint256" + "type": "uint96" } ], - "name": "__beaconCallback", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", - "name": "stakingProvider", + "name": "account", "type": "address" + }, + { + "internalType": "uint32", + "name": "pos", + "type": "uint32" } ], - "name": "approveAuthorizationDecrease", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + "name": "checkpoints", + "outputs": [ { "components": [ { - "internalType": "uint256", - "name": "submitterMemberIndex", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "groupPubKey", - "type": "bytes" - }, - { - "internalType": "uint8[]", - "name": "misbehavedMembersIndices", - "type": "uint8[]" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "uint256[]", - "name": "signingMembersIndices", - "type": "uint256[]" - }, - { - "internalType": "uint32[]", - "name": "members", - "type": "uint32[]" + "internalType": "uint32", + "name": "fromBlock", + "type": "uint32" }, { - "internalType": "bytes32", - "name": "membersHash", - "type": "bytes32" + "internalType": "uint96", + "name": "votes", + "type": "uint96" } ], - "internalType": "struct EcdsaDkg.Result", - "name": "dkgResult", + "internalType": "struct Checkpoints.Checkpoint", + "name": "checkpoint", "type": "tuple" } ], - "name": "approveDkgResult", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { @@ -2362,17 +2169,44 @@ "type": "address" }, { - "internalType": "uint96", - "name": "fromAmount", - "type": "uint96" - }, + "internalType": "address", + "name": "delegatee", + "type": "address" + } + ], + "name": "delegateVoting", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ { - "internalType": "uint96", - "name": "toAmount", - "type": "uint96" + "internalType": "address", + "name": "account", + "type": "address" } ], - "name": "authorizationDecreaseRequested", + "name": "delegates", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "application", + "type": "address" + } + ], + "name": "disableApplication", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -2385,39 +2219,43 @@ "type": "address" }, { - "internalType": "uint96", - "name": "fromAmount", - "type": "uint96" - }, - { - "internalType": "uint96", - "name": "toAmount", - "type": "uint96" + "internalType": "address", + "name": "application", + "type": "address" } ], - "name": "authorizationIncreased", + "name": "forceDecreaseAuthorization", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "authorizationParameters", + "name": "getApplicationsLength", "outputs": [ { - "internalType": "uint96", - "name": "minimumAuthorization", - "type": "uint96" - }, + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ { - "internalType": "uint64", - "name": "authorizationDecreaseDelay", - "type": "uint64" - }, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "getAutoIncreaseFlag", + "outputs": [ { - "internalType": "uint64", - "name": "authorizationDecreaseChangePeriod", - "type": "uint64" + "internalType": "bool", + "name": "", + "type": "bool" } ], "stateMutability": "view", @@ -2429,13 +2267,18 @@ "internalType": "address", "name": "stakingProvider", "type": "address" + }, + { + "internalType": "address", + "name": "application", + "type": "address" } ], - "name": "availableRewards", + "name": "getAvailableToAuthorize", "outputs": [ { "internalType": "uint96", - "name": "", + "name": "availableTValue", "type": "uint96" } ], @@ -2445,101 +2288,36 @@ { "inputs": [ { - "components": [ - { - "internalType": "uint256", - "name": "submitterMemberIndex", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "groupPubKey", - "type": "bytes" - }, - { - "internalType": "uint8[]", - "name": "misbehavedMembersIndices", - "type": "uint8[]" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "uint256[]", - "name": "signingMembersIndices", - "type": "uint256[]" - }, - { - "internalType": "uint32[]", - "name": "members", - "type": "uint32[]" - }, - { - "internalType": "bytes32", - "name": "membersHash", - "type": "bytes32" - } - ], - "internalType": "struct EcdsaDkg.Result", - "name": "dkgResult", - "type": "tuple" + "internalType": "address", + "name": "stakingProvider", + "type": "address" } ], - "name": "challengeDkgResult", - "outputs": [], - "stateMutability": "nonpayable", + "name": "getMaxAuthorization", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", "type": "function" }, { "inputs": [ { - "internalType": "bytes32", - "name": "walletID", - "type": "bytes32" + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" } ], - "name": "closeWallet", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "dkgParameters", + "name": "getPastTotalSupply", "outputs": [ { - "components": [ - { - "internalType": "uint256", - "name": "seedTimeout", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "resultChallengePeriodLength", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "resultChallengeExtraGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "resultSubmissionTimeout", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "submitterPrecedencePeriodLength", - "type": "uint256" - } - ], - "internalType": "struct EcdsaDkg.Parameters", + "internalType": "uint96", "name": "", - "type": "tuple" + "type": "uint96" } ], "stateMutability": "view", @@ -2549,11 +2327,16 @@ "inputs": [ { "internalType": "address", - "name": "stakingProvider", + "name": "account", "type": "address" + }, + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" } ], - "name": "eligibleStake", + "name": "getPastVotes", "outputs": [ { "internalType": "uint96", @@ -2566,31 +2349,30 @@ }, { "inputs": [], - "name": "gasParameters", + "name": "getSlashingQueueLength", "outputs": [ { "internalType": "uint256", - "name": "dkgResultSubmissionGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "dkgResultApprovalGasOffset", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "notifyOperatorInactivityGasOffset", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ { - "internalType": "uint256", - "name": "notifySeedTimeoutGasOffset", - "type": "uint256" - }, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "getStartStakingTimestamp", + "outputs": [ { "internalType": "uint256", - "name": "notifyDkgTimeoutNegativeGasOffset", + "name": "", "type": "uint256" } ], @@ -2600,34 +2382,17 @@ { "inputs": [ { - "internalType": "bytes32", - "name": "walletID", - "type": "bytes32" + "internalType": "address", + "name": "account", + "type": "address" } ], - "name": "getWallet", + "name": "getVotes", "outputs": [ { - "components": [ - { - "internalType": "bytes32", - "name": "membersIdsHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "publicKeyX", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "publicKeyY", - "type": "bytes32" - } - ], - "internalType": "struct Wallets.Wallet", + "internalType": "uint96", "name": "", - "type": "tuple" + "type": "uint96" } ], "stateMutability": "view", @@ -2635,12 +2400,12 @@ }, { "inputs": [], - "name": "getWalletCreationState", + "name": "governance", "outputs": [ { - "internalType": "enum EcdsaDkg.State", + "internalType": "address", "name": "", - "type": "uint8" + "type": "address" } ], "stateMutability": "view", @@ -2649,30 +2414,41 @@ { "inputs": [ { - "internalType": "bytes32", - "name": "walletID", - "type": "bytes32" - } - ], - "name": "getWalletPublicKey", - "outputs": [ + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, { - "internalType": "bytes", - "name": "", - "type": "bytes" + "internalType": "address", + "name": "application", + "type": "address" + }, + { + "internalType": "uint96", + "name": "amount", + "type": "uint96" } ], - "stateMutability": "view", + "name": "increaseAuthorization", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "governance", + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "minTStakeAmount", "outputs": [ { - "internalType": "address", + "internalType": "uint96", "name": "", - "type": "address" + "type": "uint96" } ], "stateMutability": "view", @@ -2680,12 +2456,12 @@ }, { "inputs": [], - "name": "hasDkgTimedOut", + "name": "notificationReward", "outputs": [ { - "internalType": "bool", + "internalType": "uint256", "name": "", - "type": "bool" + "type": "uint256" } ], "stateMutability": "view", @@ -2693,12 +2469,12 @@ }, { "inputs": [], - "name": "hasSeedTimedOut", + "name": "notifiersTreasury", "outputs": [ { - "internalType": "bool", + "internalType": "uint256", "name": "", - "type": "bool" + "type": "uint256" } ], "stateMutability": "view", @@ -2707,17 +2483,17 @@ { "inputs": [ { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "internalType": "address", + "name": "account", + "type": "address" } ], - "name": "inactivityClaimNonce", + "name": "numCheckpoints", "outputs": [ { - "internalType": "uint256", + "internalType": "uint32", "name": "", - "type": "uint256" + "type": "uint32" } ], "stateMutability": "view", @@ -2726,22 +2502,12 @@ { "inputs": [ { - "internalType": "contract EcdsaDkgValidator", - "name": "_ecdsaDkgValidator", - "type": "address" - }, - { - "internalType": "contract IRandomBeacon", - "name": "_randomBeacon", - "type": "address" - }, - { - "internalType": "contract ReimbursementPool", - "name": "_reimbursementPool", + "internalType": "address", + "name": "application", "type": "address" } ], - "name": "initialize", + "name": "pauseApplication", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -2749,22 +2515,25 @@ { "inputs": [ { - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, - { - "internalType": "uint96", - "name": "fromAmount", - "type": "uint96" - }, + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "processSlashing", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ { "internalType": "uint96", - "name": "toAmount", + "name": "reward", "type": "uint96" } ], - "name": "involuntaryAuthorizationDecrease", + "name": "pushNotificationReward", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -2772,97 +2541,63 @@ { "inputs": [ { - "components": [ - { - "internalType": "uint256", - "name": "submitterMemberIndex", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "groupPubKey", - "type": "bytes" - }, - { - "internalType": "uint8[]", - "name": "misbehavedMembersIndices", - "type": "uint8[]" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "uint256[]", - "name": "signingMembersIndices", - "type": "uint256[]" - }, - { - "internalType": "uint32[]", - "name": "members", - "type": "uint32[]" - }, - { - "internalType": "bytes32", - "name": "membersHash", - "type": "bytes32" - } - ], - "internalType": "struct EcdsaDkg.Result", - "name": "result", - "type": "tuple" - } - ], - "name": "isDkgResultValid", - "outputs": [ + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, { - "internalType": "bool", - "name": "", - "type": "bool" + "internalType": "address", + "name": "application", + "type": "address" }, { - "internalType": "string", - "name": "", - "type": "string" + "internalType": "uint96", + "name": "amount", + "type": "uint96" } ], - "stateMutability": "view", + "name": "requestAuthorizationDecrease", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", - "name": "operator", + "name": "stakingProvider", "type": "address" } ], - "name": "isOperatorInPool", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", + "name": "requestAuthorizationDecrease", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", - "name": "operator", + "name": "stakingProvider", "type": "address" } ], - "name": "isOperatorUpToDate", + "name": "rolesOf", "outputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address payable", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "address", + "name": "authorizer", + "type": "address" } ], "stateMutability": "view", @@ -2871,79 +2606,53 @@ { "inputs": [ { - "internalType": "bytes32", - "name": "walletID", - "type": "bytes32" + "internalType": "uint96", + "name": "amount", + "type": "uint96" }, { - "internalType": "uint32[]", - "name": "walletMembersIDs", - "type": "uint32[]" + "internalType": "uint256", + "name": "rewardMultiplier", + "type": "uint256" }, { "internalType": "address", - "name": "operator", + "name": "notifier", "type": "address" }, { - "internalType": "uint256", - "name": "walletMemberIndex", - "type": "uint256" - } - ], - "name": "isWalletMember", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" + "internalType": "address[]", + "name": "_stakingProviders", + "type": "address[]" } ], - "stateMutability": "view", + "name": "seize", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { - "internalType": "bytes32", - "name": "walletID", - "type": "bytes32" - } - ], - "name": "isWalletRegistered", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" + "internalType": "uint256", + "name": "ceiling", + "type": "uint256" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "joinSortitionPool", + "name": "setAuthorizationCeiling", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "minimumAuthorization", - "outputs": [ + "inputs": [ { "internalType": "uint96", - "name": "", + "name": "amount", "type": "uint96" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "notifyDkgTimeout", + "name": "setMinimumStakeAmount", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -2951,56 +2660,12 @@ { "inputs": [ { - "components": [ - { - "internalType": "bytes32", - "name": "walletID", - "type": "bytes32" - }, - { - "internalType": "uint256[]", - "name": "inactiveMembersIndices", - "type": "uint256[]" - }, - { - "internalType": "bool", - "name": "heartbeatFailed", - "type": "bool" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "uint256[]", - "name": "signingMembersIndices", - "type": "uint256[]" - } - ], - "internalType": "struct EcdsaInactivity.Claim", - "name": "claim", - "type": "tuple" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "uint32[]", - "name": "groupMembers", - "type": "uint32[]" + "internalType": "uint96", + "name": "reward", + "type": "uint96" } ], - "name": "notifyOperatorInactivity", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "notifySeedTimeout", + "name": "setNotificationReward", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -3009,93 +2674,57 @@ "inputs": [ { "internalType": "address", - "name": "operator", + "name": "application", "type": "address" - } - ], - "name": "operatorToStakingProvider", - "outputs": [ + }, { "internalType": "address", - "name": "", + "name": "panicButton", "type": "address" } ], - "stateMutability": "view", + "name": "setPanicButton", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ - { - "internalType": "address", - "name": "stakingProvider", - "type": "address" - } - ], - "name": "pendingAuthorizationDecrease", - "outputs": [ { "internalType": "uint96", - "name": "", + "name": "amount", "type": "uint96" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "randomBeacon", - "outputs": [ - { - "internalType": "contract IRandomBeacon", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ + }, { - "internalType": "address", - "name": "operator", - "type": "address" + "internalType": "address[]", + "name": "_stakingProviders", + "type": "address[]" } ], - "name": "registerOperator", + "name": "slash", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "reimbursementPool", - "outputs": [ + "inputs": [ { - "internalType": "contract ReimbursementPool", + "internalType": "uint256", "name": "", - "type": "address" + "type": "uint256" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ + "name": "slashingQueue", + "outputs": [ { "internalType": "address", "name": "stakingProvider", "type": "address" - } - ], - "name": "remainingAuthorizationDecreaseDelay", - "outputs": [ + }, { - "internalType": "uint64", - "name": "", - "type": "uint64" + "internalType": "uint96", + "name": "amount", + "type": "uint96" } ], "stateMutability": "view", @@ -3103,23 +2732,11 @@ }, { "inputs": [], - "name": "requestNewWallet", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "rewardParameters", + "name": "slashingQueueIndex", "outputs": [ { "internalType": "uint256", - "name": "maliciousDkgResultNotificationRewardMultiplier", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "sortitionPoolRewardsBanDuration", + "name": "", "type": "uint256" } ], @@ -3129,56 +2746,44 @@ { "inputs": [ { - "internalType": "uint96", - "name": "amount", - "type": "uint96" + "internalType": "address", + "name": "stakingProvider", + "type": "address" }, { - "internalType": "uint256", - "name": "rewardMultiplier", - "type": "uint256" + "internalType": "address payable", + "name": "beneficiary", + "type": "address" }, { "internalType": "address", - "name": "notifier", + "name": "authorizer", "type": "address" }, { - "internalType": "bytes32", - "name": "walletID", - "type": "bytes32" - }, - { - "internalType": "uint32[]", - "name": "walletMembersIDs", - "type": "uint32[]" + "internalType": "uint96", + "name": "amount", + "type": "uint96" } ], - "name": "seize", + "name": "stake", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "selectGroup", - "outputs": [ + "inputs": [ { - "internalType": "uint32[]", - "name": "", - "type": "uint32[]" + "internalType": "address", + "name": "stakingProvider", + "type": "address" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "slashingParameters", + "name": "stakeAmount", "outputs": [ { "internalType": "uint96", - "name": "maliciousDkgResultSlashingAmount", + "name": "", "type": "uint96" } ], @@ -3186,26 +2791,29 @@ "type": "function" }, { - "inputs": [], - "name": "sortitionPool", - "outputs": [ + "inputs": [ { - "internalType": "contract SortitionPool", - "name": "", + "internalType": "address", + "name": "stakingProvider", "type": "address" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "staking", + "name": "stakes", "outputs": [ { - "internalType": "contract IStaking", - "name": "", - "type": "address" + "internalType": "uint96", + "name": "tStake", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "keepInTStake", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "nuInTStake", + "type": "uint96" } ], "stateMutability": "view", @@ -3219,63 +2827,38 @@ "type": "address" } ], - "name": "stakingProviderToOperator", - "outputs": [ + "name": "toggleAutoAuthorizationIncrease", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ { "internalType": "address", - "name": "", + "name": "stakingProvider", "type": "address" + }, + { + "internalType": "uint96", + "name": "amount", + "type": "uint96" } ], - "stateMutability": "view", + "name": "topUp", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { - "components": [ - { - "internalType": "uint256", - "name": "submitterMemberIndex", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "groupPubKey", - "type": "bytes" - }, - { - "internalType": "uint8[]", - "name": "misbehavedMembersIndices", - "type": "uint8[]" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "uint256[]", - "name": "signingMembersIndices", - "type": "uint256[]" - }, - { - "internalType": "uint32[]", - "name": "members", - "type": "uint32[]" - }, - { - "internalType": "bytes32", - "name": "membersHash", - "type": "bytes32" - } - ], - "internalType": "struct EcdsaDkg.Result", - "name": "dkgResult", - "type": "tuple" + "internalType": "address", + "name": "newGuvnor", + "type": "address" } ], - "name": "submitDkgResult", + "name": "transferGovernance", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -3284,11 +2867,16 @@ "inputs": [ { "internalType": "address", - "name": "newGovernance", + "name": "stakingProvider", "type": "address" + }, + { + "internalType": "uint96", + "name": "amount", + "type": "uint96" } ], - "name": "transferGovernance", + "name": "unstakeT", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -3296,604 +2884,814 @@ { "inputs": [ { - "internalType": "uint96", - "name": "_minimumAuthorization", - "type": "uint96" - }, - { - "internalType": "uint64", - "name": "_authorizationDecreaseDelay", - "type": "uint64" + "internalType": "address", + "name": "recipient", + "type": "address" }, { - "internalType": "uint64", - "name": "_authorizationDecreaseChangePeriod", - "type": "uint64" + "internalType": "uint96", + "name": "amount", + "type": "uint96" } ], - "name": "updateAuthorizationParameters", + "name": "withdrawNotificationReward", "outputs": [], "stateMutability": "nonpayable", "type": "function" - }, + } + ] + }, + "TokenholderTimelock": { + "address": "0x05Aa229Aec102f78CE0E852A812a388F076Aa555", + "abi": [ { "inputs": [ { "internalType": "uint256", - "name": "_seedTimeout", + "name": "minDelay", "type": "uint256" }, { - "internalType": "uint256", - "name": "_resultChallengePeriodLength", - "type": "uint256" + "internalType": "address[]", + "name": "proposers", + "type": "address[]" }, { - "internalType": "uint256", - "name": "_resultChallengeExtraGas", - "type": "uint256" + "internalType": "address[]", + "name": "executors", + "type": "address[]" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "id", + "type": "bytes32" }, { + "indexed": true, "internalType": "uint256", - "name": "_resultSubmissionTimeout", + "name": "index", "type": "uint256" }, { + "indexed": false, + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "indexed": false, "internalType": "uint256", - "name": "_submitterPrecedencePeriodLength", + "name": "value", "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "data", + "type": "bytes" } ], - "name": "updateDkgParameters", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "CallExecuted", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "uint256", - "name": "dkgResultSubmissionGas", - "type": "uint256" + "indexed": true, + "internalType": "bytes32", + "name": "id", + "type": "bytes32" }, { + "indexed": true, "internalType": "uint256", - "name": "dkgResultApprovalGasOffset", + "name": "index", "type": "uint256" }, { - "internalType": "uint256", - "name": "notifyOperatorInactivityGasOffset", - "type": "uint256" + "indexed": false, + "internalType": "address", + "name": "target", + "type": "address" }, { + "indexed": false, "internalType": "uint256", - "name": "notifySeedTimeoutGasOffset", + "name": "value", "type": "uint256" }, { + "indexed": false, + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "predecessor", + "type": "bytes32" + }, + { + "indexed": false, "internalType": "uint256", - "name": "notifyDkgTimeoutNegativeGasOffset", + "name": "delay", "type": "uint256" } ], - "name": "updateGasParameters", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "CallScheduled", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "address", - "name": "operator", - "type": "address" + "indexed": true, + "internalType": "bytes32", + "name": "id", + "type": "bytes32" } ], - "name": "updateOperatorStatus", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "Cancelled", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "contract ReimbursementPool", - "name": "_reimbursementPool", - "type": "address" + "indexed": false, + "internalType": "uint256", + "name": "oldDuration", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newDuration", + "type": "uint256" } ], - "name": "updateReimbursementPool", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "MinDelayChange", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "uint256", - "name": "maliciousDkgResultNotificationRewardMultiplier", - "type": "uint256" + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" }, { - "internalType": "uint256", - "name": "sortitionPoolRewardsBanDuration", - "type": "uint256" + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" } ], - "name": "updateRewardParameters", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "RoleAdminChanged", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "uint96", - "name": "maliciousDkgResultSlashingAmount", - "type": "uint96" + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" } ], - "name": "updateSlashingParameters", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "RoleGranted", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "contract IWalletOwner", - "name": "_walletOwner", + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", "type": "address" } ], - "name": "updateWalletOwner", - "outputs": [], - "stateMutability": "nonpayable", + "name": "RoleRevoked", + "type": "event" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "EXECUTOR_ROLE", + "outputs": [ { - "internalType": "contract IRandomBeacon", - "name": "_randomBeacon", - "type": "address" + "internalType": "bytes32", + "name": "", + "type": "bytes32" } ], - "name": "upgradeRandomBeacon", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [], - "name": "walletOwner", + "name": "PROPOSER_ROLE", "outputs": [ { - "internalType": "contract IWalletOwner", + "internalType": "bytes32", "name": "", - "type": "address" + "type": "bytes32" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "TIMELOCK_ADMIN_ROLE", + "outputs": [ { - "internalType": "address", - "name": "recipient", - "type": "address" + "internalType": "bytes32", + "name": "", + "type": "bytes32" } ], - "name": "withdrawIneligibleRewards", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { - "internalType": "address", - "name": "stakingProvider", - "type": "address" + "internalType": "bytes32", + "name": "id", + "type": "bytes32" } ], - "name": "withdrawRewards", + "name": "cancel", "outputs": [], "stateMutability": "nonpayable", "type": "function" - } - ] - }, - "WalletRegistryGovernance": { - "address": "0x6aed6cC30D1b2770771052555d257Da86eD47fe8", - "abi": [ + }, { "inputs": [ { - "internalType": "contract WalletRegistry", - "name": "_walletRegistry", + "internalType": "address", + "name": "target", "type": "address" }, { "internalType": "uint256", - "name": "_governanceDelay", + "name": "value", "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "predecessor", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" } ], - "stateMutability": "nonpayable", - "type": "constructor" + "name": "execute", + "outputs": [], + "stateMutability": "payable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint64", - "name": "authorizationDecreaseChangePeriod", - "type": "uint64" + "internalType": "address[]", + "name": "targets", + "type": "address[]" }, { - "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - } - ], - "name": "AuthorizationDecreaseChangePeriodUpdateStarted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, { - "indexed": false, - "internalType": "uint64", - "name": "authorizationDecreaseChangePeriod", - "type": "uint64" + "internalType": "bytes[]", + "name": "datas", + "type": "bytes[]" + }, + { + "internalType": "bytes32", + "name": "predecessor", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" } ], - "name": "AuthorizationDecreaseChangePeriodUpdated", - "type": "event" + "name": "executeBatch", + "outputs": [], + "stateMutability": "payable", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "authorizationDecreaseDelay", - "type": "uint64" - }, + "inputs": [], + "name": "getMinDelay", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "timestamp", + "name": "duration", "type": "uint256" } ], - "name": "AuthorizationDecreaseDelayUpdateStarted", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint64", - "name": "authorizationDecreaseDelay", - "type": "uint64" + "internalType": "bytes32", + "name": "role", + "type": "bytes32" } ], - "name": "AuthorizationDecreaseDelayUpdated", - "type": "event" + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "dkgResultApprovalGasOffset", - "type": "uint256" - }, + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + } + ], + "name": "getTimestamp", + "outputs": [ { - "indexed": false, "internalType": "uint256", "name": "timestamp", "type": "uint256" } ], - "name": "DkgResultApprovalGasOffsetUpdateStarted", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "dkgResultApprovalGasOffset", - "type": "uint256" + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" } ], - "name": "DkgResultApprovalGasOffsetUpdated", - "type": "event" + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "dkgResultChallengeExtraGas", - "type": "uint256" + "internalType": "bytes32", + "name": "role", + "type": "bytes32" }, { - "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" + "internalType": "address", + "name": "account", + "type": "address" } ], - "name": "DkgResultChallengeExtraGasUpdateStarted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "name": "hasRole", + "outputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "dkgResultChallengeExtraGas", - "type": "uint256" + "internalType": "bool", + "name": "", + "type": "bool" } ], - "name": "DkgResultChallengeExtraGasUpdated", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "dkgResultChallengePeriodLength", - "type": "uint256" + "internalType": "address", + "name": "target", + "type": "address" }, { - "indexed": false, "internalType": "uint256", - "name": "timestamp", + "name": "value", "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "predecessor", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" } ], - "name": "DkgResultChallengePeriodLengthUpdateStarted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "name": "hashOperation", + "outputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "dkgResultChallengePeriodLength", - "type": "uint256" + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" } ], - "name": "DkgResultChallengePeriodLengthUpdated", - "type": "event" + "stateMutability": "pure", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "dkgResultSubmissionGas", - "type": "uint256" + "internalType": "address[]", + "name": "targets", + "type": "address[]" }, { - "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "internalType": "bytes[]", + "name": "datas", + "type": "bytes[]" + }, + { + "internalType": "bytes32", + "name": "predecessor", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" } ], - "name": "DkgResultSubmissionGasUpdateStarted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "name": "hashOperationBatch", + "outputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "dkgResultSubmissionGas", - "type": "uint256" + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" } ], - "name": "DkgResultSubmissionGasUpdated", - "type": "event" + "stateMutability": "pure", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "dkgResultSubmissionTimeout", - "type": "uint256" - }, + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + } + ], + "name": "isOperation", + "outputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" + "internalType": "bool", + "name": "pending", + "type": "bool" } ], - "name": "DkgResultSubmissionTimeoutUpdateStarted", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "dkgResultSubmissionTimeout", - "type": "uint256" + "internalType": "bytes32", + "name": "id", + "type": "bytes32" } ], - "name": "DkgResultSubmissionTimeoutUpdated", - "type": "event" + "name": "isOperationDone", + "outputs": [ + { + "internalType": "bool", + "name": "done", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "dkgSeedTimeout", - "type": "uint256" - }, + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + } + ], + "name": "isOperationPending", + "outputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" + "internalType": "bool", + "name": "pending", + "type": "bool" } ], - "name": "DkgSeedTimeoutUpdateStarted", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "dkgSeedTimeout", - "type": "uint256" + "internalType": "bytes32", + "name": "id", + "type": "bytes32" } ], - "name": "DkgSeedTimeoutUpdated", - "type": "event" + "name": "isOperationReady", + "outputs": [ + { + "internalType": "bool", + "name": "ready", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "submitterPrecedencePeriodLength", - "type": "uint256" + "internalType": "bytes32", + "name": "role", + "type": "bytes32" }, { - "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" + "internalType": "address", + "name": "account", + "type": "address" } ], - "name": "DkgSubmitterPrecedencePeriodLengthUpdateStarted", - "type": "event" + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "submitterPrecedencePeriodLength", - "type": "uint256" + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" } ], - "name": "DkgSubmitterPrecedencePeriodLengthUpdated", - "type": "event" + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, + "internalType": "address", + "name": "target", + "type": "address" + }, + { "internalType": "uint256", - "name": "governanceDelay", + "name": "value", "type": "uint256" }, { - "indexed": false, + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "predecessor", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { "internalType": "uint256", - "name": "timestamp", + "name": "delay", "type": "uint256" } ], - "name": "GovernanceDelayUpdateStarted", - "type": "event" + "name": "schedule", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "internalType": "bytes[]", + "name": "datas", + "type": "bytes[]" + }, + { + "internalType": "bytes32", + "name": "predecessor", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { "internalType": "uint256", - "name": "governanceDelay", + "name": "delay", "type": "uint256" } ], - "name": "GovernanceDelayUpdated", - "type": "event" + "name": "scheduleBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "maliciousDkgResultNotificationRewardMultiplier", - "type": "uint256" - }, + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" + "internalType": "bool", + "name": "", + "type": "bool" } ], - "name": "MaliciousDkgResultNotificationRewardMultiplierUpdateStarted", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, "internalType": "uint256", - "name": "maliciousDkgResultNotificationRewardMultiplier", + "name": "newDelay", "type": "uint256" } ], - "name": "MaliciousDkgResultNotificationRewardMultiplierUpdated", - "type": "event" + "name": "updateDelay", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ] + }, + "TokenholderGovernor": { + "address": "0x0b48aF34f4c854F5ae1A3D587da471FeA45bAD52", + "abi": [ + { + "inputs": [ + { + "internalType": "contract T", + "name": "_token", + "type": "address" + }, + { + "internalType": "contract IVotesHistory", + "name": "_staking", + "type": "address" + }, + { + "internalType": "contract TimelockController", + "name": "_timelock", + "type": "address" + }, + { + "internalType": "address", + "name": "vetoer", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" }, { "anonymous": false, "inputs": [ { "indexed": false, - "internalType": "uint256", - "name": "maliciousDkgResultSlashingAmount", - "type": "uint256" + "internalType": "uint64", + "name": "oldVoteExtension", + "type": "uint64" }, { "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" + "internalType": "uint64", + "name": "newVoteExtension", + "type": "uint64" } ], - "name": "MaliciousDkgResultSlashingAmountUpdateStarted", + "name": "LateQuorumVoteExtensionSet", "type": "event" }, { @@ -3902,11 +3700,11 @@ { "indexed": false, "internalType": "uint256", - "name": "maliciousDkgResultSlashingAmount", + "name": "proposalId", "type": "uint256" } ], - "name": "MaliciousDkgResultSlashingAmountUpdated", + "name": "ProposalCanceled", "type": "event" }, { @@ -3914,18 +3712,60 @@ "inputs": [ { "indexed": false, - "internalType": "uint96", - "name": "minimumAuthorization", - "type": "uint96" + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "proposer", + "type": "address" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "string[]", + "name": "signatures", + "type": "string[]" + }, + { + "indexed": false, + "internalType": "bytes[]", + "name": "calldatas", + "type": "bytes[]" }, { "indexed": false, "internalType": "uint256", - "name": "timestamp", + "name": "startBlock", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "endBlock", "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "description", + "type": "string" } ], - "name": "MinimumAuthorizationUpdateStarted", + "name": "ProposalCreated", "type": "event" }, { @@ -3933,31 +3773,31 @@ "inputs": [ { "indexed": false, - "internalType": "uint96", - "name": "minimumAuthorization", - "type": "uint96" + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" } ], - "name": "MinimumAuthorizationUpdated", + "name": "ProposalExecuted", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": false, + "indexed": true, "internalType": "uint256", - "name": "notifyDkgTimeoutNegativeGasOffset", + "name": "proposalId", "type": "uint256" }, { "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" + "internalType": "uint64", + "name": "extendedDeadline", + "type": "uint64" } ], - "name": "NotifyDkgTimeoutNegativeGasOffsetUpdateStarted", + "name": "ProposalExtended", "type": "event" }, { @@ -3966,11 +3806,17 @@ { "indexed": false, "internalType": "uint256", - "name": "notifyDkgTimeoutNegativeGasOffset", + "name": "proposalId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "eta", "type": "uint256" } ], - "name": "NotifyDkgTimeoutNegativeGasOffsetUpdated", + "name": "ProposalQueued", "type": "event" }, { @@ -3979,30 +3825,17 @@ { "indexed": false, "internalType": "uint256", - "name": "notifyOperatorInactivityGasOffset", + "name": "oldThresholdNumerator", "type": "uint256" }, { "indexed": false, "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - } - ], - "name": "NotifyOperatorInactivityGasOffsetUpdateStarted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "notifyOperatorInactivityGasOffset", + "name": "newThresholdNumerator", "type": "uint256" } ], - "name": "NotifyOperatorInactivityGasOffsetUpdated", + "name": "ProposalThresholdNumeratorUpdated", "type": "event" }, { @@ -4011,68 +3844,92 @@ { "indexed": false, "internalType": "uint256", - "name": "notifySeedTimeoutGasOffset", + "name": "oldQuorumNumerator", "type": "uint256" }, { "indexed": false, "internalType": "uint256", - "name": "timestamp", + "name": "newQuorumNumerator", "type": "uint256" } ], - "name": "NotifySeedTimeoutGasOffsetUpdateStarted", + "name": "QuorumNumeratorUpdated", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "notifySeedTimeoutGasOffset", - "type": "uint256" + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" } ], - "name": "NotifySeedTimeoutGasOffsetUpdated", + "name": "RoleAdminChanged", "type": "event" }, { "anonymous": false, "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, { "indexed": true, "internalType": "address", - "name": "previousOwner", + "name": "account", "type": "address" }, { "indexed": true, "internalType": "address", - "name": "newOwner", + "name": "sender", "type": "address" } ], - "name": "OwnershipTransferred", + "name": "RoleGranted", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": false, + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, "internalType": "address", - "name": "reimbursementPool", + "name": "account", "type": "address" }, { - "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" } ], - "name": "ReimbursementPoolUpdateStarted", + "name": "RoleRevoked", "type": "event" }, { @@ -4081,43 +3938,54 @@ { "indexed": false, "internalType": "address", - "name": "reimbursementPool", + "name": "oldTimelock", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newTimelock", "type": "address" } ], - "name": "ReimbursementPoolUpdated", + "name": "TimelockChange", "type": "event" }, { "anonymous": false, "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "voter", + "type": "address" + }, { "indexed": false, "internalType": "uint256", - "name": "sortitionPoolRewardsBanDuration", + "name": "proposalId", "type": "uint256" }, { "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - } - ], - "name": "SortitionPoolRewardsBanDurationUpdateStarted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "internalType": "uint8", + "name": "support", + "type": "uint8" + }, { "indexed": false, "internalType": "uint256", - "name": "sortitionPoolRewardsBanDuration", + "name": "weight", "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "reason", + "type": "string" } ], - "name": "SortitionPoolRewardsBanDurationUpdated", + "name": "VoteCast", "type": "event" }, { @@ -4125,31 +3993,18 @@ "inputs": [ { "indexed": false, - "internalType": "address", - "name": "walletOwner", - "type": "address" + "internalType": "uint256", + "name": "oldVotingDelay", + "type": "uint256" }, { "indexed": false, "internalType": "uint256", - "name": "timestamp", + "name": "newVotingDelay", "type": "uint256" } ], - "name": "WalletOwnerUpdateStarted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "walletOwner", - "type": "address" - } - ], - "name": "WalletOwnerUpdated", + "name": "VotingDelaySet", "type": "event" }, { @@ -4157,108 +4012,116 @@ "inputs": [ { "indexed": false, - "internalType": "address", - "name": "newWalletRegistryGovernance", - "type": "address" + "internalType": "uint256", + "name": "oldVotingPeriod", + "type": "uint256" }, { "indexed": false, "internalType": "uint256", - "name": "timestamp", + "name": "newVotingPeriod", "type": "uint256" } ], - "name": "WalletRegistryGovernanceTransferStarted", + "name": "VotingPeriodSet", "type": "event" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "BALLOT_TYPEHASH", + "outputs": [ { - "indexed": false, - "internalType": "address", - "name": "newWalletRegistryGovernance", - "type": "address" + "internalType": "bytes32", + "name": "", + "type": "bytes32" } ], - "name": "WalletRegistryGovernanceTransferred", - "type": "event" + "stateMutability": "view", + "type": "function" }, { "inputs": [], - "name": "authorizationDecreaseChangePeriodChangeInitiated", + "name": "COUNTING_MODE", "outputs": [ { - "internalType": "uint256", + "internalType": "string", "name": "", - "type": "uint256" + "type": "string" } ], - "stateMutability": "view", + "stateMutability": "pure", "type": "function" }, { "inputs": [], - "name": "authorizationDecreaseDelayChangeInitiated", + "name": "DEFAULT_ADMIN_ROLE", "outputs": [ { - "internalType": "uint256", + "internalType": "bytes32", "name": "", - "type": "uint256" + "type": "bytes32" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "FRACTION_DENOMINATOR", + "outputs": [ { - "internalType": "uint64", - "name": "_newAuthorizationDecreaseChangePeriod", - "type": "uint64" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "beginAuthorizationDecreaseChangePeriodUpdate", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "VETO_POWER", + "outputs": [ { - "internalType": "uint64", - "name": "_newAuthorizationDecreaseDelay", - "type": "uint64" + "internalType": "bytes32", + "name": "", + "type": "bytes32" } ], - "name": "beginAuthorizationDecreaseDelayUpdate", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { - "internalType": "uint256", - "name": "_newDkgResultApprovalGasOffset", - "type": "uint256" + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "internalType": "bytes[]", + "name": "calldatas", + "type": "bytes[]" + }, + { + "internalType": "bytes32", + "name": "descriptionHash", + "type": "bytes32" } ], - "name": "beginDkgResultApprovalGasOffsetUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + "name": "cancel", + "outputs": [ { "internalType": "uint256", - "name": "_newDkgResultChallengeExtraGas", + "name": "", "type": "uint256" } ], - "name": "beginDkgResultChallengeExtraGasUpdate", - "outputs": [], "stateMutability": "nonpayable", "type": "function" }, @@ -4266,25 +4129,23 @@ "inputs": [ { "internalType": "uint256", - "name": "_newDkgResultChallengePeriodLength", + "name": "proposalId", "type": "uint256" + }, + { + "internalType": "uint8", + "name": "support", + "type": "uint8" } ], - "name": "beginDkgResultChallengePeriodLengthUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + "name": "castVote", + "outputs": [ { "internalType": "uint256", - "name": "_newDkgResultSubmissionGas", + "name": "", "type": "uint256" } ], - "name": "beginDkgResultSubmissionGasUpdate", - "outputs": [], "stateMutability": "nonpayable", "type": "function" }, @@ -4292,25 +4153,38 @@ "inputs": [ { "internalType": "uint256", - "name": "_newDkgResultSubmissionTimeout", + "name": "proposalId", "type": "uint256" + }, + { + "internalType": "uint8", + "name": "support", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" } ], - "name": "beginDkgResultSubmissionTimeoutUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + "name": "castVoteBySig", + "outputs": [ { "internalType": "uint256", - "name": "_newDkgSeedTimeout", + "name": "", "type": "uint256" } ], - "name": "beginDkgSeedTimeoutUpdate", - "outputs": [], "stateMutability": "nonpayable", "type": "function" }, @@ -4318,102 +4192,122 @@ "inputs": [ { "internalType": "uint256", - "name": "_newSubmitterPrecedencePeriodLength", + "name": "proposalId", "type": "uint256" - } + }, + { + "internalType": "uint8", + "name": "support", + "type": "uint8" + }, + { + "internalType": "string", + "name": "reason", + "type": "string" + } ], - "name": "beginDkgSubmitterPrecedencePeriodLengthUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + "name": "castVoteWithReason", + "outputs": [ { "internalType": "uint256", - "name": "_newGovernanceDelay", + "name": "", "type": "uint256" } ], - "name": "beginGovernanceDelayUpdate", - "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ + { + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "internalType": "bytes[]", + "name": "calldatas", + "type": "bytes[]" + }, + { + "internalType": "bytes32", + "name": "descriptionHash", + "type": "bytes32" + } + ], + "name": "execute", + "outputs": [ { "internalType": "uint256", - "name": "_newMaliciousDkgResultNotificationRewardMultiplier", + "name": "", "type": "uint256" } ], - "name": "beginMaliciousDkgResultNotificationRewardMultiplierUpdate", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "payable", "type": "function" }, { "inputs": [ { - "internalType": "uint96", - "name": "_newMaliciousDkgResultSlashingAmount", - "type": "uint96" + "internalType": "bytes32", + "name": "role", + "type": "bytes32" } ], - "name": "beginMaliciousDkgResultSlashingAmountUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + "name": "getRoleAdmin", + "outputs": [ { - "internalType": "uint96", - "name": "_newMinimumAuthorization", - "type": "uint96" + "internalType": "bytes32", + "name": "", + "type": "bytes32" } ], - "name": "beginMinimumAuthorizationUpdate", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, { "internalType": "uint256", - "name": "_newNotifyDkgTimeoutNegativeGasOffset", + "name": "blockNumber", "type": "uint256" } ], - "name": "beginNotifyDkgTimeoutNegativeGasOffsetUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + "name": "getVotes", + "outputs": [ { "internalType": "uint256", - "name": "_newNotifyOperatorInactivityGasOffset", + "name": "", "type": "uint256" } ], - "name": "beginNotifyOperatorInactivityGasOffsetUpdate", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { - "internalType": "uint256", - "name": "_newNotifySeedTimeoutGasOffset", - "type": "uint256" + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" } ], - "name": "beginNotifySeedTimeoutGasOffsetUpdate", + "name": "grantRole", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -4421,71 +4315,120 @@ { "inputs": [ { - "internalType": "address payable", - "name": "_newReimbursementPool", + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", "type": "address" } ], - "name": "beginReimbursementPoolUpdate", - "outputs": [], - "stateMutability": "nonpayable", + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "uint256", - "name": "_newSortitionPoolRewardsBanDuration", + "name": "proposalId", "type": "uint256" + }, + { + "internalType": "address", + "name": "account", + "type": "address" } ], - "name": "beginSortitionPoolRewardsBanDurationUpdate", - "outputs": [], - "stateMutability": "nonpayable", + "name": "hasVoted", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", "type": "function" }, { "inputs": [ { - "internalType": "address", - "name": "_newWalletOwner", - "type": "address" + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "internalType": "bytes[]", + "name": "calldatas", + "type": "bytes[]" + }, + { + "internalType": "bytes32", + "name": "descriptionHash", + "type": "bytes32" } ], - "name": "beginWalletOwnerUpdate", - "outputs": [], - "stateMutability": "nonpayable", + "name": "hashProposal", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "lateQuorumVoteExtension", + "outputs": [ { - "internalType": "address", - "name": "_newWalletRegistryGovernance", - "type": "address" + "internalType": "uint64", + "name": "", + "type": "uint64" } ], - "name": "beginWalletRegistryGovernanceTransfer", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [], - "name": "dkgResultApprovalGasOffsetChangeInitiated", + "name": "name", "outputs": [ { - "internalType": "uint256", + "internalType": "string", "name": "", - "type": "uint256" + "type": "string" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "dkgResultChallengeExtraGasChangeInitiated", + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + } + ], + "name": "proposalDeadline", "outputs": [ { "internalType": "uint256", @@ -4497,8 +4440,14 @@ "type": "function" }, { - "inputs": [], - "name": "dkgResultChallengePeriodLengthChangeInitiated", + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + } + ], + "name": "proposalEta", "outputs": [ { "internalType": "uint256", @@ -4510,8 +4459,14 @@ "type": "function" }, { - "inputs": [], - "name": "dkgResultSubmissionGasChangeInitiated", + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + } + ], + "name": "proposalSnapshot", "outputs": [ { "internalType": "uint256", @@ -4523,8 +4478,14 @@ "type": "function" }, { - "inputs": [], - "name": "dkgResultSubmissionTimeoutChangeInitiated", + "inputs": [ + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + } + ], + "name": "proposalThreshold", "outputs": [ { "internalType": "uint256", @@ -4537,7 +4498,7 @@ }, { "inputs": [], - "name": "dkgSeedTimeoutChangeInitiated", + "name": "proposalThreshold", "outputs": [ { "internalType": "uint256", @@ -4550,7 +4511,7 @@ }, { "inputs": [], - "name": "dkgSubmitterPrecedencePeriodLengthChangeInitiated", + "name": "proposalThresholdNumerator", "outputs": [ { "internalType": "uint256", @@ -4562,153 +4523,278 @@ "type": "function" }, { - "inputs": [], - "name": "finalizeAuthorizationDecreaseChangePeriodUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeAuthorizationDecreaseDelayUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeDkgResultApprovalGasOffsetUpdate", - "outputs": [], - "stateMutability": "nonpayable", + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + } + ], + "name": "proposalVotes", + "outputs": [ + { + "internalType": "uint256", + "name": "againstVotes", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "forVotes", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "abstainVotes", + "type": "uint256" + } + ], + "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "finalizeDkgResultChallengeExtraGasUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeDkgResultChallengePeriodLengthUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeDkgResultSubmissionGasUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeDkgResultSubmissionTimeoutUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeDkgSeedTimeoutUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeDkgSubmitterPrecedencePeriodLengthUpdate", - "outputs": [], + "inputs": [ + { + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "internalType": "bytes[]", + "name": "calldatas", + "type": "bytes[]" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + } + ], + "name": "propose", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "finalizeGovernanceDelayUpdate", - "outputs": [], + "inputs": [ + { + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "internalType": "bytes[]", + "name": "calldatas", + "type": "bytes[]" + }, + { + "internalType": "bytes32", + "name": "descriptionHash", + "type": "bytes32" + } + ], + "name": "queue", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "finalizeMaliciousDkgResultNotificationRewardMultiplierUpdate", - "outputs": [], - "stateMutability": "nonpayable", + "inputs": [ + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + } + ], + "name": "quorum", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", "type": "function" }, { "inputs": [], - "name": "finalizeMaliciousDkgResultSlashingAmountUpdate", - "outputs": [], - "stateMutability": "nonpayable", + "name": "quorumNumerator", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "finalizeMinimumAuthorizationUpdate", + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "relay", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "finalizeNotifyDkgTimeoutNegativeGasOffsetUpdate", + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "renounceRole", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "finalizeNotifyOperatorInactivityGasOffsetUpdate", + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "finalizeNotifySeedTimeoutGasOffsetUpdate", + "inputs": [ + { + "internalType": "uint64", + "name": "newVoteExtension", + "type": "uint64" + } + ], + "name": "setLateQuorumVoteExtension", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "finalizeReimbursementPoolUpdate", + "inputs": [ + { + "internalType": "uint256", + "name": "newVotingDelay", + "type": "uint256" + } + ], + "name": "setVotingDelay", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "finalizeSortitionPoolRewardsBanDurationUpdate", + "inputs": [ + { + "internalType": "uint256", + "name": "newVotingPeriod", + "type": "uint256" + } + ], + "name": "setVotingPeriod", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "finalizeWalletOwnerUpdate", - "outputs": [], - "stateMutability": "nonpayable", + "name": "staking", + "outputs": [ + { + "internalType": "contract IVotesHistory", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "finalizeWalletRegistryGovernanceTransfer", - "outputs": [], - "stateMutability": "nonpayable", + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + } + ], + "name": "state", + "outputs": [ + { + "internalType": "enum IGovernor.ProposalState", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "getRemainingAuthorizationDecreaseChangePeriodUpdateTime", + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", "outputs": [ { - "internalType": "uint256", + "internalType": "bool", "name": "", - "type": "uint256" + "type": "bool" } ], "stateMutability": "view", @@ -4716,12 +4802,12 @@ }, { "inputs": [], - "name": "getRemainingAuthorizationDecreaseDelayUpdateTime", + "name": "timelock", "outputs": [ { - "internalType": "uint256", + "internalType": "address", "name": "", - "type": "uint256" + "type": "address" } ], "stateMutability": "view", @@ -4729,51 +4815,64 @@ }, { "inputs": [], - "name": "getRemainingDkgResultApprovalGasOffsetUpdateTime", + "name": "token", "outputs": [ { - "internalType": "uint256", + "internalType": "contract IVotesHistory", "name": "", - "type": "uint256" + "type": "address" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "getRemainingDkgResultChallengeExtraGasUpdateTime", - "outputs": [ + "inputs": [ { "internalType": "uint256", - "name": "", + "name": "newNumerator", "type": "uint256" } ], - "stateMutability": "view", + "name": "updateProposalThresholdNumerator", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "getRemainingDkgResultChallengePeriodLengthUpdateTime", - "outputs": [ + "inputs": [ { "internalType": "uint256", - "name": "", + "name": "newQuorumNumerator", "type": "uint256" } ], - "stateMutability": "view", + "name": "updateQuorumNumerator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract TimelockController", + "name": "newTimelock", + "type": "address" + } + ], + "name": "updateTimelock", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "getRemainingDkgResultSubmissionGasUpdateTime", + "name": "version", "outputs": [ { - "internalType": "uint256", + "internalType": "string", "name": "", - "type": "uint256" + "type": "string" } ], "stateMutability": "view", @@ -4781,7 +4880,7 @@ }, { "inputs": [], - "name": "getRemainingDkgResultSubmissionTimeoutUpdateTime", + "name": "votingDelay", "outputs": [ { "internalType": "uint256", @@ -4794,7 +4893,7 @@ }, { "inputs": [], - "name": "getRemainingDkgSeedTimeoutUpdateTime", + "name": "votingPeriod", "outputs": [ { "internalType": "uint256", @@ -4806,156 +4905,166 @@ "type": "function" }, { - "inputs": [], - "name": "getRemainingDkgSubmitterPrecedencePeriodLengthUpdateTime", - "outputs": [ + "stateMutability": "payable", + "type": "receive" + } + ] + }, + "ReimbursementPool": { + "address": "0xcA03Dc4665A8C3603cb4Fd5Ce71Af9649dC00d44", + "abi": [ + { + "inputs": [ { "internalType": "uint256", - "name": "", + "name": "_staticGas", "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getRemainingGovernanceDelayUpdateTime", - "outputs": [ + }, { "internalType": "uint256", - "name": "", + "name": "_maxGasPrice", "type": "uint256" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "nonpayable", + "type": "constructor" }, { - "inputs": [], - "name": "getRemainingMaliciousDkgResultNotificationRewardMultiplierUpdateTime", - "outputs": [ + "anonymous": false, + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "indexed": false, + "internalType": "address", + "name": "thirdPartyContract", + "type": "address" } ], - "stateMutability": "view", - "type": "function" + "name": "AuthorizedContract", + "type": "event" }, { - "inputs": [], - "name": "getRemainingMaliciousDkgResultSlashingAmountUpdateTime", - "outputs": [ + "anonymous": false, + "inputs": [ { + "indexed": false, "internalType": "uint256", - "name": "", + "name": "withdrawnAmount", "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" } ], - "stateMutability": "view", - "type": "function" + "name": "FundsWithdrawn", + "type": "event" }, { - "inputs": [], - "name": "getRemainingMimimumAuthorizationUpdateTime", - "outputs": [ + "anonymous": false, + "inputs": [ { + "indexed": false, "internalType": "uint256", - "name": "", + "name": "newMaxGasPrice", "type": "uint256" } ], - "stateMutability": "view", - "type": "function" + "name": "MaxGasPriceUpdated", + "type": "event" }, { - "inputs": [], - "name": "getRemainingNotifyDkgTimeoutNegativeGasOffsetUpdateTime", - "outputs": [ + "anonymous": false, + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" } ], - "stateMutability": "view", - "type": "function" + "name": "OwnershipTransferred", + "type": "event" }, { - "inputs": [], - "name": "getRemainingNotifyOperatorInactivityGasOffsetUpdateTime", - "outputs": [ + "anonymous": false, + "inputs": [ { + "indexed": false, "internalType": "uint256", - "name": "", + "name": "refundAmount", "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" } ], - "stateMutability": "view", - "type": "function" + "name": "SendingEtherFailed", + "type": "event" }, { - "inputs": [], - "name": "getRemainingNotifySeedTimeoutGasOffsetUpdateTime", - "outputs": [ + "anonymous": false, + "inputs": [ { + "indexed": false, "internalType": "uint256", - "name": "", + "name": "newStaticGas", "type": "uint256" } ], - "stateMutability": "view", - "type": "function" + "name": "StaticGasUpdated", + "type": "event" }, { - "inputs": [], - "name": "getRemainingReimbursementPoolUpdateTime", - "outputs": [ + "anonymous": false, + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "indexed": false, + "internalType": "address", + "name": "thirdPartyContract", + "type": "address" } ], - "stateMutability": "view", - "type": "function" + "name": "UnauthorizedContract", + "type": "event" }, { - "inputs": [], - "name": "getRemainingSortitionPoolRewardsBanDurationUpdateTime", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "address", + "name": "_contract", + "type": "address" } ], - "stateMutability": "view", + "name": "authorize", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "getRemainingWalletOwnerUpdateTime", - "outputs": [ + "inputs": [ { - "internalType": "uint256", + "internalType": "address", "name": "", - "type": "uint256" + "type": "address" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getRemainingWalletRegistryGovernanceTransferDelayTime", + "name": "isAuthorized", "outputs": [ { - "internalType": "uint256", + "internalType": "bool", "name": "", - "type": "uint256" + "type": "bool" } ], "stateMutability": "view", @@ -4963,7 +5072,7 @@ }, { "inputs": [], - "name": "governanceDelay", + "name": "maxGasPrice", "outputs": [ { "internalType": "uint256", @@ -4976,12 +5085,12 @@ }, { "inputs": [], - "name": "governanceDelayChangeInitiated", + "name": "owner", "outputs": [ { - "internalType": "uint256", + "internalType": "address", "name": "", - "type": "uint256" + "type": "address" } ], "stateMutability": "view", @@ -4989,46 +5098,58 @@ }, { "inputs": [ + { + "internalType": "uint256", + "name": "gasSpent", + "type": "uint256" + }, { "internalType": "address", - "name": "_walletOwner", + "name": "receiver", "type": "address" } ], - "name": "initializeWalletOwner", + "name": "refund", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "maliciousDkgResultNotificationRewardMultiplierChangeInitiated", - "outputs": [ + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ { "internalType": "uint256", - "name": "", + "name": "_maxGasPrice", "type": "uint256" } ], - "stateMutability": "view", + "name": "setMaxGasPrice", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "maliciousDkgResultSlashingAmountChangeInitiated", - "outputs": [ + "inputs": [ { "internalType": "uint256", - "name": "", + "name": "_staticGas", "type": "uint256" } ], - "stateMutability": "view", + "name": "setStaticGas", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "minimumAuthorizationChangeInitiated", + "name": "staticGas", "outputs": [ { "internalType": "uint256", @@ -5040,130 +5161,209 @@ "type": "function" }, { - "inputs": [], - "name": "newAuthorizationDecreaseChangePeriod", - "outputs": [ + "inputs": [ { - "internalType": "uint64", - "name": "", - "type": "uint64" + "internalType": "address", + "name": "newOwner", + "type": "address" } ], - "stateMutability": "view", + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "newAuthorizationDecreaseDelay", - "outputs": [ + "inputs": [ { - "internalType": "uint64", - "name": "", - "type": "uint64" + "internalType": "address", + "name": "_contract", + "type": "address" } ], - "stateMutability": "view", + "name": "unauthorize", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "newDkgResultApprovalGasOffset", - "outputs": [ + "inputs": [ { "internalType": "uint256", - "name": "", + "name": "amount", "type": "uint256" - } + }, + { + "internalType": "address", + "name": "receiver", + "type": "address" + } ], - "stateMutability": "view", + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "newDkgResultChallengeExtraGas", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "address", + "name": "receiver", + "type": "address" } ], - "stateMutability": "view", + "name": "withdrawAll", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "newDkgResultChallengePeriodLength", - "outputs": [ + "stateMutability": "payable", + "type": "receive" + } + ] + }, + "BeaconSortitionPool": { + "address": "0x2dE080e97B0caE9825375D31f5D0eD5751fDf16D", + "abi": [ + { + "inputs": [ + { + "internalType": "contract IERC20WithPermit", + "name": "_rewardToken", + "type": "address" + }, { "internalType": "uint256", - "name": "", + "name": "_poolWeightDivisor", "type": "uint256" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "nonpayable", + "type": "constructor" }, { - "inputs": [], - "name": "newDkgResultSubmissionGas", - "outputs": [ + "anonymous": false, + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "indexed": false, + "internalType": "address[]", + "name": "operators", + "type": "address[]" } ], - "stateMutability": "view", - "type": "function" + "name": "BetaOperatorsAdded", + "type": "event" }, { + "anonymous": false, "inputs": [], - "name": "newDkgResultSubmissionTimeout", - "outputs": [ + "name": "ChaosnetDeactivated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "indexed": false, + "internalType": "address", + "name": "oldChaosnetOwner", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newChaosnetOwner", + "type": "address" } ], - "stateMutability": "view", - "type": "function" + "name": "ChaosnetOwnerRoleTransferred", + "type": "event" }, { - "inputs": [], - "name": "newDkgSeedTimeout", - "outputs": [ + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint32[]", + "name": "ids", + "type": "uint32[]" + }, { + "indexed": false, "internalType": "uint256", - "name": "", + "name": "until", "type": "uint256" } ], - "stateMutability": "view", - "type": "function" + "name": "IneligibleForRewards", + "type": "event" }, { - "inputs": [], - "name": "newGovernanceDelay", - "outputs": [ + "anonymous": false, + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" } ], - "stateMutability": "view", + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint32", + "name": "id", + "type": "uint32" + } + ], + "name": "RewardEligibilityRestored", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "operators", + "type": "address[]" + } + ], + "name": "addBetaOperators", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "newMaliciousDkgResultNotificationRewardMultiplier", + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "canRestoreRewardEligibility", "outputs": [ { - "internalType": "uint256", + "internalType": "bool", "name": "", - "type": "uint256" + "type": "bool" } ], "stateMutability": "view", @@ -5171,12 +5371,12 @@ }, { "inputs": [], - "name": "newMaliciousDkgResultSlashingAmount", + "name": "chaosnetOwner", "outputs": [ { - "internalType": "uint96", + "internalType": "address", "name": "", - "type": "uint96" + "type": "address" } ], "stateMutability": "view", @@ -5184,7 +5384,20 @@ }, { "inputs": [], - "name": "newMinimumAuthorization", + "name": "deactivateChaosnet", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "getAvailableRewards", "outputs": [ { "internalType": "uint96", @@ -5196,60 +5409,71 @@ "type": "function" }, { - "inputs": [], - "name": "newNotifyDkgTimeoutNegativeGasOffset", + "inputs": [ + { + "internalType": "uint32", + "name": "id", + "type": "uint32" + } + ], + "name": "getIDOperator", "outputs": [ { - "internalType": "uint256", + "internalType": "address", "name": "", - "type": "uint256" + "type": "address" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "newNotifyOperatorInactivityGasOffset", + "inputs": [ + { + "internalType": "uint32[]", + "name": "ids", + "type": "uint32[]" + } + ], + "name": "getIDOperators", "outputs": [ { - "internalType": "uint256", + "internalType": "address[]", "name": "", - "type": "uint256" + "type": "address[]" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "newNotifySeedTimeoutGasOffset", + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "getOperatorID", "outputs": [ { - "internalType": "uint256", + "internalType": "uint32", "name": "", - "type": "uint256" + "type": "uint32" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "newReimbursementPool", - "outputs": [ + "inputs": [ { - "internalType": "address payable", - "name": "", + "internalType": "address", + "name": "operator", "type": "address" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "newSortitionPoolRewardsBanDuration", + "name": "getPoolWeight", "outputs": [ { "internalType": "uint256", @@ -5262,51 +5486,49 @@ }, { "inputs": [], - "name": "newSubmitterPrecedencePeriodLength", + "name": "ineligibleEarnedRewards", "outputs": [ { - "internalType": "uint256", + "internalType": "uint96", "name": "", - "type": "uint256" + "type": "uint96" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "newWalletOwner", - "outputs": [ + "inputs": [ { "internalType": "address", - "name": "", + "name": "operator", "type": "address" + }, + { + "internalType": "uint256", + "name": "authorizedStake", + "type": "uint256" } ], - "stateMutability": "view", + "name": "insertOperator", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "newWalletRegistryGovernance", - "outputs": [ + "inputs": [ { "internalType": "address", "name": "", "type": "address" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "notifyDkgTimeoutNegativeGasOffsetChangeInitiated", + "name": "isBetaOperator", "outputs": [ { - "internalType": "uint256", + "internalType": "bool", "name": "", - "type": "uint256" + "type": "bool" } ], "stateMutability": "view", @@ -5314,38 +5536,31 @@ }, { "inputs": [], - "name": "notifyOperatorInactivityGasOffsetChangeInitiated", + "name": "isChaosnetActive", "outputs": [ { - "internalType": "uint256", + "internalType": "bool", "name": "", - "type": "uint256" + "type": "bool" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "notifySeedTimeoutGasOffsetChangeInitiated", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "address", + "name": "operator", + "type": "address" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", + "name": "isEligibleForRewards", "outputs": [ { - "internalType": "address", + "internalType": "bool", "name": "", - "type": "address" + "type": "bool" } ], "stateMutability": "view", @@ -5353,32 +5568,31 @@ }, { "inputs": [], - "name": "reimbursementPoolChangeInitiated", + "name": "isLocked", "outputs": [ { - "internalType": "uint256", + "internalType": "bool", "name": "", - "type": "uint256" + "type": "bool" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "sortitionPoolRewardsBanDurationChangeInitiated", + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isOperatorInPool", "outputs": [ { - "internalType": "uint256", + "internalType": "bool", "name": "", - "type": "uint256" + "type": "bool" } ], "stateMutability": "view", @@ -5388,31 +5602,55 @@ "inputs": [ { "internalType": "address", - "name": "newOwner", + "name": "operator", "type": "address" } ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", + "name": "isOperatorRegistered", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", - "name": "_newRandomBeacon", + "name": "operator", "type": "address" + }, + { + "internalType": "uint256", + "name": "authorizedStake", + "type": "uint256" } ], - "name": "upgradeRandomBeacon", + "name": "isOperatorUpToDate", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lock", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "walletOwnerChangeInitiated", + "name": "operatorsInPool", "outputs": [ { "internalType": "uint256", @@ -5425,10 +5663,10 @@ }, { "inputs": [], - "name": "walletRegistry", + "name": "owner", "outputs": [ { - "internalType": "contract WalletRegistry", + "internalType": "address", "name": "", "type": "address" } @@ -5438,7 +5676,7 @@ }, { "inputs": [], - "name": "walletRegistryGovernanceTransferInitiated", + "name": "poolWeightDivisor", "outputs": [ { "internalType": "uint256", @@ -5453,285 +5691,308 @@ "inputs": [ { "internalType": "address", - "name": "recipient", - "type": "address" - } - ], - "name": "withdrawIneligibleRewards", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ] - }, - "RandomBeacon": { - "address": "0x5499f54b4A1CB4816eefCf78962040461be3D80b", - "abi": [ - { - "inputs": [ - { - "internalType": "contract SortitionPool", - "name": "_sortitionPool", - "type": "address" - }, - { - "internalType": "contract IERC20", - "name": "_tToken", + "name": "sender", "type": "address" }, { - "internalType": "contract IStaking", - "name": "_staking", - "type": "address" + "internalType": "uint256", + "name": "amount", + "type": "uint256" }, { - "internalType": "contract BeaconDkgValidator", - "name": "_dkgValidator", + "internalType": "address", + "name": "token", "type": "address" }, { - "internalType": "contract ReimbursementPool", - "name": "_reimbursementPool", - "type": "address" + "internalType": "bytes", + "name": "", + "type": "bytes" } ], + "name": "receiveApproval", + "outputs": [], "stateMutability": "nonpayable", - "type": "constructor" + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": true, "internalType": "address", - "name": "stakingProvider", + "name": "operator", "type": "address" } ], - "name": "AuthorizationDecreaseApproved", - "type": "event" + "name": "restoreRewardEligibility", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "rewardToken", + "outputs": [ { - "indexed": true, - "internalType": "address", - "name": "stakingProvider", + "internalType": "contract IERC20WithPermit", + "name": "", "type": "address" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ { - "indexed": true, "internalType": "address", "name": "operator", "type": "address" - }, - { - "indexed": false, - "internalType": "uint96", - "name": "fromAmount", - "type": "uint96" - }, - { - "indexed": false, - "internalType": "uint96", - "name": "toAmount", - "type": "uint96" - }, + } + ], + "name": "rewardsEligibilityRestorableAt", + "outputs": [ { - "indexed": false, - "internalType": "uint64", - "name": "decreasingAt", - "type": "uint64" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "AuthorizationDecreaseRequested", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "address", - "name": "stakingProvider", - "type": "address" + "internalType": "uint256", + "name": "groupSize", + "type": "uint256" }, { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" - }, + "internalType": "bytes32", + "name": "seed", + "type": "bytes32" + } + ], + "name": "selectGroup", + "outputs": [ { - "indexed": false, - "internalType": "uint96", - "name": "fromAmount", - "type": "uint96" - }, - { - "indexed": false, - "internalType": "uint96", - "name": "toAmount", - "type": "uint96" + "internalType": "uint32[]", + "name": "", + "type": "uint32[]" } ], - "name": "AuthorizationIncreased", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint96", - "name": "minimumAuthorization", - "type": "uint96" - }, - { - "indexed": false, - "internalType": "uint64", - "name": "authorizationDecreaseDelay", - "type": "uint64" + "internalType": "uint32[]", + "name": "operators", + "type": "uint32[]" }, { - "indexed": false, - "internalType": "uint64", - "name": "authorizationDecreaseChangePeriod", - "type": "uint64" + "internalType": "uint256", + "name": "until", + "type": "uint256" } ], - "name": "AuthorizationParametersUpdated", - "type": "event" + "name": "setRewardIneligibility", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "entry", - "type": "uint256" - }, + "inputs": [], + "name": "totalWeight", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "entrySubmittedBlock", + "name": "", "type": "uint256" } ], - "name": "CallbackFailed", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "resultHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "slashingAmount", - "type": "uint256" - }, + "internalType": "address", + "name": "newChaosnetOwner", + "type": "address" + } + ], + "name": "transferChaosnetOwnerRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ { - "indexed": false, "internalType": "address", - "name": "maliciousSubmitter", + "name": "newOwner", "type": "address" } ], - "name": "DkgMaliciousResultSlashed", - "type": "event" + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unlock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "resultHash", - "type": "bytes32" + "internalType": "address", + "name": "operator", + "type": "address" }, { - "indexed": false, "internalType": "uint256", - "name": "slashingAmount", + "name": "authorizedStake", "type": "uint256" - }, + } + ], + "name": "updateOperatorStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ { - "indexed": false, "internalType": "address", - "name": "maliciousSubmitter", + "name": "recipient", "type": "address" } ], - "name": "DkgMaliciousResultSlashingFailed", - "type": "event" + "name": "withdrawIneligible", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "resultHash", - "type": "bytes32" + "internalType": "address", + "name": "operator", + "type": "address" }, { - "indexed": true, "internalType": "address", - "name": "approver", + "name": "beneficiary", "type": "address" } ], - "name": "DkgResultApproved", - "type": "event" - }, + "name": "withdrawRewards", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ] + }, + "BeaconDkgValidator": { + "address": "0x381445710b5e73d34aF196c53A3D5cDa58EDBf7A", + "abi": [ { - "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "resultHash", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "challenger", + "internalType": "contract SortitionPool", + "name": "_sortitionPool", "type": "address" - }, + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "activeThreshold", + "outputs": [ { - "indexed": false, - "internalType": "string", - "name": "reason", - "type": "string" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "DkgResultChallenged", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "groupSize", + "outputs": [ { - "indexed": true, - "internalType": "bytes32", - "name": "resultHash", - "type": "bytes32" - }, + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "groupThreshold", + "outputs": [ { - "indexed": true, "internalType": "uint256", - "name": "seed", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "signatureByteSize", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "sortitionPool", + "outputs": [ + { + "internalType": "contract SortitionPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ { "components": [ { @@ -5770,851 +6031,5148 @@ "type": "bytes32" } ], - "indexed": false, "internalType": "struct BeaconDkg.Result", "name": "result", "type": "tuple" - } - ], - "name": "DkgResultSubmitted", + }, + { + "internalType": "uint256", + "name": "seed", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startBlock", + "type": "uint256" + } + ], + "name": "validate", + "outputs": [ + { + "internalType": "bool", + "name": "isValid", + "type": "bool" + }, + { + "internalType": "string", + "name": "errorMsg", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct BeaconDkg.Result", + "name": "result", + "type": "tuple" + } + ], + "name": "validateFields", + "outputs": [ + { + "internalType": "bool", + "name": "isValid", + "type": "bool" + }, + { + "internalType": "string", + "name": "errorMsg", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct BeaconDkg.Result", + "name": "result", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "seed", + "type": "uint256" + } + ], + "name": "validateGroupMembers", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct BeaconDkg.Result", + "name": "result", + "type": "tuple" + } + ], + "name": "validateMembersHash", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct BeaconDkg.Result", + "name": "result", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "startBlock", + "type": "uint256" + } + ], + "name": "validateSignatures", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ] + }, + "BLS": { + "address": "0xe6b98F104c1BEf218F3893ADab4160Dc73Eb8367", + "abi": [ + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "uint256", + "name": "x", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "y", + "type": "uint256" + } + ], + "internalType": "struct AltBn128.gfP2", + "name": "x", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "x", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "y", + "type": "uint256" + } + ], + "internalType": "struct AltBn128.gfP2", + "name": "y", + "type": "tuple" + } + ], + "internalType": "struct AltBn128.G2Point", + "name": "publicKey", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "x", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "y", + "type": "uint256" + } + ], + "internalType": "struct AltBn128.G1Point", + "name": "message", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "x", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "y", + "type": "uint256" + } + ], + "internalType": "struct AltBn128.G1Point", + "name": "signature", + "type": "tuple" + } + ], + "name": "_verify", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "message", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "secretKey", + "type": "uint256" + } + ], + "name": "sign", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "message", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "verify", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "message", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "verifyBytes", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ] + }, + "BeaconAuthorization": { + "address": "0x5C7c905B505f0Cf40Ab6600d05e677F717916F6B", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "AuthorizationDecreaseApproved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "decreasingAt", + "type": "uint64" + } + ], + "name": "AuthorizationDecreaseRequested", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + } + ], + "name": "AuthorizationIncreased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + } + ], + "name": "InvoluntaryAuthorizationDecreaseFailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "OperatorJoinedSortitionPool", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "OperatorRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "OperatorStatusUpdated", + "type": "event" + } + ] + }, + "BeaconDkg": { + "address": "0x0D4ff719551E23185Aeb16FFbF2ABEbB90635942", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "approver", + "type": "address" + } + ], + "name": "DkgResultApproved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "indexed": false, + "internalType": "string", + "name": "reason", + "type": "string" + } + ], + "name": "DkgResultChallenged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "seed", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "indexed": false, + "internalType": "struct BeaconDkg.Result", + "name": "result", + "type": "tuple" + } + ], + "name": "DkgResultSubmitted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "DkgSeedTimedOut", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "seed", + "type": "uint256" + } + ], + "name": "DkgStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "DkgStateLocked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "DkgTimedOut", + "type": "event" + }, + { + "inputs": [], + "name": "groupSize", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "offchainDkgTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } + ] + }, + "BeaconInactivity": { + "address": "0x85C5Dd61585773423e378146D4bEC6f8D149E248", + "abi": [ + { + "inputs": [], + "name": "groupThreshold", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "signatureByteSize", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract SortitionPool", + "name": "sortitionPool", + "type": "SortitionPool" + }, + { + "components": [ + { + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "internalType": "uint256[]", + "name": "inactiveMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + } + ], + "internalType": "struct BeaconInactivity.Claim", + "name": "claim", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint32[]", + "name": "groupMembers", + "type": "uint32[]" + } + ], + "name": "verifyClaim", + "outputs": [ + { + "internalType": "uint32[]", + "name": "inactiveMembers", + "type": "uint32[]" + } + ], + "stateMutability": "view", + "type": "function" + } + ] + }, + "RandomBeacon": { + "address": "0xfbAb4aa40C202E4e80390171E82379824f7372dd", + "abi": [ + { + "inputs": [ + { + "internalType": "contract SortitionPool", + "name": "_sortitionPool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "_tToken", + "type": "address" + }, + { + "internalType": "contract IStaking", + "name": "_staking", + "type": "address" + }, + { + "internalType": "contract BeaconDkgValidator", + "name": "_dkgValidator", + "type": "address" + }, + { + "internalType": "contract ReimbursementPool", + "name": "_reimbursementPool", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "AuthorizationDecreaseApproved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "decreasingAt", + "type": "uint64" + } + ], + "name": "AuthorizationDecreaseRequested", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + } + ], + "name": "AuthorizationIncreased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint96", + "name": "minimumAuthorization", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "authorizationDecreaseDelay", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "authorizationDecreaseChangePeriod", + "type": "uint64" + } + ], + "name": "AuthorizationParametersUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "entry", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "entrySubmittedBlock", + "type": "uint256" + } + ], + "name": "CallbackFailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "slashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "maliciousSubmitter", + "type": "address" + } + ], + "name": "DkgMaliciousResultSlashed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "slashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "maliciousSubmitter", + "type": "address" + } + ], + "name": "DkgMaliciousResultSlashingFailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "approver", + "type": "address" + } + ], + "name": "DkgResultApproved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "indexed": false, + "internalType": "string", + "name": "reason", + "type": "string" + } + ], + "name": "DkgResultChallenged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "seed", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "indexed": false, + "internalType": "struct BeaconDkg.Result", + "name": "result", + "type": "tuple" + } + ], + "name": "DkgResultSubmitted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "DkgSeedTimedOut", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "seed", + "type": "uint256" + } + ], + "name": "DkgStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "DkgStateLocked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "DkgTimedOut", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultSubmissionGas", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultApprovalGasOffset", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "notifyOperatorInactivityGasOffset", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntrySubmissionGasOffset", + "type": "uint256" + } + ], + "name": "GasParametersUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldGovernance", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newGovernance", + "type": "address" + } + ], + "name": "GovernanceTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "groupCreationFrequency", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "groupLifetime", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultChallengePeriodLength", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultChallengeExtraGas", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultSubmissionTimeout", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultSubmitterPrecedencePeriodLength", + "type": "uint256" + } + ], + "name": "GroupCreationParametersUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "indexed": true, + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + } + ], + "name": "GroupRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "notifier", + "type": "address" + } + ], + "name": "InactivityClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + } + ], + "name": "InvoluntaryAuthorizationDecreaseFailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "OperatorJoinedSortitionPool", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "OperatorRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "OperatorStatusUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newReimbursementPool", + "type": "address" + } + ], + "name": "ReimbursementPoolUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "slashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "groupMembers", + "type": "address[]" + } + ], + "name": "RelayEntryDelaySlashed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "slashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "groupMembers", + "type": "address[]" + } + ], + "name": "RelayEntryDelaySlashingFailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntrySoftTimeout", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntryHardTimeout", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "callbackGasLimit", + "type": "uint256" + } + ], + "name": "RelayEntryParametersUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "previousEntry", + "type": "bytes" + } + ], + "name": "RelayEntryRequested", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "submitter", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "entry", + "type": "bytes" + } + ], + "name": "RelayEntrySubmitted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "terminatedGroupId", + "type": "uint64" + } + ], + "name": "RelayEntryTimedOut", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "slashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "groupMembers", + "type": "address[]" + } + ], + "name": "RelayEntryTimeoutSlashed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "slashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "groupMembers", + "type": "address[]" + } + ], + "name": "RelayEntryTimeoutSlashingFailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isAuthorized", + "type": "bool" + } + ], + "name": "RequesterAuthorizationUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "sortitionPoolRewardsBanDuration", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntryTimeoutNotificationRewardMultiplier", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "unauthorizedSigningNotificationRewardMultiplier", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "dkgMaliciousResultNotificationRewardMultiplier", + "type": "uint256" + } + ], + "name": "RewardParametersUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "amount", + "type": "uint96" + } + ], + "name": "RewardsWithdrawn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntrySubmissionFailureSlashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "maliciousDkgResultSlashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "unauthorizedSigningSlashingAmount", + "type": "uint256" + } + ], + "name": "SlashingParametersUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "unauthorizedSigningSlashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "groupMembers", + "type": "address[]" + } + ], + "name": "UnauthorizedSigningSlashed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "unauthorizedSigningSlashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "groupMembers", + "type": "address[]" + } + ], + "name": "UnauthorizedSigningSlashingFailed", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "approveAuthorizationDecrease", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct BeaconDkg.Result", + "name": "dkgResult", + "type": "tuple" + } + ], + "name": "approveDkgResult", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + } + ], + "name": "authorizationDecreaseRequested", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + } + ], + "name": "authorizationIncreased", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "authorizationParameters", + "outputs": [ + { + "internalType": "uint96", + "name": "minimumAuthorization", + "type": "uint96" + }, + { + "internalType": "uint64", + "name": "authorizationDecreaseDelay", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "authorizationDecreaseChangePeriod", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "authorizedRequesters", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "availableRewards", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct BeaconDkg.Result", + "name": "dkgResult", + "type": "tuple" + } + ], + "name": "challengeDkgResult", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "eligibleStake", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gasParameters", + "outputs": [ + { + "internalType": "uint256", + "name": "dkgResultSubmissionGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultApprovalGasOffset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "notifyOperatorInactivityGasOffset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "relayEntrySubmissionGasOffset", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "genesis", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + } + ], + "name": "getGroup", + "outputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "registrationBlockNumber", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + }, + { + "internalType": "bool", + "name": "terminated", + "type": "bool" + } + ], + "internalType": "struct Groups.Group", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + } + ], + "name": "getGroup", + "outputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "registrationBlockNumber", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + }, + { + "internalType": "bool", + "name": "terminated", + "type": "bool" + } + ], + "internalType": "struct Groups.Group", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getGroupCreationState", + "outputs": [ + { + "internalType": "enum BeaconDkg.State", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getGroupsRegistry", + "outputs": [ + { + "internalType": "bytes32[]", + "name": "", + "type": "bytes32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "governance", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "groupCreationParameters", + "outputs": [ + { + "internalType": "uint256", + "name": "groupCreationFrequency", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "groupLifetime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultChallengePeriodLength", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultChallengeExtraGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultSubmissionTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgSubmitterPrecedencePeriodLength", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "hasDkgTimedOut", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "name": "inactivityClaimNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + } + ], + "name": "involuntaryAuthorizationDecrease", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isOperatorInPool", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isOperatorUpToDate", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isRelayRequestInProgress", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "joinSortitionPool", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "minimumAuthorization", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "notifyDkgTimeout", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "internalType": "uint256[]", + "name": "inactiveMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + } + ], + "internalType": "struct BeaconInactivity.Claim", + "name": "claim", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint32[]", + "name": "groupMembers", + "type": "uint32[]" + } + ], + "name": "notifyOperatorInactivity", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "operatorToStakingProvider", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "pendingAuthorizationDecrease", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "registerOperator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "reimbursementPool", + "outputs": [ + { + "internalType": "contract ReimbursementPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "relayEntryParameters", + "outputs": [ + { + "internalType": "uint256", + "name": "relayEntrySoftTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "relayEntryHardTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "callbackGasLimit", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "remainingAuthorizationDecreaseDelay", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32[]", + "name": "groupMembers", + "type": "uint32[]" + } + ], + "name": "reportRelayEntryTimeout", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "signedMsgSender", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "internalType": "uint32[]", + "name": "groupMembers", + "type": "uint32[]" + } + ], + "name": "reportUnauthorizedSigning", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IRandomBeaconConsumer", + "name": "callbackContract", + "type": "address" + } + ], + "name": "requestRelayEntry", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "rewardParameters", + "outputs": [ + { + "internalType": "uint256", + "name": "sortitionPoolRewardsBanDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "relayEntryTimeoutNotificationRewardMultiplier", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "unauthorizedSigningNotificationRewardMultiplier", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgMaliciousResultNotificationRewardMultiplier", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "selectGroup", + "outputs": [ + { + "internalType": "uint32[]", + "name": "", + "type": "uint32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "bool", + "name": "isAuthorized", + "type": "bool" + } + ], + "name": "setRequesterAuthorization", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "slashingParameters", + "outputs": [ + { + "internalType": "uint96", + "name": "relayEntrySubmissionFailureSlashingAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "maliciousDkgResultSlashingAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "unauthorizedSigningSlashingAmount", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "sortitionPool", + "outputs": [ + { + "internalType": "contract SortitionPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "staking", + "outputs": [ + { + "internalType": "contract IStaking", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "stakingProviderToOperator", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct BeaconDkg.Result", + "name": "dkgResult", + "type": "tuple" + } + ], + "name": "submitDkgResult", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "entry", + "type": "bytes" + }, + { + "internalType": "uint32[]", + "name": "groupMembers", + "type": "uint32[]" + } + ], + "name": "submitRelayEntry", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "entry", + "type": "bytes" + } + ], + "name": "submitRelayEntry", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "tToken", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newGovernance", + "type": "address" + } + ], + "name": "transferGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "_minimumAuthorization", + "type": "uint96" + }, + { + "internalType": "uint64", + "name": "_authorizationDecreaseDelay", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "_authorizationDecreaseChangePeriod", + "type": "uint64" + } + ], + "name": "updateAuthorizationParameters", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dkgResultSubmissionGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultApprovalGasOffset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "notifyOperatorInactivityGasOffset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "relayEntrySubmissionGasOffset", + "type": "uint256" + } + ], + "name": "updateGasParameters", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "groupCreationFrequency", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "groupLifetime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultChallengePeriodLength", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultChallengeExtraGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultSubmissionTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgSubmitterPrecedencePeriodLength", + "type": "uint256" + } + ], + "name": "updateGroupCreationParameters", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "updateOperatorStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ReimbursementPool", + "name": "_reimbursementPool", + "type": "address" + } + ], + "name": "updateReimbursementPool", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "relayEntrySoftTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "relayEntryHardTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "callbackGasLimit", + "type": "uint256" + } + ], + "name": "updateRelayEntryParameters", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sortitionPoolRewardsBanDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "relayEntryTimeoutNotificationRewardMultiplier", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "unauthorizedSigningNotificationRewardMultiplier", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgMaliciousResultNotificationRewardMultiplier", + "type": "uint256" + } + ], + "name": "updateRewardParameters", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "relayEntrySubmissionFailureSlashingAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "maliciousDkgResultSlashingAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "unauthorizedSigningSlashingAmount", + "type": "uint96" + } + ], + "name": "updateSlashingParameters", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + } + ], + "name": "withdrawIneligibleRewards", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "withdrawRewards", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] + }, + "RandomBeaconGovernance": { + "address": "0x1e2F4432bFeF9E9Ad39DA6d272F4aFf33629c770", + "abi": [ + { + "inputs": [ + { + "internalType": "contract RandomBeacon", + "name": "_randomBeacon", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_governanceDelay", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "authorizationDecreaseChangePeriod", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "AuthorizationDecreaseChangePeriodUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "authorizationDecreaseChangePeriod", + "type": "uint64" + } + ], + "name": "AuthorizationDecreaseChangePeriodUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "authorizationDecreaseDelay", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "AuthorizationDecreaseDelayUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "authorizationDecreaseDelay", + "type": "uint64" + } + ], + "name": "AuthorizationDecreaseDelayUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "callbackGasLimit", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "CallbackGasLimitUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "callbackGasLimit", + "type": "uint256" + } + ], + "name": "CallbackGasLimitUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgMaliciousResultNotificationRewardMultiplier", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "DkgMaliciousResultNotificationRewardMultiplierUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgMaliciousResultNotificationRewardMultiplier", + "type": "uint256" + } + ], + "name": "DkgMaliciousResultNotificationRewardMultiplierUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultApprovalGasOffset", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "DkgResultApprovalGasOffsetUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultApprovalGasOffset", + "type": "uint256" + } + ], + "name": "DkgResultApprovalGasOffsetUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultChallengeExtraGas", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "DkgResultChallengeExtraGasUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultChallengeExtraGas", + "type": "uint256" + } + ], + "name": "DkgResultChallengeExtraGasUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultChallengePeriodLength", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "DkgResultChallengePeriodLengthUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultChallengePeriodLength", + "type": "uint256" + } + ], + "name": "DkgResultChallengePeriodLengthUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultSubmissionGas", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "DkgResultSubmissionGasUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultSubmissionGas", + "type": "uint256" + } + ], + "name": "DkgResultSubmissionGasUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultSubmissionTimeout", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "DkgResultSubmissionTimeoutUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultSubmissionTimeout", + "type": "uint256" + } + ], + "name": "DkgResultSubmissionTimeoutUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "submitterPrecedencePeriodLength", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "DkgSubmitterPrecedencePeriodLengthUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "submitterPrecedencePeriodLength", + "type": "uint256" + } + ], + "name": "DkgSubmitterPrecedencePeriodLengthUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "governanceDelay", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "GovernanceDelayUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "governanceDelay", + "type": "uint256" + } + ], + "name": "GovernanceDelayUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "groupCreationFrequency", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "GroupCreationFrequencyUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "groupCreationFrequency", + "type": "uint256" + } + ], + "name": "GroupCreationFrequencyUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "groupLifetime", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "GroupLifetimeUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "groupLifetime", + "type": "uint256" + } + ], + "name": "GroupLifetimeUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint96", + "name": "maliciousDkgResultSlashingAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "MaliciousDkgResultSlashingAmountUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint96", + "name": "maliciousDkgResultSlashingAmount", + "type": "uint96" + } + ], + "name": "MaliciousDkgResultSlashingAmountUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint96", + "name": "minimumAuthorization", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "MinimumAuthorizationUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint96", + "name": "minimumAuthorization", + "type": "uint96" + } + ], + "name": "MinimumAuthorizationUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "notifyOperatorInactivityGasOffset", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "NotifyOperatorInactivityGasOffsetUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "notifyOperatorInactivityGasOffset", + "type": "uint256" + } + ], + "name": "NotifyOperatorInactivityGasOffsetUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newRandomBeaconGovernance", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "RandomBeaconGovernanceTransferStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newRandomBeaconGovernance", + "type": "address" + } + ], + "name": "RandomBeaconGovernanceTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntryHardTimeout", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "RelayEntryHardTimeoutUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntryHardTimeout", + "type": "uint256" + } + ], + "name": "RelayEntryHardTimeoutUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntrySoftTimeout", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "RelayEntrySoftTimeoutUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntrySoftTimeout", + "type": "uint256" + } + ], + "name": "RelayEntrySoftTimeoutUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint96", + "name": "relayEntrySubmissionFailureSlashingAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "RelayEntrySubmissionFailureSlashingAmountUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint96", + "name": "relayEntrySubmissionFailureSlashingAmount", + "type": "uint96" + } + ], + "name": "RelayEntrySubmissionFailureSlashingAmountUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntrySubmissionGasOffset", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "RelayEntrySubmissionGasOffsetUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntrySubmissionGasOffset", + "type": "uint256" + } + ], + "name": "RelayEntrySubmissionGasOffsetUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntryTimeoutNotificationRewardMultiplier", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "RelayEntryTimeoutNotificationRewardMultiplierUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntryTimeoutNotificationRewardMultiplier", + "type": "uint256" + } + ], + "name": "RelayEntryTimeoutNotificationRewardMultiplierUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "sortitionPoolRewardsBanDuration", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "SortitionPoolRewardsBanDurationUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "sortitionPoolRewardsBanDuration", + "type": "uint256" + } + ], + "name": "SortitionPoolRewardsBanDurationUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "unauthorizedSigningTimeoutNotificationRewardMultiplier", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "UnauthorizedSigningNotificationRewardMultiplierUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "unauthorizedSigningTimeoutNotificationRewardMultiplier", + "type": "uint256" + } + ], + "name": "UnauthorizedSigningNotificationRewardMultiplierUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint96", + "name": "unauthorizedSigningSlashingAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "UnauthorizedSigningSlashingAmountUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint96", + "name": "unauthorizedSigningSlashingAmount", + "type": "uint96" + } + ], + "name": "UnauthorizedSigningSlashingAmountUpdated", "type": "event" }, { - "anonymous": false, "inputs": [], - "name": "DkgSeedTimedOut", - "type": "event" + "name": "authorizationDecreaseChangePeriodChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "authorizationDecreaseDelayChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "_newAuthorizationDecreaseChangePeriod", + "type": "uint64" + } + ], + "name": "beginAuthorizationDecreaseChangePeriodUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "_newAuthorizationDecreaseDelay", + "type": "uint64" + } + ], + "name": "beginAuthorizationDecreaseDelayUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newCallbackGasLimit", + "type": "uint256" + } + ], + "name": "beginCallbackGasLimitUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newDkgMaliciousResultNotificationRewardMultiplier", + "type": "uint256" + } + ], + "name": "beginDkgMaliciousResultNotificationRewardMultiplierUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newDkgResultApprovalGasOffset", + "type": "uint256" + } + ], + "name": "beginDkgResultApprovalGasOffsetUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newDkgResultChallengeExtraGas", + "type": "uint256" + } + ], + "name": "beginDkgResultChallengeExtraGasUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newDkgResultChallengePeriodLength", + "type": "uint256" + } + ], + "name": "beginDkgResultChallengePeriodLengthUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newDkgResultSubmissionGas", + "type": "uint256" + } + ], + "name": "beginDkgResultSubmissionGasUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newDkgResultSubmissionTimeout", + "type": "uint256" + } + ], + "name": "beginDkgResultSubmissionTimeoutUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newDkgSubmitterPrecedencePeriodLength", + "type": "uint256" + } + ], + "name": "beginDkgSubmitterPrecedencePeriodLengthUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newGovernanceDelay", + "type": "uint256" + } + ], + "name": "beginGovernanceDelayUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newGroupCreationFrequency", + "type": "uint256" + } + ], + "name": "beginGroupCreationFrequencyUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newGroupLifetime", + "type": "uint256" + } + ], + "name": "beginGroupLifetimeUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "_newMaliciousDkgResultSlashingAmount", + "type": "uint96" + } + ], + "name": "beginMaliciousDkgResultSlashingAmountUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "_newMinimumAuthorization", + "type": "uint96" + } + ], + "name": "beginMinimumAuthorizationUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newNotifyOperatorInactivityGasOffset", + "type": "uint256" + } + ], + "name": "beginNotifyOperatorInactivityGasOffsetUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newRandomBeaconGovernance", + "type": "address" + } + ], + "name": "beginRandomBeaconGovernanceTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newRelayEntryHardTimeout", + "type": "uint256" + } + ], + "name": "beginRelayEntryHardTimeoutUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newRelayEntrySoftTimeout", + "type": "uint256" + } + ], + "name": "beginRelayEntrySoftTimeoutUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "_newRelayEntrySubmissionFailureSlashingAmount", + "type": "uint96" + } + ], + "name": "beginRelayEntrySubmissionFailureSlashingAmountUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newRelayEntrySubmissionGasOffset", + "type": "uint256" + } + ], + "name": "beginRelayEntrySubmissionGasOffsetUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newRelayEntryTimeoutNotificationRewardMultiplier", + "type": "uint256" + } + ], + "name": "beginRelayEntryTimeoutNotificationRewardMultiplierUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newSortitionPoolRewardsBanDuration", + "type": "uint256" + } + ], + "name": "beginSortitionPoolRewardsBanDurationUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newUnauthorizedSigningNotificationRewardMultiplier", + "type": "uint256" + } + ], + "name": "beginUnauthorizedSigningNotificationRewardMultiplierUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "_newUnauthorizedSigningSlashingAmount", + "type": "uint96" + } + ], + "name": "beginUnauthorizedSigningSlashingAmountUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "callbackGasLimitChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "dkgMaliciousResultNotificationRewardMultiplierChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "dkgResultApprovalGasOffsetChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "dkgResultChallengeExtraGasChangeInitiated", + "outputs": [ { - "indexed": true, "internalType": "uint256", - "name": "seed", + "name": "", "type": "uint256" } ], - "name": "DkgStarted", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [], - "name": "DkgStateLocked", - "type": "event" + "name": "dkgResultChallengePeriodLengthChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [], - "name": "DkgTimedOut", - "type": "event" + "name": "dkgResultSubmissionGasChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "dkgResultSubmissionTimeoutChangeInitiated", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "dkgResultSubmissionGas", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "dkgSubmitterPrecedencePeriodLengthChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeAuthorizationDecreaseChangePeriodUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeAuthorizationDecreaseDelayUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeCallbackGasLimitUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeDkgMaliciousResultNotificationRewardMultiplierUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeDkgResultApprovalGasOffsetUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeDkgResultChallengeExtraGasUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeDkgResultChallengePeriodLengthUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeDkgResultSubmissionGasUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeDkgResultSubmissionTimeoutUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeDkgSubmitterPrecedencePeriodLengthUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeGovernanceDelayUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeGroupCreationFrequencyUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeGroupLifetimeUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeMaliciousDkgResultSlashingAmountUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeMinimumAuthorizationUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeNotifyOperatorInactivityGasOffsetUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeRandomBeaconGovernanceTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeRelayEntryHardTimeoutUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeRelayEntrySoftTimeoutUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeRelayEntrySubmissionFailureSlashingAmountUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeRelayEntrySubmissionGasOffsetUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeRelayEntryTimeoutNotificationRewardMultiplierUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeSortitionPoolRewardsBanDurationUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeUnauthorizedSigningNotificationRewardMultiplierUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeUnauthorizedSigningSlashingAmountUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingAuthorizationDecreaseChangePeriodUpdateTime", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "dkgResultApprovalGasOffset", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingAuthorizationDecreaseDelayUpdateTime", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "notifyOperatorInactivityGasOffset", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingCallbackGasLimitUpdateTime", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "relayEntrySubmissionGasOffset", + "name": "", "type": "uint256" } ], - "name": "GasParametersUpdated", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "oldGovernance", - "type": "address" - }, + "inputs": [], + "name": "getRemainingDkgMaliciousResultNotificationRewardMultiplierUpdateTime", + "outputs": [ { - "indexed": false, - "internalType": "address", - "name": "newGovernance", - "type": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "GovernanceTransferred", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "getRemainingDkgResultApprovalGasOffsetUpdateTime", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "groupCreationFrequency", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingDkgResultChallengeExtraGasUpdateTime", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "groupLifetime", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingDkgResultChallengePeriodLengthUpdateTime", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "dkgResultChallengePeriodLength", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingDkgResultSubmissionGasUpdateTime", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "dkgResultChallengeExtraGas", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingDkgResultSubmissionTimeoutUpdateTime", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "dkgResultSubmissionTimeout", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingDkgSubmitterPrecedencePeriodLengthUpdateTime", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "dkgResultSubmitterPrecedencePeriodLength", + "name": "", "type": "uint256" } ], - "name": "GroupCreationParametersUpdated", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint64", - "name": "groupId", - "type": "uint64" - }, + "inputs": [], + "name": "getRemainingGovernanceDelayUpdateTime", + "outputs": [ { - "indexed": true, - "internalType": "bytes", - "name": "groupPubKey", - "type": "bytes" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "GroupRegistered", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint64", - "name": "groupId", - "type": "uint64" - }, + "inputs": [], + "name": "getRemainingGroupCreationFrequencyUpdateTime", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "nonce", + "name": "", "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "notifier", - "type": "address" } ], - "name": "InactivityClaimed", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint96", - "name": "fromAmount", - "type": "uint96" - }, + "inputs": [], + "name": "getRemainingGroupLifetimeUpdateTime", + "outputs": [ { - "indexed": false, - "internalType": "uint96", - "name": "toAmount", - "type": "uint96" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "InvoluntaryAuthorizationDecreaseFailed", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, + "inputs": [], + "name": "getRemainingMaliciousDkgResultSlashingAmountUpdateTime", + "outputs": [ { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "OperatorJoinedSortitionPool", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" + "inputs": [], + "name": "getRemainingMimimumAuthorizationUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "OperatorRegistered", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, + "inputs": [], + "name": "getRemainingNotifyOperatorInactivityGasOffsetUpdateTime", + "outputs": [ { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "OperatorStatusUpdated", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "getRemainingRandomBeaconGovernanceTransferDelayTime", + "outputs": [ { - "indexed": false, - "internalType": "address", - "name": "newReimbursementPool", - "type": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "ReimbursementPoolUpdated", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "getRemainingRelayEntryHardTimeoutUpdateTime", + "outputs": [ { - "indexed": true, "internalType": "uint256", - "name": "requestId", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingRelayEntrySoftTimeoutUpdateTime", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "slashingAmount", + "name": "", "type": "uint256" - }, - { - "indexed": false, - "internalType": "address[]", - "name": "groupMembers", - "type": "address[]" } ], - "name": "RelayEntryDelaySlashed", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "getRemainingRelayEntrySubmissionFailureSlashingAmountUpdateTime", + "outputs": [ { - "indexed": true, "internalType": "uint256", - "name": "requestId", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingRelayEntrySubmissionGasOffsetUpdateTime", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "slashingAmount", + "name": "", "type": "uint256" - }, - { - "indexed": false, - "internalType": "address[]", - "name": "groupMembers", - "type": "address[]" } ], - "name": "RelayEntryDelaySlashingFailed", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "getRemainingRelayEntryTimeoutNotificationRewardMultiplierUpdateTime", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "relayEntrySoftTimeout", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingSortitionPoolRewardsBanDurationUpdateTime", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "relayEntryHardTimeout", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingUnauthorizedSigningNotificationRewardMultiplierUpdateTime", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "callbackGasLimit", + "name": "", "type": "uint256" } ], - "name": "RelayEntryParametersUpdated", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "getRemainingUnauthorizedSigningSlashingAmountUpdateTime", + "outputs": [ { - "indexed": true, "internalType": "uint256", - "name": "requestId", + "name": "", "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint64", - "name": "groupId", - "type": "uint64" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "previousEntry", - "type": "bytes" } ], - "name": "RelayEntryRequested", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "governanceDelay", + "outputs": [ { - "indexed": true, "internalType": "uint256", - "name": "requestId", + "name": "", "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "submitter", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "entry", - "type": "bytes" } ], - "name": "RelayEntrySubmitted", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "governanceDelayChangeInitiated", + "outputs": [ { - "indexed": true, "internalType": "uint256", - "name": "requestId", + "name": "", "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint64", - "name": "terminatedGroupId", - "type": "uint64" } ], - "name": "RelayEntryTimedOut", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "groupCreationFrequencyChangeInitiated", + "outputs": [ { - "indexed": true, "internalType": "uint256", - "name": "requestId", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "groupLifetimeChangeInitiated", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "slashingAmount", + "name": "", "type": "uint256" - }, - { - "indexed": false, - "internalType": "address[]", - "name": "groupMembers", - "type": "address[]" } ], - "name": "RelayEntryTimeoutSlashed", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "maliciousDkgResultSlashingAmountChangeInitiated", + "outputs": [ { - "indexed": true, "internalType": "uint256", - "name": "requestId", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minimumAuthorizationChangeInitiated", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "slashingAmount", + "name": "", "type": "uint256" - }, - { - "indexed": false, - "internalType": "address[]", - "name": "groupMembers", - "type": "address[]" } ], - "name": "RelayEntryTimeoutSlashingFailed", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "requester", - "type": "address" - }, + "inputs": [], + "name": "newAuthorizationDecreaseChangePeriod", + "outputs": [ { - "indexed": false, - "internalType": "bool", - "name": "isAuthorized", - "type": "bool" + "internalType": "uint64", + "name": "", + "type": "uint64" } ], - "name": "RequesterAuthorizationUpdated", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "sortitionPoolRewardsBanDuration", - "type": "uint256" - }, + "inputs": [], + "name": "newAuthorizationDecreaseDelay", + "outputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "relayEntryTimeoutNotificationRewardMultiplier", - "type": "uint256" - }, + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newCallbackGasLimit", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "unauthorizedSigningNotificationRewardMultiplier", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newDkgMaliciousResultNotificationRewardMultiplier", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "dkgMaliciousResultNotificationRewardMultiplier", + "name": "", "type": "uint256" } ], - "name": "RewardParametersUpdated", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, + "inputs": [], + "name": "newDkgResultApprovalGasOffset", + "outputs": [ { - "indexed": false, - "internalType": "uint96", - "name": "amount", - "type": "uint96" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "RewardsWithdrawn", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "newDkgResultChallengeExtraGas", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "relayEntrySubmissionFailureSlashingAmount", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newDkgResultChallengePeriodLength", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "maliciousDkgResultSlashingAmount", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newDkgResultSubmissionGas", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "unauthorizedSigningSlashingAmount", + "name": "", "type": "uint256" } ], - "name": "SlashingParametersUpdated", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint64", - "name": "groupId", - "type": "uint64" - }, + "inputs": [], + "name": "newDkgResultSubmissionTimeout", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "unauthorizedSigningSlashingAmount", + "name": "", "type": "uint256" - }, - { - "indexed": false, - "internalType": "address[]", - "name": "groupMembers", - "type": "address[]" } ], - "name": "UnauthorizedSigningSlashed", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint64", - "name": "groupId", - "type": "uint64" - }, + "inputs": [], + "name": "newDkgSubmitterPrecedencePeriodLength", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "unauthorizedSigningSlashingAmount", + "name": "", "type": "uint256" - }, - { - "indexed": false, - "internalType": "address[]", - "name": "groupMembers", - "type": "address[]" } ], - "name": "UnauthorizedSigningSlashingFailed", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "newGovernanceDelay", + "outputs": [ { - "internalType": "address", - "name": "stakingProvider", - "type": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "approveAuthorizationDecrease", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "newGroupCreationFrequency", + "outputs": [ { - "components": [ - { - "internalType": "uint256", - "name": "submitterMemberIndex", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "groupPubKey", - "type": "bytes" - }, - { - "internalType": "uint8[]", - "name": "misbehavedMembersIndices", - "type": "uint8[]" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "uint256[]", - "name": "signingMembersIndices", - "type": "uint256[]" - }, - { - "internalType": "uint32[]", - "name": "members", - "type": "uint32[]" - }, - { - "internalType": "bytes32", - "name": "membersHash", - "type": "bytes32" - } - ], - "internalType": "struct BeaconDkg.Result", - "name": "dkgResult", - "type": "tuple" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "approveDkgResult", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, - { - "internalType": "uint96", - "name": "fromAmount", - "type": "uint96" - }, + "inputs": [], + "name": "newGroupLifetime", + "outputs": [ { - "internalType": "uint96", - "name": "toAmount", - "type": "uint96" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "authorizationDecreaseRequested", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, - { - "internalType": "uint96", - "name": "fromAmount", - "type": "uint96" - }, + "inputs": [], + "name": "newMaliciousDkgResultSlashingAmount", + "outputs": [ { "internalType": "uint96", - "name": "toAmount", + "name": "", "type": "uint96" } ], - "name": "authorizationIncreased", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [], - "name": "authorizationParameters", + "name": "newMinimumAuthorization", "outputs": [ { "internalType": "uint96", - "name": "minimumAuthorization", + "name": "", "type": "uint96" - }, - { - "internalType": "uint64", - "name": "authorizationDecreaseDelay", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "authorizationDecreaseChangePeriod", - "type": "uint64" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "authorizedRequesters", + "inputs": [], + "name": "newNotifyOperatorInactivityGasOffset", "outputs": [ { - "internalType": "bool", + "internalType": "uint256", "name": "", - "type": "bool" + "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "newRandomBeaconGovernance", + "outputs": [ { "internalType": "address", - "name": "stakingProvider", + "name": "", "type": "address" } ], - "name": "availableRewards", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newRelayEntryHardTimeout", "outputs": [ { - "internalType": "uint96", + "internalType": "uint256", "name": "", - "type": "uint96" + "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "newRelayEntrySoftTimeout", + "outputs": [ { - "components": [ - { - "internalType": "uint256", - "name": "submitterMemberIndex", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "groupPubKey", - "type": "bytes" - }, - { - "internalType": "uint8[]", - "name": "misbehavedMembersIndices", - "type": "uint8[]" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "uint256[]", - "name": "signingMembersIndices", - "type": "uint256[]" - }, - { - "internalType": "uint32[]", - "name": "members", - "type": "uint32[]" - }, - { - "internalType": "bytes32", - "name": "membersHash", - "type": "bytes32" - } - ], - "internalType": "struct BeaconDkg.Result", - "name": "dkgResult", - "type": "tuple" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "challengeDkgResult", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "stakingProvider", - "type": "address" - } - ], - "name": "eligibleStake", + "inputs": [], + "name": "newRelayEntrySubmissionFailureSlashingAmount", "outputs": [ { "internalType": "uint96", @@ -6627,26 +11185,11 @@ }, { "inputs": [], - "name": "gasParameters", + "name": "newRelayEntrySubmissionGasOffset", "outputs": [ { "internalType": "uint256", - "name": "dkgResultSubmissionGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "dkgResultApprovalGasOffset", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "notifyOperatorInactivityGasOffset", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "relayEntrySubmissionGasOffset", + "name": "", "type": "uint256" } ], @@ -6655,88 +11198,38 @@ }, { "inputs": [], - "name": "genesis", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "groupId", - "type": "uint64" - } - ], - "name": "getGroup", + "name": "newRelayEntryTimeoutNotificationRewardMultiplier", "outputs": [ { - "components": [ - { - "internalType": "bytes", - "name": "groupPubKey", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "registrationBlockNumber", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "membersHash", - "type": "bytes32" - }, - { - "internalType": "bool", - "name": "terminated", - "type": "bool" - } - ], - "internalType": "struct Groups.Group", + "internalType": "uint256", "name": "", - "type": "tuple" + "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "newSortitionPoolRewardsBanDuration", + "outputs": [ { - "internalType": "bytes", - "name": "groupPubKey", - "type": "bytes" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "getGroup", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newUnauthorizedSigningNotificationRewardMultiplier", "outputs": [ { - "components": [ - { - "internalType": "bytes", - "name": "groupPubKey", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "registrationBlockNumber", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "membersHash", - "type": "bytes32" - }, - { - "internalType": "bool", - "name": "terminated", - "type": "bool" - } - ], - "internalType": "struct Groups.Group", + "internalType": "uint256", "name": "", - "type": "tuple" + "type": "uint256" } ], "stateMutability": "view", @@ -6744,12 +11237,12 @@ }, { "inputs": [], - "name": "getGroupCreationState", + "name": "newUnauthorizedSigningSlashingAmount", "outputs": [ { - "internalType": "enum BeaconDkg.State", + "internalType": "uint96", "name": "", - "type": "uint8" + "type": "uint96" } ], "stateMutability": "view", @@ -6757,12 +11250,12 @@ }, { "inputs": [], - "name": "getGroupsRegistry", + "name": "notifyOperatorInactivityGasOffsetChangeInitiated", "outputs": [ { - "internalType": "bytes32[]", + "internalType": "uint256", "name": "", - "type": "bytes32[]" + "type": "uint256" } ], "stateMutability": "view", @@ -6770,7 +11263,7 @@ }, { "inputs": [], - "name": "governance", + "name": "owner", "outputs": [ { "internalType": "address", @@ -6783,37 +11276,12 @@ }, { "inputs": [], - "name": "groupCreationParameters", + "name": "randomBeacon", "outputs": [ { - "internalType": "uint256", - "name": "groupCreationFrequency", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "groupLifetime", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "dkgResultChallengePeriodLength", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "dkgResultChallengeExtraGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "dkgResultSubmissionTimeout", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "dkgSubmitterPrecedencePeriodLength", - "type": "uint256" + "internalType": "contract RandomBeacon", + "name": "", + "type": "address" } ], "stateMutability": "view", @@ -6821,26 +11289,20 @@ }, { "inputs": [], - "name": "hasDkgTimedOut", + "name": "randomBeaconGovernanceTransferInitiated", "outputs": [ { - "internalType": "bool", + "internalType": "uint256", "name": "", - "type": "bool" + "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "name": "inactivityClaimNonce", + "inputs": [], + "name": "relayEntryHardTimeoutChangeInitiated", "outputs": [ { "internalType": "uint256", @@ -6852,61 +11314,39 @@ "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, - { - "internalType": "uint96", - "name": "fromAmount", - "type": "uint96" - }, + "inputs": [], + "name": "relayEntrySoftTimeoutChangeInitiated", + "outputs": [ { - "internalType": "uint96", - "name": "toAmount", - "type": "uint96" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "involuntaryAuthorizationDecrease", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - } - ], - "name": "isOperatorInPool", + "inputs": [], + "name": "relayEntrySubmissionFailureSlashingAmountChangeInitiated", "outputs": [ { - "internalType": "bool", + "internalType": "uint256", "name": "", - "type": "bool" + "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - } - ], - "name": "isOperatorUpToDate", + "inputs": [], + "name": "relayEntrySubmissionGasOffsetChangeInitiated", "outputs": [ { - "internalType": "bool", + "internalType": "uint256", "name": "", - "type": "bool" + "type": "uint256" } ], "stateMutability": "view", @@ -6914,12 +11354,12 @@ }, { "inputs": [], - "name": "isRelayRequestInProgress", + "name": "relayEntryTimeoutNotificationRewardMultiplierChangeInitiated", "outputs": [ { - "internalType": "bool", + "internalType": "uint256", "name": "", - "type": "bool" + "type": "uint256" } ], "stateMutability": "view", @@ -6927,109 +11367,76 @@ }, { "inputs": [], - "name": "joinSortitionPool", + "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "minimumAuthorization", - "outputs": [ + "inputs": [ { - "internalType": "uint96", - "name": "", - "type": "uint96" + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "bool", + "name": "isAuthorized", + "type": "bool" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "notifyDkgTimeout", + "name": "setRequesterAuthorization", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [ - { - "components": [ - { - "internalType": "uint64", - "name": "groupId", - "type": "uint64" - }, - { - "internalType": "uint256[]", - "name": "inactiveMembersIndices", - "type": "uint256[]" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "uint256[]", - "name": "signingMembersIndices", - "type": "uint256[]" - } - ], - "internalType": "struct BeaconInactivity.Claim", - "name": "claim", - "type": "tuple" - }, + "inputs": [], + "name": "sortitionPoolRewardsBanDurationChangeInitiated", + "outputs": [ { "internalType": "uint256", - "name": "nonce", + "name": "", "type": "uint256" - }, - { - "internalType": "uint32[]", - "name": "groupMembers", - "type": "uint32[]" } ], - "name": "notifyOperatorInactivity", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", - "name": "operator", + "name": "newOwner", "type": "address" } ], - "name": "operatorToStakingProvider", + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unauthorizedSigningNotificationRewardMultiplierChangeInitiated", "outputs": [ { - "internalType": "address", + "internalType": "uint256", "name": "", - "type": "address" + "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "stakingProvider", - "type": "address" - } - ], - "name": "pendingAuthorizationDecrease", + "inputs": [], + "name": "unauthorizedSigningSlashingAmountChangeInitiated", "outputs": [ { - "internalType": "uint96", + "internalType": "uint256", "name": "", - "type": "uint96" + "type": "uint256" } ], "stateMutability": "view", @@ -7039,102 +11446,93 @@ "inputs": [ { "internalType": "address", - "name": "operator", + "name": "recipient", "type": "address" } ], - "name": "registerOperator", + "name": "withdrawIneligibleRewards", "outputs": [], "stateMutability": "nonpayable", "type": "function" - }, + } + ] + }, + "RandomBeaconChaosnet": { + "address": "0xed17543171C1459714cdC6519b58fFcC29A3C3c9", + "abi": [ { - "inputs": [], - "name": "reimbursementPool", - "outputs": [ + "anonymous": false, + "inputs": [ { - "internalType": "contract ReimbursementPool", - "name": "", + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", "type": "address" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "relayEntryParameters", - "outputs": [ - { - "internalType": "uint256", - "name": "relayEntrySoftTimeout", - "type": "uint256" - }, + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ { - "internalType": "uint256", - "name": "relayEntryHardTimeout", - "type": "uint256" + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" }, { - "internalType": "uint256", - "name": "callbackGasLimit", - "type": "uint256" + "indexed": false, + "internalType": "bool", + "name": "isAuthorized", + "type": "bool" } ], - "stateMutability": "view", - "type": "function" + "name": "RequesterAuthorizationUpdated", + "type": "event" }, { "inputs": [ { "internalType": "address", - "name": "stakingProvider", + "name": "", "type": "address" } ], - "name": "remainingAuthorizationDecreaseDelay", + "name": "authorizedRequesters", "outputs": [ { - "internalType": "uint64", + "internalType": "bool", "name": "", - "type": "uint64" + "type": "bool" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "owner", + "outputs": [ { - "internalType": "uint32[]", - "name": "groupMembers", - "type": "uint32[]" + "internalType": "address", + "name": "", + "type": "address" } ], - "name": "reportRelayEntryTimeout", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "bytes", - "name": "signedMsgSender", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "groupId", - "type": "uint64" - }, - { - "internalType": "uint32[]", - "name": "groupMembers", - "type": "uint32[]" - } - ], - "name": "reportUnauthorizedSigning", + "inputs": [], + "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -7152,47 +11550,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "rewardParameters", - "outputs": [ - { - "internalType": "uint256", - "name": "sortitionPoolRewardsBanDuration", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "relayEntryTimeoutNotificationRewardMultiplier", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "unauthorizedSigningNotificationRewardMultiplier", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "dkgMaliciousResultNotificationRewardMultiplier", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "selectGroup", - "outputs": [ - { - "internalType": "uint32[]", - "name": "", - "type": "uint32[]" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -7212,267 +11569,241 @@ "type": "function" }, { - "inputs": [], - "name": "slashingParameters", - "outputs": [ - { - "internalType": "uint96", - "name": "relayEntrySubmissionFailureSlashingAmount", - "type": "uint96" - }, - { - "internalType": "uint96", - "name": "maliciousDkgResultSlashingAmount", - "type": "uint96" - }, + "inputs": [ { - "internalType": "uint96", - "name": "unauthorizedSigningSlashingAmount", - "type": "uint96" + "internalType": "address", + "name": "newOwner", + "type": "address" } ], - "stateMutability": "view", + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" - }, + } + ] + }, + "EcdsaSortitionPool": { + "address": "0x677df0cb865368207999F2862Ece576dC56D8dF6", + "abi": [ { - "inputs": [], - "name": "sortitionPool", - "outputs": [ + "inputs": [ { - "internalType": "contract SortitionPool", - "name": "", + "internalType": "contract IERC20WithPermit", + "name": "_rewardToken", "type": "address" + }, + { + "internalType": "uint256", + "name": "_poolWeightDivisor", + "type": "uint256" } ], - "stateMutability": "view", - "type": "function" + "stateMutability": "nonpayable", + "type": "constructor" }, { - "inputs": [], - "name": "staking", - "outputs": [ + "anonymous": false, + "inputs": [ { - "internalType": "contract IStaking", - "name": "", - "type": "address" + "indexed": false, + "internalType": "address[]", + "name": "operators", + "type": "address[]" } ], - "stateMutability": "view", - "type": "function" + "name": "BetaOperatorsAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "ChaosnetDeactivated", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "address", - "name": "stakingProvider", + "name": "oldChaosnetOwner", "type": "address" - } - ], - "name": "stakingProviderToOperator", - "outputs": [ + }, { + "indexed": false, "internalType": "address", - "name": "", + "name": "newChaosnetOwner", "type": "address" } ], - "stateMutability": "view", - "type": "function" + "name": "ChaosnetOwnerRoleTransferred", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "components": [ - { - "internalType": "uint256", - "name": "submitterMemberIndex", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "groupPubKey", - "type": "bytes" - }, - { - "internalType": "uint8[]", - "name": "misbehavedMembersIndices", - "type": "uint8[]" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "uint256[]", - "name": "signingMembersIndices", - "type": "uint256[]" - }, - { - "internalType": "uint32[]", - "name": "members", - "type": "uint32[]" - }, - { - "internalType": "bytes32", - "name": "membersHash", - "type": "bytes32" - } - ], - "internalType": "struct BeaconDkg.Result", - "name": "dkgResult", - "type": "tuple" + "indexed": false, + "internalType": "uint32[]", + "name": "ids", + "type": "uint32[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "until", + "type": "uint256" + } + ], + "name": "IneligibleForRewards", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" } ], - "name": "submitDkgResult", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "OwnershipTransferred", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "bytes", - "name": "entry", - "type": "bytes" + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" }, { - "internalType": "uint32[]", - "name": "groupMembers", - "type": "uint32[]" + "indexed": true, + "internalType": "uint32", + "name": "id", + "type": "uint32" } ], - "name": "submitRelayEntry", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "RewardEligibilityRestored", + "type": "event" }, { "inputs": [ { - "internalType": "bytes", - "name": "entry", - "type": "bytes" + "internalType": "address[]", + "name": "operators", + "type": "address[]" } ], - "name": "submitRelayEntry", + "name": "addBetaOperators", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "tToken", + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "canRestoreRewardEligibility", "outputs": [ { - "internalType": "contract IERC20", + "internalType": "bool", "name": "", - "type": "address" + "type": "bool" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "chaosnetOwner", + "outputs": [ { "internalType": "address", - "name": "newGovernance", + "name": "", "type": "address" } ], - "name": "transferGovernance", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "deactivateChaosnet", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "getAvailableRewards", + "outputs": [ { "internalType": "uint96", - "name": "_minimumAuthorization", + "name": "", "type": "uint96" - }, - { - "internalType": "uint64", - "name": "_authorizationDecreaseDelay", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "_authorizationDecreaseChangePeriod", - "type": "uint64" } ], - "name": "updateAuthorizationParameters", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { - "internalType": "uint256", - "name": "dkgResultSubmissionGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "dkgResultApprovalGasOffset", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "notifyOperatorInactivityGasOffset", - "type": "uint256" - }, + "internalType": "uint32", + "name": "id", + "type": "uint32" + } + ], + "name": "getIDOperator", + "outputs": [ { - "internalType": "uint256", - "name": "relayEntrySubmissionGasOffset", - "type": "uint256" + "internalType": "address", + "name": "", + "type": "address" } ], - "name": "updateGasParameters", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { - "internalType": "uint256", - "name": "groupCreationFrequency", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "groupLifetime", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "dkgResultChallengePeriodLength", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "dkgResultChallengeExtraGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "dkgResultSubmissionTimeout", - "type": "uint256" - }, + "internalType": "uint32[]", + "name": "ids", + "type": "uint32[]" + } + ], + "name": "getIDOperators", + "outputs": [ { - "internalType": "uint256", - "name": "dkgSubmitterPrecedencePeriodLength", - "type": "uint256" + "internalType": "address[]", + "name": "", + "type": "address[]" } ], - "name": "updateGroupCreationParameters", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { @@ -7483,71 +11814,63 @@ "type": "address" } ], - "name": "updateOperatorStatus", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + "name": "getOperatorID", + "outputs": [ { - "internalType": "contract ReimbursementPool", - "name": "_reimbursementPool", - "type": "address" + "internalType": "uint32", + "name": "", + "type": "uint32" } ], - "name": "updateReimbursementPool", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { - "internalType": "uint256", - "name": "relayEntrySoftTimeout", - "type": "uint256" - }, + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "getPoolWeight", + "outputs": [ { "internalType": "uint256", - "name": "relayEntryHardTimeout", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ineligibleEarnedRewards", + "outputs": [ { - "internalType": "uint256", - "name": "callbackGasLimit", - "type": "uint256" + "internalType": "uint96", + "name": "", + "type": "uint96" } ], - "name": "updateRelayEntryParameters", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { - "internalType": "uint256", - "name": "sortitionPoolRewardsBanDuration", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "relayEntryTimeoutNotificationRewardMultiplier", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "unauthorizedSigningNotificationRewardMultiplier", - "type": "uint256" + "internalType": "address", + "name": "operator", + "type": "address" }, { "internalType": "uint256", - "name": "dkgMaliciousResultNotificationRewardMultiplier", + "name": "authorizedStake", "type": "uint256" } ], - "name": "updateRewardParameters", + "name": "insertOperator", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -7555,104 +11878,119 @@ { "inputs": [ { - "internalType": "uint96", - "name": "relayEntrySubmissionFailureSlashingAmount", - "type": "uint96" - }, + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isBetaOperator", + "outputs": [ { - "internalType": "uint96", - "name": "maliciousDkgResultSlashingAmount", - "type": "uint96" - }, + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isChaosnetActive", + "outputs": [ { - "internalType": "uint96", - "name": "unauthorizedSigningSlashingAmount", - "type": "uint96" + "internalType": "bool", + "name": "", + "type": "bool" } ], - "name": "updateSlashingParameters", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", - "name": "recipient", + "name": "operator", "type": "address" } ], - "name": "withdrawIneligibleRewards", - "outputs": [], - "stateMutability": "nonpayable", + "name": "isEligibleForRewards", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "isLocked", + "outputs": [ { - "internalType": "address", - "name": "stakingProvider", - "type": "address" + "internalType": "bool", + "name": "", + "type": "bool" } ], - "name": "withdrawRewards", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" - } - ] - }, - "RandomBeaconChaosnet": { - "address": "0xF23fc18EcE6Afe7fb57ba59979e8600bb4B0294a", - "abi": [ + }, { - "anonymous": false, "inputs": [ { - "indexed": true, "internalType": "address", - "name": "previousOwner", + "name": "operator", "type": "address" - }, + } + ], + "name": "isOperatorInPool", + "outputs": [ { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" + "internalType": "bool", + "name": "", + "type": "bool" } ], - "name": "OwnershipTransferred", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": true, "internalType": "address", - "name": "requester", + "name": "operator", "type": "address" - }, + } + ], + "name": "isOperatorRegistered", + "outputs": [ { - "indexed": false, "internalType": "bool", - "name": "isAuthorized", + "name": "", "type": "bool" } ], - "name": "RequesterAuthorizationUpdated", - "type": "event" + "stateMutability": "view", + "type": "function" }, { "inputs": [ { "internalType": "address", - "name": "", + "name": "operator", "type": "address" + }, + { + "internalType": "uint256", + "name": "authorizedStake", + "type": "uint256" } ], - "name": "authorizedRequesters", + "name": "isOperatorUpToDate", "outputs": [ { "internalType": "bool", @@ -7663,6 +12001,26 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "lock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "operatorsInPool", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "owner", @@ -7678,20 +12036,48 @@ }, { "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", + "name": "poolWeightDivisor", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", "type": "function" }, { "inputs": [ { - "internalType": "contract IRandomBeaconConsumer", - "name": "callbackContract", + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "token", "type": "address" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" } ], - "name": "requestRelayEntry", + "name": "receiveApproval", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -7700,565 +12086,776 @@ "inputs": [ { "internalType": "address", - "name": "requester", + "name": "operator", "type": "address" - }, - { - "internalType": "bool", - "name": "isAuthorized", - "type": "bool" } ], - "name": "setRequesterAuthorization", + "name": "restoreRewardEligibility", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "rewardToken", + "outputs": [ { - "internalType": "address", - "name": "newOwner", + "internalType": "contract IERC20WithPermit", + "name": "", "type": "address" } ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" - } - ] - }, - "RandomBeaconGovernance": { - "address": "0xd0A3088eD9fff4357b79cd3896bd38876fcB1c63", - "abi": [ + }, { "inputs": [ { - "internalType": "contract RandomBeacon", - "name": "_randomBeacon", + "internalType": "address", + "name": "operator", "type": "address" - }, + } + ], + "name": "rewardsEligibilityRestorableAt", + "outputs": [ { "internalType": "uint256", - "name": "_governanceDelay", + "name": "", "type": "uint256" } ], - "stateMutability": "nonpayable", - "type": "constructor" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint64", - "name": "authorizationDecreaseChangePeriod", - "type": "uint64" + "internalType": "uint256", + "name": "groupSize", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "seed", + "type": "bytes32" + } + ], + "name": "selectGroup", + "outputs": [ + { + "internalType": "uint32[]", + "name": "", + "type": "uint32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32[]", + "name": "operators", + "type": "uint32[]" }, { - "indexed": false, "internalType": "uint256", - "name": "timestamp", + "name": "until", + "type": "uint256" + } + ], + "name": "setRewardIneligibility", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "totalWeight", + "outputs": [ + { + "internalType": "uint256", + "name": "", "type": "uint256" } ], - "name": "AuthorizationDecreaseChangePeriodUpdateStarted", - "type": "event" + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newChaosnetOwner", + "type": "address" + } + ], + "name": "transferChaosnetOwnerRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint64", - "name": "authorizationDecreaseChangePeriod", - "type": "uint64" + "internalType": "address", + "name": "newOwner", + "type": "address" } ], - "name": "AuthorizationDecreaseChangePeriodUpdated", - "type": "event" + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unlock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint64", - "name": "authorizationDecreaseDelay", - "type": "uint64" + "internalType": "address", + "name": "operator", + "type": "address" }, { - "indexed": false, "internalType": "uint256", - "name": "timestamp", + "name": "authorizedStake", "type": "uint256" } ], - "name": "AuthorizationDecreaseDelayUpdateStarted", - "type": "event" + "name": "updateOperatorStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint64", - "name": "authorizationDecreaseDelay", - "type": "uint64" + "internalType": "address", + "name": "recipient", + "type": "address" } ], - "name": "AuthorizationDecreaseDelayUpdated", - "type": "event" + "name": "withdrawIneligible", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "callbackGasLimit", - "type": "uint256" + "internalType": "address", + "name": "operator", + "type": "address" }, { - "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" + "internalType": "address", + "name": "beneficiary", + "type": "address" } ], - "name": "CallbackGasLimitUpdateStarted", - "type": "event" - }, + "name": "withdrawRewards", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ] + }, + "EcdsaDkgValidator": { + "address": "0xcEC91d876E8f003110D43381359b1bAd124e7F2b", + "abi": [ { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "callbackGasLimit", - "type": "uint256" + "internalType": "contract SortitionPool", + "name": "_sortitionPool", + "type": "address" } ], - "name": "CallbackGasLimitUpdated", - "type": "event" + "stateMutability": "nonpayable", + "type": "constructor" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "dkgMaliciousResultNotificationRewardMultiplier", - "type": "uint256" - }, + "inputs": [], + "name": "activeThreshold", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "timestamp", + "name": "", "type": "uint256" } ], - "name": "DkgMaliciousResultNotificationRewardMultiplierUpdateStarted", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "groupSize", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "dkgMaliciousResultNotificationRewardMultiplier", + "name": "", "type": "uint256" } ], - "name": "DkgMaliciousResultNotificationRewardMultiplierUpdated", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "dkgResultApprovalGasOffset", - "type": "uint256" - }, + "inputs": [], + "name": "groupThreshold", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "timestamp", + "name": "", "type": "uint256" } ], - "name": "DkgResultApprovalGasOffsetUpdateStarted", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "publicKeyByteSize", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "dkgResultApprovalGasOffset", + "name": "", "type": "uint256" } ], - "name": "DkgResultApprovalGasOffsetUpdated", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "dkgResultChallengeExtraGas", - "type": "uint256" - }, + "inputs": [], + "name": "signatureByteSize", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "timestamp", + "name": "", "type": "uint256" } ], - "name": "DkgResultChallengeExtraGasUpdateStarted", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "sortitionPool", + "outputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "dkgResultChallengeExtraGas", - "type": "uint256" + "internalType": "contract SortitionPool", + "name": "", + "type": "address" } ], - "name": "DkgResultChallengeExtraGasUpdated", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "dkgResultChallengePeriodLength", - "type": "uint256" + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct EcdsaDkg.Result", + "name": "result", + "type": "tuple" }, { - "indexed": false, "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - } - ], - "name": "DkgResultChallengePeriodLengthUpdateStarted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "name": "seed", + "type": "uint256" + }, { - "indexed": false, "internalType": "uint256", - "name": "dkgResultChallengePeriodLength", + "name": "startBlock", "type": "uint256" } ], - "name": "DkgResultChallengePeriodLengthUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "name": "validate", + "outputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "dkgResultSubmissionGas", - "type": "uint256" + "internalType": "bool", + "name": "isValid", + "type": "bool" }, { - "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" + "internalType": "string", + "name": "errorMsg", + "type": "string" } ], - "name": "DkgResultSubmissionGasUpdateStarted", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "dkgResultSubmissionGas", - "type": "uint256" + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct EcdsaDkg.Result", + "name": "result", + "type": "tuple" } ], - "name": "DkgResultSubmissionGasUpdated", - "type": "event" + "name": "validateFields", + "outputs": [ + { + "internalType": "bool", + "name": "isValid", + "type": "bool" + }, + { + "internalType": "string", + "name": "errorMsg", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "dkgResultSubmissionTimeout", - "type": "uint256" + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct EcdsaDkg.Result", + "name": "result", + "type": "tuple" }, { - "indexed": false, "internalType": "uint256", - "name": "timestamp", + "name": "seed", "type": "uint256" } ], - "name": "DkgResultSubmissionTimeoutUpdateStarted", - "type": "event" + "name": "validateGroupMembers", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "dkgResultSubmissionTimeout", - "type": "uint256" + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct EcdsaDkg.Result", + "name": "result", + "type": "tuple" } ], - "name": "DkgResultSubmissionTimeoutUpdated", - "type": "event" + "name": "validateMembersHash", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "submitterPrecedencePeriodLength", - "type": "uint256" + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct EcdsaDkg.Result", + "name": "result", + "type": "tuple" }, { - "indexed": false, "internalType": "uint256", - "name": "timestamp", + "name": "startBlock", "type": "uint256" } ], - "name": "DkgSubmitterPrecedencePeriodLengthUpdateStarted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "name": "validateSignatures", + "outputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "submitterPrecedencePeriodLength", - "type": "uint256" + "internalType": "bool", + "name": "", + "type": "bool" } ], - "name": "DkgSubmitterPrecedencePeriodLengthUpdated", - "type": "event" - }, + "stateMutability": "view", + "type": "function" + } + ] + }, + "EcdsaInactivity": { + "address": "0x5370F78c6af2Da9cF6642382A3a75F9D5aEc9cc1", + "abi": [ { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "governanceDelay", - "type": "uint256" - }, + "inputs": [], + "name": "groupThreshold", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "timestamp", + "name": "", "type": "uint256" } ], - "name": "GovernanceDelayUpdateStarted", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "signatureByteSize", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "governanceDelay", + "name": "", "type": "uint256" } ], - "name": "GovernanceDelayUpdated", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "groupCreationFrequency", - "type": "uint256" + "internalType": "contract SortitionPool", + "name": "sortitionPool", + "type": "SortitionPool" }, { - "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - } - ], - "name": "GroupCreationFrequencyUpdateStarted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "components": [ + { + "internalType": "bytes32", + "name": "walletID", + "type": "bytes32" + }, + { + "internalType": "uint256[]", + "name": "inactiveMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "bool", + "name": "heartbeatFailed", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + } + ], + "internalType": "struct EcdsaInactivity.Claim", + "name": "claim", + "type": "tuple" + }, { - "indexed": false, - "internalType": "uint256", - "name": "groupCreationFrequency", - "type": "uint256" - } - ], - "name": "GroupCreationFrequencyUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "internalType": "bytes", + "name": "walletPubKey", + "type": "bytes" + }, { - "indexed": false, "internalType": "uint256", - "name": "groupLifetime", + "name": "nonce", "type": "uint256" }, { - "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" + "internalType": "uint32[]", + "name": "groupMembers", + "type": "uint32[]" } ], - "name": "GroupLifetimeUpdateStarted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "name": "verifyClaim", + "outputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "groupLifetime", - "type": "uint256" + "internalType": "uint32[]", + "name": "inactiveMembers", + "type": "uint32[]" } ], - "name": "GroupLifetimeUpdated", - "type": "event" - }, + "stateMutability": "view", + "type": "function" + } + ] + }, + "WalletRegistry": { + "address": "0x8613A4029EaA95dA61AE65380aC2e7366451bF2b", + "abi": [ { - "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint96", - "name": "maliciousDkgResultSlashingAmount", - "type": "uint96" + "internalType": "contract SortitionPool", + "name": "_sortitionPool", + "type": "address" }, { - "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" + "internalType": "contract IStaking", + "name": "_staking", + "type": "address" } ], - "name": "MaliciousDkgResultSlashingAmountUpdateStarted", - "type": "event" + "stateMutability": "nonpayable", + "type": "constructor" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint96", - "name": "maliciousDkgResultSlashingAmount", - "type": "uint96" - } - ], - "name": "MaliciousDkgResultSlashingAmountUpdated", - "type": "event" + "inputs": [], + "name": "AllowlistAddressZero", + "type": "error" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint96", - "name": "minimumAuthorization", - "type": "uint96" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - } - ], - "name": "MinimumAuthorizationUpdateStarted", - "type": "event" + "inputs": [], + "name": "CallerNotGovernance", + "type": "error" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint96", - "name": "minimumAuthorization", - "type": "uint96" - } - ], - "name": "MinimumAuthorizationUpdated", - "type": "event" + "inputs": [], + "name": "CallerNotRandomBeacon", + "type": "error" + }, + { + "inputs": [], + "name": "CallerNotStakingContract", + "type": "error" + }, + { + "inputs": [], + "name": "CallerNotWalletOwner", + "type": "error" + }, + { + "inputs": [], + "name": "CurrentStateNotIdle", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidGroupMembers", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidNonce", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidWalletMembersIdentifiers", + "type": "error" + }, + { + "inputs": [], + "name": "NotEnoughExtraGasLeft", + "type": "error" + }, + { + "inputs": [], + "name": "NotSortitionPoolOperator", + "type": "error" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "notifyOperatorInactivityGasOffset", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - } - ], - "name": "NotifyOperatorInactivityGasOffsetUpdateStarted", - "type": "event" + "inputs": [], + "name": "UnknownOperator", + "type": "error" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "notifyOperatorInactivityGasOffset", - "type": "uint256" - } - ], - "name": "NotifyOperatorInactivityGasOffsetUpdated", - "type": "event" + "inputs": [], + "name": "WalletMemberIndexOutOfRange", + "type": "error" }, { "anonymous": false, @@ -8266,132 +12863,79 @@ { "indexed": true, "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", + "name": "stakingProvider", "type": "address" } ], - "name": "OwnershipTransferred", + "name": "AuthorizationDecreaseApproved", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": false, + "indexed": true, "internalType": "address", - "name": "newRandomBeaconGovernance", + "name": "stakingProvider", "type": "address" }, { - "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - } - ], - "name": "RandomBeaconGovernanceTransferStarted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, + "indexed": true, "internalType": "address", - "name": "newRandomBeaconGovernance", + "name": "operator", "type": "address" - } - ], - "name": "RandomBeaconGovernanceTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + }, { "indexed": false, - "internalType": "uint256", - "name": "relayEntryHardTimeout", - "type": "uint256" + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" }, { "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - } - ], - "name": "RelayEntryHardTimeoutUpdateStarted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + }, { "indexed": false, - "internalType": "uint256", - "name": "relayEntryHardTimeout", - "type": "uint256" + "internalType": "uint64", + "name": "decreasingAt", + "type": "uint64" } ], - "name": "RelayEntryHardTimeoutUpdated", + "name": "AuthorizationDecreaseRequested", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "relayEntrySoftTimeout", - "type": "uint256" + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" }, { - "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - } - ], - "name": "RelayEntrySoftTimeoutUpdateStarted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "relayEntrySoftTimeout", - "type": "uint256" - } - ], - "name": "RelayEntrySoftTimeoutUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, { "indexed": false, "internalType": "uint96", - "name": "relayEntrySubmissionFailureSlashingAmount", + "name": "fromAmount", "type": "uint96" }, { "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" } ], - "name": "RelayEntrySubmissionFailureSlashingAmountUpdateStarted", + "name": "AuthorizationIncreased", "type": "event" }, { @@ -8400,94 +12944,73 @@ { "indexed": false, "internalType": "uint96", - "name": "relayEntrySubmissionFailureSlashingAmount", + "name": "minimumAuthorization", "type": "uint96" - } - ], - "name": "RelayEntrySubmissionFailureSlashingAmountUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + }, { "indexed": false, - "internalType": "uint256", - "name": "relayEntrySubmissionGasOffset", - "type": "uint256" + "internalType": "uint64", + "name": "authorizationDecreaseDelay", + "type": "uint64" }, { "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" + "internalType": "uint64", + "name": "authorizationDecreaseChangePeriod", + "type": "uint64" } ], - "name": "RelayEntrySubmissionGasOffsetUpdateStarted", + "name": "AuthorizationParametersUpdated", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "relayEntrySubmissionGasOffset", - "type": "uint256" - } - ], - "name": "RelayEntrySubmissionGasOffsetUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, { "indexed": false, "internalType": "uint256", - "name": "relayEntryTimeoutNotificationRewardMultiplier", + "name": "slashingAmount", "type": "uint256" }, { "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" + "internalType": "address", + "name": "maliciousSubmitter", + "type": "address" } ], - "name": "RelayEntryTimeoutNotificationRewardMultiplierUpdateStarted", + "name": "DkgMaliciousResultSlashed", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint256", - "name": "relayEntryTimeoutNotificationRewardMultiplier", - "type": "uint256" - } - ], - "name": "RelayEntryTimeoutNotificationRewardMultiplierUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, { "indexed": false, "internalType": "uint256", - "name": "sortitionPoolRewardsBanDuration", + "name": "slashingAmount", "type": "uint256" }, { "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" + "internalType": "address", + "name": "maliciousSubmitter", + "type": "address" } ], - "name": "SortitionPoolRewardsBanDurationUpdateStarted", + "name": "DkgMaliciousResultSlashingFailed", "type": "event" }, { @@ -8496,857 +13019,827 @@ { "indexed": false, "internalType": "uint256", - "name": "sortitionPoolRewardsBanDuration", + "name": "seedTimeout", "type": "uint256" - } - ], - "name": "SortitionPoolRewardsBanDurationUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + }, { "indexed": false, "internalType": "uint256", - "name": "unauthorizedSigningTimeoutNotificationRewardMultiplier", + "name": "resultChallengePeriodLength", "type": "uint256" }, { "indexed": false, "internalType": "uint256", - "name": "timestamp", + "name": "resultChallengeExtraGas", "type": "uint256" - } - ], - "name": "UnauthorizedSigningNotificationRewardMultiplierUpdateStarted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ + }, + { + "indexed": false, + "internalType": "uint256", + "name": "resultSubmissionTimeout", + "type": "uint256" + }, { "indexed": false, "internalType": "uint256", - "name": "unauthorizedSigningTimeoutNotificationRewardMultiplier", + "name": "resultSubmitterPrecedencePeriodLength", "type": "uint256" } ], - "name": "UnauthorizedSigningNotificationRewardMultiplierUpdated", + "name": "DkgParametersUpdated", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "uint96", - "name": "unauthorizedSigningSlashingAmount", - "type": "uint96" + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" }, { - "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" + "indexed": true, + "internalType": "address", + "name": "approver", + "type": "address" } ], - "name": "UnauthorizedSigningSlashingAmountUpdateStarted", + "name": "DkgResultApproved", "type": "event" }, { "anonymous": false, "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "challenger", + "type": "address" + }, { "indexed": false, - "internalType": "uint96", - "name": "unauthorizedSigningSlashingAmount", - "type": "uint96" + "internalType": "string", + "name": "reason", + "type": "string" } ], - "name": "UnauthorizedSigningSlashingAmountUpdated", + "name": "DkgResultChallenged", "type": "event" }, { - "inputs": [], - "name": "authorizationDecreaseChangePeriodChangeInitiated", - "outputs": [ + "anonymous": false, + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "authorizationDecreaseDelayChangeInitiated", - "outputs": [ + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, { + "indexed": true, "internalType": "uint256", - "name": "", + "name": "seed", "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_newAuthorizationDecreaseChangePeriod", - "type": "uint64" - } - ], - "name": "beginAuthorizationDecreaseChangePeriodUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + }, { - "internalType": "uint64", - "name": "_newAuthorizationDecreaseDelay", - "type": "uint64" + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "indexed": false, + "internalType": "struct EcdsaDkg.Result", + "name": "result", + "type": "tuple" } ], - "name": "beginAuthorizationDecreaseDelayUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "DkgResultSubmitted", + "type": "event" }, { - "inputs": [ - { - "internalType": "uint256", - "name": "_newCallbackGasLimit", - "type": "uint256" - } - ], - "name": "beginCallbackGasLimitUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "anonymous": false, + "inputs": [], + "name": "DkgSeedTimedOut", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": true, "internalType": "uint256", - "name": "_newDkgMaliciousResultNotificationRewardMultiplier", + "name": "seed", "type": "uint256" } ], - "name": "beginDkgMaliciousResultNotificationRewardMultiplierUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "DkgStarted", + "type": "event" }, { - "inputs": [ - { - "internalType": "uint256", - "name": "_newDkgResultApprovalGasOffset", - "type": "uint256" - } - ], - "name": "beginDkgResultApprovalGasOffsetUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "anonymous": false, + "inputs": [], + "name": "DkgStateLocked", + "type": "event" }, { - "inputs": [ - { - "internalType": "uint256", - "name": "_newDkgResultChallengeExtraGas", - "type": "uint256" - } - ], - "name": "beginDkgResultChallengeExtraGasUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "anonymous": false, + "inputs": [], + "name": "DkgTimedOut", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "uint256", - "name": "_newDkgResultChallengePeriodLength", + "name": "dkgResultSubmissionGas", "type": "uint256" - } - ], - "name": "beginDkgResultChallengePeriodLengthUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + }, { + "indexed": false, "internalType": "uint256", - "name": "_newDkgResultSubmissionGas", + "name": "dkgResultApprovalGasOffset", "type": "uint256" - } - ], - "name": "beginDkgResultSubmissionGasUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + }, { + "indexed": false, "internalType": "uint256", - "name": "_newDkgResultSubmissionTimeout", + "name": "notifyOperatorInactivityGasOffset", "type": "uint256" - } - ], - "name": "beginDkgResultSubmissionTimeoutUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + }, { + "indexed": false, "internalType": "uint256", - "name": "_newDkgSubmitterPrecedencePeriodLength", + "name": "notifySeedTimeoutGasOffset", "type": "uint256" - } - ], - "name": "beginDkgSubmitterPrecedencePeriodLengthUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + }, { + "indexed": false, "internalType": "uint256", - "name": "_newGovernanceDelay", + "name": "notifyDkgTimeoutNegativeGasOffset", "type": "uint256" } - ], - "name": "beginGovernanceDelayUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ], + "name": "GasParametersUpdated", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "uint256", - "name": "_newGroupCreationFrequency", - "type": "uint256" + "indexed": false, + "internalType": "address", + "name": "oldGovernance", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newGovernance", + "type": "address" } ], - "name": "beginGroupCreationFrequencyUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "GovernanceTransferred", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": true, + "internalType": "bytes32", + "name": "walletID", + "type": "bytes32" + }, + { + "indexed": false, "internalType": "uint256", - "name": "_newGroupLifetime", + "name": "nonce", "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "notifier", + "type": "address" } ], - "name": "beginGroupLifetimeUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "InactivityClaimed", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "uint96", - "name": "_newMaliciousDkgResultSlashingAmount", - "type": "uint96" + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" } ], - "name": "beginMaliciousDkgResultSlashingAmountUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "Initialized", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, "internalType": "uint96", - "name": "_newMinimumAuthorization", + "name": "fromAmount", "type": "uint96" - } - ], - "name": "beginMinimumAuthorizationUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + }, { - "internalType": "uint256", - "name": "_newNotifyOperatorInactivityGasOffset", - "type": "uint256" + "indexed": false, + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" } ], - "name": "beginNotifyOperatorInactivityGasOffsetUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "InvoluntaryAuthorizationDecreaseFailed", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": true, "internalType": "address", - "name": "_newRandomBeaconGovernance", + "name": "stakingProvider", "type": "address" - } - ], - "name": "beginRandomBeaconGovernanceTransfer", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + }, { - "internalType": "uint256", - "name": "_newRelayEntryHardTimeout", - "type": "uint256" + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" } ], - "name": "beginRelayEntryHardTimeoutUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "OperatorJoinedSortitionPool", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "uint256", - "name": "_newRelayEntrySoftTimeout", - "type": "uint256" + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" } ], - "name": "beginRelayEntrySoftTimeoutUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "OperatorRegistered", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "uint96", - "name": "_newRelayEntrySubmissionFailureSlashingAmount", - "type": "uint96" + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" } ], - "name": "beginRelayEntrySubmissionFailureSlashingAmountUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "OperatorStatusUpdated", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "uint256", - "name": "_newRelayEntrySubmissionGasOffset", - "type": "uint256" + "indexed": false, + "internalType": "address", + "name": "randomBeacon", + "type": "address" } ], - "name": "beginRelayEntrySubmissionGasOffsetUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "RandomBeaconUpgraded", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "uint256", - "name": "_newRelayEntryTimeoutNotificationRewardMultiplier", - "type": "uint256" + "indexed": false, + "internalType": "address", + "name": "newReimbursementPool", + "type": "address" } ], - "name": "beginRelayEntryTimeoutNotificationRewardMultiplierUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "ReimbursementPoolUpdated", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "uint256", - "name": "_newSortitionPoolRewardsBanDuration", + "name": "maliciousDkgResultNotificationRewardMultiplier", "type": "uint256" - } - ], - "name": "beginSortitionPoolRewardsBanDurationUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + }, { + "indexed": false, "internalType": "uint256", - "name": "_newUnauthorizedSigningNotificationRewardMultiplier", + "name": "sortitionPoolRewardsBanDuration", "type": "uint256" } ], - "name": "beginUnauthorizedSigningNotificationRewardMultiplierUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "RewardParametersUpdated", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": false, "internalType": "uint96", - "name": "_newUnauthorizedSigningSlashingAmount", + "name": "amount", "type": "uint96" } ], - "name": "beginUnauthorizedSigningSlashingAmountUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "RewardsWithdrawn", + "type": "event" }, { - "inputs": [], - "name": "callbackGasLimitChangeInitiated", - "outputs": [ + "anonymous": false, + "inputs": [ { + "indexed": false, "internalType": "uint256", - "name": "", + "name": "maliciousDkgResultSlashingAmount", "type": "uint256" } ], - "stateMutability": "view", - "type": "function" + "name": "SlashingParametersUpdated", + "type": "event" }, { - "inputs": [], - "name": "dkgMaliciousResultNotificationRewardMultiplierChangeInitiated", - "outputs": [ + "anonymous": false, + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "indexed": true, + "internalType": "bytes32", + "name": "walletID", + "type": "bytes32" } ], - "stateMutability": "view", - "type": "function" + "name": "WalletClosed", + "type": "event" }, { - "inputs": [], - "name": "dkgResultApprovalGasOffsetChangeInitiated", - "outputs": [ + "anonymous": false, + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "indexed": true, + "internalType": "bytes32", + "name": "walletID", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "dkgResultHash", + "type": "bytes32" } ], - "stateMutability": "view", - "type": "function" + "name": "WalletCreated", + "type": "event" }, { - "inputs": [], - "name": "dkgResultChallengeExtraGasChangeInitiated", - "outputs": [ + "anonymous": false, + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "indexed": false, + "internalType": "address", + "name": "walletOwner", + "type": "address" } ], - "stateMutability": "view", - "type": "function" + "name": "WalletOwnerUpdated", + "type": "event" }, { - "inputs": [], - "name": "dkgResultChallengePeriodLengthChangeInitiated", - "outputs": [ + "inputs": [ { "internalType": "uint256", - "name": "", + "name": "relayEntry", "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "dkgResultSubmissionGasChangeInitiated", - "outputs": [ + }, { "internalType": "uint256", "name": "", "type": "uint256" } ], - "stateMutability": "view", + "name": "__beaconCallback", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "dkgResultSubmissionTimeoutChangeInitiated", + "name": "allowlist", "outputs": [ { - "internalType": "uint256", + "internalType": "contract Allowlist", "name": "", - "type": "uint256" + "type": "address" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "dkgSubmitterPrecedencePeriodLengthChangeInitiated", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "address", + "name": "stakingProvider", + "type": "address" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeAuthorizationDecreaseChangePeriodUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeAuthorizationDecreaseDelayUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeCallbackGasLimitUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeDkgMaliciousResultNotificationRewardMultiplierUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeDkgResultApprovalGasOffsetUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeDkgResultChallengeExtraGasUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeDkgResultChallengePeriodLengthUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeDkgResultSubmissionGasUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeDkgResultSubmissionTimeoutUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeDkgSubmitterPrecedencePeriodLengthUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeGovernanceDelayUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeGroupCreationFrequencyUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeGroupLifetimeUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeMaliciousDkgResultSlashingAmountUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeMinimumAuthorizationUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeNotifyOperatorInactivityGasOffsetUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeRandomBeaconGovernanceTransfer", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeRelayEntryHardTimeoutUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeRelayEntrySoftTimeoutUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeRelayEntrySubmissionFailureSlashingAmountUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeRelayEntrySubmissionGasOffsetUpdate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finalizeRelayEntryTimeoutNotificationRewardMultiplierUpdate", + "name": "approveAuthorizationDecrease", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "finalizeSortitionPoolRewardsBanDurationUpdate", + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct EcdsaDkg.Result", + "name": "dkgResult", + "type": "tuple" + } + ], + "name": "approveDkgResult", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "finalizeUnauthorizedSigningNotificationRewardMultiplierUpdate", + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + } + ], + "name": "authorizationDecreaseRequested", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "finalizeUnauthorizedSigningSlashingAmountUpdate", + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + } + ], + "name": "authorizationIncreased", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "getRemainingAuthorizationDecreaseChangePeriodUpdateTime", + "name": "authorizationParameters", "outputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "uint96", + "name": "minimumAuthorization", + "type": "uint96" + }, + { + "internalType": "uint64", + "name": "authorizationDecreaseDelay", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "authorizationDecreaseChangePeriod", + "type": "uint64" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "getRemainingAuthorizationDecreaseDelayUpdateTime", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "address", + "name": "stakingProvider", + "type": "address" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getRemainingCallbackGasLimitUpdateTime", + "name": "availableRewards", "outputs": [ { - "internalType": "uint256", + "internalType": "uint96", "name": "", - "type": "uint256" + "type": "uint96" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "getRemainingDkgMaliciousResultNotificationRewardMultiplierUpdateTime", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct EcdsaDkg.Result", + "name": "dkgResult", + "type": "tuple" } ], - "stateMutability": "view", + "name": "challengeDkgResult", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "getRemainingDkgResultApprovalGasOffsetUpdateTime", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "bytes32", + "name": "walletID", + "type": "bytes32" } ], - "stateMutability": "view", + "name": "closeWallet", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "getRemainingDkgResultChallengeExtraGasUpdateTime", + "name": "dkgParameters", "outputs": [ { - "internalType": "uint256", + "components": [ + { + "internalType": "uint256", + "name": "seedTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "resultChallengePeriodLength", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "resultChallengeExtraGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "resultSubmissionTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "submitterPrecedencePeriodLength", + "type": "uint256" + } + ], + "internalType": "struct EcdsaDkg.Parameters", "name": "", - "type": "uint256" + "type": "tuple" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "getRemainingDkgResultChallengePeriodLengthUpdateTime", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "address", + "name": "stakingProvider", + "type": "address" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getRemainingDkgResultSubmissionGasUpdateTime", + "name": "eligibleStake", "outputs": [ { - "internalType": "uint256", + "internalType": "uint96", "name": "", - "type": "uint256" + "type": "uint96" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "getRemainingDkgResultSubmissionTimeoutUpdateTime", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "membersIdsHash", + "type": "bytes32" } ], - "stateMutability": "view", + "name": "forceAddWallet", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "getRemainingDkgSubmitterPrecedencePeriodLengthUpdateTime", + "name": "gasParameters", "outputs": [ { "internalType": "uint256", - "name": "", + "name": "dkgResultSubmissionGas", "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getRemainingGovernanceDelayUpdateTime", - "outputs": [ + }, + { + "internalType": "uint256", + "name": "dkgResultApprovalGasOffset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "notifyOperatorInactivityGasOffset", + "type": "uint256" + }, { "internalType": "uint256", - "name": "", + "name": "notifySeedTimeoutGasOffset", "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getRemainingGroupCreationFrequencyUpdateTime", - "outputs": [ + }, { "internalType": "uint256", - "name": "", + "name": "notifyDkgTimeoutNegativeGasOffset", "type": "uint256" } ], @@ -9355,38 +13848,127 @@ }, { "inputs": [], - "name": "getRemainingGroupLifetimeUpdateTime", + "name": "getDkgData", "outputs": [ { - "internalType": "uint256", + "components": [ + { + "internalType": "contract SortitionPool", + "name": "sortitionPool", + "type": "address" + }, + { + "internalType": "contract EcdsaDkgValidator", + "name": "dkgValidator", + "type": "address" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "seedTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "resultChallengePeriodLength", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "resultChallengeExtraGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "resultSubmissionTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "submitterPrecedencePeriodLength", + "type": "uint256" + } + ], + "internalType": "struct EcdsaDkg.Parameters", + "name": "parameters", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "stateLockBlock", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startBlock", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "seed", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "resultSubmissionStartBlockOffset", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "submittedResultHash", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "submittedResultBlock", + "type": "uint256" + }, + { + "internalType": "uint256[38]", + "name": "__gap", + "type": "uint256[38]" + } + ], + "internalType": "struct EcdsaDkg.Data", "name": "", - "type": "uint256" + "type": "tuple" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "getRemainingMaliciousDkgResultSlashingAmountUpdateTime", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "bytes32", + "name": "walletID", + "type": "bytes32" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getRemainingMimimumAuthorizationUpdateTime", + "name": "getWallet", "outputs": [ { - "internalType": "uint256", + "components": [ + { + "internalType": "bytes32", + "name": "membersIdsHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "publicKeyX", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "publicKeyY", + "type": "bytes32" + } + ], + "internalType": "struct Wallets.Wallet", "name": "", - "type": "uint256" + "type": "tuple" } ], "stateMutability": "view", @@ -9394,38 +13976,31 @@ }, { "inputs": [], - "name": "getRemainingNotifyOperatorInactivityGasOffsetUpdateTime", + "name": "getWalletCreationState", "outputs": [ { - "internalType": "uint256", + "internalType": "enum EcdsaDkg.State", "name": "", - "type": "uint256" + "type": "uint8" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "getRemainingRandomBeaconGovernanceTransferDelayTime", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "bytes32", + "name": "walletID", + "type": "bytes32" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getRemainingRelayEntryHardTimeoutUpdateTime", + "name": "getWalletPublicKey", "outputs": [ { - "internalType": "uint256", + "internalType": "bytes", "name": "", - "type": "uint256" + "type": "bytes" } ], "stateMutability": "view", @@ -9433,12 +14008,12 @@ }, { "inputs": [], - "name": "getRemainingRelayEntrySoftTimeoutUpdateTime", + "name": "governance", "outputs": [ { - "internalType": "uint256", + "internalType": "address", "name": "", - "type": "uint256" + "type": "address" } ], "stateMutability": "view", @@ -9446,12 +14021,12 @@ }, { "inputs": [], - "name": "getRemainingRelayEntrySubmissionFailureSlashingAmountUpdateTime", + "name": "hasDkgTimedOut", "outputs": [ { - "internalType": "uint256", + "internalType": "bool", "name": "", - "type": "uint256" + "type": "bool" } ], "stateMutability": "view", @@ -9459,33 +14034,26 @@ }, { "inputs": [], - "name": "getRemainingRelayEntrySubmissionGasOffsetUpdateTime", + "name": "hasSeedTimedOut", "outputs": [ { - "internalType": "uint256", + "internalType": "bool", "name": "", - "type": "uint256" + "type": "bool" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "getRemainingRelayEntryTimeoutNotificationRewardMultiplierUpdateTime", - "outputs": [ + "inputs": [ { - "internalType": "uint256", + "internalType": "bytes32", "name": "", - "type": "uint256" + "type": "bytes32" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getRemainingSortitionPoolRewardsBanDurationUpdateTime", + "name": "inactivityClaimNonce", "outputs": [ { "internalType": "uint256", @@ -9497,182 +14065,211 @@ "type": "function" }, { - "inputs": [], - "name": "getRemainingUnauthorizedSigningNotificationRewardMultiplierUpdateTime", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "contract EcdsaDkgValidator", + "name": "_ecdsaDkgValidator", + "type": "address" + }, + { + "internalType": "contract IRandomBeacon", + "name": "_randomBeacon", + "type": "address" + }, + { + "internalType": "contract ReimbursementPool", + "name": "_reimbursementPool", + "type": "address" } ], - "stateMutability": "view", + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "getRemainingUnauthorizedSigningSlashingAmountUpdateTime", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "address", + "name": "_allowlist", + "type": "address" } ], - "stateMutability": "view", + "name": "initializeV2", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "governanceDelay", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" } ], - "stateMutability": "view", + "name": "involuntaryAuthorizationDecrease", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "governanceDelayChangeInitiated", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct EcdsaDkg.Result", + "name": "result", + "type": "tuple" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "groupCreationFrequencyChangeInitiated", + "name": "isDkgResultValid", "outputs": [ { - "internalType": "uint256", + "internalType": "bool", "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "groupLifetimeChangeInitiated", - "outputs": [ + "type": "bool" + }, { - "internalType": "uint256", + "internalType": "string", "name": "", - "type": "uint256" + "type": "string" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "maliciousDkgResultSlashingAmountChangeInitiated", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "address", + "name": "operator", + "type": "address" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "minimumAuthorizationChangeInitiated", + "name": "isOperatorInPool", "outputs": [ { - "internalType": "uint256", + "internalType": "bool", "name": "", - "type": "uint256" + "type": "bool" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "newAuthorizationDecreaseChangePeriod", - "outputs": [ + "inputs": [ { - "internalType": "uint64", - "name": "", - "type": "uint64" + "internalType": "address", + "name": "operator", + "type": "address" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "newAuthorizationDecreaseDelay", + "name": "isOperatorUpToDate", "outputs": [ { - "internalType": "uint64", + "internalType": "bool", "name": "", - "type": "uint64" + "type": "bool" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "newCallbackGasLimit", - "outputs": [ + "inputs": [ + { + "internalType": "bytes32", + "name": "walletID", + "type": "bytes32" + }, + { + "internalType": "uint32[]", + "name": "walletMembersIDs", + "type": "uint32[]" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + }, { "internalType": "uint256", - "name": "", + "name": "walletMemberIndex", "type": "uint256" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "newDkgMaliciousResultNotificationRewardMultiplier", + "name": "isWalletMember", "outputs": [ { - "internalType": "uint256", + "internalType": "bool", "name": "", - "type": "uint256" + "type": "bool" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "newDkgResultApprovalGasOffset", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "bytes32", + "name": "walletID", + "type": "bytes32" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "newDkgResultChallengeExtraGas", + "name": "isWalletRegistered", "outputs": [ { - "internalType": "uint256", + "internalType": "bool", "name": "", - "type": "uint256" + "type": "bool" } ], "stateMutability": "view", @@ -9680,25 +14277,19 @@ }, { "inputs": [], - "name": "newDkgResultChallengePeriodLength", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", + "name": "joinSortitionPool", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "newDkgResultSubmissionGas", + "name": "minimumAuthorization", "outputs": [ { - "internalType": "uint256", + "internalType": "uint96", "name": "", - "type": "uint256" + "type": "uint96" } ], "stateMutability": "view", @@ -9706,85 +14297,96 @@ }, { "inputs": [], - "name": "newDkgResultSubmissionTimeout", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", + "name": "notifyDkgTimeout", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "newDkgSubmitterPrecedencePeriodLength", - "outputs": [ + "inputs": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "walletID", + "type": "bytes32" + }, + { + "internalType": "uint256[]", + "name": "inactiveMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "bool", + "name": "heartbeatFailed", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + } + ], + "internalType": "struct EcdsaInactivity.Claim", + "name": "claim", + "type": "tuple" + }, { "internalType": "uint256", - "name": "", + "name": "nonce", "type": "uint256" + }, + { + "internalType": "uint32[]", + "name": "groupMembers", + "type": "uint32[]" } ], - "stateMutability": "view", + "name": "notifyOperatorInactivity", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "newGovernanceDelay", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", + "name": "notifySeedTimeout", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "newGroupCreationFrequency", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "address", + "name": "operator", + "type": "address" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "newGroupLifetime", + "name": "operatorToStakingProvider", "outputs": [ { - "internalType": "uint256", + "internalType": "address", "name": "", - "type": "uint256" + "type": "address" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "newMaliciousDkgResultSlashingAmount", - "outputs": [ + "inputs": [ { - "internalType": "uint96", - "name": "", - "type": "uint96" + "internalType": "address", + "name": "stakingProvider", + "type": "address" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "newMinimumAuthorization", + "name": "pendingAuthorizationDecrease", "outputs": [ { "internalType": "uint96", @@ -9797,51 +14399,57 @@ }, { "inputs": [], - "name": "newNotifyOperatorInactivityGasOffset", + "name": "randomBeacon", "outputs": [ { - "internalType": "uint256", + "internalType": "contract IRandomBeacon", "name": "", - "type": "uint256" + "type": "address" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "newRandomBeaconGovernance", - "outputs": [ + "inputs": [ { "internalType": "address", - "name": "", + "name": "operator", "type": "address" } ], - "stateMutability": "view", + "name": "registerOperator", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "newRelayEntryHardTimeout", + "name": "reimbursementPool", "outputs": [ { - "internalType": "uint256", + "internalType": "contract ReimbursementPool", "name": "", - "type": "uint256" + "type": "address" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "newRelayEntrySoftTimeout", + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "remainingAuthorizationDecreaseDelay", "outputs": [ { - "internalType": "uint256", + "internalType": "uint64", "name": "", - "type": "uint256" + "type": "uint64" } ], "stateMutability": "view", @@ -9849,24 +14457,23 @@ }, { "inputs": [], - "name": "newRelayEntrySubmissionFailureSlashingAmount", - "outputs": [ - { - "internalType": "uint96", - "name": "", - "type": "uint96" - } - ], - "stateMutability": "view", + "name": "requestNewWallet", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "newRelayEntrySubmissionGasOffset", + "name": "rewardParameters", "outputs": [ { "internalType": "uint256", - "name": "", + "name": "maliciousDkgResultNotificationRewardMultiplier", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "sortitionPoolRewardsBanDuration", "type": "uint256" } ], @@ -9874,26 +14481,46 @@ "type": "function" }, { - "inputs": [], - "name": "newRelayEntryTimeoutNotificationRewardMultiplier", - "outputs": [ + "inputs": [ + { + "internalType": "uint96", + "name": "amount", + "type": "uint96" + }, { "internalType": "uint256", - "name": "", + "name": "rewardMultiplier", "type": "uint256" + }, + { + "internalType": "address", + "name": "notifier", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "walletID", + "type": "bytes32" + }, + { + "internalType": "uint32[]", + "name": "walletMembersIDs", + "type": "uint32[]" } ], - "stateMutability": "view", + "name": "seize", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "newSortitionPoolRewardsBanDuration", + "name": "selectGroup", "outputs": [ { - "internalType": "uint256", + "internalType": "uint32[]", "name": "", - "type": "uint256" + "type": "uint32[]" } ], "stateMutability": "view", @@ -9901,12 +14528,12 @@ }, { "inputs": [], - "name": "newUnauthorizedSigningNotificationRewardMultiplier", + "name": "slashingParameters", "outputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "uint96", + "name": "maliciousDkgResultSlashingAmount", + "type": "uint96" } ], "stateMutability": "view", @@ -9914,12 +14541,12 @@ }, { "inputs": [], - "name": "newUnauthorizedSigningSlashingAmount", + "name": "sortitionPool", "outputs": [ { - "internalType": "uint96", + "internalType": "contract SortitionPool", "name": "", - "type": "uint96" + "type": "address" } ], "stateMutability": "view", @@ -9927,20 +14554,26 @@ }, { "inputs": [], - "name": "notifyOperatorInactivityGasOffsetChangeInitiated", + "name": "staking", "outputs": [ { - "internalType": "uint256", + "internalType": "contract IStaking", "name": "", - "type": "uint256" + "type": "address" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "owner", + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "stakingProviderToOperator", "outputs": [ { "internalType": "address", @@ -9952,99 +14585,197 @@ "type": "function" }, { - "inputs": [], - "name": "randomBeacon", - "outputs": [ + "inputs": [ { - "internalType": "contract RandomBeacon", - "name": "", + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct EcdsaDkg.Result", + "name": "dkgResult", + "type": "tuple" + } + ], + "name": "submitDkgResult", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newGovernance", "type": "address" } ], - "stateMutability": "view", + "name": "transferGovernance", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "randomBeaconGovernanceTransferInitiated", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "uint96", + "name": "_minimumAuthorization", + "type": "uint96" + }, + { + "internalType": "uint64", + "name": "_authorizationDecreaseDelay", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "_authorizationDecreaseChangePeriod", + "type": "uint64" } ], - "stateMutability": "view", + "name": "updateAuthorizationParameters", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "relayEntryHardTimeoutChangeInitiated", - "outputs": [ + "inputs": [ { "internalType": "uint256", - "name": "", + "name": "_seedTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_resultChallengePeriodLength", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_resultChallengeExtraGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_resultSubmissionTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_submitterPrecedencePeriodLength", "type": "uint256" } ], - "stateMutability": "view", + "name": "updateDkgParameters", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "relayEntrySoftTimeoutChangeInitiated", - "outputs": [ + "inputs": [ + { + "internalType": "uint256", + "name": "dkgResultSubmissionGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultApprovalGasOffset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "notifyOperatorInactivityGasOffset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "notifySeedTimeoutGasOffset", + "type": "uint256" + }, { "internalType": "uint256", - "name": "", + "name": "notifyDkgTimeoutNegativeGasOffset", "type": "uint256" } ], - "stateMutability": "view", + "name": "updateGasParameters", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "relayEntrySubmissionFailureSlashingAmountChangeInitiated", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "address", + "name": "operator", + "type": "address" } ], - "stateMutability": "view", + "name": "updateOperatorStatus", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "relayEntrySubmissionGasOffsetChangeInitiated", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "contract ReimbursementPool", + "name": "_reimbursementPool", + "type": "address" } ], - "stateMutability": "view", + "name": "updateReimbursementPool", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "relayEntryTimeoutNotificationRewardMultiplierChangeInitiated", - "outputs": [ + "inputs": [ { "internalType": "uint256", - "name": "", + "name": "maliciousDkgResultNotificationRewardMultiplier", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "sortitionPoolRewardsBanDuration", "type": "uint256" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", + "name": "updateRewardParameters", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -10052,101 +14783,96 @@ { "inputs": [ { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "bool", - "name": "isAuthorized", - "type": "bool" + "internalType": "uint96", + "name": "maliciousDkgResultSlashingAmount", + "type": "uint96" } ], - "name": "setRequesterAuthorization", + "name": "updateSlashingParameters", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "sortitionPoolRewardsBanDurationChangeInitiated", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "contract IWalletOwner", + "name": "_walletOwner", + "type": "address" } ], - "stateMutability": "view", + "name": "updateWalletOwner", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { - "internalType": "address", - "name": "newOwner", + "internalType": "contract IRandomBeacon", + "name": "_randomBeacon", "type": "address" } ], - "name": "transferOwnership", + "name": "upgradeRandomBeacon", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "unauthorizedSigningNotificationRewardMultiplierChangeInitiated", + "name": "walletOwner", "outputs": [ { - "internalType": "uint256", + "internalType": "contract IWalletOwner", "name": "", - "type": "uint256" + "type": "address" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "unauthorizedSigningSlashingAmountChangeInitiated", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "address", + "name": "recipient", + "type": "address" } ], - "stateMutability": "view", + "name": "withdrawIneligibleRewards", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", - "name": "recipient", + "name": "stakingProvider", "type": "address" } ], - "name": "withdrawIneligibleRewards", + "name": "withdrawRewards", "outputs": [], "stateMutability": "nonpayable", "type": "function" } ] }, - "ReimbursementPool": { - "address": "0x8adF3f35dBE4026112bCFc078872bcb967732Ea8", + "WalletRegistryGovernance": { + "address": "0xAd5d57aD9bB17d34Debb88566ab2F5dB879Cc46F", "abi": [ { "inputs": [ { - "internalType": "uint256", - "name": "_staticGas", - "type": "uint256" + "internalType": "contract WalletRegistry", + "name": "_walletRegistry", + "type": "address" }, { "internalType": "uint256", - "name": "_maxGasPrice", + "name": "_governanceDelay", "type": "uint256" } ], @@ -10158,63 +14884,31 @@ "inputs": [ { "indexed": false, - "internalType": "address", - "name": "thirdPartyContract", - "type": "address" - } - ], - "name": "AuthorizedContract", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "withdrawnAmount", - "type": "uint256" + "internalType": "uint64", + "name": "authorizationDecreaseChangePeriod", + "type": "uint64" }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "FundsWithdrawn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ { "indexed": false, "internalType": "uint256", - "name": "newMaxGasPrice", + "name": "timestamp", "type": "uint256" } ], - "name": "MaxGasPriceUpdated", + "name": "AuthorizationDecreaseChangePeriodUpdateStarted", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" + "indexed": false, + "internalType": "uint64", + "name": "authorizationDecreaseChangePeriod", + "type": "uint64" } ], - "name": "OwnershipTransferred", + "name": "AuthorizationDecreaseChangePeriodUpdated", "type": "event" }, { @@ -10222,771 +14916,644 @@ "inputs": [ { "indexed": false, - "internalType": "uint256", - "name": "refundAmount", - "type": "uint256" + "internalType": "uint64", + "name": "authorizationDecreaseDelay", + "type": "uint64" }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "SendingEtherFailed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ { "indexed": false, "internalType": "uint256", - "name": "newStaticGas", + "name": "timestamp", "type": "uint256" } ], - "name": "StaticGasUpdated", + "name": "AuthorizationDecreaseDelayUpdateStarted", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": false, - "internalType": "address", - "name": "thirdPartyContract", - "type": "address" - } - ], - "name": "UnauthorizedContract", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_contract", - "type": "address" - } - ], - "name": "authorize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "isAuthorized", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "maxGasPrice", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" + "indexed": false, + "internalType": "uint64", + "name": "authorizationDecreaseDelay", + "type": "uint64" } ], - "stateMutability": "view", - "type": "function" + "name": "AuthorizationDecreaseDelayUpdated", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "uint256", - "name": "gasSpent", + "name": "dkgResultApprovalGasOffset", "type": "uint256" }, { - "internalType": "address", - "name": "receiver", - "type": "address" + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" } ], - "name": "refund", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "DkgResultApprovalGasOffsetUpdateStarted", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "uint256", - "name": "_maxGasPrice", + "name": "dkgResultApprovalGasOffset", "type": "uint256" } ], - "name": "setMaxGasPrice", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "DkgResultApprovalGasOffsetUpdated", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "uint256", - "name": "_staticGas", + "name": "dkgResultChallengeExtraGas", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", "type": "uint256" } ], - "name": "setStaticGas", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "DkgResultChallengeExtraGasUpdateStarted", + "type": "event" }, { - "inputs": [], - "name": "staticGas", - "outputs": [ + "anonymous": false, + "inputs": [ { + "indexed": false, "internalType": "uint256", - "name": "", + "name": "dkgResultChallengeExtraGas", "type": "uint256" } ], - "stateMutability": "view", - "type": "function" + "name": "DkgResultChallengeExtraGasUpdated", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "address", - "name": "newOwner", - "type": "address" + "indexed": false, + "internalType": "uint256", + "name": "dkgResultChallengePeriodLength", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" } ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "DkgResultChallengePeriodLengthUpdateStarted", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "address", - "name": "_contract", - "type": "address" + "indexed": false, + "internalType": "uint256", + "name": "dkgResultChallengePeriodLength", + "type": "uint256" } ], - "name": "unauthorize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "DkgResultChallengePeriodLengthUpdated", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "uint256", - "name": "amount", + "name": "dkgResultSubmissionGas", "type": "uint256" }, { - "internalType": "address", - "name": "receiver", - "type": "address" + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" } ], - "name": "withdraw", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "DkgResultSubmissionGasUpdateStarted", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "address", - "name": "receiver", - "type": "address" + "indexed": false, + "internalType": "uint256", + "name": "dkgResultSubmissionGas", + "type": "uint256" } ], - "name": "withdrawAll", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ] - }, - "T": { - "address": "0xCdF7028ceAB81fA0C6971208e83fa7872994beE5", - "abi": [ - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" + "name": "DkgResultSubmissionGasUpdated", + "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" + "indexed": false, + "internalType": "uint256", + "name": "dkgResultSubmissionTimeout", + "type": "uint256" }, { "indexed": false, "internalType": "uint256", - "name": "value", + "name": "timestamp", "type": "uint256" } ], - "name": "Approval", + "name": "DkgResultSubmissionTimeoutUpdateStarted", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "address", - "name": "delegator", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "fromDelegate", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "toDelegate", - "type": "address" + "indexed": false, + "internalType": "uint256", + "name": "dkgResultSubmissionTimeout", + "type": "uint256" } ], - "name": "DelegateChanged", + "name": "DkgResultSubmissionTimeoutUpdated", "type": "event" }, { "anonymous": false, "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "delegate", - "type": "address" - }, { "indexed": false, "internalType": "uint256", - "name": "previousBalance", + "name": "dkgSeedTimeout", "type": "uint256" }, { "indexed": false, "internalType": "uint256", - "name": "newBalance", + "name": "timestamp", "type": "uint256" } ], - "name": "DelegateVotesChanged", + "name": "DkgSeedTimeoutUpdateStarted", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" + "indexed": false, + "internalType": "uint256", + "name": "dkgSeedTimeout", + "type": "uint256" } ], - "name": "OwnershipTransferred", + "name": "DkgSeedTimeoutUpdated", "type": "event" }, { "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" + "indexed": false, + "internalType": "uint256", + "name": "submitterPrecedencePeriodLength", + "type": "uint256" }, { "indexed": false, "internalType": "uint256", - "name": "value", + "name": "timestamp", "type": "uint256" } ], - "name": "Transfer", + "name": "DkgSubmitterPrecedencePeriodLengthUpdateStarted", "type": "event" }, { - "inputs": [], - "name": "DELEGATION_TYPEHASH", - "outputs": [ + "anonymous": false, + "inputs": [ { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "indexed": false, + "internalType": "uint256", + "name": "submitterPrecedencePeriodLength", + "type": "uint256" } ], - "stateMutability": "view", - "type": "function" + "name": "DkgSubmitterPrecedencePeriodLengthUpdated", + "type": "event" }, { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ + "anonymous": false, + "inputs": [ { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "indexed": false, + "internalType": "uint256", + "name": "governanceDelay", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" } ], - "stateMutability": "view", - "type": "function" + "name": "GovernanceDelayUpdateStarted", + "type": "event" }, { - "inputs": [], - "name": "PERMIT_TYPEHASH", - "outputs": [ + "anonymous": false, + "inputs": [ { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "indexed": false, + "internalType": "uint256", + "name": "governanceDelay", + "type": "uint256" } ], - "stateMutability": "view", - "type": "function" + "name": "GovernanceDelayUpdated", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "indexed": false, + "internalType": "uint256", + "name": "maliciousDkgResultNotificationRewardMultiplier", + "type": "uint256" }, { - "internalType": "address", - "name": "", - "type": "address" + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" } ], - "name": "allowance", - "outputs": [ + "name": "MaliciousDkgResultNotificationRewardMultiplierUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ { + "indexed": false, "internalType": "uint256", - "name": "", + "name": "maliciousDkgResultNotificationRewardMultiplier", "type": "uint256" } ], - "stateMutability": "view", - "type": "function" + "name": "MaliciousDkgResultNotificationRewardMultiplierUpdated", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "address", - "name": "spender", - "type": "address" + "indexed": false, + "internalType": "uint256", + "name": "maliciousDkgResultSlashingAmount", + "type": "uint256" }, { + "indexed": false, "internalType": "uint256", - "name": "amount", + "name": "timestamp", "type": "uint256" } ], - "name": "approve", - "outputs": [ + "name": "MaliciousDkgResultSlashingAmountUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "indexed": false, + "internalType": "uint256", + "name": "maliciousDkgResultSlashingAmount", + "type": "uint256" } ], - "stateMutability": "nonpayable", - "type": "function" + "name": "MaliciousDkgResultSlashingAmountUpdated", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "address", - "name": "spender", - "type": "address" + "indexed": false, + "internalType": "uint96", + "name": "minimumAuthorization", + "type": "uint96" }, { + "indexed": false, "internalType": "uint256", - "name": "amount", + "name": "timestamp", "type": "uint256" - }, - { - "internalType": "bytes", - "name": "extraData", - "type": "bytes" } ], - "name": "approveAndCall", - "outputs": [ + "name": "MinimumAuthorizationUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "indexed": false, + "internalType": "uint96", + "name": "minimumAuthorization", + "type": "uint96" } ], - "stateMutability": "nonpayable", - "type": "function" + "name": "MinimumAuthorizationUpdated", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ + "indexed": false, + "internalType": "uint256", + "name": "notifyDkgTimeoutNegativeGasOffset", + "type": "uint256" + }, { + "indexed": false, "internalType": "uint256", - "name": "", + "name": "timestamp", "type": "uint256" } ], - "stateMutability": "view", - "type": "function" + "name": "NotifyDkgTimeoutNegativeGasOffsetUpdateStarted", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "uint256", - "name": "amount", + "name": "notifyDkgTimeoutNegativeGasOffset", "type": "uint256" } ], - "name": "burn", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "NotifyDkgTimeoutNegativeGasOffsetUpdated", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" + "indexed": false, + "internalType": "uint256", + "name": "notifyOperatorInactivityGasOffset", + "type": "uint256" }, { + "indexed": false, "internalType": "uint256", - "name": "amount", + "name": "timestamp", "type": "uint256" } ], - "name": "burnFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "NotifyOperatorInactivityGasOffsetUpdateStarted", + "type": "event" }, { - "inputs": [], - "name": "cachedChainId", - "outputs": [ + "anonymous": false, + "inputs": [ { + "indexed": false, "internalType": "uint256", - "name": "", + "name": "notifyOperatorInactivityGasOffset", "type": "uint256" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "cachedDomainSeparator", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" + "name": "NotifyOperatorInactivityGasOffsetUpdated", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" + "indexed": false, + "internalType": "uint256", + "name": "notifySeedTimeoutGasOffset", + "type": "uint256" }, { - "internalType": "uint32", - "name": "pos", - "type": "uint32" - } - ], - "name": "checkpoints", - "outputs": [ - { - "components": [ - { - "internalType": "uint32", - "name": "fromBlock", - "type": "uint32" - }, - { - "internalType": "uint96", - "name": "votes", - "type": "uint96" - } - ], - "internalType": "struct Checkpoints.Checkpoint", - "name": "checkpoint", - "type": "tuple" + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" } ], - "stateMutability": "view", - "type": "function" + "name": "NotifySeedTimeoutGasOffsetUpdateStarted", + "type": "event" }, { - "inputs": [], - "name": "decimals", - "outputs": [ + "anonymous": false, + "inputs": [ { - "internalType": "uint8", - "name": "", - "type": "uint8" + "indexed": false, + "internalType": "uint256", + "name": "notifySeedTimeoutGasOffset", + "type": "uint256" } ], - "stateMutability": "view", - "type": "function" + "name": "NotifySeedTimeoutGasOffsetUpdated", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": true, "internalType": "address", - "name": "delegatee", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", "type": "address" } ], - "name": "delegate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "OwnershipTransferred", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "address", - "name": "signatory", - "type": "address" - }, - { - "internalType": "address", - "name": "delegatee", + "name": "reimbursementPool", "type": "address" }, { + "indexed": false, "internalType": "uint256", - "name": "deadline", + "name": "timestamp", "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" } ], - "name": "delegateBySig", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "ReimbursementPoolUpdateStarted", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "delegates", - "outputs": [ - { - "internalType": "address", - "name": "", + "name": "reimbursementPool", "type": "address" } ], - "stateMutability": "view", - "type": "function" + "name": "ReimbursementPoolUpdated", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "uint256", - "name": "blockNumber", + "name": "sortitionPoolRewardsBanDuration", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", "type": "uint256" } ], - "name": "getPastTotalSupply", - "outputs": [ + "name": "SortitionPoolRewardsBanDurationUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ { - "internalType": "uint96", - "name": "", - "type": "uint96" + "indexed": false, + "internalType": "uint256", + "name": "sortitionPoolRewardsBanDuration", + "type": "uint256" } ], - "stateMutability": "view", - "type": "function" + "name": "SortitionPoolRewardsBanDurationUpdated", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "address", - "name": "account", + "name": "walletOwner", "type": "address" }, { + "indexed": false, "internalType": "uint256", - "name": "blockNumber", + "name": "timestamp", "type": "uint256" } ], - "name": "getPastVotes", - "outputs": [ - { - "internalType": "uint96", - "name": "", - "type": "uint96" - } - ], - "stateMutability": "view", - "type": "function" + "name": "WalletOwnerUpdateStarted", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "address", - "name": "account", + "name": "walletOwner", "type": "address" } ], - "name": "getVotes", - "outputs": [ - { - "internalType": "uint96", - "name": "", - "type": "uint96" - } - ], - "stateMutability": "view", - "type": "function" + "name": "WalletOwnerUpdated", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": false, "internalType": "address", - "name": "recipient", + "name": "newWalletRegistryGovernance", "type": "address" }, { + "indexed": false, "internalType": "uint256", - "name": "amount", + "name": "timestamp", "type": "uint256" } ], - "name": "mint", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "WalletRegistryGovernanceTransferStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newWalletRegistryGovernance", + "type": "address" + } + ], + "name": "WalletRegistryGovernanceTransferred", + "type": "event" }, { "inputs": [], - "name": "name", + "name": "authorizationDecreaseChangePeriodChangeInitiated", "outputs": [ { - "internalType": "string", + "internalType": "uint256", "name": "", - "type": "string" + "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "nonce", + "inputs": [], + "name": "authorizationDecreaseDelayChangeInitiated", "outputs": [ { "internalType": "uint256", @@ -11000,74 +15567,38 @@ { "inputs": [ { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "numCheckpoints", - "outputs": [ - { - "internalType": "uint32", - "name": "", - "type": "uint32" + "internalType": "uint64", + "name": "_newAuthorizationDecreaseChangePeriod", + "type": "uint64" } ], - "stateMutability": "view", + "name": "beginAuthorizationDecreaseChangePeriodUpdate", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "owner", - "outputs": [ + "inputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "internalType": "uint64", + "name": "_newAuthorizationDecreaseDelay", + "type": "uint64" } ], - "stateMutability": "view", + "name": "beginAuthorizationDecreaseDelayUpdate", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, { "internalType": "uint256", - "name": "deadline", + "name": "_newDkgResultApprovalGasOffset", "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" } ], - "name": "permit", + "name": "beginDkgResultApprovalGasOffsetUpdate", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -11075,774 +15606,640 @@ { "inputs": [ { - "internalType": "contract IERC20", - "name": "token", - "type": "address" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, + "internalType": "uint256", + "name": "_newDkgResultChallengeExtraGas", + "type": "uint256" + } + ], + "name": "beginDkgResultChallengeExtraGasUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ { "internalType": "uint256", - "name": "amount", + "name": "_newDkgResultChallengePeriodLength", "type": "uint256" } ], - "name": "recoverERC20", + "name": "beginDkgResultChallengePeriodLengthUpdate", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ - { - "internalType": "contract IERC721", - "name": "token", - "type": "address" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, { "internalType": "uint256", - "name": "tokenId", + "name": "_newDkgResultSubmissionGas", "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" } ], - "name": "recoverERC721", + "name": "beginDkgResultSubmissionGasUpdate", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "renounceOwnership", + "inputs": [ + { + "internalType": "uint256", + "name": "_newDkgResultSubmissionTimeout", + "type": "uint256" + } + ], + "name": "beginDkgResultSubmissionTimeoutUpdate", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "symbol", - "outputs": [ + "inputs": [ { - "internalType": "string", - "name": "", - "type": "string" + "internalType": "uint256", + "name": "_newDkgSeedTimeout", + "type": "uint256" } ], - "stateMutability": "view", + "name": "beginDkgSeedTimeoutUpdate", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "totalSupply", - "outputs": [ + "inputs": [ { "internalType": "uint256", - "name": "", + "name": "_newSubmitterPrecedencePeriodLength", "type": "uint256" } ], - "stateMutability": "view", + "name": "beginDkgSubmitterPrecedencePeriodLengthUpdate", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, { "internalType": "uint256", - "name": "amount", + "name": "_newGovernanceDelay", "type": "uint256" } ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], + "name": "beginGovernanceDelayUpdate", + "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, { "internalType": "uint256", - "name": "amount", + "name": "_newMaliciousDkgResultNotificationRewardMultiplier", "type": "uint256" } ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], + "name": "beginMaliciousDkgResultNotificationRewardMultiplierUpdate", + "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { - "internalType": "address", - "name": "newOwner", - "type": "address" + "internalType": "uint96", + "name": "_newMaliciousDkgResultSlashingAmount", + "type": "uint96" } ], - "name": "transferOwnership", + "name": "beginMaliciousDkgResultSlashingAmountUpdate", "outputs": [], "stateMutability": "nonpayable", "type": "function" - } - ] - }, - "TokenStaking": { - "address": "0x01B67b1194C75264d06F808A921228a95C765dd7", - "abi": [ + }, { "inputs": [ { - "internalType": "contract T", - "name": "_token", - "type": "address" - }, - { - "internalType": "contract IKeepTokenStaking", - "name": "_keepStakingContract", - "type": "address" - }, - { - "internalType": "contract INuCypherStakingEscrow", - "name": "_nucypherStakingContract", - "type": "address" - }, - { - "internalType": "contract VendingMachine", - "name": "_keepVendingMachine", - "type": "address" - }, - { - "internalType": "contract VendingMachine", - "name": "_nucypherVendingMachine", - "type": "address" - }, - { - "internalType": "contract KeepStake", - "name": "_keepStake", - "type": "address" + "internalType": "uint96", + "name": "_newMinimumAuthorization", + "type": "uint96" } ], + "name": "beginMinimumAuthorizationUpdate", + "outputs": [], "stateMutability": "nonpayable", - "type": "constructor" + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "address", - "name": "application", - "type": "address" - }, - { - "indexed": true, - "internalType": "enum TokenStaking.ApplicationStatus", - "name": "newStatus", - "type": "uint8" + "internalType": "uint256", + "name": "_newNotifyDkgTimeoutNegativeGasOffset", + "type": "uint256" } ], - "name": "ApplicationStatusChanged", - "type": "event" + "name": "beginNotifyDkgTimeoutNegativeGasOffsetUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": false, "internalType": "uint256", - "name": "ceiling", + "name": "_newNotifyOperatorInactivityGasOffset", "type": "uint256" } ], - "name": "AuthorizationCeilingSet", - "type": "event" + "name": "beginNotifyOperatorInactivityGasOffsetUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "application", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint96", - "name": "fromAmount", - "type": "uint96" - }, - { - "indexed": false, - "internalType": "uint96", - "name": "toAmount", - "type": "uint96" + "internalType": "uint256", + "name": "_newNotifySeedTimeoutGasOffset", + "type": "uint256" } ], - "name": "AuthorizationDecreaseApproved", - "type": "event" + "name": "beginNotifySeedTimeoutGasOffsetUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "application", + "internalType": "address payable", + "name": "_newReimbursementPool", "type": "address" - }, - { - "indexed": false, - "internalType": "uint96", - "name": "fromAmount", - "type": "uint96" - }, - { - "indexed": false, - "internalType": "uint96", - "name": "toAmount", - "type": "uint96" } ], - "name": "AuthorizationDecreaseRequested", - "type": "event" + "name": "beginReimbursementPoolUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "application", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint96", - "name": "fromAmount", - "type": "uint96" - }, - { - "indexed": false, - "internalType": "uint96", - "name": "toAmount", - "type": "uint96" + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newSortitionPoolRewardsBanDuration", + "type": "uint256" } ], - "name": "AuthorizationIncreased", - "type": "event" + "name": "beginSortitionPoolRewardsBanDurationUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, - { - "indexed": true, "internalType": "address", - "name": "application", + "name": "_newWalletOwner", "type": "address" - }, - { - "indexed": false, - "internalType": "uint96", - "name": "fromAmount", - "type": "uint96" - }, - { - "indexed": false, - "internalType": "uint96", - "name": "toAmount", - "type": "uint96" - }, - { - "indexed": true, - "internalType": "bool", - "name": "successfulCall", - "type": "bool" } ], - "name": "AuthorizationInvoluntaryDecreased", - "type": "event" + "name": "beginWalletOwnerUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": true, "internalType": "address", - "name": "delegator", + "name": "_newWalletRegistryGovernance", "type": "address" - }, + } + ], + "name": "beginWalletRegistryGovernanceTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "dkgResultApprovalGasOffsetChangeInitiated", + "outputs": [ { - "indexed": true, - "internalType": "address", - "name": "fromDelegate", - "type": "address" - }, + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "dkgResultChallengeExtraGasChangeInitiated", + "outputs": [ { - "indexed": true, - "internalType": "address", - "name": "toDelegate", - "type": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "DelegateChanged", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "dkgResultChallengePeriodLengthChangeInitiated", + "outputs": [ { - "indexed": true, - "internalType": "address", - "name": "delegate", - "type": "address" - }, + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "dkgResultSubmissionGasChangeInitiated", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "previousBalance", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "dkgResultSubmissionTimeoutChangeInitiated", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "newBalance", + "name": "", "type": "uint256" } ], - "name": "DelegateVotesChanged", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ + "inputs": [], + "name": "dkgSeedTimeoutChangeInitiated", + "outputs": [ { - "indexed": false, - "internalType": "address", - "name": "oldGovernance", - "type": "address" - }, + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "dkgSubmitterPrecedencePeriodLengthChangeInitiated", + "outputs": [ { - "indexed": false, - "internalType": "address", - "name": "newGovernance", - "type": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "GovernanceTransferred", - "type": "event" + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeAuthorizationDecreaseChangePeriodUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeAuthorizationDecreaseDelayUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeDkgResultApprovalGasOffsetUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeDkgResultChallengeExtraGasUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeDkgResultChallengePeriodLengthUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeDkgResultSubmissionGasUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeDkgResultSubmissionTimeoutUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeDkgSeedTimeoutUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeDkgSubmitterPrecedencePeriodLengthUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeGovernanceDelayUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeMaliciousDkgResultNotificationRewardMultiplierUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeMaliciousDkgResultSlashingAmountUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeMinimumAuthorizationUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint96", - "name": "amount", - "type": "uint96" - } - ], - "name": "MinimumStakeAmountSet", - "type": "event" + "inputs": [], + "name": "finalizeNotifyDkgTimeoutNegativeGasOffsetUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint96", - "name": "reward", - "type": "uint96" - } - ], - "name": "NotificationRewardPushed", - "type": "event" + "inputs": [], + "name": "finalizeNotifyOperatorInactivityGasOffsetUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint96", - "name": "reward", - "type": "uint96" - } - ], - "name": "NotificationRewardSet", - "type": "event" + "inputs": [], + "name": "finalizeNotifySeedTimeoutGasOffsetUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint96", - "name": "amount", - "type": "uint96" - } - ], - "name": "NotificationRewardWithdrawn", - "type": "event" + "inputs": [], + "name": "finalizeReimbursementPoolUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "notifier", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "NotifierRewarded", - "type": "event" + "inputs": [], + "name": "finalizeSortitionPoolRewardsBanDurationUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "oldOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnerRefreshed", - "type": "event" + "inputs": [], + "name": "finalizeWalletOwnerUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "application", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "panicButton", - "type": "address" - } - ], - "name": "PanicButtonSet", - "type": "event" + "inputs": [], + "name": "finalizeWalletRegistryGovernanceTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, + "inputs": [], + "name": "getRemainingAuthorizationDecreaseChangePeriodUpdateTime", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "count", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingAuthorizationDecreaseDelayUpdateTime", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "tAmount", + "name": "", "type": "uint256" } ], - "name": "SlashingProcessed", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint96", - "name": "penalty", - "type": "uint96" - }, + "inputs": [], + "name": "getRemainingDkgResultApprovalGasOffsetUpdateTime", + "outputs": [ { - "indexed": false, "internalType": "uint256", - "name": "rewardMultiplier", + "name": "", "type": "uint256" } ], - "name": "StakeDiscrepancyPenaltySet", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "enum IStaking.StakeType", - "name": "stakeType", - "type": "uint8" - }, - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "beneficiary", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "authorizer", - "type": "address" - }, + "inputs": [], + "name": "getRemainingDkgResultChallengeExtraGasUpdateTime", + "outputs": [ { - "indexed": false, - "internalType": "uint96", - "name": "amount", - "type": "uint96" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "Staked", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint96", - "name": "amount", - "type": "uint96" - }, + "inputs": [], + "name": "getRemainingDkgResultChallengePeriodLengthUpdateTime", + "outputs": [ { - "indexed": true, - "internalType": "bool", - "name": "discrepancy", - "type": "bool" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "TokensSeized", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, + "inputs": [], + "name": "getRemainingDkgResultSubmissionGasUpdateTime", + "outputs": [ { - "indexed": false, - "internalType": "uint96", - "name": "amount", - "type": "uint96" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "ToppedUp", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, + "inputs": [], + "name": "getRemainingDkgResultSubmissionTimeoutUpdateTime", + "outputs": [ { - "indexed": false, - "internalType": "uint96", - "name": "amount", - "type": "uint96" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "Unstaked", - "type": "event" + "stateMutability": "view", + "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "getRemainingDkgSeedTimeoutUpdateTime", + "outputs": [ { - "internalType": "address", + "internalType": "uint256", "name": "", - "type": "address" + "type": "uint256" } ], - "name": "applicationInfo", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingDkgSubmitterPrecedencePeriodLengthUpdateTime", "outputs": [ { - "internalType": "enum TokenStaking.ApplicationStatus", - "name": "status", - "type": "uint8" - }, - { - "internalType": "address", - "name": "panicButton", - "type": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "getRemainingGovernanceDelayUpdateTime", + "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], - "name": "applications", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingMaliciousDkgResultNotificationRewardMultiplierUpdateTime", "outputs": [ { - "internalType": "address", + "internalType": "uint256", "name": "", - "type": "address" + "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "getRemainingMaliciousDkgResultSlashingAmountUpdateTime", + "outputs": [ { - "internalType": "address", - "name": "application", - "type": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "approveApplication", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "getRemainingMimimumAuthorizationUpdateTime", + "outputs": [ { - "internalType": "address", - "name": "stakingProvider", - "type": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "approveAuthorizationDecrease", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingNotifyDkgTimeoutNegativeGasOffsetUpdateTime", "outputs": [ { - "internalType": "uint96", + "internalType": "uint256", "name": "", - "type": "uint96" + "type": "uint256" } ], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [], - "name": "authorizationCeiling", + "name": "getRemainingNotifyOperatorInactivityGasOffsetUpdateTime", "outputs": [ { "internalType": "uint256", @@ -11854,97 +16251,91 @@ "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, + "inputs": [], + "name": "getRemainingNotifySeedTimeoutGasOffsetUpdateTime", + "outputs": [ { - "internalType": "address", - "name": "application", - "type": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "authorizedStake", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingReimbursementPoolUpdateTime", "outputs": [ { - "internalType": "uint96", + "internalType": "uint256", "name": "", - "type": "uint96" + "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, + "inputs": [], + "name": "getRemainingSortitionPoolRewardsBanDurationUpdateTime", + "outputs": [ { - "internalType": "uint32", - "name": "pos", - "type": "uint32" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "checkpoints", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingWalletOwnerUpdateTime", "outputs": [ { - "components": [ - { - "internalType": "uint32", - "name": "fromBlock", - "type": "uint32" - }, - { - "internalType": "uint96", - "name": "votes", - "type": "uint96" - } - ], - "internalType": "struct Checkpoints.Checkpoint", - "name": "checkpoint", - "type": "tuple" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, + "inputs": [], + "name": "getRemainingWalletRegistryGovernanceTransferDelayTime", + "outputs": [ { - "internalType": "address", - "name": "delegatee", - "type": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "delegateVoting", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "governanceDelay", + "outputs": [ { - "internalType": "address", - "name": "account", - "type": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "delegates", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "governanceDelayChangeInitiated", "outputs": [ { - "internalType": "address", + "internalType": "uint256", "name": "", - "type": "address" + "type": "uint256" } ], "stateMutability": "view", @@ -11954,36 +16345,31 @@ "inputs": [ { "internalType": "address", - "name": "application", + "name": "_walletOwner", "type": "address" } ], - "name": "disableApplication", + "name": "initializeWalletOwner", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, + "inputs": [], + "name": "maliciousDkgResultNotificationRewardMultiplierChangeInitiated", + "outputs": [ { - "internalType": "address", - "name": "application", - "type": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "forceDecreaseAuthorization", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [], - "name": "getApplicationsLength", + "name": "maliciousDkgResultSlashingAmountChangeInitiated", "outputs": [ { "internalType": "uint256", @@ -11995,91 +16381,91 @@ "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, - { - "internalType": "address", - "name": "application", - "type": "address" - } - ], - "name": "getAvailableToAuthorize", + "inputs": [], + "name": "minimumAuthorizationChangeInitiated", "outputs": [ { - "internalType": "uint96", - "name": "availableTValue", - "type": "uint96" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, + "inputs": [], + "name": "newAuthorizationDecreaseChangePeriod", + "outputs": [ { - "internalType": "enum IStaking.StakeType", - "name": "stakeTypes", - "type": "uint8" + "internalType": "uint64", + "name": "", + "type": "uint64" } ], - "name": "getMinStaked", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newAuthorizationDecreaseDelay", "outputs": [ { - "internalType": "uint96", + "internalType": "uint64", "name": "", - "type": "uint96" + "type": "uint64" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "newDkgResultApprovalGasOffset", + "outputs": [ { "internalType": "uint256", - "name": "blockNumber", + "name": "", "type": "uint256" } ], - "name": "getPastTotalSupply", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newDkgResultChallengeExtraGas", "outputs": [ { - "internalType": "uint96", + "internalType": "uint256", "name": "", - "type": "uint96" + "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, + "inputs": [], + "name": "newDkgResultChallengePeriodLength", + "outputs": [ { "internalType": "uint256", - "name": "blockNumber", + "name": "", "type": "uint256" } ], - "name": "getPastVotes", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newDkgResultSubmissionGas", "outputs": [ { - "internalType": "uint96", + "internalType": "uint256", "name": "", - "type": "uint96" + "type": "uint256" } ], "stateMutability": "view", @@ -12087,7 +16473,7 @@ }, { "inputs": [], - "name": "getSlashingQueueLength", + "name": "newDkgResultSubmissionTimeout", "outputs": [ { "internalType": "uint256", @@ -12099,14 +16485,8 @@ "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "stakingProvider", - "type": "address" - } - ], - "name": "getStartStakingTimestamp", + "inputs": [], + "name": "newDkgSeedTimeout", "outputs": [ { "internalType": "uint256", @@ -12118,19 +16498,13 @@ "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "getVotes", + "inputs": [], + "name": "newGovernanceDelay", "outputs": [ { - "internalType": "uint96", + "internalType": "uint256", "name": "", - "type": "uint96" + "type": "uint256" } ], "stateMutability": "view", @@ -12138,50 +16512,33 @@ }, { "inputs": [], - "name": "governance", + "name": "newMaliciousDkgResultNotificationRewardMultiplier", "outputs": [ { - "internalType": "address", + "internalType": "uint256", "name": "", - "type": "address" + "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, - { - "internalType": "address", - "name": "application", - "type": "address" - }, + "inputs": [], + "name": "newMaliciousDkgResultSlashingAmount", + "outputs": [ { "internalType": "uint96", - "name": "amount", + "name": "", "type": "uint96" } ], - "name": "increaseAuthorization", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [], - "name": "minTStakeAmount", + "name": "newMinimumAuthorization", "outputs": [ { "internalType": "uint96", @@ -12194,7 +16551,7 @@ }, { "inputs": [], - "name": "notificationReward", + "name": "newNotifyDkgTimeoutNegativeGasOffset", "outputs": [ { "internalType": "uint256", @@ -12207,7 +16564,7 @@ }, { "inputs": [], - "name": "notifiersTreasury", + "name": "newNotifyOperatorInactivityGasOffset", "outputs": [ { "internalType": "uint256", @@ -12219,230 +16576,177 @@ "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "stakingProvider", - "type": "address" - } - ], - "name": "notifyKeepStakeDiscrepancy", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "stakingProvider", - "type": "address" - } - ], - "name": "notifyNuStakeDiscrepancy", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "numCheckpoints", + "inputs": [], + "name": "newNotifySeedTimeoutGasOffset", "outputs": [ { - "internalType": "uint32", + "internalType": "uint256", "name": "", - "type": "uint32" + "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "newReimbursementPool", + "outputs": [ { - "internalType": "address", - "name": "application", + "internalType": "address payable", + "name": "", "type": "address" } ], - "name": "pauseApplication", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "newSortitionPoolRewardsBanDuration", + "outputs": [ { "internalType": "uint256", - "name": "count", + "name": "", "type": "uint256" } ], - "name": "processSlashing", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint96", - "name": "reward", - "type": "uint96" - } - ], - "name": "pushNotificationReward", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "newSubmitterPrecedencePeriodLength", + "outputs": [ { - "internalType": "address", - "name": "stakingProvider", - "type": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "refreshKeepStakeOwner", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "stakingProvider", - "type": "address" - }, + "inputs": [], + "name": "newWalletOwner", + "outputs": [ { "internalType": "address", - "name": "application", + "name": "", "type": "address" - }, - { - "internalType": "uint96", - "name": "amount", - "type": "uint96" } ], - "name": "requestAuthorizationDecrease", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "newWalletRegistryGovernance", + "outputs": [ { "internalType": "address", - "name": "stakingProvider", + "name": "", "type": "address" } ], - "name": "requestAuthorizationDecrease", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "notifyDkgTimeoutNegativeGasOffsetChangeInitiated", + "outputs": [ { - "internalType": "address", - "name": "stakingProvider", - "type": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "rolesOf", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "notifyOperatorInactivityGasOffsetChangeInitiated", "outputs": [ { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address payable", - "name": "beneficiary", - "type": "address" - }, - { - "internalType": "address", - "name": "authorizer", - "type": "address" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "uint96", - "name": "amount", - "type": "uint96" - }, + "inputs": [], + "name": "notifySeedTimeoutGasOffsetChangeInitiated", + "outputs": [ { "internalType": "uint256", - "name": "rewardMultiplier", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ { "internalType": "address", - "name": "notifier", + "name": "", "type": "address" - }, - { - "internalType": "address[]", - "name": "_stakingProviders", - "type": "address[]" } ], - "name": "seize", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "reimbursementPoolChangeInitiated", + "outputs": [ { "internalType": "uint256", - "name": "ceiling", + "name": "", "type": "uint256" } ], - "name": "setAuthorizationCeiling", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "sortitionPoolRewardsBanDurationChangeInitiated", + "outputs": [ { - "internalType": "uint96", - "name": "amount", - "type": "uint96" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "setMinimumStakeAmount", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { - "internalType": "uint96", - "name": "reward", - "type": "uint96" + "internalType": "address", + "name": "newOwner", + "type": "address" } ], - "name": "setNotificationReward", + "name": "transferOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -12451,156 +16755,254 @@ "inputs": [ { "internalType": "address", - "name": "application", - "type": "address" - }, - { - "internalType": "address", - "name": "panicButton", + "name": "_newRandomBeacon", "type": "address" } ], - "name": "setPanicButton", + "name": "upgradeRandomBeacon", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "walletOwnerChangeInitiated", + "outputs": [ { - "internalType": "uint96", - "name": "penalty", - "type": "uint96" - }, + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "walletRegistry", + "outputs": [ + { + "internalType": "contract WalletRegistry", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "walletRegistryGovernanceTransferInitiated", + "outputs": [ { "internalType": "uint256", - "name": "rewardMultiplier", + "name": "", "type": "uint256" } ], - "name": "setStakeDiscrepancyPenalty", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { - "internalType": "uint96", - "name": "amount", - "type": "uint96" - }, - { - "internalType": "address[]", - "name": "_stakingProviders", - "type": "address[]" + "internalType": "address", + "name": "recipient", + "type": "address" } ], - "name": "slash", + "name": "withdrawIneligibleRewards", "outputs": [], "stateMutability": "nonpayable", "type": "function" + } + ] + }, + "Allowlist": { + "address": "0x1a6a3e7Bb246158dF31d8f924B84D961669Ba4e5", + "abi": [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "NoDecreasePending", + "type": "error" + }, + { + "inputs": [], + "name": "NotWalletRegistry", + "type": "error" + }, + { + "inputs": [], + "name": "RequestedWeightNotBelowCurrentWeight", + "type": "error" + }, + { + "inputs": [], + "name": "StakingProviderAlreadyAdded", + "type": "error" + }, + { + "inputs": [], + "name": "StakingProviderUnknown", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroWeight", + "type": "error" }, { + "anonymous": false, "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" } ], - "name": "slashingQueue", - "outputs": [ + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ { + "indexed": false, "internalType": "address", - "name": "stakingProvider", + "name": "notifier", "type": "address" }, { - "internalType": "uint96", - "name": "amount", - "type": "uint96" + "indexed": false, + "internalType": "address[]", + "name": "stakingProviders", + "type": "address[]" } ], - "stateMutability": "view", - "type": "function" + "name": "MaliciousBehaviorIdentified", + "type": "event" }, { - "inputs": [], - "name": "slashingQueueIndex", - "outputs": [ + "anonymous": false, + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" } ], - "stateMutability": "view", - "type": "function" + "name": "OwnershipTransferStarted", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": true, "internalType": "address", - "name": "stakingProvider", + "name": "previousOwner", "type": "address" }, { - "internalType": "address payable", - "name": "beneficiary", + "indexed": true, + "internalType": "address", + "name": "newOwner", "type": "address" - }, + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ { + "indexed": true, "internalType": "address", - "name": "authorizer", + "name": "stakingProvider", "type": "address" }, { + "indexed": false, "internalType": "uint96", - "name": "amount", + "name": "weight", "type": "uint96" } ], - "name": "stake", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "StakingProviderAdded", + "type": "event" }, { - "inputs": [], - "name": "stakeDiscrepancyPenalty", - "outputs": [ + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, { + "indexed": false, "internalType": "uint96", - "name": "", + "name": "oldWeight", "type": "uint96" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "stakeDiscrepancyRewardMultiplier", - "outputs": [ + }, { - "internalType": "uint256", - "name": "", - "type": "uint256" + "indexed": false, + "internalType": "uint96", + "name": "newWeight", + "type": "uint96" } ], - "stateMutability": "view", - "type": "function" + "name": "WeightDecreaseFinalized", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": true, "internalType": "address", "name": "stakingProvider", "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "oldWeight", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "newWeight", + "type": "uint96" } ], - "name": "stakeKeep", + "name": "WeightDecreaseRequested", + "type": "event" + }, + { + "inputs": [], + "name": "acceptOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -12613,17 +17015,12 @@ "type": "address" }, { - "internalType": "address payable", - "name": "beneficiary", - "type": "address" - }, - { - "internalType": "address", - "name": "authorizer", - "type": "address" + "internalType": "uint96", + "name": "weight", + "type": "uint96" } ], - "name": "stakeNu", + "name": "addStakingProvider", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -12636,15 +17033,15 @@ "type": "address" } ], - "name": "stakedNu", + "name": "approveAuthorizationDecrease", "outputs": [ { - "internalType": "uint256", - "name": "nuAmount", - "type": "uint256" + "internalType": "uint96", + "name": "", + "type": "uint96" } ], - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" }, { @@ -12653,23 +17050,18 @@ "internalType": "address", "name": "stakingProvider", "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" } ], - "name": "stakes", + "name": "authorizedStake", "outputs": [ { "internalType": "uint96", - "name": "tStake", - "type": "uint96" - }, - { - "internalType": "uint96", - "name": "keepInTStake", - "type": "uint96" - }, - { - "internalType": "uint96", - "name": "nuInTStake", + "name": "", "type": "uint96" } ], @@ -12680,42 +17072,44 @@ "inputs": [ { "internalType": "address", - "name": "stakingProvider", + "name": "_walletRegistry", "type": "address" - }, - { - "internalType": "uint96", - "name": "amount", - "type": "uint96" } ], - "name": "topUp", + "name": "initialize", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "owner", + "outputs": [ { "internalType": "address", - "name": "stakingProvider", + "name": "", "type": "address" } ], - "name": "topUpKeep", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "pendingOwner", + "outputs": [ { "internalType": "address", - "name": "stakingProvider", + "name": "", "type": "address" } ], - "name": "topUpNu", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -12724,11 +17118,16 @@ "inputs": [ { "internalType": "address", - "name": "newGuvnor", + "name": "stakingProvider", "type": "address" + }, + { + "internalType": "uint96", + "name": "newWeight", + "type": "uint96" } ], - "name": "transferGovernance", + "name": "requestWeightDecrease", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -12741,38 +17140,51 @@ "type": "address" } ], - "name": "unstakeAll", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + "name": "rolesOf", + "outputs": [ { "internalType": "address", - "name": "stakingProvider", + "name": "stakeOwner", + "type": "address" + }, + { + "internalType": "address payable", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "address", + "name": "authorizer", "type": "address" } ], - "name": "unstakeKeep", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, { "internalType": "address", - "name": "stakingProvider", + "name": "notifier", "type": "address" }, { - "internalType": "uint96", - "name": "amount", - "type": "uint96" + "internalType": "address[]", + "name": "_stakingProviders", + "type": "address[]" } ], - "name": "unstakeNu", + "name": "seize", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -12781,37 +17193,56 @@ "inputs": [ { "internalType": "address", - "name": "stakingProvider", + "name": "", "type": "address" + } + ], + "name": "stakingProviders", + "outputs": [ + { + "internalType": "uint96", + "name": "weight", + "type": "uint96" }, { "internalType": "uint96", - "name": "amount", + "name": "pendingNewWeight", "type": "uint96" + }, + { + "internalType": "bool", + "name": "decreasePending", + "type": "bool" } ], - "name": "unstakeT", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", - "name": "recipient", + "name": "newOwner", "type": "address" - }, - { - "internalType": "uint96", - "name": "amount", - "type": "uint96" } ], - "name": "withdrawNotificationReward", + "name": "transferOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" + }, + { + "inputs": [], + "name": "walletRegistry", + "outputs": [ + { + "internalType": "contract WalletRegistry", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" } ] } diff --git a/solidity/ecdsa/external/random-beacon-export/LICENSE b/solidity/ecdsa/external/random-beacon-export/LICENSE new file mode 100644 index 0000000000..e72bfddabc --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/solidity/ecdsa/external/random-beacon-export/README.md b/solidity/ecdsa/external/random-beacon-export/README.md index 620b5abbb2..911a56eeec 100644 --- a/solidity/ecdsa/external/random-beacon-export/README.md +++ b/solidity/ecdsa/external/random-beacon-export/README.md @@ -1,42 +1,39 @@ -# Bundled random-beacon deploy scripts - -This directory contains a committed copy of the `export/deploy/*.js` scripts that -the `@keep-network/random-beacon` package publishes to npm. The ecdsa package -needs these so its hardhat-deploy run can resolve random-beacon's deploy phase -when the local `../random-beacon/export/` directory is unavailable (it is -gitignored) and falling back to `node_modules/@keep-network/random-beacon/export` -would pull a stale published version. - -The resolution order is defined in `solidity/ecdsa/hardhat.config.ts` -(`resolveRandomBeaconExport`): local sibling export first, this bundled copy -second, npm fallback last. - -This README lives one level above `deploy/` because hardhat-deploy walks that -directory and tries to `require()` every file; a Markdown sibling there would -crash deployment. +# Frozen Beacon deployment compatibility + +ECDSA uses this committed snapshot for legacy deployment replay. It no longer +installs the published Random Beacon package, which pulled sortition-pools back +into the dependency graph after its direct removal. + +`artifacts/` contains the eleven required deployment artifacts from +`@keep-network/random-beacon@2.1.0-dev.18`. ABI, bytecode, link references, +metadata (including original Solidity sources), storage layouts, and docs are +preserved. Duplicate EVM assembly/opcode output is omitted. `VENDOR.json` records +provenance and upstream hashes. The embedded SortitionPool artifact retains +the upstream ISC licensing (see `../../contracts/legacy/sortition/LICENSE`). The deployment scripts below retain their +existing fixes. Contract interfaces and reimbursement support live in +`contracts/legacy/random-beacon`; initialization tasks live in +`tasks/legacy-random-beacon` and are copied to `export/tasks` during packaging. + +There is no npm fallback or automatic refresh from a dist-tag. Updates to this +legacy snapshot must be explicit, reviewed changes. Keep this README outside +`deploy/`, because hardhat-deploy requires every file in that directory. ## Source -The scripts are the TypeScript-compiled output of `solidity/random-beacon/deploy/*.ts`, -produced by `yarn prepack` (i.e. `tsc -p tsconfig.export.json`) in the -`@keep-network/random-beacon` package. +The scripts are the TypeScript-compiled output of +`solidity/random-beacon/deploy/*.ts`, produced by `yarn prepack` (i.e. +`tsc -p tsconfig.export.json`) in the `@keep-network/random-beacon` package. ## Format -The bundled scripts intentionally mix two formats: - -- **`01..04, 06..09_*.js`**: `tsc`-compiled ES5 output from the upstream - package's TypeScript sources (`__awaiter` / `__generator` runtime helpers, - `var` declarations). Treat as build artifacts; do not hand-edit. -- **`05_approve_random_beacon_in_token_staking.js`**: hand-written modern - async/await. Adds an `ifaceHasFunction("approveApplication")` precheck (so it - skips cleanly on the Threshold `TokenStaking` ABI, which does not expose - `approveApplication`) plus an idempotency guard that swallows errors only - while reading `applicationInfo(...)`. The `approveApplication(...)` call - itself is intentionally left unwrapped so a genuine revert propagates. - **Do not regenerate from upstream without preserving this precheck** — - blind regeneration will reintroduce a hard failure on networks running the - Threshold staking contract. +The committed scripts are `tsc`-compiled ES5 output from the upstream +package's TypeScript sources (`__awaiter` / `__generator` runtime helpers, +`var` declarations). Treat as build artifacts; do not hand-edit. The approval +script's missing-function and already-approved guards now live in the +TypeScript source on `dev`, so regeneration is uniform across all nine scripts +and produces ES2020/CommonJS output with ethers v6. The frozen ES5 scripts are +the committed state; regeneration from the current source produces ES2020 +output that supersedes them once re-verified. ## Known limitation: verification is not wrapped @@ -55,42 +52,23 @@ the run. ## Regenerate -From the repo root: +From `solidity/random-beacon`, regenerate with: ```sh -cd solidity/random-beacon -yarn install yarn prepack -# Copy every script EXCEPT 05_* — that one is hand-maintained (see below). -cp export/deploy/0[1-4]_*.js ../ecdsa/external/random-beacon-export/deploy/ -cp export/deploy/0[6-9]_*.js ../ecdsa/external/random-beacon-export/deploy/ +cp export/deploy/*.js ../ecdsa/external/random-beacon-export/deploy/ +mkdir -p ../ecdsa/external/random-beacon-export/utils +cp export/utils/wait-for-confirmations.js ../ecdsa/external/random-beacon-export/utils/ +mkdir -p ../ecdsa/external/random-beacon-export/tasks/utils +cp export/tasks/initialize.js export/tasks/unlock-eth-accounts.js ../ecdsa/external/random-beacon-export/tasks/ +cp export/tasks/utils/*.js ../ecdsa/external/random-beacon-export/tasks/utils/ ``` -Then verify `git diff` matches the intended deploy-script change in the -sibling `solidity/random-beacon/deploy/*.ts` source — divergence between -the `.ts` source and the bundled `.js` is the failure mode this directory -guards against. - -### Regeneration policy - -When syncing from upstream: - -1. Regenerate `01..04, 06..09_*.js` from `@keep-network/random-beacon`'s - `export/deploy` source via its `tsc` build (the `yarn prepack` step above). -2. **Skip `05_*.js`** during bulk regeneration — it is maintained deliberately. - If you do regenerate it, ensure it matches - `solidity/random-beacon/deploy/05_approve_random_beacon_in_token_staking.ts` - and preserves the `ifaceHasFunction("approveApplication")` gating and the - `applicationInfo(...)` idempotency check. -3. Verify by running deploys against both a network that exposes - `approveApplication` (legacy Keep TokenStaking) and one that does not - (Threshold TokenStaking). - -## Why we don't just `ts-node` the upstream +Compare the generated files with their sources, then exercise ECDSA with the +sibling export unavailable. Separately test actual npm tarballs with +`RANDOM_BEACON_EXPORT_PATH`; a passing bundled fallback does not validate a +published producer. See [the compatibility checks](../../../docs/ethers-v6-compatibility.md). -`hardhat-deploy` reads deploy scripts from the configured external paths as -plain CommonJS modules. The `external/*/deploy` directories are listed in -`hardhat.config.ts` and loaded via `require`, so they must be runnable JS. -The bundled `.js` here matches what `@keep-network/random-beacon` ships to -npm consumers, keeping the in-monorepo and published-consumer code paths -identical. +The Beacon scripts still call explorer verification directly when the network +tags enable it. Verification failure can halt a deploy. The local compatibility +checks do not test explorer services or enable public-network tags. diff --git a/solidity/ecdsa/external/random-beacon-export/VENDOR.json b/solidity/ecdsa/external/random-beacon-export/VENDOR.json new file mode 100644 index 0000000000..fae05be30a --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/VENDOR.json @@ -0,0 +1,45 @@ +{ + "package": "@keep-network/random-beacon", + "version": "2.1.0-dev.18", + "tarballSha256": "cb78e285cebfd4e37fa458cb0f1d2f098b11b14957abc06f0eead49472de4bb6", + "sourceSha256": { + "Reimbursable.sol": "ccf7c5679a5eee9a76ffeccab7b93aebef1d31a8951c370e0f3f446182bf203a", + "ReimbursementPool.sol": "4e13f1afad5dc51fc9acfe58e7d96c815deb3a6436eddf5781434f27bc699f6b", + "Governable.sol": "5927a8a6a8f8795a30fa6b037f0727268d70b211a7564d33942a5002fed1fa55", + "api/IRandomBeacon.sol": "2997582fc26e0ee596f328f0f182e846724a0babd77a78a023ae79e23910857e", + "api/IRandomBeaconConsumer.sol": "af7eda30e7b3b0ebeb9b5ba4f967cd743a2b8ff3c2ecab69ccd7e2a6ca3229d0", + "libraries/BytesLib.sol": "a1c0dfc7effdc613ef1c185b90bd85221d82c770c48e5dbbf5086a73b1ad8e0f", + "libraries/Callback.sol": "b3566d7234cf2fc216baa3a1adfe02aa079db5cbca8b648337079301a6274f12" + }, + "artifactSha256": { + "contracts/libraries/BeaconAuthorization.sol/BeaconAuthorization.json": "603ae4b7523b725ba21f393162ca089df3163d454ea460b10fdf18ba480851b1", + "contracts/libraries/BeaconDkg.sol/BeaconDkg.json": "467ba9dbfe09ce0c3a70019cb1d813058e7d78861ec9ae23c49bf604974040f3", + "contracts/BeaconDkgValidator.sol/BeaconDkgValidator.json": "f5933499c2eca676a85121c9e8586f7ecd6bbb13a41d3b4a4d5331af630ef61c", + "contracts/libraries/BeaconInactivity.sol/BeaconInactivity.json": "ae047204d4f5fa702e3841f8c2dd2b8f8a1a2f29993e545359fd1971095be87e", + "contracts/libraries/BLS.sol/BLS.json": "94f1c7453bba969c6e2be7fb9e289bd9733c0f252c5b32ab04732edb8af47086", + "contracts/RandomBeacon.sol/RandomBeacon.json": "24f2974f6ad2a301a621ab11e312d515e28f9b9bed53d5fea75ae6e2cae22aef", + "contracts/RandomBeaconChaosnet.sol/RandomBeaconChaosnet.json": "d29ac51ac65fba747f66b92fe498c4b59656effadd37fdace27fd73110f23817", + "contracts/RandomBeaconGovernance.sol/RandomBeaconGovernance.json": "ac1647a99aeba289ba829050e77ddcd9cff5d4161362f9d322566424cf97d26f", + "contracts/test/RandomBeaconStub.sol/RandomBeaconStub.json": "b86f052694f7188170f218683cd7527ed1623e3493039a2fe61303d8a7543e5c", + "contracts/ReimbursementPool.sol/ReimbursementPool.json": "ca443da8001bf6e224b10f36c80db159cbc65b170e1521993c7a47cbbe70fdec", + "@keep-network/sortition-pools/contracts/SortitionPool.sol/SortitionPool.json": "170b8915288ea6fd504bb4f2272cf8868995d3ebdf2d91d04acd39e1619c359c" + }, + "committedSha256": { + "contracts/libraries/BeaconAuthorization.sol/BeaconAuthorization.json": "1b1cec54dd0ba61e4115d99592f21384655be08f07cf34d99bc30de83026ae4d", + "contracts/libraries/BeaconDkg.sol/BeaconDkg.json": "12932aa4f8ff11115c1890e3c1a91f6698d6326ac9375852722848f77c54eac2", + "contracts/BeaconDkgValidator.sol/BeaconDkgValidator.json": "986c92c37ad94c36ce960075aedea41d9868d7d1beb954830777bfbf49c091b8", + "contracts/libraries/BeaconInactivity.sol/BeaconInactivity.json": "ebb85e7faaf6a5cf92fec25020f1394872f9169cf802748d7b916d1154cdae83", + "contracts/libraries/BLS.sol/BLS.json": "f06fe052ec3d633b37a07505e4d3c8c021fbe29ae808a5d4cd8d1ea139af0d98", + "contracts/RandomBeacon.sol/RandomBeacon.json": "26d500a02e01cd885c4f7afbf7931639471fe18f8ca2bacbc144fb5386f7fbcc", + "contracts/RandomBeaconChaosnet.sol/RandomBeaconChaosnet.json": "98a2c106c70ba39847fed3f0eeb9a27cd18e6680b3f1821248ba180dc9ff7ec5", + "contracts/RandomBeaconGovernance.sol/RandomBeaconGovernance.json": "f5a550ccfd1f5f5f060ec2359e59a9597e9fd7b526cd923967e2a019a172b441", + "contracts/test/RandomBeaconStub.sol/RandomBeaconStub.json": "e060d03716c5703b12934a0184f1ba4d24963f5ae2e7086c1dbd76ba36fa6bb2", + "contracts/ReimbursementPool.sol/ReimbursementPool.json": "6076f9f9976433461dd02d9d27f51681e45cd84c824cf51f6e140e7a6b986865", + "@keep-network/sortition-pools/contracts/SortitionPool.sol/SortitionPool.json": "ee2ce2742667798646a19ea4bdf4fcc77779f0d42f5f498889ba11fcddff584e" + }, + "changes": [ + "Only required legacy artifacts are retained.", + "Duplicate evm assembly/opcodes are omitted; ABI, bytecode, metadata, and storage layout are preserved.", + "Existing locally corrected deployment scripts are retained." + ] +} diff --git a/solidity/ecdsa/external/random-beacon-export/artifacts/@keep-network/sortition-pools/contracts/SortitionPool.sol/SortitionPool.json b/solidity/ecdsa/external/random-beacon-export/artifacts/@keep-network/sortition-pools/contracts/SortitionPool.sol/SortitionPool.json new file mode 100644 index 0000000000..91090a6299 --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/artifacts/@keep-network/sortition-pools/contracts/SortitionPool.sol/SortitionPool.json @@ -0,0 +1,1142 @@ +{ + "contractName": "SortitionPool", + "sourceName": "@keep-network/sortition-pools/contracts/SortitionPool.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "contract IERC20WithPermit", + "name": "_rewardToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_poolWeightDivisor", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address[]", + "name": "operators", + "type": "address[]" + } + ], + "name": "BetaOperatorsAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "ChaosnetDeactivated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldChaosnetOwner", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newChaosnetOwner", + "type": "address" + } + ], + "name": "ChaosnetOwnerRoleTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint32[]", + "name": "ids", + "type": "uint32[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "until", + "type": "uint256" + } + ], + "name": "IneligibleForRewards", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint32", + "name": "id", + "type": "uint32" + } + ], + "name": "RewardEligibilityRestored", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "operators", + "type": "address[]" + } + ], + "name": "addBetaOperators", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "canRestoreRewardEligibility", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "chaosnetOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "deactivateChaosnet", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "getAvailableRewards", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "id", + "type": "uint32" + } + ], + "name": "getIDOperator", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32[]", + "name": "ids", + "type": "uint32[]" + } + ], + "name": "getIDOperators", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "getOperatorID", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "getPoolWeight", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ineligibleEarnedRewards", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "authorizedStake", + "type": "uint256" + } + ], + "name": "insertOperator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isBetaOperator", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isChaosnetActive", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isEligibleForRewards", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isLocked", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isOperatorInPool", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isOperatorRegistered", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "authorizedStake", + "type": "uint256" + } + ], + "name": "isOperatorUpToDate", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "operatorsInPool", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "poolWeightDivisor", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "receiveApproval", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "restoreRewardEligibility", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "rewardToken", + "outputs": [ + { + "internalType": "contract IERC20WithPermit", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "rewardsEligibilityRestorableAt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "groupSize", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "seed", + "type": "bytes32" + } + ], + "name": "selectGroup", + "outputs": [ + { + "internalType": "uint32[]", + "name": "", + "type": "uint32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32[]", + "name": "operators", + "type": "uint32[]" + }, + { + "internalType": "uint256", + "name": "until", + "type": "uint256" + } + ], + "name": "setRewardIneligibility", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "totalWeight", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newChaosnetOwner", + "type": "address" + } + ], + "name": "transferChaosnetOwnerRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unlock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "authorizedStake", + "type": "uint256" + } + ], + "name": "updateOperatorStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + } + ], + "name": "withdrawIneligible", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "address", + "name": "beneficiary", + "type": "address" + } + ], + "name": "withdrawRewards", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x60e06040523480156200001157600080fd5b5060405162002c7138038062002c71833981016040819052620000349162000140565b6000808055600481905560078054600101815590524260805262000058336200008d565b6200006333620000df565b600b805460ff60a01b1916600160a01b1790556001600160a01b0390911660a05260c0526200017c565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600d80546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527ff7d2871c195d5dcbeca7c9bfb4f7ae4149d0915a5d3d03c8c2286c9a24e932be910160405180910390a15050565b600080604083850312156200015457600080fd5b82516001600160a01b03811681146200016c57600080fd5b6020939093015192949293505050565b60805160a05160c051612a9b620001d6600039600081816102a6015261139001526000818161050101528181610ac801528181610b6701528181610cfb0152610fb10152600081816113040152611aa50152612a9b6000f3fe608060405234801561001057600080fd5b506004361061021b5760003560e01c806396c82e5711610125578063dc7520c5116100ad578063f2fde38b1161007c578063f2fde38b146104e9578063f7186ce014610329578063f7c618c1146104fc578063f7f9a8fa14610523578063f83d08ba1461054357600080fd5b8063dc7520c5146104b3578063e20981ca146104c6578063e7bfd899146104d9578063f23baf4a146104e157600080fd5b8063a9649414116100f4578063a964941414610453578063b0f3828e14610466578063b2f3db4d1461047a578063c0a3f9eb1461048d578063c545b3a9146104a057600080fd5b806396c82e571461041c578063a4e2d63414610424578063a69df4b514610438578063a7a7d3911461044057600080fd5b80636b1906f8116101a8578063873e31fa11610177578063873e31fa146103a75780638871ca5d146103d25780638da5cb5b146103e55780638f4ffcb1146103f6578063942f68921461040957600080fd5b80636b1906f8146103295780636c2530b914610354578063715018a6146103745780637c2cf6cd1461037c57600080fd5b806343a3db30116101ef57806343a3db30146102a15780634de824f0146102c85780635757ed5b146102db5780635a48b46b146102ee578063660186e61461031657600080fd5b8062983b7314610220578063241a418814610246578063398ece9c1461025b5780633e723fc91461028e575b600080fd5b61023361022e3660046123d2565b61054b565b6040519081526020015b60405180910390f35b6102596102543660046123ed565b610569565b005b61027e6102693660046123d2565b600c6020526000908152604090205460ff1681565b604051901515815260200161023d565b61025961029c36600461245c565b6106be565b6102337f000000000000000000000000000000000000000000000000000000000000000081565b61027e6102d63660046123ed565b6107ea565b6102336102e93660046123d2565b610808565b6103016102fc3660046123d2565b610856565b60405163ffffffff909116815260200161023d565b61027e6103243660046123d2565b610877565b61027e6103373660046123d2565b6001600160a01b0316600090815260036020526040902054151590565b61036761036236600461249e565b6108ac565b60405161023d91906124c0565b610259610a4e565b600d5461038f906001600160a01b031681565b6040516001600160a01b03909116815260200161023d565b6103ba6103b53660046123d2565b610a62565b6040516001600160601b03909116815260200161023d565b61038f6103e036600461251e565b610a79565b600b546001600160a01b031661038f565b610259610404366004612539565b610ac6565b6102596104173660046125d4565b610bf0565b610233610c76565b600d5461027e90600160a01b900460ff1681565b610259610c88565b6009546103ba906001600160601b031681565b6102596104613660046123d2565b610c9f565b600b5461027e90600160a01b900460ff1681565b6102596104883660046123d2565b610d6f565b61027e61049b3660046123d2565b610dc5565b6102596104ae3660046123d2565b610ddc565b6102596104c13660046123ed565b610e7c565b6103ba6104d4366004612620565b610f1a565b610233611029565b610259611044565b6102596104f73660046123d2565b6110f8565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b61053661053136600461245c565b61116e565b60405161023d9190612653565b610259611271565b60008061055783610856565b90506105628161128e565b9392505050565b61057161132f565b600d54600160a01b900460ff16156105c85760405162461bcd60e51b815260206004820152601560248201527414dbdc9d1a5d1a5bdb881c1bdbdb081b1bd8dad959605a1b60448201526064015b60405180910390fd5b60006105d382611389565b90506000811161061d5760405162461bcd60e51b81526020600482015260156024820152744f70657261746f72206e6f7420656c696769626c6560581b60448201526064016105bf565b600b54600160a01b900460ff1615610697576001600160a01b0383166000908152600c602052604090205460ff166106975760405162461bcd60e51b815260206004820152601e60248201527f4e6f742062657461206f70657261746f7220666f72206368616f736e6574000060448201526064016105bf565b6106a183826113b5565b60006106ac84610856565b90506106b881836114ab565b50505050565b600b54600160a01b900460ff166107105760405162461bcd60e51b81526020600482015260166024820152754368616f736e6574206973206e6f742061637469766560501b60448201526064016105bf565b600d546001600160a01b0316331461073a5760405162461bcd60e51b81526004016105bf90612694565b60005b818110156107ac576001600c600085858581811061075d5761075d6126c4565b905060200201602081019061077291906123d2565b6001600160a01b031681526020810191909152604001600020805460ff1916911515919091179055806107a4816126f0565b91505061073d565b507f79b60dc9f29a0514f5ce9bf1e89b7add7a22440cde3b203c03a842e3b534071b82826040516107de929190612709565b60405180910390a15050565b60006107f583610808565b6107fe83611389565b1490505b92915050565b6001600160a01b038116600090815260036020526040812054806000036108325750600092915050565b6001600160ff1b038116600061084782611631565b95945050505050565b50919050565b6001600160a01b031660009081526006602052604090205463ffffffff1690565b60008061088383610856565b90506105628163ffffffff9081166000908152600a6020526040902054600160c01b9004161590565b600d54606090600160a01b900460ff166109085760405162461bcd60e51b815260206004820152601760248201527f536f72746974696f6e20706f6f6c20756e6c6f636b656400000000000000000060448201526064016105bf565b600080549083906109188361168e565b90506000811161096a5760405162461bcd60e51b815260206004820152601c60248201527f4e6f7420656e6f756768206f70657261746f727320696e20706f6f6c0000000060448201526064016105bf565b600080610976836116b5565b905060008867ffffffffffffffff81111561099357610993612755565b6040519080825280602002602001820160405280156109bc578160200160208202803683370190505b50905060005b89811015610a41576109d58587856116e7565b9650935060006109e5858961175f565b600081815260026020526040902054909150610a008161182a565b848481518110610a1257610a126126c4565b602002602001019063ffffffff16908163ffffffff168152505050508080610a39906126f0565b9150506109c2565b5098975050505050505050565b610a5661132f565b610a606000611863565b565b600080610a6e83610856565b9050610562816118b5565b60075460009063ffffffff831610610a92576000610802565b60078263ffffffff1681548110610aab57610aab6126c4565b6000918252602090912001546001600160a01b031692915050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b031614610b3b5760405162461bcd60e51b81526020600482015260116024820152702ab739bab83837b93a32b2103a37b5b2b760791b60448201526064016105bf565b6040516323b872dd60e01b81526001600160a01b038681166004830152306024830152604482018690527f000000000000000000000000000000000000000000000000000000000000000016906323b872dd906064016020604051808303816000875af1158015610bb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bd4919061276b565b50610be984610be460005461168e565b611963565b5050505050565b610bf861132f565b610c36838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250859250611a6b915050565b7f01f5838e3dde8cf4817b958fe95be92bdfeccb34317e1d9f58d1cfe5230de231838383604051610c699392919061278d565b60405180910390a1505050565b6000610c8360005461168e565b905090565b610c9061132f565b600d805460ff60a01b19169055565b610ca761132f565b6000610cca600980546001600160601b031981169091556001600160601b031690565b60405163a9059cbb60e01b81526001600160a01b0384811660048301526001600160601b03831660248301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af1158015610d46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6a919061276b565b505050565b6000610d7a82610856565b9050610d8581611c6d565b60405163ffffffff8216906001600160a01b038416907fe61e9f0f049b3bfae1ae903a5e3018c02a008aa0d238ffddf23a4fb4c027853690600090a35050565b600080610dd183610856565b905061056281611e09565b600d546001600160a01b03163314610e065760405162461bcd60e51b81526004016105bf90612694565b6001600160a01b038116610e705760405162461bcd60e51b815260206004820152602b60248201527f4e6577206368616f736e6574206f776e6572206d757374206e6f74206265207a60448201526a65726f206164647265737360a81b60648201526084016105bf565b610e7981611e1d565b50565b610e8461132f565b600d54600160a01b900460ff1615610ed65760405162461bcd60e51b815260206004820152601560248201527414dbdc9d1a5d1a5bdb881c1bdbdb081b1bd8dad959605a1b60448201526064016105bf565b6000610ee182611389565b90506000610eee84610856565b9050610efa81836114ab565b81600003610f1057610f0b84611e77565b6106b8565b6106b88483611eeb565b6000610f2461132f565b6000610f2f84610856565b9050610f4381610f3e86610808565b6114ab565b63ffffffff81166000908152600a6020526040812080546bffffffffffffffffffffffff60601b198116909155600160601b90046001600160601b031660405163a9059cbb60e01b81526001600160a01b0386811660048301526001600160601b03831660248301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af1158015610ffc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611020919061276b565b50949350505050565b6004546005546000919061103d81836127de565b9250505090565b600b54600160a01b900460ff166110965760405162461bcd60e51b81526020600482015260166024820152754368616f736e6574206973206e6f742061637469766560501b60448201526064016105bf565b600d546001600160a01b031633146110c05760405162461bcd60e51b81526004016105bf90612694565b600b805460ff60a01b191690556040517fbea11dc6cfde2788be7e8a6ceef5c8d181bb1c628ba6d71675fca0e754367c7490600090a1565b61110061132f565b6001600160a01b0381166111655760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016105bf565b610e7981611863565b60075460609060008367ffffffffffffffff81111561118f5761118f612755565b6040519080825280602002602001820160405280156111b8578160200160208202803683370190505b50905060005b848110156110205760008686838181106111da576111da6126c4565b90506020020160208101906111ef919061251e565b90508063ffffffff168411611205576000611234565b60078163ffffffff168154811061121e5761121e6126c4565b6000918252602090912001546001600160a01b03165b838381518110611246576112466126c4565b6001600160a01b03909216602092830291909101909101525080611269816126f0565b9150506111be565b61127961132f565b600d805460ff60a01b1916600160a01b179055565b63ffffffff8082166000908152600a60205260408120549091600160c01b909104168082036112ff5760405162461bcd60e51b815260206004820152601960248201527f4f70657261746f7220616c726561647920656c696769626c650000000000000060448201526064016105bf565b6105627f000000000000000000000000000000000000000000000000000000000000000063ffffffff83166127f1565b600b546001600160a01b03163314610a605760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016105bf565b60006108027f00000000000000000000000000000000000000000000000000000000000000008361281a565b6001600160a01b0382166000908152600360205260409020541561142e5760405162461bcd60e51b815260206004820152602a60248201527f4f70657261746f7220697320616c7265616479207265676973746572656420696044820152691b881d1a19481c1bdbdb60b21b60648201526084016105bf565b600061143983610856565b63ffffffff169050806000036114555761145283611f5c565b90505b600061145f61201f565b9050600061146e854385612102565b905061147e8282866000546121db565b600055600160ff1b82176001600160a01b0390951660009081526003602052604090209490945550505050565b60085463ffffffff8084166000908152600a60209081526040808320815160808101835290546001600160601b03818116808452600160601b8304821695840195909552600160c01b8204871693830193909352600160e01b9004909416606085018190529416939061151e908561282e565b6115289190612855565b9050816040015163ffffffff1660000361155f57808260200181815161154e9190612880565b6001600160601b03169052506115a2565b6009805482919060009061157d9084906001600160601b0316612880565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b506001600160601b03918216815263ffffffff928316606082019081529383166000908152600a60209081526040918290208351815492850151939094015196518616600160e01b026001600160e01b0397909616600160c01b02969096166001600160c01b03928516600160601b026001600160c01b03199092169390941692909217919091171617179055565b60008061163d836121f7565b9050600061164b8460031c90565b60008181527fdc686ec4a0ff239c70e7c7c36e8f853eced3bc8618f48d2b816da2a74311237e602052604090205490915061084781846020021c63ffffffff1690565b63ffffffff8116602082901c5b80156108505763ffffffff8116919091019060201c61169b565b6000816001036116c757506000919050565b601f5b82816001901b106116de57600019016116ca565b60010192915050565b6000808080855b82611752576000196001871b0181169150803060405160200161172892919091825260601b6001600160601b031916602082015260340190565b6040516020818303038152906040528051906020012090508782101561174d57600192505b6116ee565b9097909650945050505050565b60008282828061176e8361168e565b87106117b35760405162461bcd60e51b8152602060048201526014602482015273125b99195e08195e18d959591cc81dd95a59da1d60621b60448201526064016105bf565b6117bd8385612207565b9450905060025b60078111611814576117d6838361223e565b6000828152600160209081526040808320848452909152902054945092506117fe8486612207565b955091508061180c816126f0565b9150506117c4565b5061181f828261223e565b979650505050505050565b6000600161183a60036002612984565b6118469061010061281a565b611851906002612984565b61185b91906127de565b909116919050565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60085463ffffffff8083166000908152600a60209081526040808320815160808101835290546001600160601b038181168352600160601b8204811694830194909452600160c01b81048616928201839052600160e01b9004909416606085015291931691908303611958576060810151815160009163ffffffff169061193c908561282e565b6119469190612855565b90508082602001516108479190612880565b602001519392505050565b60008163ffffffff16116119b15760405162461bcd60e51b8152602060048201526015602482015274139bc81c9958da5c1a595b9d1cc81a5b881c1bdbdb605a1b60448201526064016105bf565b6008546000906119d190600160601b90046001600160601b031684612880565b905060006119e563ffffffff841683612990565b905060006119f963ffffffff8516846129b6565b600880549192508391600090611a199084906001600160601b0316612880565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550806008600c6101000a8154816001600160601b0302191690836001600160601b031602179055505050505050565b604080516080810182526000808252602082018190529181018290526060810182905260085490916001600160601b039091169080611aca7f0000000000000000000000000000000000000000000000000000000000000000866127de565b905060005b8651811015611c64576000878281518110611aec57611aec6126c4565b60209081029190910181015163ffffffff8082166000908152600a845260409081902080546001600160601b03600160601b82048116968d01969096529485168b52600160c01b85048316918b01829052600160e01b90940490911660608a015290925015611b7f578363ffffffff16876040015163ffffffff161015611b7a5763ffffffff841660408801525b611bcb565b63ffffffff808516604089015260608801518851911690611ba0908861282e565b611baa9190612855565b94508487602001818151611bbe9190612880565b6001600160601b03169052505b6001600160601b038681168089526020890151835460408b015160608c01516001600160e01b0319909216600160601b93909516929092027fffffffff00000000ffffffffffffffffffffffff0000000000000000000000001693909317909117600160c01b63ffffffff92831602176001600160e01b0316600160e01b91909216021790555080611c5c816126f0565b915050611acf565b50505050505050565b611c7681611e09565b611cc25760405162461bcd60e51b815260206004820152601960248201527f4f70657261746f72207374696c6c20696e656c696769626c650000000000000060448201526064016105bf565b60085463ffffffff8083166000908152600a60209081526040808320815160808101835290546001600160601b03818116808452600160601b8304821695840195909552600160c01b8204871693830193909352600160e01b90049094166060850181905294169390611d35908561282e565b611d3f9190612855565b600980549192508291600090611d5f9084906001600160601b0316612880565b82546001600160601b039182166101009390930a928302928202191691909117909155938416835250506000604080830182815263ffffffff9586168352600a602090815291909220835181549285015193516060909501518716600160e01b026001600160e01b0395909716600160c01b02949094166001600160c01b03938616600160601b026001600160c01b03199093169490951693909317171691909117919091179055565b600042611e158361128e565b111592915050565b600d80546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527ff7d2871c195d5dcbeca7c9bfb4f7ae4149d0915a5d3d03c8c2286c9a24e932be91016107de565b6001600160a01b03811660009081526003602052604081205490819003611eb05760405162461bcd60e51b81526004016105bf906129dc565b60006001600160ff1b0382169050611eca81600054612268565b600055610d6a836001600160a01b0316600090815260036020526040812055565b6001600160a01b038216600090815260036020526040902054611f205760405162461bcd60e51b81526004016105bf906129dc565b6001600160a01b03821660009081526003602052604081205490546001600160ff1b03821690611f5390829085906122dd565b60005550505050565b60075460009063ffffffff811115611faf5760405162461bcd60e51b8152602060048201526016602482015275141bdbdb0818d85c1858da5d1e48195e18d95959195960521b60448201526064016105bf565b6001600160a01b03929092166000818152600660205260408120805463ffffffff191663ffffffff86161790556007805460018101825591527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6880180546001600160a01b03191690911790555090565b60045460009081600761203460036002612984565b61203e9190612984565b6120498360016127f1565b10905080156120665761205d8260016127f1565b60045550919050565b600554806120a55760405162461bcd60e51b815260206004820152600c60248201526b141bdbdb081a5cc8199d5b1b60a21b60448201526064016105bf565b600060056120b46001846127de565b815481106120c4576120c46126c4565b9060005260206000200154905060058054806120e2576120e2612a22565b600190038181906000526020600020016000905590558094505050505090565b600067ffffffffffffffff83111561211c5761211c612a38565b63ffffffff82111561213057612130612a38565b6001600160601b0319606085901b166000600161214f60036002612984565b61215b9061010061281a565b612166906002612984565b61217091906127de565b84169050600061218260036002612984565b61218e9061010061281a565b600161219c60036002612984565b6121a89061010061281a565b6121b39060606127de565b6121be906002612984565b6121c891906127de565b8716901b92909217179150509392505050565b6000848152600260205260408120849055610847858484612307565b6000600161185160036002612984565b6000818363ffffffff81165b80831061223457600193909301929091039060201c63ffffffff8116612213565b50505b9250929050565b6000600161224e60036002612984565b61225891906127de565b8216600384901b17905092915050565b600080600160045461227a91906127de565b9050838114600061228d868280886121db565b9050811561229f576004839055610847565b600580546001810182556000919091527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00186905595945050505050565b6000826122e985611631565b14612300576122f9848484612307565b9050610562565b5080610562565b6000808080858760075b6002811061238857612322826121f7565b955061232e8260031c90565b60008281526001602090815260408083208484528252909120805463ffffffff928a0283811b198216938816901b9290921790819055909650945091506123748461168e565b92508061238081612a4e565b915050612311565b50612392816121f7565b945063ffffffff6020860281811b198916918416901b179998505050505050505050565b80356001600160a01b03811681146123cd57600080fd5b919050565b6000602082840312156123e457600080fd5b610562826123b6565b6000806040838503121561240057600080fd5b612409836123b6565b946020939093013593505050565b60008083601f84011261242957600080fd5b50813567ffffffffffffffff81111561244157600080fd5b6020830191508360208260051b850101111561223757600080fd5b6000806020838503121561246f57600080fd5b823567ffffffffffffffff81111561248657600080fd5b61249285828601612417565b90969095509350505050565b600080604083850312156124b157600080fd5b50508035926020909101359150565b6020808252825182820181905260009190848201906040850190845b818110156124fe57835163ffffffff16835292840192918401916001016124dc565b50909695505050505050565b803563ffffffff811681146123cd57600080fd5b60006020828403121561253057600080fd5b6105628261250a565b60008060008060006080868803121561255157600080fd5b61255a866123b6565b94506020860135935061256f604087016123b6565b9250606086013567ffffffffffffffff8082111561258c57600080fd5b818801915088601f8301126125a057600080fd5b8135818111156125af57600080fd5b8960208285010111156125c157600080fd5b9699959850939650602001949392505050565b6000806000604084860312156125e957600080fd5b833567ffffffffffffffff81111561260057600080fd5b61260c86828701612417565b909790965060209590950135949350505050565b6000806040838503121561263357600080fd5b61263c836123b6565b915061264a602084016123b6565b90509250929050565b6020808252825182820181905260009190848201906040850190845b818110156124fe5783516001600160a01b03168352928401929184019160010161266f565b6020808252601690820152752737ba103a34329031b430b7b9b732ba1037bbb732b960511b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612702576127026126da565b5060010190565b60208082528181018390526000908460408401835b8681101561274a576001600160a01b03612737846123b6565b168252918301919083019060010161271e565b509695505050505050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561277d57600080fd5b8151801515811461056257600080fd5b6040808252810183905260008460608301825b868110156127cb5763ffffffff6127b68461250a565b168252602092830192909101906001016127a0565b5060209390930193909352509392505050565b81810381811115610802576108026126da565b80820180821115610802576108026126da565b634e487b7160e01b600052601260045260246000fd5b60008261282957612829612804565b500490565b6001600160601b0382811682821603908082111561284e5761284e6126da565b5092915050565b6001600160601b03818116838216028082169190828114612878576128786126da565b505092915050565b6001600160601b0381811683821601908082111561284e5761284e6126da565b600181815b808511156128db5781600019048211156128c1576128c16126da565b808516156128ce57918102915b93841c93908002906128a5565b509250929050565b6000826128f257506001610802565b816128ff57506000610802565b8160018114612915576002811461291f5761293b565b6001915050610802565b60ff841115612930576129306126da565b50506001821b610802565b5060208310610133831016604e8410600b841016171561295e575081810a610802565b61296883836128a0565b806000190482111561297c5761297c6126da565b029392505050565b600061056283836128e3565b60006001600160601b03808416806129aa576129aa612804565b92169190910492915050565b60006001600160601b03808416806129d0576129d0612804565b92169190910692915050565b60208082526026908201527f4f70657261746f72206973206e6f74207265676973746572656420696e20746860408201526519481c1bdbdb60d21b606082015260800190565b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052600160045260246000fd5b600081612a5d57612a5d6126da565b50600019019056fea26469706673582212200777efb6bbaffaf3c12f9366651c0738fd0510bf19a96c3af0a337226cca78d364736f6c63430008110033", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061021b5760003560e01c806396c82e5711610125578063dc7520c5116100ad578063f2fde38b1161007c578063f2fde38b146104e9578063f7186ce014610329578063f7c618c1146104fc578063f7f9a8fa14610523578063f83d08ba1461054357600080fd5b8063dc7520c5146104b3578063e20981ca146104c6578063e7bfd899146104d9578063f23baf4a146104e157600080fd5b8063a9649414116100f4578063a964941414610453578063b0f3828e14610466578063b2f3db4d1461047a578063c0a3f9eb1461048d578063c545b3a9146104a057600080fd5b806396c82e571461041c578063a4e2d63414610424578063a69df4b514610438578063a7a7d3911461044057600080fd5b80636b1906f8116101a8578063873e31fa11610177578063873e31fa146103a75780638871ca5d146103d25780638da5cb5b146103e55780638f4ffcb1146103f6578063942f68921461040957600080fd5b80636b1906f8146103295780636c2530b914610354578063715018a6146103745780637c2cf6cd1461037c57600080fd5b806343a3db30116101ef57806343a3db30146102a15780634de824f0146102c85780635757ed5b146102db5780635a48b46b146102ee578063660186e61461031657600080fd5b8062983b7314610220578063241a418814610246578063398ece9c1461025b5780633e723fc91461028e575b600080fd5b61023361022e3660046123d2565b61054b565b6040519081526020015b60405180910390f35b6102596102543660046123ed565b610569565b005b61027e6102693660046123d2565b600c6020526000908152604090205460ff1681565b604051901515815260200161023d565b61025961029c36600461245c565b6106be565b6102337f000000000000000000000000000000000000000000000000000000000000000081565b61027e6102d63660046123ed565b6107ea565b6102336102e93660046123d2565b610808565b6103016102fc3660046123d2565b610856565b60405163ffffffff909116815260200161023d565b61027e6103243660046123d2565b610877565b61027e6103373660046123d2565b6001600160a01b0316600090815260036020526040902054151590565b61036761036236600461249e565b6108ac565b60405161023d91906124c0565b610259610a4e565b600d5461038f906001600160a01b031681565b6040516001600160a01b03909116815260200161023d565b6103ba6103b53660046123d2565b610a62565b6040516001600160601b03909116815260200161023d565b61038f6103e036600461251e565b610a79565b600b546001600160a01b031661038f565b610259610404366004612539565b610ac6565b6102596104173660046125d4565b610bf0565b610233610c76565b600d5461027e90600160a01b900460ff1681565b610259610c88565b6009546103ba906001600160601b031681565b6102596104613660046123d2565b610c9f565b600b5461027e90600160a01b900460ff1681565b6102596104883660046123d2565b610d6f565b61027e61049b3660046123d2565b610dc5565b6102596104ae3660046123d2565b610ddc565b6102596104c13660046123ed565b610e7c565b6103ba6104d4366004612620565b610f1a565b610233611029565b610259611044565b6102596104f73660046123d2565b6110f8565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b61053661053136600461245c565b61116e565b60405161023d9190612653565b610259611271565b60008061055783610856565b90506105628161128e565b9392505050565b61057161132f565b600d54600160a01b900460ff16156105c85760405162461bcd60e51b815260206004820152601560248201527414dbdc9d1a5d1a5bdb881c1bdbdb081b1bd8dad959605a1b60448201526064015b60405180910390fd5b60006105d382611389565b90506000811161061d5760405162461bcd60e51b81526020600482015260156024820152744f70657261746f72206e6f7420656c696769626c6560581b60448201526064016105bf565b600b54600160a01b900460ff1615610697576001600160a01b0383166000908152600c602052604090205460ff166106975760405162461bcd60e51b815260206004820152601e60248201527f4e6f742062657461206f70657261746f7220666f72206368616f736e6574000060448201526064016105bf565b6106a183826113b5565b60006106ac84610856565b90506106b881836114ab565b50505050565b600b54600160a01b900460ff166107105760405162461bcd60e51b81526020600482015260166024820152754368616f736e6574206973206e6f742061637469766560501b60448201526064016105bf565b600d546001600160a01b0316331461073a5760405162461bcd60e51b81526004016105bf90612694565b60005b818110156107ac576001600c600085858581811061075d5761075d6126c4565b905060200201602081019061077291906123d2565b6001600160a01b031681526020810191909152604001600020805460ff1916911515919091179055806107a4816126f0565b91505061073d565b507f79b60dc9f29a0514f5ce9bf1e89b7add7a22440cde3b203c03a842e3b534071b82826040516107de929190612709565b60405180910390a15050565b60006107f583610808565b6107fe83611389565b1490505b92915050565b6001600160a01b038116600090815260036020526040812054806000036108325750600092915050565b6001600160ff1b038116600061084782611631565b95945050505050565b50919050565b6001600160a01b031660009081526006602052604090205463ffffffff1690565b60008061088383610856565b90506105628163ffffffff9081166000908152600a6020526040902054600160c01b9004161590565b600d54606090600160a01b900460ff166109085760405162461bcd60e51b815260206004820152601760248201527f536f72746974696f6e20706f6f6c20756e6c6f636b656400000000000000000060448201526064016105bf565b600080549083906109188361168e565b90506000811161096a5760405162461bcd60e51b815260206004820152601c60248201527f4e6f7420656e6f756768206f70657261746f727320696e20706f6f6c0000000060448201526064016105bf565b600080610976836116b5565b905060008867ffffffffffffffff81111561099357610993612755565b6040519080825280602002602001820160405280156109bc578160200160208202803683370190505b50905060005b89811015610a41576109d58587856116e7565b9650935060006109e5858961175f565b600081815260026020526040902054909150610a008161182a565b848481518110610a1257610a126126c4565b602002602001019063ffffffff16908163ffffffff168152505050508080610a39906126f0565b9150506109c2565b5098975050505050505050565b610a5661132f565b610a606000611863565b565b600080610a6e83610856565b9050610562816118b5565b60075460009063ffffffff831610610a92576000610802565b60078263ffffffff1681548110610aab57610aab6126c4565b6000918252602090912001546001600160a01b031692915050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b031614610b3b5760405162461bcd60e51b81526020600482015260116024820152702ab739bab83837b93a32b2103a37b5b2b760791b60448201526064016105bf565b6040516323b872dd60e01b81526001600160a01b038681166004830152306024830152604482018690527f000000000000000000000000000000000000000000000000000000000000000016906323b872dd906064016020604051808303816000875af1158015610bb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bd4919061276b565b50610be984610be460005461168e565b611963565b5050505050565b610bf861132f565b610c36838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250859250611a6b915050565b7f01f5838e3dde8cf4817b958fe95be92bdfeccb34317e1d9f58d1cfe5230de231838383604051610c699392919061278d565b60405180910390a1505050565b6000610c8360005461168e565b905090565b610c9061132f565b600d805460ff60a01b19169055565b610ca761132f565b6000610cca600980546001600160601b031981169091556001600160601b031690565b60405163a9059cbb60e01b81526001600160a01b0384811660048301526001600160601b03831660248301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af1158015610d46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6a919061276b565b505050565b6000610d7a82610856565b9050610d8581611c6d565b60405163ffffffff8216906001600160a01b038416907fe61e9f0f049b3bfae1ae903a5e3018c02a008aa0d238ffddf23a4fb4c027853690600090a35050565b600080610dd183610856565b905061056281611e09565b600d546001600160a01b03163314610e065760405162461bcd60e51b81526004016105bf90612694565b6001600160a01b038116610e705760405162461bcd60e51b815260206004820152602b60248201527f4e6577206368616f736e6574206f776e6572206d757374206e6f74206265207a60448201526a65726f206164647265737360a81b60648201526084016105bf565b610e7981611e1d565b50565b610e8461132f565b600d54600160a01b900460ff1615610ed65760405162461bcd60e51b815260206004820152601560248201527414dbdc9d1a5d1a5bdb881c1bdbdb081b1bd8dad959605a1b60448201526064016105bf565b6000610ee182611389565b90506000610eee84610856565b9050610efa81836114ab565b81600003610f1057610f0b84611e77565b6106b8565b6106b88483611eeb565b6000610f2461132f565b6000610f2f84610856565b9050610f4381610f3e86610808565b6114ab565b63ffffffff81166000908152600a6020526040812080546bffffffffffffffffffffffff60601b198116909155600160601b90046001600160601b031660405163a9059cbb60e01b81526001600160a01b0386811660048301526001600160601b03831660248301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af1158015610ffc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611020919061276b565b50949350505050565b6004546005546000919061103d81836127de565b9250505090565b600b54600160a01b900460ff166110965760405162461bcd60e51b81526020600482015260166024820152754368616f736e6574206973206e6f742061637469766560501b60448201526064016105bf565b600d546001600160a01b031633146110c05760405162461bcd60e51b81526004016105bf90612694565b600b805460ff60a01b191690556040517fbea11dc6cfde2788be7e8a6ceef5c8d181bb1c628ba6d71675fca0e754367c7490600090a1565b61110061132f565b6001600160a01b0381166111655760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016105bf565b610e7981611863565b60075460609060008367ffffffffffffffff81111561118f5761118f612755565b6040519080825280602002602001820160405280156111b8578160200160208202803683370190505b50905060005b848110156110205760008686838181106111da576111da6126c4565b90506020020160208101906111ef919061251e565b90508063ffffffff168411611205576000611234565b60078163ffffffff168154811061121e5761121e6126c4565b6000918252602090912001546001600160a01b03165b838381518110611246576112466126c4565b6001600160a01b03909216602092830291909101909101525080611269816126f0565b9150506111be565b61127961132f565b600d805460ff60a01b1916600160a01b179055565b63ffffffff8082166000908152600a60205260408120549091600160c01b909104168082036112ff5760405162461bcd60e51b815260206004820152601960248201527f4f70657261746f7220616c726561647920656c696769626c650000000000000060448201526064016105bf565b6105627f000000000000000000000000000000000000000000000000000000000000000063ffffffff83166127f1565b600b546001600160a01b03163314610a605760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016105bf565b60006108027f00000000000000000000000000000000000000000000000000000000000000008361281a565b6001600160a01b0382166000908152600360205260409020541561142e5760405162461bcd60e51b815260206004820152602a60248201527f4f70657261746f7220697320616c7265616479207265676973746572656420696044820152691b881d1a19481c1bdbdb60b21b60648201526084016105bf565b600061143983610856565b63ffffffff169050806000036114555761145283611f5c565b90505b600061145f61201f565b9050600061146e854385612102565b905061147e8282866000546121db565b600055600160ff1b82176001600160a01b0390951660009081526003602052604090209490945550505050565b60085463ffffffff8084166000908152600a60209081526040808320815160808101835290546001600160601b03818116808452600160601b8304821695840195909552600160c01b8204871693830193909352600160e01b9004909416606085018190529416939061151e908561282e565b6115289190612855565b9050816040015163ffffffff1660000361155f57808260200181815161154e9190612880565b6001600160601b03169052506115a2565b6009805482919060009061157d9084906001600160601b0316612880565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b506001600160601b03918216815263ffffffff928316606082019081529383166000908152600a60209081526040918290208351815492850151939094015196518616600160e01b026001600160e01b0397909616600160c01b02969096166001600160c01b03928516600160601b026001600160c01b03199092169390941692909217919091171617179055565b60008061163d836121f7565b9050600061164b8460031c90565b60008181527fdc686ec4a0ff239c70e7c7c36e8f853eced3bc8618f48d2b816da2a74311237e602052604090205490915061084781846020021c63ffffffff1690565b63ffffffff8116602082901c5b80156108505763ffffffff8116919091019060201c61169b565b6000816001036116c757506000919050565b601f5b82816001901b106116de57600019016116ca565b60010192915050565b6000808080855b82611752576000196001871b0181169150803060405160200161172892919091825260601b6001600160601b031916602082015260340190565b6040516020818303038152906040528051906020012090508782101561174d57600192505b6116ee565b9097909650945050505050565b60008282828061176e8361168e565b87106117b35760405162461bcd60e51b8152602060048201526014602482015273125b99195e08195e18d959591cc81dd95a59da1d60621b60448201526064016105bf565b6117bd8385612207565b9450905060025b60078111611814576117d6838361223e565b6000828152600160209081526040808320848452909152902054945092506117fe8486612207565b955091508061180c816126f0565b9150506117c4565b5061181f828261223e565b979650505050505050565b6000600161183a60036002612984565b6118469061010061281a565b611851906002612984565b61185b91906127de565b909116919050565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60085463ffffffff8083166000908152600a60209081526040808320815160808101835290546001600160601b038181168352600160601b8204811694830194909452600160c01b81048616928201839052600160e01b9004909416606085015291931691908303611958576060810151815160009163ffffffff169061193c908561282e565b6119469190612855565b90508082602001516108479190612880565b602001519392505050565b60008163ffffffff16116119b15760405162461bcd60e51b8152602060048201526015602482015274139bc81c9958da5c1a595b9d1cc81a5b881c1bdbdb605a1b60448201526064016105bf565b6008546000906119d190600160601b90046001600160601b031684612880565b905060006119e563ffffffff841683612990565b905060006119f963ffffffff8516846129b6565b600880549192508391600090611a199084906001600160601b0316612880565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550806008600c6101000a8154816001600160601b0302191690836001600160601b031602179055505050505050565b604080516080810182526000808252602082018190529181018290526060810182905260085490916001600160601b039091169080611aca7f0000000000000000000000000000000000000000000000000000000000000000866127de565b905060005b8651811015611c64576000878281518110611aec57611aec6126c4565b60209081029190910181015163ffffffff8082166000908152600a845260409081902080546001600160601b03600160601b82048116968d01969096529485168b52600160c01b85048316918b01829052600160e01b90940490911660608a015290925015611b7f578363ffffffff16876040015163ffffffff161015611b7a5763ffffffff841660408801525b611bcb565b63ffffffff808516604089015260608801518851911690611ba0908861282e565b611baa9190612855565b94508487602001818151611bbe9190612880565b6001600160601b03169052505b6001600160601b038681168089526020890151835460408b015160608c01516001600160e01b0319909216600160601b93909516929092027fffffffff00000000ffffffffffffffffffffffff0000000000000000000000001693909317909117600160c01b63ffffffff92831602176001600160e01b0316600160e01b91909216021790555080611c5c816126f0565b915050611acf565b50505050505050565b611c7681611e09565b611cc25760405162461bcd60e51b815260206004820152601960248201527f4f70657261746f72207374696c6c20696e656c696769626c650000000000000060448201526064016105bf565b60085463ffffffff8083166000908152600a60209081526040808320815160808101835290546001600160601b03818116808452600160601b8304821695840195909552600160c01b8204871693830193909352600160e01b90049094166060850181905294169390611d35908561282e565b611d3f9190612855565b600980549192508291600090611d5f9084906001600160601b0316612880565b82546001600160601b039182166101009390930a928302928202191691909117909155938416835250506000604080830182815263ffffffff9586168352600a602090815291909220835181549285015193516060909501518716600160e01b026001600160e01b0395909716600160c01b02949094166001600160c01b03938616600160601b026001600160c01b03199093169490951693909317171691909117919091179055565b600042611e158361128e565b111592915050565b600d80546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527ff7d2871c195d5dcbeca7c9bfb4f7ae4149d0915a5d3d03c8c2286c9a24e932be91016107de565b6001600160a01b03811660009081526003602052604081205490819003611eb05760405162461bcd60e51b81526004016105bf906129dc565b60006001600160ff1b0382169050611eca81600054612268565b600055610d6a836001600160a01b0316600090815260036020526040812055565b6001600160a01b038216600090815260036020526040902054611f205760405162461bcd60e51b81526004016105bf906129dc565b6001600160a01b03821660009081526003602052604081205490546001600160ff1b03821690611f5390829085906122dd565b60005550505050565b60075460009063ffffffff811115611faf5760405162461bcd60e51b8152602060048201526016602482015275141bdbdb0818d85c1858da5d1e48195e18d95959195960521b60448201526064016105bf565b6001600160a01b03929092166000818152600660205260408120805463ffffffff191663ffffffff86161790556007805460018101825591527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6880180546001600160a01b03191690911790555090565b60045460009081600761203460036002612984565b61203e9190612984565b6120498360016127f1565b10905080156120665761205d8260016127f1565b60045550919050565b600554806120a55760405162461bcd60e51b815260206004820152600c60248201526b141bdbdb081a5cc8199d5b1b60a21b60448201526064016105bf565b600060056120b46001846127de565b815481106120c4576120c46126c4565b9060005260206000200154905060058054806120e2576120e2612a22565b600190038181906000526020600020016000905590558094505050505090565b600067ffffffffffffffff83111561211c5761211c612a38565b63ffffffff82111561213057612130612a38565b6001600160601b0319606085901b166000600161214f60036002612984565b61215b9061010061281a565b612166906002612984565b61217091906127de565b84169050600061218260036002612984565b61218e9061010061281a565b600161219c60036002612984565b6121a89061010061281a565b6121b39060606127de565b6121be906002612984565b6121c891906127de565b8716901b92909217179150509392505050565b6000848152600260205260408120849055610847858484612307565b6000600161185160036002612984565b6000818363ffffffff81165b80831061223457600193909301929091039060201c63ffffffff8116612213565b50505b9250929050565b6000600161224e60036002612984565b61225891906127de565b8216600384901b17905092915050565b600080600160045461227a91906127de565b9050838114600061228d868280886121db565b9050811561229f576004839055610847565b600580546001810182556000919091527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00186905595945050505050565b6000826122e985611631565b14612300576122f9848484612307565b9050610562565b5080610562565b6000808080858760075b6002811061238857612322826121f7565b955061232e8260031c90565b60008281526001602090815260408083208484528252909120805463ffffffff928a0283811b198216938816901b9290921790819055909650945091506123748461168e565b92508061238081612a4e565b915050612311565b50612392816121f7565b945063ffffffff6020860281811b198916918416901b179998505050505050505050565b80356001600160a01b03811681146123cd57600080fd5b919050565b6000602082840312156123e457600080fd5b610562826123b6565b6000806040838503121561240057600080fd5b612409836123b6565b946020939093013593505050565b60008083601f84011261242957600080fd5b50813567ffffffffffffffff81111561244157600080fd5b6020830191508360208260051b850101111561223757600080fd5b6000806020838503121561246f57600080fd5b823567ffffffffffffffff81111561248657600080fd5b61249285828601612417565b90969095509350505050565b600080604083850312156124b157600080fd5b50508035926020909101359150565b6020808252825182820181905260009190848201906040850190845b818110156124fe57835163ffffffff16835292840192918401916001016124dc565b50909695505050505050565b803563ffffffff811681146123cd57600080fd5b60006020828403121561253057600080fd5b6105628261250a565b60008060008060006080868803121561255157600080fd5b61255a866123b6565b94506020860135935061256f604087016123b6565b9250606086013567ffffffffffffffff8082111561258c57600080fd5b818801915088601f8301126125a057600080fd5b8135818111156125af57600080fd5b8960208285010111156125c157600080fd5b9699959850939650602001949392505050565b6000806000604084860312156125e957600080fd5b833567ffffffffffffffff81111561260057600080fd5b61260c86828701612417565b909790965060209590950135949350505050565b6000806040838503121561263357600080fd5b61263c836123b6565b915061264a602084016123b6565b90509250929050565b6020808252825182820181905260009190848201906040850190845b818110156124fe5783516001600160a01b03168352928401929184019160010161266f565b6020808252601690820152752737ba103a34329031b430b7b9b732ba1037bbb732b960511b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612702576127026126da565b5060010190565b60208082528181018390526000908460408401835b8681101561274a576001600160a01b03612737846123b6565b168252918301919083019060010161271e565b509695505050505050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561277d57600080fd5b8151801515811461056257600080fd5b6040808252810183905260008460608301825b868110156127cb5763ffffffff6127b68461250a565b168252602092830192909101906001016127a0565b5060209390930193909352509392505050565b81810381811115610802576108026126da565b80820180821115610802576108026126da565b634e487b7160e01b600052601260045260246000fd5b60008261282957612829612804565b500490565b6001600160601b0382811682821603908082111561284e5761284e6126da565b5092915050565b6001600160601b03818116838216028082169190828114612878576128786126da565b505092915050565b6001600160601b0381811683821601908082111561284e5761284e6126da565b600181815b808511156128db5781600019048211156128c1576128c16126da565b808516156128ce57918102915b93841c93908002906128a5565b509250929050565b6000826128f257506001610802565b816128ff57506000610802565b8160018114612915576002811461291f5761293b565b6001915050610802565b60ff841115612930576129306126da565b50506001821b610802565b5060208310610133831016604e8410600b841016171561295e575081810a610802565b61296883836128a0565b806000190482111561297c5761297c6126da565b029392505050565b600061056283836128e3565b60006001600160601b03808416806129aa576129aa612804565b92169190910492915050565b60006001600160601b03808416806129d0576129d0612804565b92169190910692915050565b60208082526026908201527f4f70657261746f72206973206e6f74207265676973746572656420696e20746860408201526519481c1bdbdb60d21b606082015260800190565b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052600160045260246000fd5b600081612a5d57612a5d6126da565b50600019019056fea26469706673582212200777efb6bbaffaf3c12f9366651c0738fd0510bf19a96c3af0a337226cca78d364736f6c63430008110033", + "linkReferences": {}, + "deployedLinkReferences": {}, + "devdoc": { + "kind": "dev", + "methods": { + "getIDOperator(uint32)": { + "params": { + "id": "ID of the operator" + }, + "returns": { + "_0": "the address of the operator" + } + }, + "getIDOperators(uint32[])": { + "params": { + "ids": "the array of the operator ids" + }, + "returns": { + "_0": "an array of the associated operator addresses" + } + }, + "getOperatorID(address)": { + "params": { + "operator": "Address of the operator." + }, + "returns": { + "_0": "the ID number of the given operator address" + } + }, + "insertOperator(address,uint256)": { + "details": "Can be called only by the contract owner.", + "params": { + "authorizedStake": "Inserted operator's authorized stake for the application.", + "operator": "Address of the inserted operator." + } + }, + "isOperatorRegistered(address)": { + "params": { + "operator": "the address of the operator" + }, + "returns": { + "_0": "whether or not the operator is already registered in the pool" + } + }, + "lock()": { + "details": "Can be called only by the contract owner." + }, + "operatorsInPool()": { + "returns": { + "_0": "the number of operators in the pool" + } + }, + "owner()": { + "details": "Returns the address of the current owner." + }, + "renounceOwnership()": { + "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner." + }, + "selectGroup(uint256,bytes32)": { + "params": { + "groupSize": "Size of the requested group", + "seed": "Pseudo-random number used to select operators to group" + }, + "returns": { + "_0": "selected Members of the selected group" + } + }, + "totalWeight()": { + "returns": { + "_0": "the total weight of the pool" + } + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." + }, + "unlock()": { + "details": "Can be called only by the contract owner." + }, + "updateOperatorStatus(address,uint256)": { + "details": "Can be called only by the contract owner.", + "params": { + "authorizedStake": "Operator's authorized stake for the application.", + "operator": "Address of the updated operator." + } + }, + "withdrawIneligible(address)": { + "details": "Can be called only by the owner." + }, + "withdrawRewards(address,address)": { + "details": "Can be called only be the owner. Does not validate if the provided beneficiary is associated with the provided operator - this needs to be done by the owner calling this function.", + "returns": { + "_0": "The amount of rewards withdrawn in this call." + } + } + }, + "title": "Sortition Pool", + "version": 1 + }, + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IERC20WithPermit\",\"name\":\"_rewardToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_poolWeightDivisor\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"operators\",\"type\":\"address[]\"}],\"name\":\"BetaOperatorsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"ChaosnetDeactivated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldChaosnetOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newChaosnetOwner\",\"type\":\"address\"}],\"name\":\"ChaosnetOwnerRoleTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32[]\",\"name\":\"ids\",\"type\":\"uint32[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"until\",\"type\":\"uint256\"}],\"name\":\"IneligibleForRewards\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"id\",\"type\":\"uint32\"}],\"name\":\"RewardEligibilityRestored\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"operators\",\"type\":\"address[]\"}],\"name\":\"addBetaOperators\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"canRestoreRewardEligibility\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chaosnetOwner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deactivateChaosnet\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"getAvailableRewards\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"id\",\"type\":\"uint32\"}],\"name\":\"getIDOperator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32[]\",\"name\":\"ids\",\"type\":\"uint32[]\"}],\"name\":\"getIDOperators\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"getOperatorID\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"getPoolWeight\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ineligibleEarnedRewards\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"authorizedStake\",\"type\":\"uint256\"}],\"name\":\"insertOperator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isBetaOperator\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isChaosnetActive\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isEligibleForRewards\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isLocked\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isOperatorInPool\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isOperatorRegistered\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"authorizedStake\",\"type\":\"uint256\"}],\"name\":\"isOperatorUpToDate\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lock\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"operatorsInPool\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"poolWeightDivisor\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"receiveApproval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"restoreRewardEligibility\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardToken\",\"outputs\":[{\"internalType\":\"contract IERC20WithPermit\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"rewardsEligibilityRestorableAt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"groupSize\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"seed\",\"type\":\"bytes32\"}],\"name\":\"selectGroup\",\"outputs\":[{\"internalType\":\"uint32[]\",\"name\":\"\",\"type\":\"uint32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32[]\",\"name\":\"operators\",\"type\":\"uint32[]\"},{\"internalType\":\"uint256\",\"name\":\"until\",\"type\":\"uint256\"}],\"name\":\"setRewardIneligibility\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalWeight\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newChaosnetOwner\",\"type\":\"address\"}],\"name\":\"transferChaosnetOwnerRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unlock\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"authorizedStake\",\"type\":\"uint256\"}],\"name\":\"updateOperatorStatus\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"withdrawIneligible\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"}],\"name\":\"withdrawRewards\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"getIDOperator(uint32)\":{\"params\":{\"id\":\"ID of the operator\"},\"returns\":{\"_0\":\"the address of the operator\"}},\"getIDOperators(uint32[])\":{\"params\":{\"ids\":\"the array of the operator ids\"},\"returns\":{\"_0\":\"an array of the associated operator addresses\"}},\"getOperatorID(address)\":{\"params\":{\"operator\":\"Address of the operator.\"},\"returns\":{\"_0\":\"the ID number of the given operator address\"}},\"insertOperator(address,uint256)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"authorizedStake\":\"Inserted operator's authorized stake for the application.\",\"operator\":\"Address of the inserted operator.\"}},\"isOperatorRegistered(address)\":{\"params\":{\"operator\":\"the address of the operator\"},\"returns\":{\"_0\":\"whether or not the operator is already registered in the pool\"}},\"lock()\":{\"details\":\"Can be called only by the contract owner.\"},\"operatorsInPool()\":{\"returns\":{\"_0\":\"the number of operators in the pool\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"selectGroup(uint256,bytes32)\":{\"params\":{\"groupSize\":\"Size of the requested group\",\"seed\":\"Pseudo-random number used to select operators to group\"},\"returns\":{\"_0\":\"selected Members of the selected group\"}},\"totalWeight()\":{\"returns\":{\"_0\":\"the total weight of the pool\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"unlock()\":{\"details\":\"Can be called only by the contract owner.\"},\"updateOperatorStatus(address,uint256)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"authorizedStake\":\"Operator's authorized stake for the application.\",\"operator\":\"Address of the updated operator.\"}},\"withdrawIneligible(address)\":{\"details\":\"Can be called only by the owner.\"},\"withdrawRewards(address,address)\":{\"details\":\"Can be called only be the owner. Does not validate if the provided beneficiary is associated with the provided operator - this needs to be done by the owner calling this function.\",\"returns\":{\"_0\":\"The amount of rewards withdrawn in this call.\"}}},\"title\":\"Sortition Pool\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"addBetaOperators(address[])\":{\"notice\":\"Adds beta operator to chaosnet. Can be called only by the chaosnet owner when the chaosnet is active. Once the operator is added as a beta operator, it can not be removed.\"},\"canRestoreRewardEligibility(address)\":{\"notice\":\"Returns whether the operator is able to restore their eligibility for rewards right away.\"},\"chaosnetOwner()\":{\"notice\":\"Address controlling chaosnet status and beta operator addresses.\"},\"deactivateChaosnet()\":{\"notice\":\"Deactivates the chaosnet. Can be called only by the chaosnet owner. Once deactivated chaosnet can not be activated again.\"},\"getAvailableRewards(address)\":{\"notice\":\"Returns the amount of rewards withdrawable for the given operator.\"},\"getIDOperator(uint32)\":{\"notice\":\"Get the operator address corresponding to the given ID number. A zero address means the ID number has not been allocated yet.\"},\"getIDOperators(uint32[])\":{\"notice\":\"Gets the operator addresses corresponding to the given ID numbers. A zero address means the ID number has not been allocated yet. This function works just like getIDOperator except that it allows to fetch operator addresses for multiple IDs in one call.\"},\"getOperatorID(address)\":{\"notice\":\"Return the ID number of the given operator address. An ID number of 0 means the operator has not been allocated an ID number yet.\"},\"getPoolWeight(address)\":{\"notice\":\"Return the weight of the operator in the pool, which may or may not be out of date.\"},\"insertOperator(address,uint256)\":{\"notice\":\"Inserts an operator to the pool. Reverts if the operator is already present. Reverts if the operator is not eligible because of their authorized stake. Reverts if the chaosnet is active and the operator is not a beta operator.\"},\"isBetaOperator(address)\":{\"notice\":\"Indicates if the given operator is a beta operator for chaosnet.\"},\"isChaosnetActive()\":{\"notice\":\"Indicates if the chaosnet is active. The chaosnet is active after the contract deployment and can be ended with a call to `deactivateChaosnet()`. Once deactivated chaosnet can not be activated again.\"},\"isEligibleForRewards(address)\":{\"notice\":\"Returns whether the operator is eligible for rewards or not.\"},\"isOperatorInPool(address)\":{\"notice\":\"Return whether the operator is present in the pool.\"},\"isOperatorRegistered(address)\":{\"notice\":\"Checks if operator is already registered in the pool.\"},\"isOperatorUpToDate(address,uint256)\":{\"notice\":\"Return whether the operator's weight in the pool matches their eligible weight.\"},\"lock()\":{\"notice\":\"Locks the sortition pool. In locked state, members cannot be inserted and removed from the pool. Members statuses cannot be updated as well.\"},\"operatorsInPool()\":{\"notice\":\"Sum the number of operators in each trunk.\"},\"restoreRewardEligibility(address)\":{\"notice\":\"Restores reward eligibility for the operator.\"},\"rewardsEligibilityRestorableAt(address)\":{\"notice\":\"Returns the time the operator's reward eligibility can be restored.\"},\"selectGroup(uint256,bytes32)\":{\"notice\":\"Selects a new group of operators of the provided size based on the provided pseudo-random seed. At least one operator has to be registered in the pool, otherwise the function fails reverting the transaction.\"},\"setRewardIneligibility(uint32[],uint256)\":{\"notice\":\"Set the given operators as ineligible for rewards. The operators can restore their eligibility at the given time.\"},\"totalWeight()\":{\"notice\":\"Convenience method to return the total weight of the pool\"},\"transferChaosnetOwnerRole(address)\":{\"notice\":\"Transfers the chaosnet owner role to another non-zero address.\"},\"unlock()\":{\"notice\":\"Unlocks the sortition pool. Removes all restrictions set by the `lock` method.\"},\"updateOperatorStatus(address,uint256)\":{\"notice\":\"Update the operator's weight if present and eligible, or remove from the pool if present and ineligible.\"},\"withdrawIneligible(address)\":{\"notice\":\"Withdraws rewards not allocated to operators marked as ineligible to the given recipient address.\"},\"withdrawRewards(address,address)\":{\"notice\":\"Withdraws all available rewards for the given operator to the given beneficiary.\"}},\"notice\":\"A logarithmic data structure used to store the pool of eligible operators weighted by their stakes. It allows to select a group of operators based on the provided pseudo-random seed.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"@keep-network/sortition-pools/contracts/SortitionPool.sol\":\"SortitionPool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@keep-network/sortition-pools/contracts/Branch.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\n/// @notice The implicit 8-ary trees of the sortition pool\\n/// rely on packing 8 \\\"slots\\\" of 32-bit values into each uint256.\\n/// The Branch library permits efficient calculations on these slots.\\nlibrary Branch {\\n /// @notice Calculate the right shift required\\n /// to make the 32 least significant bits of an uint256\\n /// be the bits of the `position`th slot\\n /// when treating the uint256 as a uint32[8].\\n ///\\n /// @dev Not used for efficiency reasons,\\n /// but left to illustrate the meaning of a common pattern.\\n /// I wish solidity had macros, even C macros.\\n function slotShift(uint256 position) internal pure returns (uint256) {\\n unchecked {\\n return position * Constants.SLOT_WIDTH;\\n }\\n }\\n\\n /// @notice Return the `position`th slot of the `node`,\\n /// treating `node` as a uint32[32].\\n function getSlot(uint256 node, uint256 position)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Doing a bitwise AND with `SLOT_MAX`\\n // clears all but the 32 least significant bits.\\n // Because of the right shift by `slotShift(position)` bits,\\n // those 32 bits contain the 32 bits in the `position`th slot of `node`.\\n return (node >> shiftBits) & Constants.SLOT_MAX;\\n }\\n }\\n\\n /// @notice Return `node` with the `position`th slot set to zero.\\n function clearSlot(uint256 node, uint256 position)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Shifting `SLOT_MAX` left by `slotShift(position)` bits\\n // gives us a number where all bits of the `position`th slot are set,\\n // and all other bits are unset.\\n //\\n // Using a bitwise NOT on this number,\\n // we get a uint256 where all bits are set\\n // except for those of the `position`th slot.\\n //\\n // Bitwise ANDing the original `node` with this number\\n // sets the bits of `position`th slot to zero,\\n // leaving all other bits unchanged.\\n return node & ~(Constants.SLOT_MAX << shiftBits);\\n }\\n }\\n\\n /// @notice Return `node` with the `position`th slot set to `weight`.\\n ///\\n /// @param weight The weight of of the node.\\n /// Safely truncated to a 32-bit number,\\n /// but this should never be called with an overflowing weight regardless.\\n function setSlot(\\n uint256 node,\\n uint256 position,\\n uint256 weight\\n ) internal pure returns (uint256) {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Clear the `position`th slot like in `clearSlot()`.\\n uint256 clearedNode = node & ~(Constants.SLOT_MAX << shiftBits);\\n // Bitwise AND `weight` with `SLOT_MAX`\\n // to clear all but the 32 least significant bits.\\n //\\n // Shift this left by `slotShift(position)` bits\\n // to obtain a uint256 with all bits unset\\n // except in the `position`th slot\\n // which contains the 32-bit value of `weight`.\\n uint256 shiftedWeight = (weight & Constants.SLOT_MAX) << shiftBits;\\n // When we bitwise OR these together,\\n // all other slots except the `position`th one come from the left argument,\\n // and the `position`th gets filled with `weight` from the right argument.\\n return clearedNode | shiftedWeight;\\n }\\n }\\n\\n /// @notice Calculate the summed weight of all slots in the `node`.\\n function sumWeight(uint256 node) internal pure returns (uint256 sum) {\\n unchecked {\\n sum = node & Constants.SLOT_MAX;\\n // Iterate through each slot\\n // by shifting `node` right in increments of 32 bits,\\n // and adding the 32 least significant bits to the `sum`.\\n uint256 newNode = node >> Constants.SLOT_WIDTH;\\n while (newNode > 0) {\\n sum += (newNode & Constants.SLOT_MAX);\\n newNode = newNode >> Constants.SLOT_WIDTH;\\n }\\n return sum;\\n }\\n }\\n\\n /// @notice Pick a slot in `node` that corresponds to `index`.\\n /// Treats the node like an array of virtual stakers,\\n /// the number of virtual stakers in each slot corresponding to its weight,\\n /// and picks which slot contains the `index`th virtual staker.\\n ///\\n /// @dev Requires that `index` be lower than `sumWeight(node)`.\\n /// However, this is not enforced for performance reasons.\\n /// If `index` exceeds the permitted range,\\n /// `pickWeightedSlot()` returns the rightmost slot\\n /// and an excessively high `newIndex`.\\n ///\\n /// @return slot The slot of `node` containing the `index`th virtual staker.\\n ///\\n /// @return newIndex The index of the `index`th virtual staker of `node`\\n /// within the returned slot.\\n function pickWeightedSlot(uint256 node, uint256 index)\\n internal\\n pure\\n returns (uint256 slot, uint256 newIndex)\\n {\\n unchecked {\\n newIndex = index;\\n uint256 newNode = node;\\n uint256 currentSlotWeight = newNode & Constants.SLOT_MAX;\\n while (newIndex >= currentSlotWeight) {\\n newIndex -= currentSlotWeight;\\n slot++;\\n newNode = newNode >> Constants.SLOT_WIDTH;\\n currentSlotWeight = newNode & Constants.SLOT_MAX;\\n }\\n return (slot, newIndex);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa7fb1c9c9789f30493e9a40e24a24f46875dc5e7630b4f67478167759f6d1882\"},\"@keep-network/sortition-pools/contracts/Chaosnet.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\n/// @title Chaosnet\\n/// @notice This is a beta staker program for stakers willing to go the extra\\n/// mile with monitoring, share their logs with the dev team, and allow to more\\n/// carefully monitor the bootstrapping network. As the network matures, the\\n/// beta program will be ended.\\ncontract Chaosnet {\\n /// @notice Indicates if the chaosnet is active. The chaosnet is active\\n /// after the contract deployment and can be ended with a call to\\n /// `deactivateChaosnet()`. Once deactivated chaosnet can not be activated\\n /// again.\\n bool public isChaosnetActive;\\n\\n /// @notice Indicates if the given operator is a beta operator for chaosnet.\\n mapping(address => bool) public isBetaOperator;\\n\\n /// @notice Address controlling chaosnet status and beta operator addresses.\\n address public chaosnetOwner;\\n\\n event BetaOperatorsAdded(address[] operators);\\n\\n event ChaosnetOwnerRoleTransferred(\\n address oldChaosnetOwner,\\n address newChaosnetOwner\\n );\\n\\n event ChaosnetDeactivated();\\n\\n constructor() {\\n _transferChaosnetOwner(msg.sender);\\n isChaosnetActive = true;\\n }\\n\\n modifier onlyChaosnetOwner() {\\n require(msg.sender == chaosnetOwner, \\\"Not the chaosnet owner\\\");\\n _;\\n }\\n\\n modifier onlyOnChaosnet() {\\n require(isChaosnetActive, \\\"Chaosnet is not active\\\");\\n _;\\n }\\n\\n /// @notice Adds beta operator to chaosnet. Can be called only by the\\n /// chaosnet owner when the chaosnet is active. Once the operator is added\\n /// as a beta operator, it can not be removed.\\n function addBetaOperators(address[] calldata operators)\\n public\\n onlyOnChaosnet\\n onlyChaosnetOwner\\n {\\n for (uint256 i = 0; i < operators.length; i++) {\\n isBetaOperator[operators[i]] = true;\\n }\\n\\n emit BetaOperatorsAdded(operators);\\n }\\n\\n /// @notice Deactivates the chaosnet. Can be called only by the chaosnet\\n /// owner. Once deactivated chaosnet can not be activated again.\\n function deactivateChaosnet() public onlyOnChaosnet onlyChaosnetOwner {\\n isChaosnetActive = false;\\n emit ChaosnetDeactivated();\\n }\\n\\n /// @notice Transfers the chaosnet owner role to another non-zero address.\\n function transferChaosnetOwnerRole(address newChaosnetOwner)\\n public\\n onlyChaosnetOwner\\n {\\n require(\\n newChaosnetOwner != address(0),\\n \\\"New chaosnet owner must not be zero address\\\"\\n );\\n _transferChaosnetOwner(newChaosnetOwner);\\n }\\n\\n function _transferChaosnetOwner(address newChaosnetOwner) internal {\\n address oldChaosnetOwner = chaosnetOwner;\\n chaosnetOwner = newChaosnetOwner;\\n emit ChaosnetOwnerRoleTransferred(oldChaosnetOwner, newChaosnetOwner);\\n }\\n}\\n\",\"keccak256\":\"0xeaf7bdd5626f88c329793a012621039692ce1b6e1f13013997ddb13d7e3032df\"},\"@keep-network/sortition-pools/contracts/Constants.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nlibrary Constants {\\n ////////////////////////////////////////////////////////////////////////////\\n // Parameters for configuration\\n\\n // How many bits a position uses per level of the tree;\\n // each branch of the tree contains 2**SLOT_BITS slots.\\n uint256 constant SLOT_BITS = 3;\\n uint256 constant LEVELS = 7;\\n ////////////////////////////////////////////////////////////////////////////\\n\\n ////////////////////////////////////////////////////////////////////////////\\n // Derived constants, do not touch\\n uint256 constant SLOT_COUNT = 2**SLOT_BITS;\\n uint256 constant SLOT_WIDTH = 256 / SLOT_COUNT;\\n uint256 constant LAST_SLOT = SLOT_COUNT - 1;\\n uint256 constant SLOT_MAX = (2**SLOT_WIDTH) - 1;\\n uint256 constant POOL_CAPACITY = SLOT_COUNT**LEVELS;\\n\\n uint256 constant ID_WIDTH = SLOT_WIDTH;\\n uint256 constant ID_MAX = SLOT_MAX;\\n\\n uint256 constant BLOCKHEIGHT_WIDTH = 96 - ID_WIDTH;\\n uint256 constant BLOCKHEIGHT_MAX = (2**BLOCKHEIGHT_WIDTH) - 1;\\n\\n uint256 constant SLOT_POINTER_MAX = (2**SLOT_BITS) - 1;\\n uint256 constant LEAF_FLAG = 1 << 255;\\n\\n uint256 constant WEIGHT_WIDTH = 256 / SLOT_COUNT;\\n ////////////////////////////////////////////////////////////////////////////\\n}\\n\",\"keccak256\":\"0xaef690ced707935745ff1482b7bb9bd9eb77bf6a39c717465e64cf12db8a7d39\"},\"@keep-network/sortition-pools/contracts/Leaf.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary Leaf {\\n function make(\\n address _operator,\\n uint256 _creationBlock,\\n uint256 _id\\n ) internal pure returns (uint256) {\\n assert(_creationBlock <= type(uint64).max);\\n assert(_id <= type(uint32).max);\\n // Converting a bytesX type into a larger type\\n // adds zero bytes on the right.\\n uint256 op = uint256(bytes32(bytes20(_operator)));\\n // Bitwise AND the id to erase\\n // all but the 32 least significant bits\\n uint256 uid = _id & Constants.ID_MAX;\\n // Erase all but the 64 least significant bits,\\n // then shift left by 32 bits to make room for the id\\n uint256 cb = (_creationBlock & Constants.BLOCKHEIGHT_MAX) <<\\n Constants.ID_WIDTH;\\n // Bitwise OR them all together to get\\n // [address operator || uint64 creationBlock || uint32 id]\\n return (op | cb | uid);\\n }\\n\\n function operator(uint256 leaf) internal pure returns (address) {\\n // Converting a bytesX type into a smaller type\\n // truncates it on the right.\\n return address(bytes20(bytes32(leaf)));\\n }\\n\\n /// @notice Return the block number the leaf was created in.\\n function creationBlock(uint256 leaf) internal pure returns (uint256) {\\n return ((leaf >> Constants.ID_WIDTH) & Constants.BLOCKHEIGHT_MAX);\\n }\\n\\n function id(uint256 leaf) internal pure returns (uint32) {\\n // Id is stored in the 32 least significant bits.\\n // Bitwise AND ensures that we only get the contents of those bits.\\n return uint32(leaf & Constants.ID_MAX);\\n }\\n}\\n\",\"keccak256\":\"0xbd107a1a43e48884885e5e966ffcbcd8fa5e89863715d717bb4006e9f89cdc2b\"},\"@keep-network/sortition-pools/contracts/Position.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary Position {\\n // Return the last 3 bits of a position number,\\n // corresponding to its slot in its parent\\n function slot(uint256 a) internal pure returns (uint256) {\\n return a & Constants.SLOT_POINTER_MAX;\\n }\\n\\n // Return the parent of a position number\\n function parent(uint256 a) internal pure returns (uint256) {\\n return a >> Constants.SLOT_BITS;\\n }\\n\\n // Return the location of the child of a at the given slot\\n function child(uint256 a, uint256 s) internal pure returns (uint256) {\\n return (a << Constants.SLOT_BITS) | (s & Constants.SLOT_POINTER_MAX); // slot(s)\\n }\\n\\n // Return the uint p as a flagged position uint:\\n // the least significant 21 bits contain the position\\n // and the 22nd bit is set as a flag\\n // to distinguish the position 0x000000 from an empty field.\\n function setFlag(uint256 p) internal pure returns (uint256) {\\n return p | Constants.LEAF_FLAG;\\n }\\n\\n // Turn a flagged position into an unflagged position\\n // by removing the flag at the 22nd least significant bit.\\n //\\n // We shouldn't _actually_ need this\\n // as all position-manipulating code should ignore non-position bits anyway\\n // but it's cheap to call so might as well do it.\\n function unsetFlag(uint256 p) internal pure returns (uint256) {\\n return p & (~Constants.LEAF_FLAG);\\n }\\n}\\n\",\"keccak256\":\"0xd3a927908080ac21353a92a6bce3d69e94a5c30f6b51f16b271b6cc679f110e2\"},\"@keep-network/sortition-pools/contracts/RNG.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Leaf.sol\\\";\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary RNG {\\n /// @notice Get an index in the range `[0 .. range-1]`\\n /// and the new state of the RNG,\\n /// using the provided `state` of the RNG.\\n ///\\n /// @param range The upper bound of the index, exclusive.\\n ///\\n /// @param state The previous state of the RNG.\\n /// The initial state needs to be obtained\\n /// from a trusted randomness oracle (the random beacon),\\n /// or from a chain of earlier calls to `RNG.getIndex()`\\n /// on an originally trusted seed.\\n ///\\n /// @dev Calculates the number of bits required for the desired range,\\n /// takes the least significant bits of `state`\\n /// and checks if the obtained index is within the desired range.\\n /// The original state is hashed with `keccak256` to get a new state.\\n /// If the index is outside the range,\\n /// the function retries until it gets a suitable index.\\n ///\\n /// @return index A random integer between `0` and `range - 1`, inclusive.\\n ///\\n /// @return newState The new state of the RNG.\\n /// When `getIndex()` is called one or more times,\\n /// care must be taken to always use the output `state`\\n /// of the most recent call as the input `state` of a subsequent call.\\n /// At the end of a transaction calling `RNG.getIndex()`,\\n /// the previous stored state must be overwritten with the latest output.\\n function getIndex(\\n uint256 range,\\n bytes32 state,\\n uint256 bits\\n ) internal view returns (uint256, bytes32) {\\n bool found = false;\\n uint256 index = 0;\\n bytes32 newState = state;\\n while (!found) {\\n index = truncate(bits, uint256(newState));\\n newState = keccak256(abi.encodePacked(newState, address(this)));\\n if (index < range) {\\n found = true;\\n }\\n }\\n return (index, newState);\\n }\\n\\n /// @notice Calculate how many bits are required\\n /// for an index in the range `[0 .. range-1]`.\\n ///\\n /// @param range The upper bound of the desired range, exclusive.\\n ///\\n /// @return uint The smallest number of bits\\n /// that can contain the number `range-1`.\\n function bitsRequired(uint256 range) internal pure returns (uint256) {\\n unchecked {\\n if (range == 1) {\\n return 0;\\n }\\n\\n uint256 bits = Constants.WEIGHT_WIDTH - 1;\\n\\n // Left shift by `bits`,\\n // so we have a 1 in the (bits + 1)th least significant bit\\n // and 0 in other bits.\\n // If this number is equal or greater than `range`,\\n // the range [0, range-1] fits in `bits` bits.\\n //\\n // Because we loop from high bits to low bits,\\n // we find the highest number of bits that doesn't fit the range,\\n // and return that number + 1.\\n while (1 << bits >= range) {\\n bits--;\\n }\\n\\n return bits + 1;\\n }\\n }\\n\\n /// @notice Truncate `input` to the `bits` least significant bits.\\n function truncate(uint256 bits, uint256 input)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n return input & ((1 << bits) - 1);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x67f87f589cd5123ffa32f883ea2f09b0e56258508bae82b8c655b3c27c71eb5e\"},\"@keep-network/sortition-pools/contracts/Rewards.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\n/// @title Rewards\\n/// @notice Rewards are allocated proportionally to operators\\n/// present in the pool at payout based on their weight in the pool.\\n///\\n/// To facilitate this, we use a global accumulator value\\n/// to track the total rewards one unit of weight would've earned\\n/// since the creation of the pool.\\n///\\n/// Whenever a reward is paid, the accumulator is increased\\n/// by the size of the reward divided by the total weight\\n/// of all eligible operators in the pool.\\n///\\n/// Each operator has an individual accumulator value,\\n/// set to equal the global accumulator when the operator joins the pool.\\n/// This accumulator reflects the amount of rewards\\n/// that have already been accounted for with that operator.\\n///\\n/// Whenever an operator's weight in the pool changes,\\n/// we can update the amount of rewards the operator has earned\\n/// by subtracting the operator's accumulator from the global accumulator.\\n/// This gives us the amount of rewards one unit of weight has earned\\n/// since the last time the operator's rewards have been updated.\\n/// Then we multiply that by the operator's previous (pre-change) weight\\n/// to determine how much rewards in total the operator has earned,\\n/// and add this to the operator's earned rewards.\\n/// Finally, we set the operator's accumulator to the global accumulator value.\\ncontract Rewards {\\n struct OperatorRewards {\\n // The state of the global accumulator\\n // when the operator's rewards were last updated\\n uint96 accumulated;\\n // The amount of rewards collected by the operator after the latest update.\\n // The amount the operator could withdraw may equal `available`\\n // or it may be greater, if more rewards have been paid in since then.\\n // To evaulate the most recent amount including rewards potentially paid\\n // since the last update, use `availableRewards` function.\\n uint96 available;\\n // If nonzero, the operator is ineligible for rewards\\n // and may only re-enable rewards after the specified timestamp.\\n // XXX: unsigned 32-bit integer unix seconds, will break around 2106\\n uint32 ineligibleUntil;\\n // Locally cached weight of the operator,\\n // used to reduce the cost of setting operators ineligible.\\n uint32 weight;\\n }\\n\\n // The global accumulator of how much rewards\\n // a hypothetical operator of weight 1 would have earned\\n // since the creation of the pool.\\n uint96 internal globalRewardAccumulator;\\n // If the amount of reward tokens paid in\\n // does not divide cleanly by pool weight,\\n // the difference is recorded as rounding dust\\n // and added to the next reward.\\n uint96 internal rewardRoundingDust;\\n\\n // The amount of rewards that would've been earned by ineligible operators\\n // had they not been ineligible.\\n uint96 public ineligibleEarnedRewards;\\n\\n // Ineligibility times are calculated from this offset,\\n // set at contract creation.\\n uint256 internal immutable ineligibleOffsetStart;\\n\\n mapping(uint32 => OperatorRewards) internal operatorRewards;\\n\\n constructor() {\\n // solhint-disable-next-line not-rely-on-time\\n ineligibleOffsetStart = block.timestamp;\\n }\\n\\n /// @notice Return whether the operator is eligible for rewards or not.\\n function isEligibleForRewards(uint32 operator) internal view returns (bool) {\\n return operatorRewards[operator].ineligibleUntil == 0;\\n }\\n\\n /// @notice Return the time the operator's reward eligibility can be restored.\\n function rewardsEligibilityRestorableAt(uint32 operator)\\n internal\\n view\\n returns (uint256)\\n {\\n uint32 until = operatorRewards[operator].ineligibleUntil;\\n require(until != 0, \\\"Operator already eligible\\\");\\n return (uint256(until) + ineligibleOffsetStart);\\n }\\n\\n /// @notice Return whether the operator is able to restore their eligibility\\n /// for rewards right away.\\n function canRestoreRewardEligibility(uint32 operator)\\n internal\\n view\\n returns (bool)\\n {\\n // solhint-disable-next-line not-rely-on-time\\n return rewardsEligibilityRestorableAt(operator) <= block.timestamp;\\n }\\n\\n /// @notice Internal function for updating the global state of rewards.\\n function addRewards(uint96 rewardAmount, uint32 currentPoolWeight) internal {\\n require(currentPoolWeight > 0, \\\"No recipients in pool\\\");\\n\\n uint96 totalAmount = rewardAmount + rewardRoundingDust;\\n uint96 perWeightReward = totalAmount / currentPoolWeight;\\n uint96 newRoundingDust = totalAmount % currentPoolWeight;\\n\\n globalRewardAccumulator += perWeightReward;\\n rewardRoundingDust = newRoundingDust;\\n }\\n\\n /// @notice Internal function for updating the operator's reward state.\\n function updateOperatorRewards(uint32 operator, uint32 newWeight) internal {\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n if (o.ineligibleUntil == 0) {\\n // If operator is not ineligible, update their earned rewards\\n o.available += accruedRewards;\\n } else {\\n // If ineligible, put the rewards into the ineligible pot\\n ineligibleEarnedRewards += accruedRewards;\\n }\\n // In any case, update their accumulator and weight\\n o.accumulated = acc;\\n o.weight = newWeight;\\n operatorRewards[operator] = o;\\n }\\n\\n /// @notice Set the amount of withdrawable tokens to zero\\n /// and return the previous withdrawable amount.\\n /// @dev Does not update the withdrawable amount,\\n /// but should usually be accompanied by an update.\\n function withdrawOperatorRewards(uint32 operator)\\n internal\\n returns (uint96 withdrawable)\\n {\\n OperatorRewards storage o = operatorRewards[operator];\\n withdrawable = o.available;\\n o.available = 0;\\n }\\n\\n /// @notice Set the amount of ineligible-earned tokens to zero\\n /// and return the previous amount.\\n function withdrawIneligibleRewards() internal returns (uint96 withdrawable) {\\n withdrawable = ineligibleEarnedRewards;\\n ineligibleEarnedRewards = 0;\\n }\\n\\n /// @notice Set the given operators as ineligible for rewards.\\n /// The operators can restore their eligibility at the given time.\\n function setIneligible(uint32[] memory operators, uint256 until) internal {\\n OperatorRewards memory o = OperatorRewards(0, 0, 0, 0);\\n uint96 globalAcc = globalRewardAccumulator;\\n uint96 accrued = 0;\\n // Record ineligibility as seconds after contract creation\\n uint32 _until = uint32(until - ineligibleOffsetStart);\\n\\n for (uint256 i = 0; i < operators.length; i++) {\\n uint32 operator = operators[i];\\n OperatorRewards storage r = operatorRewards[operator];\\n o.available = r.available;\\n o.accumulated = r.accumulated;\\n o.ineligibleUntil = r.ineligibleUntil;\\n o.weight = r.weight;\\n\\n if (o.ineligibleUntil != 0) {\\n // If operator is already ineligible,\\n // don't earn rewards or shorten its ineligibility\\n if (o.ineligibleUntil < _until) {\\n o.ineligibleUntil = _until;\\n }\\n } else {\\n // The operator becomes ineligible -> earn rewards\\n o.ineligibleUntil = _until;\\n accrued = (globalAcc - o.accumulated) * uint96(o.weight);\\n o.available += accrued;\\n }\\n o.accumulated = globalAcc;\\n\\n r.available = o.available;\\n r.accumulated = o.accumulated;\\n r.ineligibleUntil = o.ineligibleUntil;\\n r.weight = o.weight;\\n }\\n }\\n\\n /// @notice Restore the given operator's eligibility for rewards.\\n function restoreEligibility(uint32 operator) internal {\\n // solhint-disable-next-line not-rely-on-time\\n require(canRestoreRewardEligibility(operator), \\\"Operator still ineligible\\\");\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n ineligibleEarnedRewards += accruedRewards;\\n o.accumulated = acc;\\n o.ineligibleUntil = 0;\\n operatorRewards[operator] = o;\\n }\\n\\n /// @notice Returns the amount of rewards currently available for withdrawal\\n /// for the given operator.\\n function availableRewards(uint32 operator) internal view returns (uint96) {\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n if (o.ineligibleUntil == 0) {\\n // If operator is not ineligible, calculate newly accrued rewards and add\\n // them to the available ones, calculated during the last update.\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n return o.available + accruedRewards;\\n } else {\\n // If ineligible, return only the rewards calculated during the last\\n // update.\\n return o.available;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3a10abb408b44335a092387b2c7ee01db3b27997f1f2c888d9b7a2d92934c4e2\"},\"@keep-network/sortition-pools/contracts/SortitionPool.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"@thesis/solidity-contracts/contracts/token/IERC20WithPermit.sol\\\";\\nimport \\\"@thesis/solidity-contracts/contracts/token/IReceiveApproval.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\nimport \\\"./RNG.sol\\\";\\nimport \\\"./SortitionTree.sol\\\";\\nimport \\\"./Rewards.sol\\\";\\nimport \\\"./Chaosnet.sol\\\";\\n\\n/// @title Sortition Pool\\n/// @notice A logarithmic data structure used to store the pool of eligible\\n/// operators weighted by their stakes. It allows to select a group of operators\\n/// based on the provided pseudo-random seed.\\ncontract SortitionPool is\\n SortitionTree,\\n Rewards,\\n Ownable,\\n Chaosnet,\\n IReceiveApproval\\n{\\n using Branch for uint256;\\n using Leaf for uint256;\\n using Position for uint256;\\n\\n IERC20WithPermit public immutable rewardToken;\\n\\n uint256 public immutable poolWeightDivisor;\\n\\n bool public isLocked;\\n\\n event IneligibleForRewards(uint32[] ids, uint256 until);\\n\\n event RewardEligibilityRestored(address indexed operator, uint32 indexed id);\\n\\n /// @notice Reverts if called while pool is locked.\\n modifier onlyUnlocked() {\\n require(!isLocked, \\\"Sortition pool locked\\\");\\n _;\\n }\\n\\n /// @notice Reverts if called while pool is unlocked.\\n modifier onlyLocked() {\\n require(isLocked, \\\"Sortition pool unlocked\\\");\\n _;\\n }\\n\\n constructor(IERC20WithPermit _rewardToken, uint256 _poolWeightDivisor) {\\n rewardToken = _rewardToken;\\n poolWeightDivisor = _poolWeightDivisor;\\n }\\n\\n function receiveApproval(\\n address sender,\\n uint256 amount,\\n address token,\\n bytes calldata\\n ) external override {\\n require(token == address(rewardToken), \\\"Unsupported token\\\");\\n rewardToken.transferFrom(sender, address(this), amount);\\n Rewards.addRewards(uint96(amount), uint32(root.sumWeight()));\\n }\\n\\n /// @notice Withdraws all available rewards for the given operator to the\\n /// given beneficiary.\\n /// @dev Can be called only be the owner. Does not validate if the provided\\n /// beneficiary is associated with the provided operator - this needs to\\n /// be done by the owner calling this function.\\n /// @return The amount of rewards withdrawn in this call.\\n function withdrawRewards(address operator, address beneficiary)\\n public\\n onlyOwner\\n returns (uint96)\\n {\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(getPoolWeight(operator)));\\n uint96 earned = Rewards.withdrawOperatorRewards(id);\\n rewardToken.transfer(beneficiary, uint256(earned));\\n return earned;\\n }\\n\\n /// @notice Withdraws rewards not allocated to operators marked as ineligible\\n /// to the given recipient address.\\n /// @dev Can be called only by the owner.\\n function withdrawIneligible(address recipient) public onlyOwner {\\n uint96 earned = Rewards.withdrawIneligibleRewards();\\n rewardToken.transfer(recipient, uint256(earned));\\n }\\n\\n /// @notice Locks the sortition pool. In locked state, members cannot be\\n /// inserted and removed from the pool. Members statuses cannot\\n /// be updated as well.\\n /// @dev Can be called only by the contract owner.\\n function lock() public onlyOwner {\\n isLocked = true;\\n }\\n\\n /// @notice Unlocks the sortition pool. Removes all restrictions set by\\n /// the `lock` method.\\n /// @dev Can be called only by the contract owner.\\n function unlock() public onlyOwner {\\n isLocked = false;\\n }\\n\\n /// @notice Inserts an operator to the pool. Reverts if the operator is\\n /// already present. Reverts if the operator is not eligible because of their\\n /// authorized stake. Reverts if the chaosnet is active and the operator is\\n /// not a beta operator.\\n /// @dev Can be called only by the contract owner.\\n /// @param operator Address of the inserted operator.\\n /// @param authorizedStake Inserted operator's authorized stake for the application.\\n function insertOperator(address operator, uint256 authorizedStake)\\n public\\n onlyOwner\\n onlyUnlocked\\n {\\n uint256 weight = getWeight(authorizedStake);\\n require(weight > 0, \\\"Operator not eligible\\\");\\n\\n if (isChaosnetActive) {\\n require(isBetaOperator[operator], \\\"Not beta operator for chaosnet\\\");\\n }\\n\\n _insertOperator(operator, weight);\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(weight));\\n }\\n\\n /// @notice Update the operator's weight if present and eligible,\\n /// or remove from the pool if present and ineligible.\\n /// @dev Can be called only by the contract owner.\\n /// @param operator Address of the updated operator.\\n /// @param authorizedStake Operator's authorized stake for the application.\\n function updateOperatorStatus(address operator, uint256 authorizedStake)\\n public\\n onlyOwner\\n onlyUnlocked\\n {\\n uint256 weight = getWeight(authorizedStake);\\n\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(weight));\\n\\n if (weight == 0) {\\n _removeOperator(operator);\\n } else {\\n updateOperator(operator, weight);\\n }\\n }\\n\\n /// @notice Set the given operators as ineligible for rewards.\\n /// The operators can restore their eligibility at the given time.\\n function setRewardIneligibility(uint32[] calldata operators, uint256 until)\\n public\\n onlyOwner\\n {\\n Rewards.setIneligible(operators, until);\\n emit IneligibleForRewards(operators, until);\\n }\\n\\n /// @notice Restores reward eligibility for the operator.\\n function restoreRewardEligibility(address operator) public {\\n uint32 id = getOperatorID(operator);\\n Rewards.restoreEligibility(id);\\n emit RewardEligibilityRestored(operator, id);\\n }\\n\\n /// @notice Returns whether the operator is eligible for rewards or not.\\n function isEligibleForRewards(address operator) public view returns (bool) {\\n uint32 id = getOperatorID(operator);\\n return Rewards.isEligibleForRewards(id);\\n }\\n\\n /// @notice Returns the time the operator's reward eligibility can be restored.\\n function rewardsEligibilityRestorableAt(address operator)\\n public\\n view\\n returns (uint256)\\n {\\n uint32 id = getOperatorID(operator);\\n return Rewards.rewardsEligibilityRestorableAt(id);\\n }\\n\\n /// @notice Returns whether the operator is able to restore their eligibility\\n /// for rewards right away.\\n function canRestoreRewardEligibility(address operator)\\n public\\n view\\n returns (bool)\\n {\\n uint32 id = getOperatorID(operator);\\n return Rewards.canRestoreRewardEligibility(id);\\n }\\n\\n /// @notice Returns the amount of rewards withdrawable for the given operator.\\n function getAvailableRewards(address operator) public view returns (uint96) {\\n uint32 id = getOperatorID(operator);\\n return availableRewards(id);\\n }\\n\\n /// @notice Return whether the operator is present in the pool.\\n function isOperatorInPool(address operator) public view returns (bool) {\\n return getFlaggedLeafPosition(operator) != 0;\\n }\\n\\n /// @notice Return whether the operator's weight in the pool\\n /// matches their eligible weight.\\n function isOperatorUpToDate(address operator, uint256 authorizedStake)\\n public\\n view\\n returns (bool)\\n {\\n return getWeight(authorizedStake) == getPoolWeight(operator);\\n }\\n\\n /// @notice Return the weight of the operator in the pool,\\n /// which may or may not be out of date.\\n function getPoolWeight(address operator) public view returns (uint256) {\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n if (flaggedPosition == 0) {\\n return 0;\\n } else {\\n uint256 leafPosition = flaggedPosition.unsetFlag();\\n uint256 leafWeight = getLeafWeight(leafPosition);\\n return leafWeight;\\n }\\n }\\n\\n /// @notice Selects a new group of operators of the provided size based on\\n /// the provided pseudo-random seed. At least one operator has to be\\n /// registered in the pool, otherwise the function fails reverting the\\n /// transaction.\\n /// @param groupSize Size of the requested group\\n /// @param seed Pseudo-random number used to select operators to group\\n /// @return selected Members of the selected group\\n function selectGroup(uint256 groupSize, bytes32 seed)\\n public\\n view\\n onlyLocked\\n returns (uint32[] memory)\\n {\\n uint256 _root = root;\\n\\n bytes32 rngState = seed;\\n uint256 rngRange = _root.sumWeight();\\n require(rngRange > 0, \\\"Not enough operators in pool\\\");\\n uint256 currentIndex;\\n\\n uint256 bits = RNG.bitsRequired(rngRange);\\n\\n uint32[] memory selected = new uint32[](groupSize);\\n\\n for (uint256 i = 0; i < groupSize; i++) {\\n (currentIndex, rngState) = RNG.getIndex(rngRange, rngState, bits);\\n\\n uint256 leafPosition = pickWeightedLeaf(currentIndex, _root);\\n\\n uint256 leaf = leaves[leafPosition];\\n selected[i] = leaf.id();\\n }\\n return selected;\\n }\\n\\n function getWeight(uint256 authorization) internal view returns (uint256) {\\n return authorization / poolWeightDivisor;\\n }\\n}\\n\",\"keccak256\":\"0xab42e7c5b1828f42a73f699eb2dc96d4f793572a6323b8b1fbd7c5e0c065bda7\"},\"@keep-network/sortition-pools/contracts/SortitionTree.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Branch.sol\\\";\\nimport \\\"./Position.sol\\\";\\nimport \\\"./Leaf.sol\\\";\\nimport \\\"./Constants.sol\\\";\\n\\ncontract SortitionTree {\\n using Branch for uint256;\\n using Position for uint256;\\n using Leaf for uint256;\\n\\n // implicit tree\\n // root 8\\n // level2 64\\n // level3 512\\n // level4 4k\\n // level5 32k\\n // level6 256k\\n // level7 2M\\n uint256 internal root;\\n\\n // A 2-index mapping from layer => (index (0-index) => branch). For example,\\n // to access the 6th branch in the 2nd layer (right below the root node; the\\n // first branch layer), call branches[2][5]. Mappings are used in place of\\n // arrays for efficiency. The root is the first layer, the branches occupy\\n // layers 2 through 7, and layer 8 is for the leaves. Following this\\n // convention, the first index in `branches` is `2`, and the last index is\\n // `7`.\\n mapping(uint256 => mapping(uint256 => uint256)) internal branches;\\n\\n // A 0-index mapping from index => leaf, acting as an array. For example, to\\n // access the 42nd leaf, call leaves[41].\\n mapping(uint256 => uint256) internal leaves;\\n\\n // the flagged (see setFlag() and unsetFlag() in Position.sol) positions\\n // of all operators present in the pool\\n mapping(address => uint256) internal flaggedLeafPosition;\\n\\n // the leaf after the rightmost occupied leaf of each stack\\n uint256 internal rightmostLeaf;\\n\\n // the empty leaves in each stack\\n // between 0 and the rightmost occupied leaf\\n uint256[] internal emptyLeaves;\\n\\n // Each operator has an uint32 ID number\\n // which is allocated when they first join the pool\\n // and remains unchanged even if they leave and rejoin the pool.\\n mapping(address => uint32) internal operatorID;\\n\\n // The idAddress array records the address corresponding to each ID number.\\n // The ID number 0 is initialized with a zero address and is not used.\\n address[] internal idAddress;\\n\\n constructor() {\\n root = 0;\\n rightmostLeaf = 0;\\n idAddress.push();\\n }\\n\\n /// @notice Return the ID number of the given operator address. An ID number\\n /// of 0 means the operator has not been allocated an ID number yet.\\n /// @param operator Address of the operator.\\n /// @return the ID number of the given operator address\\n function getOperatorID(address operator) public view returns (uint32) {\\n return operatorID[operator];\\n }\\n\\n /// @notice Get the operator address corresponding to the given ID number. A\\n /// zero address means the ID number has not been allocated yet.\\n /// @param id ID of the operator\\n /// @return the address of the operator\\n function getIDOperator(uint32 id) public view returns (address) {\\n return idAddress.length > id ? idAddress[id] : address(0);\\n }\\n\\n /// @notice Gets the operator addresses corresponding to the given ID\\n /// numbers. A zero address means the ID number has not been allocated yet.\\n /// This function works just like getIDOperator except that it allows to fetch\\n /// operator addresses for multiple IDs in one call.\\n /// @param ids the array of the operator ids\\n /// @return an array of the associated operator addresses\\n function getIDOperators(uint32[] calldata ids)\\n public\\n view\\n returns (address[] memory)\\n {\\n uint256 idCount = idAddress.length;\\n\\n address[] memory operators = new address[](ids.length);\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint32 id = ids[i];\\n operators[i] = idCount > id ? idAddress[id] : address(0);\\n }\\n return operators;\\n }\\n\\n /// @notice Checks if operator is already registered in the pool.\\n /// @param operator the address of the operator\\n /// @return whether or not the operator is already registered in the pool\\n function isOperatorRegistered(address operator) public view returns (bool) {\\n return getFlaggedLeafPosition(operator) != 0;\\n }\\n\\n /// @notice Sum the number of operators in each trunk.\\n /// @return the number of operators in the pool\\n function operatorsInPool() public view returns (uint256) {\\n // Get the number of leaves that might be occupied;\\n // if `rightmostLeaf` equals `firstLeaf()` the tree must be empty,\\n // otherwise the difference between these numbers\\n // gives the number of leaves that may be occupied.\\n uint256 nPossiblyUsedLeaves = rightmostLeaf;\\n // Get the number of empty leaves\\n // not accounted for by the `rightmostLeaf`\\n uint256 nEmptyLeaves = emptyLeaves.length;\\n\\n return (nPossiblyUsedLeaves - nEmptyLeaves);\\n }\\n\\n /// @notice Convenience method to return the total weight of the pool\\n /// @return the total weight of the pool\\n function totalWeight() public view returns (uint256) {\\n return root.sumWeight();\\n }\\n\\n /// @notice Give the operator a new ID number.\\n /// Does not check if the operator already has an ID number.\\n /// @param operator the address of the operator\\n /// @return a new ID for that operator\\n function allocateOperatorID(address operator) internal returns (uint256) {\\n uint256 id = idAddress.length;\\n\\n require(id <= type(uint32).max, \\\"Pool capacity exceeded\\\");\\n\\n operatorID[operator] = uint32(id);\\n idAddress.push(operator);\\n return id;\\n }\\n\\n /// @notice Inserts an operator into the sortition pool\\n /// @param operator the address of an operator to insert\\n /// @param weight how much weight that operator has in the pool\\n function _insertOperator(address operator, uint256 weight) internal {\\n require(\\n !isOperatorRegistered(operator),\\n \\\"Operator is already registered in the pool\\\"\\n );\\n\\n // Fetch the operator's ID, and if they don't have one, allocate them one.\\n uint256 id = getOperatorID(operator);\\n if (id == 0) {\\n id = allocateOperatorID(operator);\\n }\\n\\n // Determine which leaf to insert them into\\n uint256 position = getEmptyLeafPosition();\\n // Record the block the operator was inserted in\\n uint256 theLeaf = Leaf.make(operator, block.number, id);\\n\\n // Update the leaf, and propagate the weight changes all the way up to the\\n // root.\\n root = setLeaf(position, theLeaf, weight, root);\\n\\n // Without position flags,\\n // the position 0x000000 would be treated as empty\\n flaggedLeafPosition[operator] = position.setFlag();\\n }\\n\\n /// @notice Remove an operator (and their weight) from the pool.\\n /// @param operator the address of the operator to remove\\n function _removeOperator(address operator) internal {\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n require(flaggedPosition != 0, \\\"Operator is not registered in the pool\\\");\\n uint256 unflaggedPosition = flaggedPosition.unsetFlag();\\n\\n // Update the leaf, and propagate the weight changes all the way up to the\\n // root.\\n root = removeLeaf(unflaggedPosition, root);\\n removeLeafPositionRecord(operator);\\n }\\n\\n /// @notice Update an operator's weight in the pool.\\n /// @param operator the address of the operator to update\\n /// @param weight the new weight\\n function updateOperator(address operator, uint256 weight) internal {\\n require(\\n isOperatorRegistered(operator),\\n \\\"Operator is not registered in the pool\\\"\\n );\\n\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n uint256 unflaggedPosition = flaggedPosition.unsetFlag();\\n root = updateLeaf(unflaggedPosition, weight, root);\\n }\\n\\n /// @notice Helper method to remove a leaf position record for an operator.\\n /// @param operator the address of the operator to remove the record for\\n function removeLeafPositionRecord(address operator) internal {\\n flaggedLeafPosition[operator] = 0;\\n }\\n\\n /// @notice Removes the data and weight from a particular leaf.\\n /// @param position the leaf index to remove\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function removeLeaf(uint256 position, uint256 _root)\\n internal\\n returns (uint256)\\n {\\n uint256 rightmostSubOne = rightmostLeaf - 1;\\n bool isRightmost = position == rightmostSubOne;\\n\\n // Clears out the data in the leaf node, and then propagates the weight\\n // changes all the way up to the root.\\n uint256 newRoot = setLeaf(position, 0, 0, _root);\\n\\n // Infer if need to fall back on emptyLeaves yet\\n if (isRightmost) {\\n rightmostLeaf = rightmostSubOne;\\n } else {\\n emptyLeaves.push(position);\\n }\\n return newRoot;\\n }\\n\\n /// @notice Updates the tree to give a particular leaf a new weight.\\n /// @param position the index of the leaf to update\\n /// @param weight the new weight\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function updateLeaf(\\n uint256 position,\\n uint256 weight,\\n uint256 _root\\n ) internal returns (uint256) {\\n if (getLeafWeight(position) != weight) {\\n return updateTree(position, weight, _root);\\n } else {\\n return _root;\\n }\\n }\\n\\n /// @notice Places a leaf into a particular position, with a given weight and\\n /// propagates that change.\\n /// @param position the index to place the leaf in\\n /// @param theLeaf the new leaf to place in the position\\n /// @param leafWeight the weight of the leaf\\n /// @param _root the root containing the new leaf\\n /// @return the updated root node\\n function setLeaf(\\n uint256 position,\\n uint256 theLeaf,\\n uint256 leafWeight,\\n uint256 _root\\n ) internal returns (uint256) {\\n // set leaf\\n leaves[position] = theLeaf;\\n\\n return (updateTree(position, leafWeight, _root));\\n }\\n\\n /// @notice Propagates a weight change at a position through the tree,\\n /// eventually returning the updated root.\\n /// @param position the index of leaf to update\\n /// @param weight the new weight of the leaf\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function updateTree(\\n uint256 position,\\n uint256 weight,\\n uint256 _root\\n ) internal returns (uint256) {\\n uint256 childSlot;\\n uint256 treeNode;\\n uint256 newNode;\\n uint256 nodeWeight = weight;\\n\\n uint256 parent = position;\\n // set levels 7 to 2\\n for (uint256 level = Constants.LEVELS; level >= 2; level--) {\\n childSlot = parent.slot();\\n parent = parent.parent();\\n treeNode = branches[level][parent];\\n newNode = treeNode.setSlot(childSlot, nodeWeight);\\n branches[level][parent] = newNode;\\n nodeWeight = newNode.sumWeight();\\n }\\n\\n // set level Root\\n childSlot = parent.slot();\\n return _root.setSlot(childSlot, nodeWeight);\\n }\\n\\n /// @notice Retrieves the next available empty leaf position. Tries to fill\\n /// left to right first, ignoring leaf removals, and then fills\\n /// most-recent-removals first.\\n /// @return the position of the empty leaf\\n function getEmptyLeafPosition() internal returns (uint256) {\\n uint256 rLeaf = rightmostLeaf;\\n bool spaceOnRight = (rLeaf + 1) < Constants.POOL_CAPACITY;\\n if (spaceOnRight) {\\n rightmostLeaf = rLeaf + 1;\\n return rLeaf;\\n } else {\\n uint256 emptyLeafCount = emptyLeaves.length;\\n require(emptyLeafCount > 0, \\\"Pool is full\\\");\\n uint256 emptyLeaf = emptyLeaves[emptyLeafCount - 1];\\n emptyLeaves.pop();\\n return emptyLeaf;\\n }\\n }\\n\\n /// @notice Gets the flagged leaf position for an operator.\\n /// @param operator the address of the operator\\n /// @return the leaf position of that operator\\n function getFlaggedLeafPosition(address operator)\\n internal\\n view\\n returns (uint256)\\n {\\n return flaggedLeafPosition[operator];\\n }\\n\\n /// @notice Gets the weight of a leaf at a particular position.\\n /// @param position the index of the leaf\\n /// @return the weight of the leaf at that position\\n function getLeafWeight(uint256 position) internal view returns (uint256) {\\n uint256 slot = position.slot();\\n uint256 parent = position.parent();\\n\\n // A leaf's weight information is stored a 32-bit slot in the branch layer\\n // directly above the leaf layer. To access it, we calculate that slot and\\n // parent position, and always know the hard-coded layer index.\\n uint256 node = branches[Constants.LEVELS][parent];\\n return node.getSlot(slot);\\n }\\n\\n /// @notice Picks a leaf given a random index.\\n /// @param index a number in `[0, _root.totalWeight())` used to decide\\n /// between leaves\\n /// @param _root the root of the tree\\n function pickWeightedLeaf(uint256 index, uint256 _root)\\n internal\\n view\\n returns (uint256 leafPosition)\\n {\\n uint256 currentIndex = index;\\n uint256 currentNode = _root;\\n uint256 currentPosition = 0;\\n uint256 currentSlot;\\n\\n require(index < currentNode.sumWeight(), \\\"Index exceeds weight\\\");\\n\\n // get root slot\\n (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex);\\n\\n // get slots from levels 2 to 7\\n for (uint256 level = 2; level <= Constants.LEVELS; level++) {\\n currentPosition = currentPosition.child(currentSlot);\\n currentNode = branches[level][currentPosition];\\n (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex);\\n }\\n\\n // get leaf position\\n leafPosition = currentPosition.child(currentSlot);\\n }\\n}\\n\",\"keccak256\":\"0x51daeca62ef52be78a1a9de4d2a1c5900c873165f59eda14d5965d7d7da90a03\"},\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IApproveAndCall.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\n/// @notice An interface that should be implemented by tokens supporting\\n/// `approveAndCall`/`receiveApproval` pattern.\\ninterface IApproveAndCall {\\n /// @notice Executes `receiveApproval` function on spender as specified in\\n /// `IReceiveApproval` interface. Approves spender to withdraw from\\n /// the caller multiple times, up to the `amount`. If this\\n /// function is called again, it overwrites the current allowance\\n /// with `amount`. Reverts if the approval reverted or if\\n /// `receiveApproval` call on the spender reverted.\\n function approveAndCall(\\n address spender,\\n uint256 amount,\\n bytes memory extraData\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x393d18ef81a57dcc96fff4c340cc2945deaebb37b9796c322cf2bc96872c3df8\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IERC20WithPermit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\\\";\\n\\nimport \\\"./IApproveAndCall.sol\\\";\\n\\n/// @title IERC20WithPermit\\n/// @notice Burnable ERC20 token with EIP2612 permit functionality. User can\\n/// authorize a transfer of their token with a signature conforming\\n/// EIP712 standard instead of an on-chain transaction from their\\n/// address. Anyone can submit this signature on the user's behalf by\\n/// calling the permit function, as specified in EIP2612 standard,\\n/// paying gas fees, and possibly performing other actions in the same\\n/// transaction.\\ninterface IERC20WithPermit is IERC20, IERC20Metadata, IApproveAndCall {\\n /// @notice EIP2612 approval made with secp256k1 signature.\\n /// Users can authorize a transfer of their tokens with a signature\\n /// conforming EIP712 standard, rather than an on-chain transaction\\n /// from their address. Anyone can submit this signature on the\\n /// user's behalf by calling the permit function, paying gas fees,\\n /// and possibly performing other actions in the same transaction.\\n /// @dev The deadline argument can be set to `type(uint256).max to create\\n /// permits that effectively never expire.\\n function permit(\\n address owner,\\n address spender,\\n uint256 amount,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /// @notice Destroys `amount` tokens from the caller.\\n function burn(uint256 amount) external;\\n\\n /// @notice Destroys `amount` of tokens from `account`, deducting the amount\\n /// from caller's allowance.\\n function burnFrom(address account, uint256 amount) external;\\n\\n /// @notice Returns hash of EIP712 Domain struct with the token name as\\n /// a signing domain and token contract as a verifying contract.\\n /// Used to construct EIP2612 signature provided to `permit`\\n /// function.\\n /* solhint-disable-next-line func-name-mixedcase */\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n\\n /// @notice Returns the current nonce for EIP2612 permission for the\\n /// provided token owner for a replay protection. Used to construct\\n /// EIP2612 signature provided to `permit` function.\\n function nonce(address owner) external view returns (uint256);\\n\\n /// @notice Returns EIP2612 Permit message hash. Used to construct EIP2612\\n /// signature provided to `permit` function.\\n /* solhint-disable-next-line func-name-mixedcase */\\n function PERMIT_TYPEHASH() external pure returns (bytes32);\\n}\\n\",\"keccak256\":\"0xdac9a5086c19a7128b505a7be1ab0ac1aa314f6989cb88d2417e9d7383f89fa9\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IReceiveApproval.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\n/// @notice An interface that should be implemented by contracts supporting\\n/// `approveAndCall`/`receiveApproval` pattern.\\ninterface IReceiveApproval {\\n /// @notice Receives approval to spend tokens. Called as a result of\\n /// `approveAndCall` call on the token.\\n function receiveApproval(\\n address from,\\n uint256 amount,\\n address token,\\n bytes calldata extraData\\n ) external;\\n}\\n\",\"keccak256\":\"0x6a30d83ad230548b1e7839737affc8489a035314209de14b89dbef7fb0f66395\",\"license\":\"MIT\"}},\"version\":1}", + "storageLayout": { + "storage": [ + { + "astId": 1997, + "contract": "@keep-network/sortition-pools/contracts/SortitionPool.sol:SortitionPool", + "label": "root", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 2003, + "contract": "@keep-network/sortition-pools/contracts/SortitionPool.sol:SortitionPool", + "label": "branches", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_uint256,t_mapping(t_uint256,t_uint256))" + }, + { + "astId": 2007, + "contract": "@keep-network/sortition-pools/contracts/SortitionPool.sol:SortitionPool", + "label": "leaves", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_uint256,t_uint256)" + }, + { + "astId": 2011, + "contract": "@keep-network/sortition-pools/contracts/SortitionPool.sol:SortitionPool", + "label": "flaggedLeafPosition", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_address,t_uint256)" + }, + { + "astId": 2013, + "contract": "@keep-network/sortition-pools/contracts/SortitionPool.sol:SortitionPool", + "label": "rightmostLeaf", + "offset": 0, + "slot": "4", + "type": "t_uint256" + }, + { + "astId": 2016, + "contract": "@keep-network/sortition-pools/contracts/SortitionPool.sol:SortitionPool", + "label": "emptyLeaves", + "offset": 0, + "slot": "5", + "type": "t_array(t_uint256)dyn_storage" + }, + { + "astId": 2020, + "contract": "@keep-network/sortition-pools/contracts/SortitionPool.sol:SortitionPool", + "label": "operatorID", + "offset": 0, + "slot": "6", + "type": "t_mapping(t_address,t_uint32)" + }, + { + "astId": 2023, + "contract": "@keep-network/sortition-pools/contracts/SortitionPool.sol:SortitionPool", + "label": "idAddress", + "offset": 0, + "slot": "7", + "type": "t_array(t_address)dyn_storage" + }, + { + "astId": 810, + "contract": "@keep-network/sortition-pools/contracts/SortitionPool.sol:SortitionPool", + "label": "globalRewardAccumulator", + "offset": 0, + "slot": "8", + "type": "t_uint96" + }, + { + "astId": 812, + "contract": "@keep-network/sortition-pools/contracts/SortitionPool.sol:SortitionPool", + "label": "rewardRoundingDust", + "offset": 12, + "slot": "8", + "type": "t_uint96" + }, + { + "astId": 814, + "contract": "@keep-network/sortition-pools/contracts/SortitionPool.sol:SortitionPool", + "label": "ineligibleEarnedRewards", + "offset": 0, + "slot": "9", + "type": "t_uint96" + }, + { + "astId": 821, + "contract": "@keep-network/sortition-pools/contracts/SortitionPool.sol:SortitionPool", + "label": "operatorRewards", + "offset": 0, + "slot": "10", + "type": "t_mapping(t_uint32,t_struct(OperatorRewards)808_storage)" + }, + { + "astId": 3888, + "contract": "@keep-network/sortition-pools/contracts/SortitionPool.sol:SortitionPool", + "label": "_owner", + "offset": 0, + "slot": "11", + "type": "t_address" + }, + { + "astId": 231, + "contract": "@keep-network/sortition-pools/contracts/SortitionPool.sol:SortitionPool", + "label": "isChaosnetActive", + "offset": 20, + "slot": "11", + "type": "t_bool" + }, + { + "astId": 236, + "contract": "@keep-network/sortition-pools/contracts/SortitionPool.sol:SortitionPool", + "label": "isBetaOperator", + "offset": 0, + "slot": "12", + "type": "t_mapping(t_address,t_bool)" + }, + { + "astId": 239, + "contract": "@keep-network/sortition-pools/contracts/SortitionPool.sol:SortitionPool", + "label": "chaosnetOwner", + "offset": 0, + "slot": "13", + "type": "t_address" + }, + { + "astId": 1363, + "contract": "@keep-network/sortition-pools/contracts/SortitionPool.sol:SortitionPool", + "label": "isLocked", + "offset": 20, + "slot": "13", + "type": "t_bool" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_address)dyn_storage": { + "base": "t_address", + "encoding": "dynamic_array", + "label": "address[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)dyn_storage": { + "base": "t_uint256", + "encoding": "dynamic_array", + "label": "uint256[]", + "numberOfBytes": "32" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_address,t_uint256)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_mapping(t_address,t_uint32)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => uint32)", + "numberOfBytes": "32", + "value": "t_uint32" + }, + "t_mapping(t_uint256,t_mapping(t_uint256,t_uint256))": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => mapping(uint256 => uint256))", + "numberOfBytes": "32", + "value": "t_mapping(t_uint256,t_uint256)" + }, + "t_mapping(t_uint256,t_uint256)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_mapping(t_uint32,t_struct(OperatorRewards)808_storage)": { + "encoding": "mapping", + "key": "t_uint32", + "label": "mapping(uint32 => struct Rewards.OperatorRewards)", + "numberOfBytes": "32", + "value": "t_struct(OperatorRewards)808_storage" + }, + "t_struct(OperatorRewards)808_storage": { + "encoding": "inplace", + "label": "struct Rewards.OperatorRewards", + "members": [ + { + "astId": 801, + "contract": "@keep-network/sortition-pools/contracts/SortitionPool.sol:SortitionPool", + "label": "accumulated", + "offset": 0, + "slot": "0", + "type": "t_uint96" + }, + { + "astId": 803, + "contract": "@keep-network/sortition-pools/contracts/SortitionPool.sol:SortitionPool", + "label": "available", + "offset": 12, + "slot": "0", + "type": "t_uint96" + }, + { + "astId": 805, + "contract": "@keep-network/sortition-pools/contracts/SortitionPool.sol:SortitionPool", + "label": "ineligibleUntil", + "offset": 24, + "slot": "0", + "type": "t_uint32" + }, + { + "astId": 807, + "contract": "@keep-network/sortition-pools/contracts/SortitionPool.sol:SortitionPool", + "label": "weight", + "offset": 28, + "slot": "0", + "type": "t_uint32" + } + ], + "numberOfBytes": "32" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint32": { + "encoding": "inplace", + "label": "uint32", + "numberOfBytes": "4" + }, + "t_uint96": { + "encoding": "inplace", + "label": "uint96", + "numberOfBytes": "12" + } + } + }, + "userdoc": { + "kind": "user", + "methods": { + "addBetaOperators(address[])": { + "notice": "Adds beta operator to chaosnet. Can be called only by the chaosnet owner when the chaosnet is active. Once the operator is added as a beta operator, it can not be removed." + }, + "canRestoreRewardEligibility(address)": { + "notice": "Returns whether the operator is able to restore their eligibility for rewards right away." + }, + "chaosnetOwner()": { + "notice": "Address controlling chaosnet status and beta operator addresses." + }, + "deactivateChaosnet()": { + "notice": "Deactivates the chaosnet. Can be called only by the chaosnet owner. Once deactivated chaosnet can not be activated again." + }, + "getAvailableRewards(address)": { + "notice": "Returns the amount of rewards withdrawable for the given operator." + }, + "getIDOperator(uint32)": { + "notice": "Get the operator address corresponding to the given ID number. A zero address means the ID number has not been allocated yet." + }, + "getIDOperators(uint32[])": { + "notice": "Gets the operator addresses corresponding to the given ID numbers. A zero address means the ID number has not been allocated yet. This function works just like getIDOperator except that it allows to fetch operator addresses for multiple IDs in one call." + }, + "getOperatorID(address)": { + "notice": "Return the ID number of the given operator address. An ID number of 0 means the operator has not been allocated an ID number yet." + }, + "getPoolWeight(address)": { + "notice": "Return the weight of the operator in the pool, which may or may not be out of date." + }, + "insertOperator(address,uint256)": { + "notice": "Inserts an operator to the pool. Reverts if the operator is already present. Reverts if the operator is not eligible because of their authorized stake. Reverts if the chaosnet is active and the operator is not a beta operator." + }, + "isBetaOperator(address)": { + "notice": "Indicates if the given operator is a beta operator for chaosnet." + }, + "isChaosnetActive()": { + "notice": "Indicates if the chaosnet is active. The chaosnet is active after the contract deployment and can be ended with a call to `deactivateChaosnet()`. Once deactivated chaosnet can not be activated again." + }, + "isEligibleForRewards(address)": { + "notice": "Returns whether the operator is eligible for rewards or not." + }, + "isOperatorInPool(address)": { + "notice": "Return whether the operator is present in the pool." + }, + "isOperatorRegistered(address)": { + "notice": "Checks if operator is already registered in the pool." + }, + "isOperatorUpToDate(address,uint256)": { + "notice": "Return whether the operator's weight in the pool matches their eligible weight." + }, + "lock()": { + "notice": "Locks the sortition pool. In locked state, members cannot be inserted and removed from the pool. Members statuses cannot be updated as well." + }, + "operatorsInPool()": { + "notice": "Sum the number of operators in each trunk." + }, + "restoreRewardEligibility(address)": { + "notice": "Restores reward eligibility for the operator." + }, + "rewardsEligibilityRestorableAt(address)": { + "notice": "Returns the time the operator's reward eligibility can be restored." + }, + "selectGroup(uint256,bytes32)": { + "notice": "Selects a new group of operators of the provided size based on the provided pseudo-random seed. At least one operator has to be registered in the pool, otherwise the function fails reverting the transaction." + }, + "setRewardIneligibility(uint32[],uint256)": { + "notice": "Set the given operators as ineligible for rewards. The operators can restore their eligibility at the given time." + }, + "totalWeight()": { + "notice": "Convenience method to return the total weight of the pool" + }, + "transferChaosnetOwnerRole(address)": { + "notice": "Transfers the chaosnet owner role to another non-zero address." + }, + "unlock()": { + "notice": "Unlocks the sortition pool. Removes all restrictions set by the `lock` method." + }, + "updateOperatorStatus(address,uint256)": { + "notice": "Update the operator's weight if present and eligible, or remove from the pool if present and ineligible." + }, + "withdrawIneligible(address)": { + "notice": "Withdraws rewards not allocated to operators marked as ineligible to the given recipient address." + }, + "withdrawRewards(address,address)": { + "notice": "Withdraws all available rewards for the given operator to the given beneficiary." + } + }, + "notice": "A logarithmic data structure used to store the pool of eligible operators weighted by their stakes. It allows to select a group of operators based on the provided pseudo-random seed.", + "version": 1 + } +} diff --git a/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/BeaconDkgValidator.sol/BeaconDkgValidator.json b/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/BeaconDkgValidator.sol/BeaconDkgValidator.json new file mode 100644 index 0000000000..4001f30a63 --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/BeaconDkgValidator.sol/BeaconDkgValidator.json @@ -0,0 +1,484 @@ +{ + "contractName": "BeaconDkgValidator", + "sourceName": "contracts/BeaconDkgValidator.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "contract SortitionPool", + "name": "_sortitionPool", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "activeThreshold", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "groupSize", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "groupThreshold", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "signatureByteSize", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "sortitionPool", + "outputs": [ + { + "internalType": "contract SortitionPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct BeaconDkg.Result", + "name": "result", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "seed", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startBlock", + "type": "uint256" + } + ], + "name": "validate", + "outputs": [ + { + "internalType": "bool", + "name": "isValid", + "type": "bool" + }, + { + "internalType": "string", + "name": "errorMsg", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct BeaconDkg.Result", + "name": "result", + "type": "tuple" + } + ], + "name": "validateFields", + "outputs": [ + { + "internalType": "bool", + "name": "isValid", + "type": "bool" + }, + { + "internalType": "string", + "name": "errorMsg", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct BeaconDkg.Result", + "name": "result", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "seed", + "type": "uint256" + } + ], + "name": "validateGroupMembers", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct BeaconDkg.Result", + "name": "result", + "type": "tuple" + } + ], + "name": "validateMembersHash", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct BeaconDkg.Result", + "name": "result", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "startBlock", + "type": "uint256" + } + ], + "name": "validateSignatures", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": "0x60a060405234801561001057600080fd5b5060405161195238038061195283398101604081905261002f9161009a565b6001600160a01b0381166100895760405162461bcd60e51b815260206004820152601660248201527f5a65726f2d61646472657373207265666572656e636500000000000000000000604482015260640160405180910390fd5b6001600160a01b03166080526100ca565b6000602082840312156100ac57600080fd5b81516001600160a01b03811681146100c357600080fd5b9392505050565b60805161185f6100f360003960008181610132015281816106d50152610cc2015261185f6000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c80639617c2a8116100665780639617c2a8146100f7578063b2d44fce1461011a578063b54a23741461012d578063e7667aba1461016c578063e7d10d9b1461017f57600080fd5b8063281efe71146100a35780632c5c72df146100be57806363b635ea146100df5780636dcc64f8146100e757806389ef44b0146100ef575b600080fd5b6100ab603a81565b6040519081526020015b60405180910390f35b6100d16100cc36600461120d565b610192565b6040516100b592919061124a565b6100ab604081565b6100ab602181565b6100ab604181565b61010a6101053660046112a2565b61069d565b60405190151581526020016100b5565b61010a61012836600461120d565b6107ee565b6101547f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100b5565b6100d161017a3660046112e7565b6109fb565b61010a61018d3660046112a2565b610b18565b600060606101a36020840184611335565b90506080146101ea57505060408051808201909152601a81527f4d616c666f726d65642067726f7570207075626c6963206b65790000000000006020820152600092909150565b3660006101fa604086018661137c565b9092509050603a61020c8260406113dc565b10156102385760006040518060600160405280602781526020016117df60279139935093505050915091565b600181111561038157600182826000818110610256576102566113ef565b905060200201602081019061026b919061141b565b60ff1610806102ad5750604082826102846001826113dc565b818110610293576102936113ef565b90506020020160208101906102a8919061141b565b60ff16115b156102d857600060405180606001604052806024815260200161180660249139935093505050915091565b60015b8181101561037f578282828181106102f5576102f56113ef565b905060200201602081019061030a919061141b565b60ff16838361031a6001856113dc565b818110610329576103296113ef565b905060200201602081019061033e919061141b565b60ff161061036d5760006040518060600160405280602481526020016118066024913994509450505050915091565b806103778161143d565b9150506102db565b505b600060416103926060880188611335565b61039d92915061146c565b90506103ac6060870187611335565b90506000036103f257600060405180604001604052806016815260200175139bc81cda59db985d1d5c995cc81c1c9bdd9a59195960521b81525094509450505050915091565b60416104016060880188611335565b61040c929150611480565b156104555760006040518060400160405280601a81526020017f4d616c666f726d6564207369676e61747572657320617272617900000000000081525094509450505050915091565b366000610465608089018961137c565b90925090508281146104b75760006040518060400160405280601b81526020017f556e6578706563746564207369676e61747572657320636f756e740000000000815250965096505050505050915091565b60218310156104fb57600060405180604001604052806012815260200171546f6f20666577207369676e61747572657360701b815250965096505050505050915091565b604083111561054057600060405180604001604052806013815260200172546f6f206d616e79207369676e61747572657360681b815250965096505050505050915091565b600182826000818110610555576105556113ef565b90506020020135108061058a5750604082826105726001826113dc565b818110610581576105816113ef565b90506020020135115b156105d55760006040518060400160405280602081526020017f436f72727570746564207369676e696e67206d656d62657220696e6469636573815250965096505050505050915091565b60015b8181101561067c578282828181106105f2576105f26113ef565b90506020020135838360018461060891906113dc565b818110610617576106176113ef565b905060200201351061066a5760006040518060400160405280602081526020017f436f72727570746564207369676e696e67206d656d62657220696e646963657381525097509750505050505050915091565b806106748161143d565b9150506105d8565b50600160405180602001604052806000815250965096505050505050915091565b600036816106ae60a086018661137c565b60408051636c2530b960e01b815260048101919091526024810187905291935091506000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636c2530b990604401600060405180830381865afa158015610724573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261074c9190810190611511565b8051909150821461076357600093505050506107e8565b60005b828110156107df57818181518110610780576107806113ef565b602002602001015163ffffffff168484838181106107a0576107a06113ef565b90506020020160208101906107b591906115b0565b63ffffffff16146107cd5760009450505050506107e8565b806107d78161143d565b915050610766565b50600193505050505b92915050565b6000806107fe604084018461137c565b905011156109ba576000610815604084018461137c565b905061082460a085018561137c565b61082f9291506113dc565b67ffffffffffffffff81111561084757610847611494565b604051908082528060200260200182016040528015610870578160200160208202803683370190505b50905060008060005b61088660a087018761137c565b905081101561098257600161089e604088018861137c565b858181106108ae576108ae6113ef565b90506020020160208101906108c3919061141b565b6108cd91906115cd565b60ff168114610941576108e360a087018761137c565b828181106108f3576108f36113ef565b905060200201602081019061090891906115b0565b84838151811061091a5761091a6113ef565b63ffffffff90921660209283029190910190910152816109398161143d565b925050610970565b6001610950604088018861137c565b61095b9291506113dc565b831015610970578261096c8161143d565b9350505b8061097a8161143d565b915050610879565b508460c001358360405160200161099991906115e6565b60405160208183030381529060405280519060200120149350505050919050565b60c08201356109cc60a084018461137c565b6040516020016109dd929190611630565b60405160208183030381529060405280519060200120149050919050565b60006060600080610a0b87610192565b9150915081610a2157600093509150610b109050565b610a2b8786610b18565b610a6757600060405180604001604052806012815260200171496e76616c6964207369676e61747572657360701b815250935093505050610b10565b610a71878761069d565b610ab057600060405180604001604052806015815260200174496e76616c69642067726f7570206d656d6265727360581b815250935093505050610b10565b610ab9876107ee565b610af757600060405180604001604052806014815260200173092dcecc2d8d2c840dacadac4cae4e640d0c2e6d60631b815250935093505050610b10565b6001604051806020016040528060008152509350935050505b935093915050565b600080610baf46610b2c6020870187611335565b610b39604089018961137c565b88604051602001610b4f9695949392919061167b565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b9050366000610bc1608087018761137c565b909250905060008167ffffffffffffffff811115610be157610be1611494565b604051908082528060200260200182016040528015610c0a578160200160208202803683370190505b50905060005b82811015610ca757610c2560a089018961137c565b6001868685818110610c3957610c396113ef565b90506020020135610c4a91906113dc565b818110610c5957610c596113ef565b9050602002016020810190610c6e91906115b0565b828281518110610c8057610c806113ef565b63ffffffff9092166020928302919091019091015280610c9f8161143d565b915050610c10565b50604051637bfcd47d60e11b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f7f9a8fa90610cf79085906004016115e6565b600060405180830381865afa158015610d14573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d3c9190810190611702565b9050606060006041610d508b84018c611335565b610d5b92915061146c565b905060005b81811015610e2a57610dc3610d7682604161179e565b6041610d8560608f018f611335565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929493925050610e3b9050565b92506000610dd18985610ee6565b9050806001600160a01b0316858381518110610def57610def6113ef565b60200260200101516001600160a01b031614610e1757600099505050505050505050506107e8565b5080610e228161143d565b915050610d60565b5060019a9950505050505050505050565b60606000610e4983856117b5565b90508381118015610e5b575080855110155b610ea25760405162461bcd60e51b8152602060048201526013602482015272536c696365206f7574206f6620626f756e647360681b60448201526064015b60405180910390fd5b604051915082604083010160405282825283850182038460208701018481015b80821015610edb57815183830152602082019150610ec2565b505050509392505050565b6000806000610ef58585610f0a565b91509150610f0281610f4f565b509392505050565b6000808251604103610f405760208301516040840151606085015160001a610f3487828585611108565b94509450505050610f48565b506000905060025b9250929050565b6000816004811115610f6357610f636117c8565b03610f6b5750565b6001816004811115610f7f57610f7f6117c8565b03610fcc5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610e99565b6002816004811115610fe057610fe06117c8565b0361102d5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610e99565b6003816004811115611041576110416117c8565b036110995760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610e99565b60048160048111156110ad576110ad6117c8565b036111055760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401610e99565b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561113f57506000905060036111ec565b8460ff16601b1415801561115757508460ff16601c14155b1561116857506000905060046111ec565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156111bc573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166111e5576000600192509250506111ec565b9150600090505b94509492505050565b600060e0828403121561120757600080fd5b50919050565b60006020828403121561121f57600080fd5b813567ffffffffffffffff81111561123657600080fd5b611242848285016111f5565b949350505050565b821515815260006020604081840152835180604085015260005b8181101561128057858101830151858201606001528201611264565b506000606082860101526060601f19601f830116850101925050509392505050565b600080604083850312156112b557600080fd5b823567ffffffffffffffff8111156112cc57600080fd5b6112d8858286016111f5565b95602094909401359450505050565b6000806000606084860312156112fc57600080fd5b833567ffffffffffffffff81111561131357600080fd5b61131f868287016111f5565b9660208601359650604090950135949350505050565b6000808335601e1984360301811261134c57600080fd5b83018035915067ffffffffffffffff82111561136757600080fd5b602001915036819003821315610f4857600080fd5b6000808335601e1984360301811261139357600080fd5b83018035915067ffffffffffffffff8211156113ae57600080fd5b6020019150600581901b3603821315610f4857600080fd5b634e487b7160e01b600052601160045260246000fd5b818103818111156107e8576107e86113c6565b634e487b7160e01b600052603260045260246000fd5b803560ff8116811461141657600080fd5b919050565b60006020828403121561142d57600080fd5b61143682611405565b9392505050565b60006001820161144f5761144f6113c6565b5060010190565b634e487b7160e01b600052601260045260246000fd5b60008261147b5761147b611456565b500490565b60008261148f5761148f611456565b500690565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156114d3576114d3611494565b604052919050565b600067ffffffffffffffff8211156114f5576114f5611494565b5060051b60200190565b63ffffffff8116811461110557600080fd5b6000602080838503121561152457600080fd5b825167ffffffffffffffff81111561153b57600080fd5b8301601f8101851361154c57600080fd5b805161155f61155a826114db565b6114aa565b81815260059190911b8201830190838101908783111561157e57600080fd5b928401925b828410156115a5578351611596816114ff565b82529284019290840190611583565b979650505050505050565b6000602082840312156115c257600080fd5b8135611436816114ff565b60ff82811682821603908111156107e8576107e86113c6565b6020808252825182820181905260009190848201906040850190845b8181101561162457835163ffffffff1683529284019291840191600101611602565b50909695505050505050565b60208082528181018390526000908460408401835b86811015611670578235611658816114ff565b63ffffffff1682529183019190830190600101611645565b509695505050505050565b86815260006020608081840152866080840152868860a0850137600060a08885018101829052601f19601f8a011685018581038201604087015290810187905287919060c0015b878210156116ea5760ff6116d584611405565b168152918301916001919091019083016116c2565b80945050505050826060830152979650505050505050565b6000602080838503121561171557600080fd5b825167ffffffffffffffff81111561172c57600080fd5b8301601f8101851361173d57600080fd5b805161174b61155a826114db565b81815260059190911b8201830190838101908783111561176a57600080fd5b928401925b828410156115a55783516001600160a01b038116811461178f5760008081fd5b8252928401929084019061176f565b80820281158282048414176107e8576107e86113c6565b808201808211156107e8576107e86113c6565b634e487b7160e01b600052602160045260246000fdfe546f6f206d616e79206d656d62657273206d69736265686176696e6720647572696e6720444b47436f72727570746564206d697362656861766564206d656d6265727320696e6469636573a26469706673582212208f9bef7dbb3b3c3396c4db29a0a0cf2a455196d33f6d5cd44437727a5a1f03d964736f6c63430008110033", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061009e5760003560e01c80639617c2a8116100665780639617c2a8146100f7578063b2d44fce1461011a578063b54a23741461012d578063e7667aba1461016c578063e7d10d9b1461017f57600080fd5b8063281efe71146100a35780632c5c72df146100be57806363b635ea146100df5780636dcc64f8146100e757806389ef44b0146100ef575b600080fd5b6100ab603a81565b6040519081526020015b60405180910390f35b6100d16100cc36600461120d565b610192565b6040516100b592919061124a565b6100ab604081565b6100ab602181565b6100ab604181565b61010a6101053660046112a2565b61069d565b60405190151581526020016100b5565b61010a61012836600461120d565b6107ee565b6101547f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100b5565b6100d161017a3660046112e7565b6109fb565b61010a61018d3660046112a2565b610b18565b600060606101a36020840184611335565b90506080146101ea57505060408051808201909152601a81527f4d616c666f726d65642067726f7570207075626c6963206b65790000000000006020820152600092909150565b3660006101fa604086018661137c565b9092509050603a61020c8260406113dc565b10156102385760006040518060600160405280602781526020016117df60279139935093505050915091565b600181111561038157600182826000818110610256576102566113ef565b905060200201602081019061026b919061141b565b60ff1610806102ad5750604082826102846001826113dc565b818110610293576102936113ef565b90506020020160208101906102a8919061141b565b60ff16115b156102d857600060405180606001604052806024815260200161180660249139935093505050915091565b60015b8181101561037f578282828181106102f5576102f56113ef565b905060200201602081019061030a919061141b565b60ff16838361031a6001856113dc565b818110610329576103296113ef565b905060200201602081019061033e919061141b565b60ff161061036d5760006040518060600160405280602481526020016118066024913994509450505050915091565b806103778161143d565b9150506102db565b505b600060416103926060880188611335565b61039d92915061146c565b90506103ac6060870187611335565b90506000036103f257600060405180604001604052806016815260200175139bc81cda59db985d1d5c995cc81c1c9bdd9a59195960521b81525094509450505050915091565b60416104016060880188611335565b61040c929150611480565b156104555760006040518060400160405280601a81526020017f4d616c666f726d6564207369676e61747572657320617272617900000000000081525094509450505050915091565b366000610465608089018961137c565b90925090508281146104b75760006040518060400160405280601b81526020017f556e6578706563746564207369676e61747572657320636f756e740000000000815250965096505050505050915091565b60218310156104fb57600060405180604001604052806012815260200171546f6f20666577207369676e61747572657360701b815250965096505050505050915091565b604083111561054057600060405180604001604052806013815260200172546f6f206d616e79207369676e61747572657360681b815250965096505050505050915091565b600182826000818110610555576105556113ef565b90506020020135108061058a5750604082826105726001826113dc565b818110610581576105816113ef565b90506020020135115b156105d55760006040518060400160405280602081526020017f436f72727570746564207369676e696e67206d656d62657220696e6469636573815250965096505050505050915091565b60015b8181101561067c578282828181106105f2576105f26113ef565b90506020020135838360018461060891906113dc565b818110610617576106176113ef565b905060200201351061066a5760006040518060400160405280602081526020017f436f72727570746564207369676e696e67206d656d62657220696e646963657381525097509750505050505050915091565b806106748161143d565b9150506105d8565b50600160405180602001604052806000815250965096505050505050915091565b600036816106ae60a086018661137c565b60408051636c2530b960e01b815260048101919091526024810187905291935091506000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636c2530b990604401600060405180830381865afa158015610724573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261074c9190810190611511565b8051909150821461076357600093505050506107e8565b60005b828110156107df57818181518110610780576107806113ef565b602002602001015163ffffffff168484838181106107a0576107a06113ef565b90506020020160208101906107b591906115b0565b63ffffffff16146107cd5760009450505050506107e8565b806107d78161143d565b915050610766565b50600193505050505b92915050565b6000806107fe604084018461137c565b905011156109ba576000610815604084018461137c565b905061082460a085018561137c565b61082f9291506113dc565b67ffffffffffffffff81111561084757610847611494565b604051908082528060200260200182016040528015610870578160200160208202803683370190505b50905060008060005b61088660a087018761137c565b905081101561098257600161089e604088018861137c565b858181106108ae576108ae6113ef565b90506020020160208101906108c3919061141b565b6108cd91906115cd565b60ff168114610941576108e360a087018761137c565b828181106108f3576108f36113ef565b905060200201602081019061090891906115b0565b84838151811061091a5761091a6113ef565b63ffffffff90921660209283029190910190910152816109398161143d565b925050610970565b6001610950604088018861137c565b61095b9291506113dc565b831015610970578261096c8161143d565b9350505b8061097a8161143d565b915050610879565b508460c001358360405160200161099991906115e6565b60405160208183030381529060405280519060200120149350505050919050565b60c08201356109cc60a084018461137c565b6040516020016109dd929190611630565b60405160208183030381529060405280519060200120149050919050565b60006060600080610a0b87610192565b9150915081610a2157600093509150610b109050565b610a2b8786610b18565b610a6757600060405180604001604052806012815260200171496e76616c6964207369676e61747572657360701b815250935093505050610b10565b610a71878761069d565b610ab057600060405180604001604052806015815260200174496e76616c69642067726f7570206d656d6265727360581b815250935093505050610b10565b610ab9876107ee565b610af757600060405180604001604052806014815260200173092dcecc2d8d2c840dacadac4cae4e640d0c2e6d60631b815250935093505050610b10565b6001604051806020016040528060008152509350935050505b935093915050565b600080610baf46610b2c6020870187611335565b610b39604089018961137c565b88604051602001610b4f9695949392919061167b565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b9050366000610bc1608087018761137c565b909250905060008167ffffffffffffffff811115610be157610be1611494565b604051908082528060200260200182016040528015610c0a578160200160208202803683370190505b50905060005b82811015610ca757610c2560a089018961137c565b6001868685818110610c3957610c396113ef565b90506020020135610c4a91906113dc565b818110610c5957610c596113ef565b9050602002016020810190610c6e91906115b0565b828281518110610c8057610c806113ef565b63ffffffff9092166020928302919091019091015280610c9f8161143d565b915050610c10565b50604051637bfcd47d60e11b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f7f9a8fa90610cf79085906004016115e6565b600060405180830381865afa158015610d14573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d3c9190810190611702565b9050606060006041610d508b84018c611335565b610d5b92915061146c565b905060005b81811015610e2a57610dc3610d7682604161179e565b6041610d8560608f018f611335565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929493925050610e3b9050565b92506000610dd18985610ee6565b9050806001600160a01b0316858381518110610def57610def6113ef565b60200260200101516001600160a01b031614610e1757600099505050505050505050506107e8565b5080610e228161143d565b915050610d60565b5060019a9950505050505050505050565b60606000610e4983856117b5565b90508381118015610e5b575080855110155b610ea25760405162461bcd60e51b8152602060048201526013602482015272536c696365206f7574206f6620626f756e647360681b60448201526064015b60405180910390fd5b604051915082604083010160405282825283850182038460208701018481015b80821015610edb57815183830152602082019150610ec2565b505050509392505050565b6000806000610ef58585610f0a565b91509150610f0281610f4f565b509392505050565b6000808251604103610f405760208301516040840151606085015160001a610f3487828585611108565b94509450505050610f48565b506000905060025b9250929050565b6000816004811115610f6357610f636117c8565b03610f6b5750565b6001816004811115610f7f57610f7f6117c8565b03610fcc5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610e99565b6002816004811115610fe057610fe06117c8565b0361102d5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610e99565b6003816004811115611041576110416117c8565b036110995760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610e99565b60048160048111156110ad576110ad6117c8565b036111055760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401610e99565b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561113f57506000905060036111ec565b8460ff16601b1415801561115757508460ff16601c14155b1561116857506000905060046111ec565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156111bc573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166111e5576000600192509250506111ec565b9150600090505b94509492505050565b600060e0828403121561120757600080fd5b50919050565b60006020828403121561121f57600080fd5b813567ffffffffffffffff81111561123657600080fd5b611242848285016111f5565b949350505050565b821515815260006020604081840152835180604085015260005b8181101561128057858101830151858201606001528201611264565b506000606082860101526060601f19601f830116850101925050509392505050565b600080604083850312156112b557600080fd5b823567ffffffffffffffff8111156112cc57600080fd5b6112d8858286016111f5565b95602094909401359450505050565b6000806000606084860312156112fc57600080fd5b833567ffffffffffffffff81111561131357600080fd5b61131f868287016111f5565b9660208601359650604090950135949350505050565b6000808335601e1984360301811261134c57600080fd5b83018035915067ffffffffffffffff82111561136757600080fd5b602001915036819003821315610f4857600080fd5b6000808335601e1984360301811261139357600080fd5b83018035915067ffffffffffffffff8211156113ae57600080fd5b6020019150600581901b3603821315610f4857600080fd5b634e487b7160e01b600052601160045260246000fd5b818103818111156107e8576107e86113c6565b634e487b7160e01b600052603260045260246000fd5b803560ff8116811461141657600080fd5b919050565b60006020828403121561142d57600080fd5b61143682611405565b9392505050565b60006001820161144f5761144f6113c6565b5060010190565b634e487b7160e01b600052601260045260246000fd5b60008261147b5761147b611456565b500490565b60008261148f5761148f611456565b500690565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156114d3576114d3611494565b604052919050565b600067ffffffffffffffff8211156114f5576114f5611494565b5060051b60200190565b63ffffffff8116811461110557600080fd5b6000602080838503121561152457600080fd5b825167ffffffffffffffff81111561153b57600080fd5b8301601f8101851361154c57600080fd5b805161155f61155a826114db565b6114aa565b81815260059190911b8201830190838101908783111561157e57600080fd5b928401925b828410156115a5578351611596816114ff565b82529284019290840190611583565b979650505050505050565b6000602082840312156115c257600080fd5b8135611436816114ff565b60ff82811682821603908111156107e8576107e86113c6565b6020808252825182820181905260009190848201906040850190845b8181101561162457835163ffffffff1683529284019291840191600101611602565b50909695505050505050565b60208082528181018390526000908460408401835b86811015611670578235611658816114ff565b63ffffffff1682529183019190830190600101611645565b509695505050505050565b86815260006020608081840152866080840152868860a0850137600060a08885018101829052601f19601f8a011685018581038201604087015290810187905287919060c0015b878210156116ea5760ff6116d584611405565b168152918301916001919091019083016116c2565b80945050505050826060830152979650505050505050565b6000602080838503121561171557600080fd5b825167ffffffffffffffff81111561172c57600080fd5b8301601f8101851361173d57600080fd5b805161174b61155a826114db565b81815260059190911b8201830190838101908783111561176a57600080fd5b928401925b828410156115a55783516001600160a01b038116811461178f5760008081fd5b8252928401929084019061176f565b80820281158282048414176107e8576107e86113c6565b808201808211156107e8576107e86113c6565b634e487b7160e01b600052602160045260246000fdfe546f6f206d616e79206d656d62657273206d69736265686176696e6720647572696e6720444b47436f72727570746564206d697362656861766564206d656d6265727320696e6469636573a26469706673582212208f9bef7dbb3b3c3396c4db29a0a0cf2a455196d33f6d5cd44437727a5a1f03d964736f6c63430008110033", + "linkReferences": {}, + "deployedLinkReferences": {}, + "devdoc": { + "kind": "dev", + "methods": { + "validate((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32),uint256,uint256)": { + "params": { + "seed": "seed used to start the DKG and select group members", + "startBlock": "DKG start block" + }, + "returns": { + "errorMsg": "validation error message; empty for a valid result", + "isValid": "true if the result is valid, false otherwise" + } + }, + "validateFields((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))": { + "returns": { + "errorMsg": "validation error message; empty for a valid result", + "isValid": "true if the result is valid, false otherwise" + } + }, + "validateGroupMembers((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32),uint256)": { + "params": { + "seed": "seed used to start the DKG and select group members" + }, + "returns": { + "_0": "true if group members matches; false otherwise" + } + }, + "validateMembersHash((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))": { + "params": { + "result": "DKG result" + }, + "returns": { + "_0": "true if result's group members hash matches with the one that is challenged." + } + }, + "validateSignatures((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32),uint256)": { + "params": { + "startBlock": "DKG start block" + }, + "returns": { + "_0": "true if group members matches; false otherwise" + } + } + }, + "stateVariables": { + "activeThreshold": { + "details": "The minimum number of active and properly behaving group members during the DKG needed to accept the result. This number is higher than `groupThreshold` to keep a safety margin for members becoming inactive after DKG so that the group can still produce a relay entry." + }, + "groupSize": { + "details": "Size of a group in the threshold relay." + }, + "groupThreshold": { + "details": "The minimum number of group members needed to interact according to the protocol to produce a relay entry. The adversary can not learn anything about the key as long as it does not break into groupThreshold+1 of members." + }, + "signatureByteSize": { + "details": "Size in bytes of a single signature produced by operator supporting DKG result." + } + }, + "title": "DKG result validator", + "version": 1 + }, + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract SortitionPool\",\"name\":\"_sortitionPool\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"activeThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"groupSize\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"groupThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"signatureByteSize\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sortitionPool\",\"outputs\":[{\"internalType\":\"contract SortitionPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"submitterMemberIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"},{\"internalType\":\"uint8[]\",\"name\":\"misbehavedMembersIndices\",\"type\":\"uint8[]\"},{\"internalType\":\"bytes\",\"name\":\"signatures\",\"type\":\"bytes\"},{\"internalType\":\"uint256[]\",\"name\":\"signingMembersIndices\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32[]\",\"name\":\"members\",\"type\":\"uint32[]\"},{\"internalType\":\"bytes32\",\"name\":\"membersHash\",\"type\":\"bytes32\"}],\"internalType\":\"struct BeaconDkg.Result\",\"name\":\"result\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startBlock\",\"type\":\"uint256\"}],\"name\":\"validate\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isValid\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"errorMsg\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"submitterMemberIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"},{\"internalType\":\"uint8[]\",\"name\":\"misbehavedMembersIndices\",\"type\":\"uint8[]\"},{\"internalType\":\"bytes\",\"name\":\"signatures\",\"type\":\"bytes\"},{\"internalType\":\"uint256[]\",\"name\":\"signingMembersIndices\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32[]\",\"name\":\"members\",\"type\":\"uint32[]\"},{\"internalType\":\"bytes32\",\"name\":\"membersHash\",\"type\":\"bytes32\"}],\"internalType\":\"struct BeaconDkg.Result\",\"name\":\"result\",\"type\":\"tuple\"}],\"name\":\"validateFields\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isValid\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"errorMsg\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"submitterMemberIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"},{\"internalType\":\"uint8[]\",\"name\":\"misbehavedMembersIndices\",\"type\":\"uint8[]\"},{\"internalType\":\"bytes\",\"name\":\"signatures\",\"type\":\"bytes\"},{\"internalType\":\"uint256[]\",\"name\":\"signingMembersIndices\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32[]\",\"name\":\"members\",\"type\":\"uint32[]\"},{\"internalType\":\"bytes32\",\"name\":\"membersHash\",\"type\":\"bytes32\"}],\"internalType\":\"struct BeaconDkg.Result\",\"name\":\"result\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"}],\"name\":\"validateGroupMembers\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"submitterMemberIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"},{\"internalType\":\"uint8[]\",\"name\":\"misbehavedMembersIndices\",\"type\":\"uint8[]\"},{\"internalType\":\"bytes\",\"name\":\"signatures\",\"type\":\"bytes\"},{\"internalType\":\"uint256[]\",\"name\":\"signingMembersIndices\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32[]\",\"name\":\"members\",\"type\":\"uint32[]\"},{\"internalType\":\"bytes32\",\"name\":\"membersHash\",\"type\":\"bytes32\"}],\"internalType\":\"struct BeaconDkg.Result\",\"name\":\"result\",\"type\":\"tuple\"}],\"name\":\"validateMembersHash\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"submitterMemberIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"},{\"internalType\":\"uint8[]\",\"name\":\"misbehavedMembersIndices\",\"type\":\"uint8[]\"},{\"internalType\":\"bytes\",\"name\":\"signatures\",\"type\":\"bytes\"},{\"internalType\":\"uint256[]\",\"name\":\"signingMembersIndices\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32[]\",\"name\":\"members\",\"type\":\"uint32[]\"},{\"internalType\":\"bytes32\",\"name\":\"membersHash\",\"type\":\"bytes32\"}],\"internalType\":\"struct BeaconDkg.Result\",\"name\":\"result\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"startBlock\",\"type\":\"uint256\"}],\"name\":\"validateSignatures\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"validate((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32),uint256,uint256)\":{\"params\":{\"seed\":\"seed used to start the DKG and select group members\",\"startBlock\":\"DKG start block\"},\"returns\":{\"errorMsg\":\"validation error message; empty for a valid result\",\"isValid\":\"true if the result is valid, false otherwise\"}},\"validateFields((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))\":{\"returns\":{\"errorMsg\":\"validation error message; empty for a valid result\",\"isValid\":\"true if the result is valid, false otherwise\"}},\"validateGroupMembers((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32),uint256)\":{\"params\":{\"seed\":\"seed used to start the DKG and select group members\"},\"returns\":{\"_0\":\"true if group members matches; false otherwise\"}},\"validateMembersHash((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))\":{\"params\":{\"result\":\"DKG result\"},\"returns\":{\"_0\":\"true if result's group members hash matches with the one that is challenged.\"}},\"validateSignatures((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32),uint256)\":{\"params\":{\"startBlock\":\"DKG start block\"},\"returns\":{\"_0\":\"true if group members matches; false otherwise\"}}},\"stateVariables\":{\"activeThreshold\":{\"details\":\"The minimum number of active and properly behaving group members during the DKG needed to accept the result. This number is higher than `groupThreshold` to keep a safety margin for members becoming inactive after DKG so that the group can still produce a relay entry.\"},\"groupSize\":{\"details\":\"Size of a group in the threshold relay.\"},\"groupThreshold\":{\"details\":\"The minimum number of group members needed to interact according to the protocol to produce a relay entry. The adversary can not learn anything about the key as long as it does not break into groupThreshold+1 of members.\"},\"signatureByteSize\":{\"details\":\"Size in bytes of a single signature produced by operator supporting DKG result.\"}},\"title\":\"DKG result validator\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"validate((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32),uint256,uint256)\":{\"notice\":\"Performs a full validation of DKG result, including checking the format of fields in the result, declared selected group members, and signatures of operators supporting the result.\"},\"validateFields((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))\":{\"notice\":\"Performs a static validation of DKG result fields: lengths, ranges, and order of arrays.\"},\"validateGroupMembers((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32),uint256)\":{\"notice\":\"Performs validation of group members as declared in DKG result against group members selected by the sortition pool.\"},\"validateMembersHash((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))\":{\"notice\":\"Performs validation of hashed group members that actively took part in DKG.\"},\"validateSignatures((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32),uint256)\":{\"notice\":\"Performs validation of signatures supplied in DKG result. Note that this function does not check if addresses which supplied signatures supporting the result are the ones selected to the group by sortition pool. This function should be used together with `validateGroupMembers`.\"}},\"notice\":\"DKGValidator allows performing a full validation of DKG result, including checking the format of fields in the result, declared selected group members, and signatures of operators supporting the result. The operator submitting the result should perform the validation using a free contract call before submitting the result to ensure their result is valid and can not be challenged. All other network operators should perform validation of the submitted result using a free contract call and challenge the result if the validation fails.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/BeaconDkgValidator.sol\":\"BeaconDkgValidator\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@keep-network/sortition-pools/contracts/Branch.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\n/// @notice The implicit 8-ary trees of the sortition pool\\n/// rely on packing 8 \\\"slots\\\" of 32-bit values into each uint256.\\n/// The Branch library permits efficient calculations on these slots.\\nlibrary Branch {\\n /// @notice Calculate the right shift required\\n /// to make the 32 least significant bits of an uint256\\n /// be the bits of the `position`th slot\\n /// when treating the uint256 as a uint32[8].\\n ///\\n /// @dev Not used for efficiency reasons,\\n /// but left to illustrate the meaning of a common pattern.\\n /// I wish solidity had macros, even C macros.\\n function slotShift(uint256 position) internal pure returns (uint256) {\\n unchecked {\\n return position * Constants.SLOT_WIDTH;\\n }\\n }\\n\\n /// @notice Return the `position`th slot of the `node`,\\n /// treating `node` as a uint32[32].\\n function getSlot(uint256 node, uint256 position)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Doing a bitwise AND with `SLOT_MAX`\\n // clears all but the 32 least significant bits.\\n // Because of the right shift by `slotShift(position)` bits,\\n // those 32 bits contain the 32 bits in the `position`th slot of `node`.\\n return (node >> shiftBits) & Constants.SLOT_MAX;\\n }\\n }\\n\\n /// @notice Return `node` with the `position`th slot set to zero.\\n function clearSlot(uint256 node, uint256 position)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Shifting `SLOT_MAX` left by `slotShift(position)` bits\\n // gives us a number where all bits of the `position`th slot are set,\\n // and all other bits are unset.\\n //\\n // Using a bitwise NOT on this number,\\n // we get a uint256 where all bits are set\\n // except for those of the `position`th slot.\\n //\\n // Bitwise ANDing the original `node` with this number\\n // sets the bits of `position`th slot to zero,\\n // leaving all other bits unchanged.\\n return node & ~(Constants.SLOT_MAX << shiftBits);\\n }\\n }\\n\\n /// @notice Return `node` with the `position`th slot set to `weight`.\\n ///\\n /// @param weight The weight of of the node.\\n /// Safely truncated to a 32-bit number,\\n /// but this should never be called with an overflowing weight regardless.\\n function setSlot(\\n uint256 node,\\n uint256 position,\\n uint256 weight\\n ) internal pure returns (uint256) {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Clear the `position`th slot like in `clearSlot()`.\\n uint256 clearedNode = node & ~(Constants.SLOT_MAX << shiftBits);\\n // Bitwise AND `weight` with `SLOT_MAX`\\n // to clear all but the 32 least significant bits.\\n //\\n // Shift this left by `slotShift(position)` bits\\n // to obtain a uint256 with all bits unset\\n // except in the `position`th slot\\n // which contains the 32-bit value of `weight`.\\n uint256 shiftedWeight = (weight & Constants.SLOT_MAX) << shiftBits;\\n // When we bitwise OR these together,\\n // all other slots except the `position`th one come from the left argument,\\n // and the `position`th gets filled with `weight` from the right argument.\\n return clearedNode | shiftedWeight;\\n }\\n }\\n\\n /// @notice Calculate the summed weight of all slots in the `node`.\\n function sumWeight(uint256 node) internal pure returns (uint256 sum) {\\n unchecked {\\n sum = node & Constants.SLOT_MAX;\\n // Iterate through each slot\\n // by shifting `node` right in increments of 32 bits,\\n // and adding the 32 least significant bits to the `sum`.\\n uint256 newNode = node >> Constants.SLOT_WIDTH;\\n while (newNode > 0) {\\n sum += (newNode & Constants.SLOT_MAX);\\n newNode = newNode >> Constants.SLOT_WIDTH;\\n }\\n return sum;\\n }\\n }\\n\\n /// @notice Pick a slot in `node` that corresponds to `index`.\\n /// Treats the node like an array of virtual stakers,\\n /// the number of virtual stakers in each slot corresponding to its weight,\\n /// and picks which slot contains the `index`th virtual staker.\\n ///\\n /// @dev Requires that `index` be lower than `sumWeight(node)`.\\n /// However, this is not enforced for performance reasons.\\n /// If `index` exceeds the permitted range,\\n /// `pickWeightedSlot()` returns the rightmost slot\\n /// and an excessively high `newIndex`.\\n ///\\n /// @return slot The slot of `node` containing the `index`th virtual staker.\\n ///\\n /// @return newIndex The index of the `index`th virtual staker of `node`\\n /// within the returned slot.\\n function pickWeightedSlot(uint256 node, uint256 index)\\n internal\\n pure\\n returns (uint256 slot, uint256 newIndex)\\n {\\n unchecked {\\n newIndex = index;\\n uint256 newNode = node;\\n uint256 currentSlotWeight = newNode & Constants.SLOT_MAX;\\n while (newIndex >= currentSlotWeight) {\\n newIndex -= currentSlotWeight;\\n slot++;\\n newNode = newNode >> Constants.SLOT_WIDTH;\\n currentSlotWeight = newNode & Constants.SLOT_MAX;\\n }\\n return (slot, newIndex);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa7fb1c9c9789f30493e9a40e24a24f46875dc5e7630b4f67478167759f6d1882\"},\"@keep-network/sortition-pools/contracts/Chaosnet.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\n/// @title Chaosnet\\n/// @notice This is a beta staker program for stakers willing to go the extra\\n/// mile with monitoring, share their logs with the dev team, and allow to more\\n/// carefully monitor the bootstrapping network. As the network matures, the\\n/// beta program will be ended.\\ncontract Chaosnet {\\n /// @notice Indicates if the chaosnet is active. The chaosnet is active\\n /// after the contract deployment and can be ended with a call to\\n /// `deactivateChaosnet()`. Once deactivated chaosnet can not be activated\\n /// again.\\n bool public isChaosnetActive;\\n\\n /// @notice Indicates if the given operator is a beta operator for chaosnet.\\n mapping(address => bool) public isBetaOperator;\\n\\n /// @notice Address controlling chaosnet status and beta operator addresses.\\n address public chaosnetOwner;\\n\\n event BetaOperatorsAdded(address[] operators);\\n\\n event ChaosnetOwnerRoleTransferred(\\n address oldChaosnetOwner,\\n address newChaosnetOwner\\n );\\n\\n event ChaosnetDeactivated();\\n\\n constructor() {\\n _transferChaosnetOwner(msg.sender);\\n isChaosnetActive = true;\\n }\\n\\n modifier onlyChaosnetOwner() {\\n require(msg.sender == chaosnetOwner, \\\"Not the chaosnet owner\\\");\\n _;\\n }\\n\\n modifier onlyOnChaosnet() {\\n require(isChaosnetActive, \\\"Chaosnet is not active\\\");\\n _;\\n }\\n\\n /// @notice Adds beta operator to chaosnet. Can be called only by the\\n /// chaosnet owner when the chaosnet is active. Once the operator is added\\n /// as a beta operator, it can not be removed.\\n function addBetaOperators(address[] calldata operators)\\n public\\n onlyOnChaosnet\\n onlyChaosnetOwner\\n {\\n for (uint256 i = 0; i < operators.length; i++) {\\n isBetaOperator[operators[i]] = true;\\n }\\n\\n emit BetaOperatorsAdded(operators);\\n }\\n\\n /// @notice Deactivates the chaosnet. Can be called only by the chaosnet\\n /// owner. Once deactivated chaosnet can not be activated again.\\n function deactivateChaosnet() public onlyOnChaosnet onlyChaosnetOwner {\\n isChaosnetActive = false;\\n emit ChaosnetDeactivated();\\n }\\n\\n /// @notice Transfers the chaosnet owner role to another non-zero address.\\n function transferChaosnetOwnerRole(address newChaosnetOwner)\\n public\\n onlyChaosnetOwner\\n {\\n require(\\n newChaosnetOwner != address(0),\\n \\\"New chaosnet owner must not be zero address\\\"\\n );\\n _transferChaosnetOwner(newChaosnetOwner);\\n }\\n\\n function _transferChaosnetOwner(address newChaosnetOwner) internal {\\n address oldChaosnetOwner = chaosnetOwner;\\n chaosnetOwner = newChaosnetOwner;\\n emit ChaosnetOwnerRoleTransferred(oldChaosnetOwner, newChaosnetOwner);\\n }\\n}\\n\",\"keccak256\":\"0xeaf7bdd5626f88c329793a012621039692ce1b6e1f13013997ddb13d7e3032df\"},\"@keep-network/sortition-pools/contracts/Constants.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nlibrary Constants {\\n ////////////////////////////////////////////////////////////////////////////\\n // Parameters for configuration\\n\\n // How many bits a position uses per level of the tree;\\n // each branch of the tree contains 2**SLOT_BITS slots.\\n uint256 constant SLOT_BITS = 3;\\n uint256 constant LEVELS = 7;\\n ////////////////////////////////////////////////////////////////////////////\\n\\n ////////////////////////////////////////////////////////////////////////////\\n // Derived constants, do not touch\\n uint256 constant SLOT_COUNT = 2**SLOT_BITS;\\n uint256 constant SLOT_WIDTH = 256 / SLOT_COUNT;\\n uint256 constant LAST_SLOT = SLOT_COUNT - 1;\\n uint256 constant SLOT_MAX = (2**SLOT_WIDTH) - 1;\\n uint256 constant POOL_CAPACITY = SLOT_COUNT**LEVELS;\\n\\n uint256 constant ID_WIDTH = SLOT_WIDTH;\\n uint256 constant ID_MAX = SLOT_MAX;\\n\\n uint256 constant BLOCKHEIGHT_WIDTH = 96 - ID_WIDTH;\\n uint256 constant BLOCKHEIGHT_MAX = (2**BLOCKHEIGHT_WIDTH) - 1;\\n\\n uint256 constant SLOT_POINTER_MAX = (2**SLOT_BITS) - 1;\\n uint256 constant LEAF_FLAG = 1 << 255;\\n\\n uint256 constant WEIGHT_WIDTH = 256 / SLOT_COUNT;\\n ////////////////////////////////////////////////////////////////////////////\\n}\\n\",\"keccak256\":\"0xaef690ced707935745ff1482b7bb9bd9eb77bf6a39c717465e64cf12db8a7d39\"},\"@keep-network/sortition-pools/contracts/Leaf.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary Leaf {\\n function make(\\n address _operator,\\n uint256 _creationBlock,\\n uint256 _id\\n ) internal pure returns (uint256) {\\n assert(_creationBlock <= type(uint64).max);\\n assert(_id <= type(uint32).max);\\n // Converting a bytesX type into a larger type\\n // adds zero bytes on the right.\\n uint256 op = uint256(bytes32(bytes20(_operator)));\\n // Bitwise AND the id to erase\\n // all but the 32 least significant bits\\n uint256 uid = _id & Constants.ID_MAX;\\n // Erase all but the 64 least significant bits,\\n // then shift left by 32 bits to make room for the id\\n uint256 cb = (_creationBlock & Constants.BLOCKHEIGHT_MAX) <<\\n Constants.ID_WIDTH;\\n // Bitwise OR them all together to get\\n // [address operator || uint64 creationBlock || uint32 id]\\n return (op | cb | uid);\\n }\\n\\n function operator(uint256 leaf) internal pure returns (address) {\\n // Converting a bytesX type into a smaller type\\n // truncates it on the right.\\n return address(bytes20(bytes32(leaf)));\\n }\\n\\n /// @notice Return the block number the leaf was created in.\\n function creationBlock(uint256 leaf) internal pure returns (uint256) {\\n return ((leaf >> Constants.ID_WIDTH) & Constants.BLOCKHEIGHT_MAX);\\n }\\n\\n function id(uint256 leaf) internal pure returns (uint32) {\\n // Id is stored in the 32 least significant bits.\\n // Bitwise AND ensures that we only get the contents of those bits.\\n return uint32(leaf & Constants.ID_MAX);\\n }\\n}\\n\",\"keccak256\":\"0xbd107a1a43e48884885e5e966ffcbcd8fa5e89863715d717bb4006e9f89cdc2b\"},\"@keep-network/sortition-pools/contracts/Position.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary Position {\\n // Return the last 3 bits of a position number,\\n // corresponding to its slot in its parent\\n function slot(uint256 a) internal pure returns (uint256) {\\n return a & Constants.SLOT_POINTER_MAX;\\n }\\n\\n // Return the parent of a position number\\n function parent(uint256 a) internal pure returns (uint256) {\\n return a >> Constants.SLOT_BITS;\\n }\\n\\n // Return the location of the child of a at the given slot\\n function child(uint256 a, uint256 s) internal pure returns (uint256) {\\n return (a << Constants.SLOT_BITS) | (s & Constants.SLOT_POINTER_MAX); // slot(s)\\n }\\n\\n // Return the uint p as a flagged position uint:\\n // the least significant 21 bits contain the position\\n // and the 22nd bit is set as a flag\\n // to distinguish the position 0x000000 from an empty field.\\n function setFlag(uint256 p) internal pure returns (uint256) {\\n return p | Constants.LEAF_FLAG;\\n }\\n\\n // Turn a flagged position into an unflagged position\\n // by removing the flag at the 22nd least significant bit.\\n //\\n // We shouldn't _actually_ need this\\n // as all position-manipulating code should ignore non-position bits anyway\\n // but it's cheap to call so might as well do it.\\n function unsetFlag(uint256 p) internal pure returns (uint256) {\\n return p & (~Constants.LEAF_FLAG);\\n }\\n}\\n\",\"keccak256\":\"0xd3a927908080ac21353a92a6bce3d69e94a5c30f6b51f16b271b6cc679f110e2\"},\"@keep-network/sortition-pools/contracts/RNG.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Leaf.sol\\\";\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary RNG {\\n /// @notice Get an index in the range `[0 .. range-1]`\\n /// and the new state of the RNG,\\n /// using the provided `state` of the RNG.\\n ///\\n /// @param range The upper bound of the index, exclusive.\\n ///\\n /// @param state The previous state of the RNG.\\n /// The initial state needs to be obtained\\n /// from a trusted randomness oracle (the random beacon),\\n /// or from a chain of earlier calls to `RNG.getIndex()`\\n /// on an originally trusted seed.\\n ///\\n /// @dev Calculates the number of bits required for the desired range,\\n /// takes the least significant bits of `state`\\n /// and checks if the obtained index is within the desired range.\\n /// The original state is hashed with `keccak256` to get a new state.\\n /// If the index is outside the range,\\n /// the function retries until it gets a suitable index.\\n ///\\n /// @return index A random integer between `0` and `range - 1`, inclusive.\\n ///\\n /// @return newState The new state of the RNG.\\n /// When `getIndex()` is called one or more times,\\n /// care must be taken to always use the output `state`\\n /// of the most recent call as the input `state` of a subsequent call.\\n /// At the end of a transaction calling `RNG.getIndex()`,\\n /// the previous stored state must be overwritten with the latest output.\\n function getIndex(\\n uint256 range,\\n bytes32 state,\\n uint256 bits\\n ) internal view returns (uint256, bytes32) {\\n bool found = false;\\n uint256 index = 0;\\n bytes32 newState = state;\\n while (!found) {\\n index = truncate(bits, uint256(newState));\\n newState = keccak256(abi.encodePacked(newState, address(this)));\\n if (index < range) {\\n found = true;\\n }\\n }\\n return (index, newState);\\n }\\n\\n /// @notice Calculate how many bits are required\\n /// for an index in the range `[0 .. range-1]`.\\n ///\\n /// @param range The upper bound of the desired range, exclusive.\\n ///\\n /// @return uint The smallest number of bits\\n /// that can contain the number `range-1`.\\n function bitsRequired(uint256 range) internal pure returns (uint256) {\\n unchecked {\\n if (range == 1) {\\n return 0;\\n }\\n\\n uint256 bits = Constants.WEIGHT_WIDTH - 1;\\n\\n // Left shift by `bits`,\\n // so we have a 1 in the (bits + 1)th least significant bit\\n // and 0 in other bits.\\n // If this number is equal or greater than `range`,\\n // the range [0, range-1] fits in `bits` bits.\\n //\\n // Because we loop from high bits to low bits,\\n // we find the highest number of bits that doesn't fit the range,\\n // and return that number + 1.\\n while (1 << bits >= range) {\\n bits--;\\n }\\n\\n return bits + 1;\\n }\\n }\\n\\n /// @notice Truncate `input` to the `bits` least significant bits.\\n function truncate(uint256 bits, uint256 input)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n return input & ((1 << bits) - 1);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x67f87f589cd5123ffa32f883ea2f09b0e56258508bae82b8c655b3c27c71eb5e\"},\"@keep-network/sortition-pools/contracts/Rewards.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\n/// @title Rewards\\n/// @notice Rewards are allocated proportionally to operators\\n/// present in the pool at payout based on their weight in the pool.\\n///\\n/// To facilitate this, we use a global accumulator value\\n/// to track the total rewards one unit of weight would've earned\\n/// since the creation of the pool.\\n///\\n/// Whenever a reward is paid, the accumulator is increased\\n/// by the size of the reward divided by the total weight\\n/// of all eligible operators in the pool.\\n///\\n/// Each operator has an individual accumulator value,\\n/// set to equal the global accumulator when the operator joins the pool.\\n/// This accumulator reflects the amount of rewards\\n/// that have already been accounted for with that operator.\\n///\\n/// Whenever an operator's weight in the pool changes,\\n/// we can update the amount of rewards the operator has earned\\n/// by subtracting the operator's accumulator from the global accumulator.\\n/// This gives us the amount of rewards one unit of weight has earned\\n/// since the last time the operator's rewards have been updated.\\n/// Then we multiply that by the operator's previous (pre-change) weight\\n/// to determine how much rewards in total the operator has earned,\\n/// and add this to the operator's earned rewards.\\n/// Finally, we set the operator's accumulator to the global accumulator value.\\ncontract Rewards {\\n struct OperatorRewards {\\n // The state of the global accumulator\\n // when the operator's rewards were last updated\\n uint96 accumulated;\\n // The amount of rewards collected by the operator after the latest update.\\n // The amount the operator could withdraw may equal `available`\\n // or it may be greater, if more rewards have been paid in since then.\\n // To evaulate the most recent amount including rewards potentially paid\\n // since the last update, use `availableRewards` function.\\n uint96 available;\\n // If nonzero, the operator is ineligible for rewards\\n // and may only re-enable rewards after the specified timestamp.\\n // XXX: unsigned 32-bit integer unix seconds, will break around 2106\\n uint32 ineligibleUntil;\\n // Locally cached weight of the operator,\\n // used to reduce the cost of setting operators ineligible.\\n uint32 weight;\\n }\\n\\n // The global accumulator of how much rewards\\n // a hypothetical operator of weight 1 would have earned\\n // since the creation of the pool.\\n uint96 internal globalRewardAccumulator;\\n // If the amount of reward tokens paid in\\n // does not divide cleanly by pool weight,\\n // the difference is recorded as rounding dust\\n // and added to the next reward.\\n uint96 internal rewardRoundingDust;\\n\\n // The amount of rewards that would've been earned by ineligible operators\\n // had they not been ineligible.\\n uint96 public ineligibleEarnedRewards;\\n\\n // Ineligibility times are calculated from this offset,\\n // set at contract creation.\\n uint256 internal immutable ineligibleOffsetStart;\\n\\n mapping(uint32 => OperatorRewards) internal operatorRewards;\\n\\n constructor() {\\n // solhint-disable-next-line not-rely-on-time\\n ineligibleOffsetStart = block.timestamp;\\n }\\n\\n /// @notice Return whether the operator is eligible for rewards or not.\\n function isEligibleForRewards(uint32 operator) internal view returns (bool) {\\n return operatorRewards[operator].ineligibleUntil == 0;\\n }\\n\\n /// @notice Return the time the operator's reward eligibility can be restored.\\n function rewardsEligibilityRestorableAt(uint32 operator)\\n internal\\n view\\n returns (uint256)\\n {\\n uint32 until = operatorRewards[operator].ineligibleUntil;\\n require(until != 0, \\\"Operator already eligible\\\");\\n return (uint256(until) + ineligibleOffsetStart);\\n }\\n\\n /// @notice Return whether the operator is able to restore their eligibility\\n /// for rewards right away.\\n function canRestoreRewardEligibility(uint32 operator)\\n internal\\n view\\n returns (bool)\\n {\\n // solhint-disable-next-line not-rely-on-time\\n return rewardsEligibilityRestorableAt(operator) <= block.timestamp;\\n }\\n\\n /// @notice Internal function for updating the global state of rewards.\\n function addRewards(uint96 rewardAmount, uint32 currentPoolWeight) internal {\\n require(currentPoolWeight > 0, \\\"No recipients in pool\\\");\\n\\n uint96 totalAmount = rewardAmount + rewardRoundingDust;\\n uint96 perWeightReward = totalAmount / currentPoolWeight;\\n uint96 newRoundingDust = totalAmount % currentPoolWeight;\\n\\n globalRewardAccumulator += perWeightReward;\\n rewardRoundingDust = newRoundingDust;\\n }\\n\\n /// @notice Internal function for updating the operator's reward state.\\n function updateOperatorRewards(uint32 operator, uint32 newWeight) internal {\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n if (o.ineligibleUntil == 0) {\\n // If operator is not ineligible, update their earned rewards\\n o.available += accruedRewards;\\n } else {\\n // If ineligible, put the rewards into the ineligible pot\\n ineligibleEarnedRewards += accruedRewards;\\n }\\n // In any case, update their accumulator and weight\\n o.accumulated = acc;\\n o.weight = newWeight;\\n operatorRewards[operator] = o;\\n }\\n\\n /// @notice Set the amount of withdrawable tokens to zero\\n /// and return the previous withdrawable amount.\\n /// @dev Does not update the withdrawable amount,\\n /// but should usually be accompanied by an update.\\n function withdrawOperatorRewards(uint32 operator)\\n internal\\n returns (uint96 withdrawable)\\n {\\n OperatorRewards storage o = operatorRewards[operator];\\n withdrawable = o.available;\\n o.available = 0;\\n }\\n\\n /// @notice Set the amount of ineligible-earned tokens to zero\\n /// and return the previous amount.\\n function withdrawIneligibleRewards() internal returns (uint96 withdrawable) {\\n withdrawable = ineligibleEarnedRewards;\\n ineligibleEarnedRewards = 0;\\n }\\n\\n /// @notice Set the given operators as ineligible for rewards.\\n /// The operators can restore their eligibility at the given time.\\n function setIneligible(uint32[] memory operators, uint256 until) internal {\\n OperatorRewards memory o = OperatorRewards(0, 0, 0, 0);\\n uint96 globalAcc = globalRewardAccumulator;\\n uint96 accrued = 0;\\n // Record ineligibility as seconds after contract creation\\n uint32 _until = uint32(until - ineligibleOffsetStart);\\n\\n for (uint256 i = 0; i < operators.length; i++) {\\n uint32 operator = operators[i];\\n OperatorRewards storage r = operatorRewards[operator];\\n o.available = r.available;\\n o.accumulated = r.accumulated;\\n o.ineligibleUntil = r.ineligibleUntil;\\n o.weight = r.weight;\\n\\n if (o.ineligibleUntil != 0) {\\n // If operator is already ineligible,\\n // don't earn rewards or shorten its ineligibility\\n if (o.ineligibleUntil < _until) {\\n o.ineligibleUntil = _until;\\n }\\n } else {\\n // The operator becomes ineligible -> earn rewards\\n o.ineligibleUntil = _until;\\n accrued = (globalAcc - o.accumulated) * uint96(o.weight);\\n o.available += accrued;\\n }\\n o.accumulated = globalAcc;\\n\\n r.available = o.available;\\n r.accumulated = o.accumulated;\\n r.ineligibleUntil = o.ineligibleUntil;\\n r.weight = o.weight;\\n }\\n }\\n\\n /// @notice Restore the given operator's eligibility for rewards.\\n function restoreEligibility(uint32 operator) internal {\\n // solhint-disable-next-line not-rely-on-time\\n require(canRestoreRewardEligibility(operator), \\\"Operator still ineligible\\\");\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n ineligibleEarnedRewards += accruedRewards;\\n o.accumulated = acc;\\n o.ineligibleUntil = 0;\\n operatorRewards[operator] = o;\\n }\\n\\n /// @notice Returns the amount of rewards currently available for withdrawal\\n /// for the given operator.\\n function availableRewards(uint32 operator) internal view returns (uint96) {\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n if (o.ineligibleUntil == 0) {\\n // If operator is not ineligible, calculate newly accrued rewards and add\\n // them to the available ones, calculated during the last update.\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n return o.available + accruedRewards;\\n } else {\\n // If ineligible, return only the rewards calculated during the last\\n // update.\\n return o.available;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3a10abb408b44335a092387b2c7ee01db3b27997f1f2c888d9b7a2d92934c4e2\"},\"@keep-network/sortition-pools/contracts/SortitionPool.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"@thesis/solidity-contracts/contracts/token/IERC20WithPermit.sol\\\";\\nimport \\\"@thesis/solidity-contracts/contracts/token/IReceiveApproval.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\nimport \\\"./RNG.sol\\\";\\nimport \\\"./SortitionTree.sol\\\";\\nimport \\\"./Rewards.sol\\\";\\nimport \\\"./Chaosnet.sol\\\";\\n\\n/// @title Sortition Pool\\n/// @notice A logarithmic data structure used to store the pool of eligible\\n/// operators weighted by their stakes. It allows to select a group of operators\\n/// based on the provided pseudo-random seed.\\ncontract SortitionPool is\\n SortitionTree,\\n Rewards,\\n Ownable,\\n Chaosnet,\\n IReceiveApproval\\n{\\n using Branch for uint256;\\n using Leaf for uint256;\\n using Position for uint256;\\n\\n IERC20WithPermit public immutable rewardToken;\\n\\n uint256 public immutable poolWeightDivisor;\\n\\n bool public isLocked;\\n\\n event IneligibleForRewards(uint32[] ids, uint256 until);\\n\\n event RewardEligibilityRestored(address indexed operator, uint32 indexed id);\\n\\n /// @notice Reverts if called while pool is locked.\\n modifier onlyUnlocked() {\\n require(!isLocked, \\\"Sortition pool locked\\\");\\n _;\\n }\\n\\n /// @notice Reverts if called while pool is unlocked.\\n modifier onlyLocked() {\\n require(isLocked, \\\"Sortition pool unlocked\\\");\\n _;\\n }\\n\\n constructor(IERC20WithPermit _rewardToken, uint256 _poolWeightDivisor) {\\n rewardToken = _rewardToken;\\n poolWeightDivisor = _poolWeightDivisor;\\n }\\n\\n function receiveApproval(\\n address sender,\\n uint256 amount,\\n address token,\\n bytes calldata\\n ) external override {\\n require(token == address(rewardToken), \\\"Unsupported token\\\");\\n rewardToken.transferFrom(sender, address(this), amount);\\n Rewards.addRewards(uint96(amount), uint32(root.sumWeight()));\\n }\\n\\n /// @notice Withdraws all available rewards for the given operator to the\\n /// given beneficiary.\\n /// @dev Can be called only be the owner. Does not validate if the provided\\n /// beneficiary is associated with the provided operator - this needs to\\n /// be done by the owner calling this function.\\n /// @return The amount of rewards withdrawn in this call.\\n function withdrawRewards(address operator, address beneficiary)\\n public\\n onlyOwner\\n returns (uint96)\\n {\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(getPoolWeight(operator)));\\n uint96 earned = Rewards.withdrawOperatorRewards(id);\\n rewardToken.transfer(beneficiary, uint256(earned));\\n return earned;\\n }\\n\\n /// @notice Withdraws rewards not allocated to operators marked as ineligible\\n /// to the given recipient address.\\n /// @dev Can be called only by the owner.\\n function withdrawIneligible(address recipient) public onlyOwner {\\n uint96 earned = Rewards.withdrawIneligibleRewards();\\n rewardToken.transfer(recipient, uint256(earned));\\n }\\n\\n /// @notice Locks the sortition pool. In locked state, members cannot be\\n /// inserted and removed from the pool. Members statuses cannot\\n /// be updated as well.\\n /// @dev Can be called only by the contract owner.\\n function lock() public onlyOwner {\\n isLocked = true;\\n }\\n\\n /// @notice Unlocks the sortition pool. Removes all restrictions set by\\n /// the `lock` method.\\n /// @dev Can be called only by the contract owner.\\n function unlock() public onlyOwner {\\n isLocked = false;\\n }\\n\\n /// @notice Inserts an operator to the pool. Reverts if the operator is\\n /// already present. Reverts if the operator is not eligible because of their\\n /// authorized stake. Reverts if the chaosnet is active and the operator is\\n /// not a beta operator.\\n /// @dev Can be called only by the contract owner.\\n /// @param operator Address of the inserted operator.\\n /// @param authorizedStake Inserted operator's authorized stake for the application.\\n function insertOperator(address operator, uint256 authorizedStake)\\n public\\n onlyOwner\\n onlyUnlocked\\n {\\n uint256 weight = getWeight(authorizedStake);\\n require(weight > 0, \\\"Operator not eligible\\\");\\n\\n if (isChaosnetActive) {\\n require(isBetaOperator[operator], \\\"Not beta operator for chaosnet\\\");\\n }\\n\\n _insertOperator(operator, weight);\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(weight));\\n }\\n\\n /// @notice Update the operator's weight if present and eligible,\\n /// or remove from the pool if present and ineligible.\\n /// @dev Can be called only by the contract owner.\\n /// @param operator Address of the updated operator.\\n /// @param authorizedStake Operator's authorized stake for the application.\\n function updateOperatorStatus(address operator, uint256 authorizedStake)\\n public\\n onlyOwner\\n onlyUnlocked\\n {\\n uint256 weight = getWeight(authorizedStake);\\n\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(weight));\\n\\n if (weight == 0) {\\n _removeOperator(operator);\\n } else {\\n updateOperator(operator, weight);\\n }\\n }\\n\\n /// @notice Set the given operators as ineligible for rewards.\\n /// The operators can restore their eligibility at the given time.\\n function setRewardIneligibility(uint32[] calldata operators, uint256 until)\\n public\\n onlyOwner\\n {\\n Rewards.setIneligible(operators, until);\\n emit IneligibleForRewards(operators, until);\\n }\\n\\n /// @notice Restores reward eligibility for the operator.\\n function restoreRewardEligibility(address operator) public {\\n uint32 id = getOperatorID(operator);\\n Rewards.restoreEligibility(id);\\n emit RewardEligibilityRestored(operator, id);\\n }\\n\\n /// @notice Returns whether the operator is eligible for rewards or not.\\n function isEligibleForRewards(address operator) public view returns (bool) {\\n uint32 id = getOperatorID(operator);\\n return Rewards.isEligibleForRewards(id);\\n }\\n\\n /// @notice Returns the time the operator's reward eligibility can be restored.\\n function rewardsEligibilityRestorableAt(address operator)\\n public\\n view\\n returns (uint256)\\n {\\n uint32 id = getOperatorID(operator);\\n return Rewards.rewardsEligibilityRestorableAt(id);\\n }\\n\\n /// @notice Returns whether the operator is able to restore their eligibility\\n /// for rewards right away.\\n function canRestoreRewardEligibility(address operator)\\n public\\n view\\n returns (bool)\\n {\\n uint32 id = getOperatorID(operator);\\n return Rewards.canRestoreRewardEligibility(id);\\n }\\n\\n /// @notice Returns the amount of rewards withdrawable for the given operator.\\n function getAvailableRewards(address operator) public view returns (uint96) {\\n uint32 id = getOperatorID(operator);\\n return availableRewards(id);\\n }\\n\\n /// @notice Return whether the operator is present in the pool.\\n function isOperatorInPool(address operator) public view returns (bool) {\\n return getFlaggedLeafPosition(operator) != 0;\\n }\\n\\n /// @notice Return whether the operator's weight in the pool\\n /// matches their eligible weight.\\n function isOperatorUpToDate(address operator, uint256 authorizedStake)\\n public\\n view\\n returns (bool)\\n {\\n return getWeight(authorizedStake) == getPoolWeight(operator);\\n }\\n\\n /// @notice Return the weight of the operator in the pool,\\n /// which may or may not be out of date.\\n function getPoolWeight(address operator) public view returns (uint256) {\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n if (flaggedPosition == 0) {\\n return 0;\\n } else {\\n uint256 leafPosition = flaggedPosition.unsetFlag();\\n uint256 leafWeight = getLeafWeight(leafPosition);\\n return leafWeight;\\n }\\n }\\n\\n /// @notice Selects a new group of operators of the provided size based on\\n /// the provided pseudo-random seed. At least one operator has to be\\n /// registered in the pool, otherwise the function fails reverting the\\n /// transaction.\\n /// @param groupSize Size of the requested group\\n /// @param seed Pseudo-random number used to select operators to group\\n /// @return selected Members of the selected group\\n function selectGroup(uint256 groupSize, bytes32 seed)\\n public\\n view\\n onlyLocked\\n returns (uint32[] memory)\\n {\\n uint256 _root = root;\\n\\n bytes32 rngState = seed;\\n uint256 rngRange = _root.sumWeight();\\n require(rngRange > 0, \\\"Not enough operators in pool\\\");\\n uint256 currentIndex;\\n\\n uint256 bits = RNG.bitsRequired(rngRange);\\n\\n uint32[] memory selected = new uint32[](groupSize);\\n\\n for (uint256 i = 0; i < groupSize; i++) {\\n (currentIndex, rngState) = RNG.getIndex(rngRange, rngState, bits);\\n\\n uint256 leafPosition = pickWeightedLeaf(currentIndex, _root);\\n\\n uint256 leaf = leaves[leafPosition];\\n selected[i] = leaf.id();\\n }\\n return selected;\\n }\\n\\n function getWeight(uint256 authorization) internal view returns (uint256) {\\n return authorization / poolWeightDivisor;\\n }\\n}\\n\",\"keccak256\":\"0xab42e7c5b1828f42a73f699eb2dc96d4f793572a6323b8b1fbd7c5e0c065bda7\"},\"@keep-network/sortition-pools/contracts/SortitionTree.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Branch.sol\\\";\\nimport \\\"./Position.sol\\\";\\nimport \\\"./Leaf.sol\\\";\\nimport \\\"./Constants.sol\\\";\\n\\ncontract SortitionTree {\\n using Branch for uint256;\\n using Position for uint256;\\n using Leaf for uint256;\\n\\n // implicit tree\\n // root 8\\n // level2 64\\n // level3 512\\n // level4 4k\\n // level5 32k\\n // level6 256k\\n // level7 2M\\n uint256 internal root;\\n\\n // A 2-index mapping from layer => (index (0-index) => branch). For example,\\n // to access the 6th branch in the 2nd layer (right below the root node; the\\n // first branch layer), call branches[2][5]. Mappings are used in place of\\n // arrays for efficiency. The root is the first layer, the branches occupy\\n // layers 2 through 7, and layer 8 is for the leaves. Following this\\n // convention, the first index in `branches` is `2`, and the last index is\\n // `7`.\\n mapping(uint256 => mapping(uint256 => uint256)) internal branches;\\n\\n // A 0-index mapping from index => leaf, acting as an array. For example, to\\n // access the 42nd leaf, call leaves[41].\\n mapping(uint256 => uint256) internal leaves;\\n\\n // the flagged (see setFlag() and unsetFlag() in Position.sol) positions\\n // of all operators present in the pool\\n mapping(address => uint256) internal flaggedLeafPosition;\\n\\n // the leaf after the rightmost occupied leaf of each stack\\n uint256 internal rightmostLeaf;\\n\\n // the empty leaves in each stack\\n // between 0 and the rightmost occupied leaf\\n uint256[] internal emptyLeaves;\\n\\n // Each operator has an uint32 ID number\\n // which is allocated when they first join the pool\\n // and remains unchanged even if they leave and rejoin the pool.\\n mapping(address => uint32) internal operatorID;\\n\\n // The idAddress array records the address corresponding to each ID number.\\n // The ID number 0 is initialized with a zero address and is not used.\\n address[] internal idAddress;\\n\\n constructor() {\\n root = 0;\\n rightmostLeaf = 0;\\n idAddress.push();\\n }\\n\\n /// @notice Return the ID number of the given operator address. An ID number\\n /// of 0 means the operator has not been allocated an ID number yet.\\n /// @param operator Address of the operator.\\n /// @return the ID number of the given operator address\\n function getOperatorID(address operator) public view returns (uint32) {\\n return operatorID[operator];\\n }\\n\\n /// @notice Get the operator address corresponding to the given ID number. A\\n /// zero address means the ID number has not been allocated yet.\\n /// @param id ID of the operator\\n /// @return the address of the operator\\n function getIDOperator(uint32 id) public view returns (address) {\\n return idAddress.length > id ? idAddress[id] : address(0);\\n }\\n\\n /// @notice Gets the operator addresses corresponding to the given ID\\n /// numbers. A zero address means the ID number has not been allocated yet.\\n /// This function works just like getIDOperator except that it allows to fetch\\n /// operator addresses for multiple IDs in one call.\\n /// @param ids the array of the operator ids\\n /// @return an array of the associated operator addresses\\n function getIDOperators(uint32[] calldata ids)\\n public\\n view\\n returns (address[] memory)\\n {\\n uint256 idCount = idAddress.length;\\n\\n address[] memory operators = new address[](ids.length);\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint32 id = ids[i];\\n operators[i] = idCount > id ? idAddress[id] : address(0);\\n }\\n return operators;\\n }\\n\\n /// @notice Checks if operator is already registered in the pool.\\n /// @param operator the address of the operator\\n /// @return whether or not the operator is already registered in the pool\\n function isOperatorRegistered(address operator) public view returns (bool) {\\n return getFlaggedLeafPosition(operator) != 0;\\n }\\n\\n /// @notice Sum the number of operators in each trunk.\\n /// @return the number of operators in the pool\\n function operatorsInPool() public view returns (uint256) {\\n // Get the number of leaves that might be occupied;\\n // if `rightmostLeaf` equals `firstLeaf()` the tree must be empty,\\n // otherwise the difference between these numbers\\n // gives the number of leaves that may be occupied.\\n uint256 nPossiblyUsedLeaves = rightmostLeaf;\\n // Get the number of empty leaves\\n // not accounted for by the `rightmostLeaf`\\n uint256 nEmptyLeaves = emptyLeaves.length;\\n\\n return (nPossiblyUsedLeaves - nEmptyLeaves);\\n }\\n\\n /// @notice Convenience method to return the total weight of the pool\\n /// @return the total weight of the pool\\n function totalWeight() public view returns (uint256) {\\n return root.sumWeight();\\n }\\n\\n /// @notice Give the operator a new ID number.\\n /// Does not check if the operator already has an ID number.\\n /// @param operator the address of the operator\\n /// @return a new ID for that operator\\n function allocateOperatorID(address operator) internal returns (uint256) {\\n uint256 id = idAddress.length;\\n\\n require(id <= type(uint32).max, \\\"Pool capacity exceeded\\\");\\n\\n operatorID[operator] = uint32(id);\\n idAddress.push(operator);\\n return id;\\n }\\n\\n /// @notice Inserts an operator into the sortition pool\\n /// @param operator the address of an operator to insert\\n /// @param weight how much weight that operator has in the pool\\n function _insertOperator(address operator, uint256 weight) internal {\\n require(\\n !isOperatorRegistered(operator),\\n \\\"Operator is already registered in the pool\\\"\\n );\\n\\n // Fetch the operator's ID, and if they don't have one, allocate them one.\\n uint256 id = getOperatorID(operator);\\n if (id == 0) {\\n id = allocateOperatorID(operator);\\n }\\n\\n // Determine which leaf to insert them into\\n uint256 position = getEmptyLeafPosition();\\n // Record the block the operator was inserted in\\n uint256 theLeaf = Leaf.make(operator, block.number, id);\\n\\n // Update the leaf, and propagate the weight changes all the way up to the\\n // root.\\n root = setLeaf(position, theLeaf, weight, root);\\n\\n // Without position flags,\\n // the position 0x000000 would be treated as empty\\n flaggedLeafPosition[operator] = position.setFlag();\\n }\\n\\n /// @notice Remove an operator (and their weight) from the pool.\\n /// @param operator the address of the operator to remove\\n function _removeOperator(address operator) internal {\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n require(flaggedPosition != 0, \\\"Operator is not registered in the pool\\\");\\n uint256 unflaggedPosition = flaggedPosition.unsetFlag();\\n\\n // Update the leaf, and propagate the weight changes all the way up to the\\n // root.\\n root = removeLeaf(unflaggedPosition, root);\\n removeLeafPositionRecord(operator);\\n }\\n\\n /// @notice Update an operator's weight in the pool.\\n /// @param operator the address of the operator to update\\n /// @param weight the new weight\\n function updateOperator(address operator, uint256 weight) internal {\\n require(\\n isOperatorRegistered(operator),\\n \\\"Operator is not registered in the pool\\\"\\n );\\n\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n uint256 unflaggedPosition = flaggedPosition.unsetFlag();\\n root = updateLeaf(unflaggedPosition, weight, root);\\n }\\n\\n /// @notice Helper method to remove a leaf position record for an operator.\\n /// @param operator the address of the operator to remove the record for\\n function removeLeafPositionRecord(address operator) internal {\\n flaggedLeafPosition[operator] = 0;\\n }\\n\\n /// @notice Removes the data and weight from a particular leaf.\\n /// @param position the leaf index to remove\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function removeLeaf(uint256 position, uint256 _root)\\n internal\\n returns (uint256)\\n {\\n uint256 rightmostSubOne = rightmostLeaf - 1;\\n bool isRightmost = position == rightmostSubOne;\\n\\n // Clears out the data in the leaf node, and then propagates the weight\\n // changes all the way up to the root.\\n uint256 newRoot = setLeaf(position, 0, 0, _root);\\n\\n // Infer if need to fall back on emptyLeaves yet\\n if (isRightmost) {\\n rightmostLeaf = rightmostSubOne;\\n } else {\\n emptyLeaves.push(position);\\n }\\n return newRoot;\\n }\\n\\n /// @notice Updates the tree to give a particular leaf a new weight.\\n /// @param position the index of the leaf to update\\n /// @param weight the new weight\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function updateLeaf(\\n uint256 position,\\n uint256 weight,\\n uint256 _root\\n ) internal returns (uint256) {\\n if (getLeafWeight(position) != weight) {\\n return updateTree(position, weight, _root);\\n } else {\\n return _root;\\n }\\n }\\n\\n /// @notice Places a leaf into a particular position, with a given weight and\\n /// propagates that change.\\n /// @param position the index to place the leaf in\\n /// @param theLeaf the new leaf to place in the position\\n /// @param leafWeight the weight of the leaf\\n /// @param _root the root containing the new leaf\\n /// @return the updated root node\\n function setLeaf(\\n uint256 position,\\n uint256 theLeaf,\\n uint256 leafWeight,\\n uint256 _root\\n ) internal returns (uint256) {\\n // set leaf\\n leaves[position] = theLeaf;\\n\\n return (updateTree(position, leafWeight, _root));\\n }\\n\\n /// @notice Propagates a weight change at a position through the tree,\\n /// eventually returning the updated root.\\n /// @param position the index of leaf to update\\n /// @param weight the new weight of the leaf\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function updateTree(\\n uint256 position,\\n uint256 weight,\\n uint256 _root\\n ) internal returns (uint256) {\\n uint256 childSlot;\\n uint256 treeNode;\\n uint256 newNode;\\n uint256 nodeWeight = weight;\\n\\n uint256 parent = position;\\n // set levels 7 to 2\\n for (uint256 level = Constants.LEVELS; level >= 2; level--) {\\n childSlot = parent.slot();\\n parent = parent.parent();\\n treeNode = branches[level][parent];\\n newNode = treeNode.setSlot(childSlot, nodeWeight);\\n branches[level][parent] = newNode;\\n nodeWeight = newNode.sumWeight();\\n }\\n\\n // set level Root\\n childSlot = parent.slot();\\n return _root.setSlot(childSlot, nodeWeight);\\n }\\n\\n /// @notice Retrieves the next available empty leaf position. Tries to fill\\n /// left to right first, ignoring leaf removals, and then fills\\n /// most-recent-removals first.\\n /// @return the position of the empty leaf\\n function getEmptyLeafPosition() internal returns (uint256) {\\n uint256 rLeaf = rightmostLeaf;\\n bool spaceOnRight = (rLeaf + 1) < Constants.POOL_CAPACITY;\\n if (spaceOnRight) {\\n rightmostLeaf = rLeaf + 1;\\n return rLeaf;\\n } else {\\n uint256 emptyLeafCount = emptyLeaves.length;\\n require(emptyLeafCount > 0, \\\"Pool is full\\\");\\n uint256 emptyLeaf = emptyLeaves[emptyLeafCount - 1];\\n emptyLeaves.pop();\\n return emptyLeaf;\\n }\\n }\\n\\n /// @notice Gets the flagged leaf position for an operator.\\n /// @param operator the address of the operator\\n /// @return the leaf position of that operator\\n function getFlaggedLeafPosition(address operator)\\n internal\\n view\\n returns (uint256)\\n {\\n return flaggedLeafPosition[operator];\\n }\\n\\n /// @notice Gets the weight of a leaf at a particular position.\\n /// @param position the index of the leaf\\n /// @return the weight of the leaf at that position\\n function getLeafWeight(uint256 position) internal view returns (uint256) {\\n uint256 slot = position.slot();\\n uint256 parent = position.parent();\\n\\n // A leaf's weight information is stored a 32-bit slot in the branch layer\\n // directly above the leaf layer. To access it, we calculate that slot and\\n // parent position, and always know the hard-coded layer index.\\n uint256 node = branches[Constants.LEVELS][parent];\\n return node.getSlot(slot);\\n }\\n\\n /// @notice Picks a leaf given a random index.\\n /// @param index a number in `[0, _root.totalWeight())` used to decide\\n /// between leaves\\n /// @param _root the root of the tree\\n function pickWeightedLeaf(uint256 index, uint256 _root)\\n internal\\n view\\n returns (uint256 leafPosition)\\n {\\n uint256 currentIndex = index;\\n uint256 currentNode = _root;\\n uint256 currentPosition = 0;\\n uint256 currentSlot;\\n\\n require(index < currentNode.sumWeight(), \\\"Index exceeds weight\\\");\\n\\n // get root slot\\n (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex);\\n\\n // get slots from levels 2 to 7\\n for (uint256 level = 2; level <= Constants.LEVELS; level++) {\\n currentPosition = currentPosition.child(currentSlot);\\n currentNode = branches[level][currentPosition];\\n (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex);\\n }\\n\\n // get leaf position\\n leafPosition = currentPosition.child(currentSlot);\\n }\\n}\\n\",\"keccak256\":\"0x51daeca62ef52be78a1a9de4d2a1c5900c873165f59eda14d5965d7d7da90a03\"},\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n uint8 private constant _ADDRESS_LENGTH = 20;\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\\n */\\n function toHexString(address addr) internal pure returns (string memory) {\\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\\n }\\n}\\n\",\"keccak256\":\"0xaf159a8b1923ad2a26d516089bceca9bdeaeacd04be50983ea00ba63070f08a3\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.3) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n /// @solidity memory-safe-assembly\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0xdb7f5c28fc61cda0bd8ab60ce288e206b791643bcd3ba464a70cbec18895a2f5\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IApproveAndCall.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\n/// @notice An interface that should be implemented by tokens supporting\\n/// `approveAndCall`/`receiveApproval` pattern.\\ninterface IApproveAndCall {\\n /// @notice Executes `receiveApproval` function on spender as specified in\\n /// `IReceiveApproval` interface. Approves spender to withdraw from\\n /// the caller multiple times, up to the `amount`. If this\\n /// function is called again, it overwrites the current allowance\\n /// with `amount`. Reverts if the approval reverted or if\\n /// `receiveApproval` call on the spender reverted.\\n function approveAndCall(\\n address spender,\\n uint256 amount,\\n bytes memory extraData\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x393d18ef81a57dcc96fff4c340cc2945deaebb37b9796c322cf2bc96872c3df8\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IERC20WithPermit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\\\";\\n\\nimport \\\"./IApproveAndCall.sol\\\";\\n\\n/// @title IERC20WithPermit\\n/// @notice Burnable ERC20 token with EIP2612 permit functionality. User can\\n/// authorize a transfer of their token with a signature conforming\\n/// EIP712 standard instead of an on-chain transaction from their\\n/// address. Anyone can submit this signature on the user's behalf by\\n/// calling the permit function, as specified in EIP2612 standard,\\n/// paying gas fees, and possibly performing other actions in the same\\n/// transaction.\\ninterface IERC20WithPermit is IERC20, IERC20Metadata, IApproveAndCall {\\n /// @notice EIP2612 approval made with secp256k1 signature.\\n /// Users can authorize a transfer of their tokens with a signature\\n /// conforming EIP712 standard, rather than an on-chain transaction\\n /// from their address. Anyone can submit this signature on the\\n /// user's behalf by calling the permit function, paying gas fees,\\n /// and possibly performing other actions in the same transaction.\\n /// @dev The deadline argument can be set to `type(uint256).max to create\\n /// permits that effectively never expire.\\n function permit(\\n address owner,\\n address spender,\\n uint256 amount,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /// @notice Destroys `amount` tokens from the caller.\\n function burn(uint256 amount) external;\\n\\n /// @notice Destroys `amount` of tokens from `account`, deducting the amount\\n /// from caller's allowance.\\n function burnFrom(address account, uint256 amount) external;\\n\\n /// @notice Returns hash of EIP712 Domain struct with the token name as\\n /// a signing domain and token contract as a verifying contract.\\n /// Used to construct EIP2612 signature provided to `permit`\\n /// function.\\n /* solhint-disable-next-line func-name-mixedcase */\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n\\n /// @notice Returns the current nonce for EIP2612 permission for the\\n /// provided token owner for a replay protection. Used to construct\\n /// EIP2612 signature provided to `permit` function.\\n function nonce(address owner) external view returns (uint256);\\n\\n /// @notice Returns EIP2612 Permit message hash. Used to construct EIP2612\\n /// signature provided to `permit` function.\\n /* solhint-disable-next-line func-name-mixedcase */\\n function PERMIT_TYPEHASH() external pure returns (bytes32);\\n}\\n\",\"keccak256\":\"0xdac9a5086c19a7128b505a7be1ab0ac1aa314f6989cb88d2417e9d7383f89fa9\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IReceiveApproval.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\n/// @notice An interface that should be implemented by contracts supporting\\n/// `approveAndCall`/`receiveApproval` pattern.\\ninterface IReceiveApproval {\\n /// @notice Receives approval to spend tokens. Called as a result of\\n /// `approveAndCall` call on the token.\\n function receiveApproval(\\n address from,\\n uint256 amount,\\n address token,\\n bytes calldata extraData\\n ) external;\\n}\\n\",\"keccak256\":\"0x6a30d83ad230548b1e7839737affc8489a035314209de14b89dbef7fb0f66395\",\"license\":\"MIT\"},\"contracts/BeaconDkgValidator.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\nimport \\\"./libraries/BytesLib.sol\\\";\\nimport {BeaconDkg as DKG} from \\\"./libraries/BeaconDkg.sol\\\";\\n\\n/// @title DKG result validator\\n/// @notice DKGValidator allows performing a full validation of DKG result,\\n/// including checking the format of fields in the result, declared\\n/// selected group members, and signatures of operators supporting the\\n/// result. The operator submitting the result should perform the\\n/// validation using a free contract call before submitting the result\\n/// to ensure their result is valid and can not be challenged. All other\\n/// network operators should perform validation of the submitted result\\n/// using a free contract call and challenge the result if the\\n/// validation fails.\\ncontract BeaconDkgValidator {\\n using BytesLib for bytes;\\n using ECDSA for bytes32;\\n\\n /// @dev Size of a group in the threshold relay.\\n uint256 public constant groupSize = 64;\\n\\n /// @dev The minimum number of group members needed to interact according to\\n /// the protocol to produce a relay entry. The adversary can not learn\\n /// anything about the key as long as it does not break into\\n /// groupThreshold+1 of members.\\n uint256 public constant groupThreshold = 33;\\n\\n /// @dev The minimum number of active and properly behaving group members\\n /// during the DKG needed to accept the result. This number is higher\\n /// than `groupThreshold` to keep a safety margin for members becoming\\n /// inactive after DKG so that the group can still produce a relay\\n /// entry.\\n uint256 public constant activeThreshold = 58; // 90% of groupSize\\n\\n /// @dev Size in bytes of a single signature produced by operator supporting\\n /// DKG result.\\n uint256 public constant signatureByteSize = 65;\\n\\n SortitionPool public immutable sortitionPool;\\n\\n constructor(SortitionPool _sortitionPool) {\\n require(\\n address(_sortitionPool) != address(0),\\n \\\"Zero-address reference\\\"\\n );\\n\\n sortitionPool = _sortitionPool;\\n }\\n\\n /// @notice Performs a full validation of DKG result, including checking the\\n /// format of fields in the result, declared selected group members,\\n /// and signatures of operators supporting the result.\\n /// @param seed seed used to start the DKG and select group members\\n /// @param startBlock DKG start block\\n /// @return isValid true if the result is valid, false otherwise\\n /// @return errorMsg validation error message; empty for a valid result\\n function validate(\\n DKG.Result calldata result,\\n uint256 seed,\\n uint256 startBlock\\n ) external view returns (bool isValid, string memory errorMsg) {\\n (bool hasValidFields, string memory error) = validateFields(result);\\n if (!hasValidFields) {\\n return (false, error);\\n }\\n\\n if (!validateSignatures(result, startBlock)) {\\n return (false, \\\"Invalid signatures\\\");\\n }\\n\\n if (!validateGroupMembers(result, seed)) {\\n return (false, \\\"Invalid group members\\\");\\n }\\n\\n // At this point all group members and mishbehaved members were verified\\n if (!validateMembersHash(result)) {\\n return (false, \\\"Invalid members hash\\\");\\n }\\n\\n return (true, \\\"\\\");\\n }\\n\\n /// @notice Performs a static validation of DKG result fields: lengths,\\n /// ranges, and order of arrays.\\n /// @return isValid true if the result is valid, false otherwise\\n /// @return errorMsg validation error message; empty for a valid result\\n function validateFields(DKG.Result calldata result)\\n public\\n pure\\n returns (bool isValid, string memory errorMsg)\\n {\\n // Group public key needs to be 128 bytes long.\\n if (result.groupPubKey.length != 128) {\\n return (false, \\\"Malformed group public key\\\");\\n }\\n\\n // The number of misbehaved members can not exceed the threshold.\\n // Misbehaved member indices needs to be unique, between [1, groupSize],\\n // and sorted in ascending order.\\n uint8[] calldata misbehavedMembersIndices = result\\n .misbehavedMembersIndices;\\n if (groupSize - misbehavedMembersIndices.length < activeThreshold) {\\n return (false, \\\"Too many members misbehaving during DKG\\\");\\n }\\n if (misbehavedMembersIndices.length > 1) {\\n if (\\n misbehavedMembersIndices[0] < 1 ||\\n misbehavedMembersIndices[misbehavedMembersIndices.length - 1] >\\n groupSize\\n ) {\\n return (false, \\\"Corrupted misbehaved members indices\\\");\\n }\\n for (uint256 i = 1; i < misbehavedMembersIndices.length; i++) {\\n if (\\n misbehavedMembersIndices[i - 1] >=\\n misbehavedMembersIndices[i]\\n ) {\\n return (false, \\\"Corrupted misbehaved members indices\\\");\\n }\\n }\\n }\\n\\n // Each signature needs to have a correct length and signatures need to\\n // be provided.\\n uint256 signaturesCount = result.signatures.length / signatureByteSize;\\n if (result.signatures.length == 0) {\\n return (false, \\\"No signatures provided\\\");\\n }\\n if (result.signatures.length % signatureByteSize != 0) {\\n return (false, \\\"Malformed signatures array\\\");\\n }\\n\\n // We expect the same amount of signatures as the number of declared\\n // group member indices that signed the result.\\n uint256[] calldata signingMembersIndices = result.signingMembersIndices;\\n if (signaturesCount != signingMembersIndices.length) {\\n return (false, \\\"Unexpected signatures count\\\");\\n }\\n if (signaturesCount < groupThreshold) {\\n return (false, \\\"Too few signatures\\\");\\n }\\n if (signaturesCount > groupSize) {\\n return (false, \\\"Too many signatures\\\");\\n }\\n\\n // Signing member indices needs to be unique, between [1,groupSize],\\n // and sorted in ascending order.\\n if (\\n signingMembersIndices[0] < 1 ||\\n signingMembersIndices[signingMembersIndices.length - 1] > groupSize\\n ) {\\n return (false, \\\"Corrupted signing member indices\\\");\\n }\\n for (uint256 i = 1; i < signingMembersIndices.length; i++) {\\n if (signingMembersIndices[i - 1] >= signingMembersIndices[i]) {\\n return (false, \\\"Corrupted signing member indices\\\");\\n }\\n }\\n\\n return (true, \\\"\\\");\\n }\\n\\n /// @notice Performs validation of group members as declared in DKG\\n /// result against group members selected by the sortition pool.\\n /// @param seed seed used to start the DKG and select group members\\n /// @return true if group members matches; false otherwise\\n function validateGroupMembers(DKG.Result calldata result, uint256 seed)\\n public\\n view\\n returns (bool)\\n {\\n uint32[] calldata resultMembers = result.members;\\n uint32[] memory actualGroupMembers = sortitionPool.selectGroup(\\n groupSize,\\n bytes32(seed)\\n );\\n if (resultMembers.length != actualGroupMembers.length) {\\n return false;\\n }\\n for (uint256 i = 0; i < resultMembers.length; i++) {\\n if (resultMembers[i] != actualGroupMembers[i]) {\\n return false;\\n }\\n }\\n return true;\\n }\\n\\n /// @notice Performs validation of signatures supplied in DKG result.\\n /// Note that this function does not check if addresses which\\n /// supplied signatures supporting the result are the ones selected\\n /// to the group by sortition pool. This function should be used\\n /// together with `validateGroupMembers`.\\n /// @param startBlock DKG start block\\n /// @return true if group members matches; false otherwise\\n function validateSignatures(DKG.Result calldata result, uint256 startBlock)\\n public\\n view\\n returns (bool)\\n {\\n bytes32 hash = keccak256(\\n abi.encode(\\n block.chainid,\\n result.groupPubKey,\\n result.misbehavedMembersIndices,\\n startBlock\\n )\\n ).toEthSignedMessageHash();\\n\\n uint256[] calldata signingMembersIndices = result.signingMembersIndices;\\n uint32[] memory signingMemberIds = new uint32[](\\n signingMembersIndices.length\\n );\\n for (uint256 i = 0; i < signingMembersIndices.length; i++) {\\n signingMemberIds[i] = result.members[signingMembersIndices[i] - 1];\\n }\\n\\n address[] memory signingMemberAddresses = sortitionPool.getIDOperators(\\n signingMemberIds\\n );\\n\\n bytes memory current; // Current signature to be checked.\\n\\n uint256 signaturesCount = result.signatures.length / signatureByteSize;\\n for (uint256 i = 0; i < signaturesCount; i++) {\\n current = result.signatures.slice(\\n signatureByteSize * i,\\n signatureByteSize\\n );\\n address recoveredAddress = hash.recover(current);\\n\\n if (signingMemberAddresses[i] != recoveredAddress) {\\n return false;\\n }\\n }\\n\\n return true;\\n }\\n\\n /// @notice Performs validation of hashed group members that actively took\\n /// part in DKG.\\n /// @param result DKG result\\n /// @return true if result's group members hash matches with the one that is\\n /// challenged.\\n function validateMembersHash(DKG.Result calldata result)\\n public\\n pure\\n returns (bool)\\n {\\n if (result.misbehavedMembersIndices.length > 0) {\\n // members that generated a group signing key\\n uint32[] memory groupMembers = new uint32[](\\n result.members.length - result.misbehavedMembersIndices.length\\n );\\n uint256 k = 0; // misbehaved members counter\\n uint256 j = 0; // group members counter\\n for (uint256 i = 0; i < result.members.length; i++) {\\n // misbehaved member indices start from 1, so we need to -1 on misbehaved\\n if (i != result.misbehavedMembersIndices[k] - 1) {\\n groupMembers[j] = result.members[i];\\n j++;\\n } else if (k < result.misbehavedMembersIndices.length - 1) {\\n k++;\\n }\\n }\\n\\n return keccak256(abi.encode(groupMembers)) == result.membersHash;\\n }\\n\\n return keccak256(abi.encode(result.members)) == result.membersHash;\\n }\\n}\\n\",\"keccak256\":\"0xaacb5961dc3181238036f1e747b3d1935f356ca5ff27bd9c9c1c0c22dee6630c\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BeaconDkg.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\nimport \\\"./BytesLib.sol\\\";\\nimport {BeaconDkgValidator as DKGValidator} from \\\"../BeaconDkgValidator.sol\\\";\\n\\nlibrary BeaconDkg {\\n using BytesLib for bytes;\\n using ECDSA for bytes32;\\n\\n struct Parameters {\\n // Time in blocks during which a submitted result can be challenged.\\n uint256 resultChallengePeriodLength;\\n // Extra gas required to be left at the end of the challenge DKG result\\n // transaction.\\n uint256 resultChallengeExtraGas;\\n // Time in blocks during which a result is expected to be submitted.\\n uint256 resultSubmissionTimeout;\\n // Time in blocks during which only the result submitter is allowed to\\n // approve it. Once this period ends and the submitter have not approved\\n // the result, anyone can do it.\\n uint256 submitterPrecedencePeriodLength;\\n }\\n\\n struct Data {\\n // Address of the Sortition Pool contract.\\n SortitionPool sortitionPool;\\n // Address of the DKGValidator contract.\\n DKGValidator dkgValidator;\\n // DKG parameters. The parameters should persist between DKG executions.\\n // They should be updated with dedicated set functions only when DKG is not\\n // in progress.\\n Parameters parameters;\\n // Time in blocks at which DKG started.\\n uint256 startBlock;\\n // Seed used to start DKG.\\n uint256 seed;\\n // Time in blocks that should be added to result submission period calculation.\\n // It is used in case of a challenge to adjust DKG timeout calculation.\\n uint256 resultSubmissionStartBlockOffset;\\n // Hash of submitted DKG result.\\n bytes32 submittedResultHash;\\n // Block number from the moment of the DKG result submission.\\n uint256 submittedResultBlock;\\n }\\n\\n /// @notice DKG result.\\n struct Result {\\n // Claimed submitter candidate group member index.\\n // Must be in range [1, groupSize].\\n uint256 submitterMemberIndex;\\n // Generated candidate group public key\\n bytes groupPubKey;\\n // Array of misbehaved members indices (disqualified or inactive).\\n // Indices must be in range [1, groupSize], unique, and sorted in ascending\\n // order.\\n uint8[] misbehavedMembersIndices;\\n // Concatenation of signatures from members supporting the result.\\n // The message to be signed by each member is keccak256 hash of the\\n // calculated group public key, misbehaved members indices and DKG\\n // start block. The calculated hash should be prefixed with prefixed with\\n // `\\\\x19Ethereum signed message:\\\\n` before signing, so the message to\\n // sign is:\\n // `\\\\x19Ethereum signed message:\\\\n${keccak256(\\n // groupPubKey, misbehavedMembersIndices, dkgStartBlock\\n // )}`\\n bytes signatures;\\n // Indices of members corresponding to each signature. Indices must be\\n // be in range [1, groupSize], unique, and sorted in ascending order.\\n uint256[] signingMembersIndices;\\n // Identifiers of candidate group members as outputted by the group\\n // selection protocol.\\n uint32[] members;\\n // Keccak256 hash of group members identifiers that actively took part\\n // in DKG (excluding IA/DQ members).\\n bytes32 membersHash;\\n }\\n\\n /// @notice States for phases of group creation. The states doesn't include\\n /// timeouts which should be tracked and notified individually.\\n enum State {\\n // Group creation is not in progress. It is a state set after group creation\\n // completion either by timeout or by a result approval.\\n IDLE,\\n // Group creation is awaiting the seed and sortition pool is locked.\\n AWAITING_SEED,\\n // Off-chain DKG protocol execution is in progress. A result is being calculated\\n // by the clients in this state. It's not yet possible to submit the result.\\n KEY_GENERATION,\\n // After off-chain DKG protocol execution the contract awaits result submission.\\n // This is a state to which group creation returns in case of a result\\n // challenge notification.\\n AWAITING_RESULT,\\n // DKG result was submitted and awaits an approval or a challenge. If a result\\n // gets challenge the state returns to `AWAITING_RESULT`. If a result gets\\n // approval the state changes to `IDLE`.\\n CHALLENGE\\n }\\n\\n /// @dev Size of a group in the threshold relay.\\n uint256 public constant groupSize = 64;\\n\\n /// @notice Time in blocks after which DKG result is complete and ready to be\\n // published by clients.\\n uint256 public constant offchainDkgTime = 5 * (1 + 5) + 2 * (1 + 10) + 20;\\n\\n event DkgStarted(uint256 indexed seed);\\n\\n // To recreate the members that actively took part in dkg, the selected members\\n // array should be filtered out from misbehavedMembersIndices.\\n event DkgResultSubmitted(\\n bytes32 indexed resultHash,\\n uint256 indexed seed,\\n Result result\\n );\\n\\n event DkgTimedOut();\\n\\n event DkgResultApproved(\\n bytes32 indexed resultHash,\\n address indexed approver\\n );\\n\\n event DkgResultChallenged(\\n bytes32 indexed resultHash,\\n address indexed challenger,\\n string reason\\n );\\n\\n event DkgStateLocked();\\n\\n event DkgSeedTimedOut();\\n\\n /// @notice Initializes SortitionPool and DKGValidator addresses.\\n /// Can be performed only once.\\n /// @param _sortitionPool Sortition Pool reference\\n /// @param _dkgValidator DKGValidator reference\\n function init(\\n Data storage self,\\n SortitionPool _sortitionPool,\\n DKGValidator _dkgValidator\\n ) internal {\\n require(\\n address(self.sortitionPool) == address(0),\\n \\\"Sortition Pool address already set\\\"\\n );\\n\\n require(\\n address(self.dkgValidator) == address(0),\\n \\\"DKG Validator address already set\\\"\\n );\\n\\n self.sortitionPool = _sortitionPool;\\n self.dkgValidator = _dkgValidator;\\n }\\n\\n /// @notice Determines the current state of group creation. It doesn't take\\n /// timeouts into consideration. The timeouts should be tracked and\\n /// notified separately.\\n function currentState(Data storage self)\\n internal\\n view\\n returns (State state)\\n {\\n state = State.IDLE;\\n\\n if (self.sortitionPool.isLocked()) {\\n state = State.AWAITING_SEED;\\n\\n if (self.startBlock > 0) {\\n state = State.KEY_GENERATION;\\n\\n if (block.number > self.startBlock + offchainDkgTime) {\\n state = State.AWAITING_RESULT;\\n\\n if (self.submittedResultBlock > 0) {\\n state = State.CHALLENGE;\\n }\\n }\\n }\\n }\\n }\\n\\n /// @notice Locks the sortition pool and starts awaiting for the\\n /// group creation seed.\\n function lockState(Data storage self) internal {\\n require(currentState(self) == State.IDLE, \\\"Current state is not IDLE\\\");\\n\\n emit DkgStateLocked();\\n\\n self.sortitionPool.lock();\\n }\\n\\n function start(Data storage self, uint256 seed) internal {\\n require(\\n currentState(self) == State.AWAITING_SEED,\\n \\\"Current state is not AWAITING_SEED\\\"\\n );\\n\\n emit DkgStarted(seed);\\n\\n self.startBlock = block.number;\\n self.seed = seed;\\n }\\n\\n /// @notice Allows to submit a DKG result. The submitted result does not go\\n /// through a validation and before it gets accepted, it needs to\\n /// wait through the challenge period during which everyone has\\n /// a chance to challenge the result as invalid one. Submitter of\\n /// the result needs to be in the sortition pool and if the result\\n /// gets challenged, the submitter will get slashed.\\n function submitResult(Data storage self, Result calldata result) external {\\n require(\\n currentState(self) == State.AWAITING_RESULT,\\n \\\"Current state is not AWAITING_RESULT\\\"\\n );\\n require(!hasDkgTimedOut(self), \\\"DKG timeout already passed\\\");\\n\\n SortitionPool sortitionPool = self.sortitionPool;\\n\\n // Submitter must be an operator in the sortition pool.\\n // Declared submitter's member index in the DKG result needs to match\\n // the address calling this function.\\n require(\\n sortitionPool.isOperatorInPool(msg.sender),\\n \\\"Submitter not in the sortition pool\\\"\\n );\\n require(\\n sortitionPool.getIDOperator(\\n result.members[result.submitterMemberIndex - 1]\\n ) == msg.sender,\\n \\\"Unexpected submitter index\\\"\\n );\\n\\n self.submittedResultHash = keccak256(abi.encode(result));\\n self.submittedResultBlock = block.number;\\n\\n emit DkgResultSubmitted(self.submittedResultHash, self.seed, result);\\n }\\n\\n /// @notice Checks if DKG timed out. The DKG timeout period includes time required\\n /// for off-chain protocol execution and time for the result publication.\\n /// After this time a result cannot be submitted and DKG can be notified\\n /// about the timeout. DKG period is adjusted by result submission\\n /// offset that include blocks that were mined while invalid result\\n /// has been registered until it got challenged.\\n /// @return True if DKG timed out, false otherwise.\\n function hasDkgTimedOut(Data storage self) internal view returns (bool) {\\n return\\n currentState(self) == State.AWAITING_RESULT &&\\n block.number >\\n (self.startBlock +\\n offchainDkgTime +\\n self.resultSubmissionStartBlockOffset +\\n self.parameters.resultSubmissionTimeout);\\n }\\n\\n /// @notice Notifies about DKG timeout.\\n function notifyTimeout(Data storage self) internal {\\n require(hasDkgTimedOut(self), \\\"DKG has not timed out\\\");\\n\\n emit DkgTimedOut();\\n\\n complete(self);\\n }\\n\\n /// @notice Notifies about the seed was not delivered and restores the\\n /// initial DKG state (IDLE).\\n function notifySeedTimedOut(Data storage self) internal {\\n require(\\n currentState(self) == State.AWAITING_SEED,\\n \\\"Current state is not AWAITING_SEED\\\"\\n );\\n\\n emit DkgSeedTimedOut();\\n\\n complete(self);\\n }\\n\\n /// @notice Approves DKG result. Can be called when the challenge period for\\n /// the submitted result is finished. Considers the submitted result\\n /// as valid. For the first `submitterPrecedencePeriodLength`\\n /// blocks after the end of the challenge period can be called only\\n /// by the DKG result submitter. After that time, can be called by\\n /// anyone.\\n /// @dev Can be called after a challenge period for the submitted result.\\n /// @param result Result to approve. Must match the submitted result stored\\n /// during `submitResult`.\\n /// @return misbehavedMembers Identifiers of members who misbehaved during DKG.\\n function approveResult(Data storage self, Result calldata result)\\n external\\n returns (uint32[] memory misbehavedMembers)\\n {\\n require(\\n currentState(self) == State.CHALLENGE,\\n \\\"Current state is not CHALLENGE\\\"\\n );\\n\\n uint256 challengePeriodEnd = self.submittedResultBlock +\\n self.parameters.resultChallengePeriodLength;\\n\\n require(\\n block.number > challengePeriodEnd,\\n \\\"Challenge period has not passed yet\\\"\\n );\\n\\n require(\\n keccak256(abi.encode(result)) == self.submittedResultHash,\\n \\\"Result under approval is different than the submitted one\\\"\\n );\\n\\n // Extract submitter member address. Submitter member index is in\\n // range [1, groupSize] so we need to -1 when fetching identifier from members\\n // array.\\n address submitterMember = self.sortitionPool.getIDOperator(\\n result.members[result.submitterMemberIndex - 1]\\n );\\n\\n require(\\n msg.sender == submitterMember ||\\n block.number >\\n challengePeriodEnd +\\n self.parameters.submitterPrecedencePeriodLength,\\n \\\"Only the DKG result submitter can approve the result at this moment\\\"\\n );\\n\\n // Extract misbehaved members identifiers. Misbehaved members indices\\n // are in range [1, groupSize], so we need to -1 when fetching identifiers from\\n // members array.\\n misbehavedMembers = new uint32[](\\n result.misbehavedMembersIndices.length\\n );\\n for (uint256 i = 0; i < result.misbehavedMembersIndices.length; i++) {\\n misbehavedMembers[i] = result.members[\\n result.misbehavedMembersIndices[i] - 1\\n ];\\n }\\n\\n emit DkgResultApproved(self.submittedResultHash, msg.sender);\\n\\n return misbehavedMembers;\\n }\\n\\n /// @notice Challenges DKG result. If the submitted result is proved to be\\n /// invalid it reverts the DKG back to the result submission phase.\\n /// @dev Can be called during a challenge period for the submitted result.\\n /// @param result Result to challenge. Must match the submitted result\\n /// stored during `submitResult`.\\n /// @return maliciousResultHash Hash of the malicious result.\\n /// @return maliciousSubmitter Identifier of the malicious submitter.\\n function challengeResult(Data storage self, Result calldata result)\\n external\\n returns (bytes32 maliciousResultHash, uint32 maliciousSubmitter)\\n {\\n require(\\n currentState(self) == State.CHALLENGE,\\n \\\"Current state is not CHALLENGE\\\"\\n );\\n\\n require(\\n block.number <=\\n self.submittedResultBlock +\\n self.parameters.resultChallengePeriodLength,\\n \\\"Challenge period has already passed\\\"\\n );\\n\\n require(\\n keccak256(abi.encode(result)) == self.submittedResultHash,\\n \\\"Result under challenge is different than the submitted one\\\"\\n );\\n\\n // https://github.com/crytic/slither/issues/982\\n // slither-disable-next-line unused-return\\n try\\n self.dkgValidator.validate(result, self.seed, self.startBlock)\\n returns (\\n // slither-disable-next-line uninitialized-local,variable-scope\\n bool isValid,\\n // slither-disable-next-line uninitialized-local,variable-scope\\n string memory errorMsg\\n ) {\\n if (isValid) {\\n revert(\\\"unjustified challenge\\\");\\n }\\n\\n emit DkgResultChallenged(\\n self.submittedResultHash,\\n msg.sender,\\n errorMsg\\n );\\n } catch {\\n // if the validation reverted we consider the DKG result as invalid\\n emit DkgResultChallenged(\\n self.submittedResultHash,\\n msg.sender,\\n \\\"validation reverted\\\"\\n );\\n }\\n\\n // Consider result hash as malicious.\\n maliciousResultHash = self.submittedResultHash;\\n maliciousSubmitter = result.members[result.submitterMemberIndex - 1];\\n\\n // Adjust DKG result submission block start, so submission stage starts\\n // from the beginning.\\n self.resultSubmissionStartBlockOffset =\\n block.number -\\n self.startBlock -\\n offchainDkgTime;\\n\\n submittedResultCleanup(self);\\n\\n return (maliciousResultHash, maliciousSubmitter);\\n }\\n\\n /// @notice Due to EIP150, 1/64 of the gas is not forwarded to the call, and\\n /// will be kept to execute the remaining operations in the function\\n /// after the call inside the try-catch.\\n ///\\n /// To ensure there is no way for the caller to manipulate gas limit\\n /// in such a way that the call inside try-catch fails with out-of-gas\\n /// and the rest of the function is executed with the remaining\\n /// 1/64 of gas, we require an extra gas amount to be left at the\\n /// end of the call to the function challenging DKG result and\\n /// wrapping the call to BeaconDkgValidator and TokenStaking\\n /// contracts inside a try-catch.\\n function requireChallengeExtraGas(Data storage self) internal view {\\n require(\\n gasleft() >= self.parameters.resultChallengeExtraGas,\\n \\\"Not enough extra gas left\\\"\\n );\\n }\\n\\n /// @notice Updates DKG-related parameters\\n /// @param _resultChallengePeriodLength New value of the result challenge\\n /// period length. It is the number of blocks for which a DKG result\\n /// can be challenged.\\n /// @param _resultChallengeExtraGas New value of the result challenge extra\\n /// gas. It is the extra gas required to be left at the end of the\\n /// challenge DKG result transaction.\\n /// @param _resultSubmissionTimeout New value of the result submission\\n /// timeout in seconds. It is a timeout for a group to provide a DKG\\n /// result.\\n /// @param _submitterPrecedencePeriodLength New value of the submitter\\n /// precedence period length in blocks. It is the time during which\\n /// only the original DKG result submitter can approve it.\\n function setParameters(\\n Data storage self,\\n uint256 _resultChallengePeriodLength,\\n uint256 _resultChallengeExtraGas,\\n uint256 _resultSubmissionTimeout,\\n uint256 _submitterPrecedencePeriodLength\\n ) internal {\\n require(currentState(self) == State.IDLE, \\\"Current state is not IDLE\\\");\\n\\n require(\\n _resultChallengePeriodLength > 0,\\n \\\"Result challenge period length should be greater than zero\\\"\\n );\\n require(\\n _resultSubmissionTimeout > 0,\\n \\\"Result submission timeout should be greater than zero\\\"\\n );\\n require(\\n _submitterPrecedencePeriodLength < _resultSubmissionTimeout,\\n \\\"Submitter precedence period length should be less than the result submission timeout\\\"\\n );\\n\\n self\\n .parameters\\n .resultChallengePeriodLength = _resultChallengePeriodLength;\\n self.parameters.resultChallengeExtraGas = _resultChallengeExtraGas;\\n self.parameters.resultSubmissionTimeout = _resultSubmissionTimeout;\\n self\\n .parameters\\n .submitterPrecedencePeriodLength = _submitterPrecedencePeriodLength;\\n }\\n\\n /// @notice Completes DKG by cleaning up state.\\n /// @dev Should be called after DKG times out or a result is approved.\\n function complete(Data storage self) internal {\\n delete self.startBlock;\\n delete self.seed;\\n delete self.resultSubmissionStartBlockOffset;\\n submittedResultCleanup(self);\\n self.sortitionPool.unlock();\\n }\\n\\n /// @notice Cleans up submitted result state either after DKG completion\\n /// (as part of `complete` method) or after justified challenge.\\n function submittedResultCleanup(Data storage self) private {\\n delete self.submittedResultHash;\\n delete self.submittedResultBlock;\\n }\\n}\\n\",\"keccak256\":\"0x86bea35ab775ec969bc91208305f6f85aa9dd49bb74f8e57e7d453797e8ad98e\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BytesLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\n/*\\nVersion pulled from keep-core v1:\\nhttps://github.com/keep-network/keep-core/blob/f297202db00c027978ad8e7103a356503de5773c/solidity-v1/contracts/utils/BytesLib.sol\\n\\nTo compile it with solidity 0.8 `_preBytes_slot` was replaced with `_preBytes.slot`.\\n*/\\n\\n/*\\nhttps://github.com/GNSPS/solidity-bytes-utils/\\nThis is free and unencumbered software released into the public domain.\\nAnyone is free to copy, modify, publish, use, compile, sell, or\\ndistribute this software, either in source code form or as a compiled\\nbinary, for any purpose, commercial or non-commercial, and by any\\nmeans.\\nIn jurisdictions that recognize copyright laws, the author or authors\\nof this software dedicate any and all copyright interest in the\\nsoftware to the public domain. We make this dedication for the benefit\\nof the public at large and to the detriment of our heirs and\\nsuccessors. We intend this dedication to be an overt act of\\nrelinquishment in perpetuity of all present and future rights to this\\nsoftware under copyright law.\\nTHE SOFTWARE IS PROVIDED \\\"AS IS\\\", WITHOUT WARRANTY OF ANY KIND,\\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\\nIN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\\nOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\\nOTHER DEALINGS IN THE SOFTWARE.\\nFor more information, please refer to \\n*/\\n\\n/** @title BytesLib **/\\n/** @author https://github.com/GNSPS **/\\n\\nlibrary BytesLib {\\n function concatStorage(bytes storage _preBytes, bytes memory _postBytes)\\n internal\\n {\\n assembly {\\n // Read the first 32 bytes of _preBytes storage, which is the length\\n // of the array. (We don't need to use the offset into the slot\\n // because arrays use the entire slot.)\\n let fslot := sload(_preBytes.slot)\\n // Arrays of 31 bytes or less have an even value in their slot,\\n // while longer arrays have an odd value. The actual length is\\n // the slot divided by two for odd values, and the lowest order\\n // byte divided by two for even values.\\n // If the slot is even, bitwise and the slot with 255 and divide by\\n // two to get the length. If the slot is odd, bitwise and the slot\\n // with -1 and divide by two.\\n let slength := div(\\n and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)),\\n 2\\n )\\n let mlength := mload(_postBytes)\\n let newlength := add(slength, mlength)\\n // slength can contain both the length and contents of the array\\n // if length < 32 bytes so let's prepare for that\\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\\n switch add(lt(slength, 32), lt(newlength, 32))\\n case 2 {\\n // Since the new array still fits in the slot, we just need to\\n // update the contents of the slot.\\n // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length\\n sstore(\\n _preBytes.slot,\\n // all the modifications to the slot are inside this\\n // next block\\n add(\\n // we can just add to the slot contents because the\\n // bytes we want to change are the LSBs\\n fslot,\\n add(\\n mul(\\n div(\\n // load the bytes from memory\\n mload(add(_postBytes, 0x20)),\\n // zero all bytes to the right\\n exp(0x100, sub(32, mlength))\\n ),\\n // and now shift left the number of bytes to\\n // leave space for the length in the slot\\n exp(0x100, sub(32, newlength))\\n ),\\n // increase length by the double of the memory\\n // bytes length\\n mul(mlength, 2)\\n )\\n )\\n )\\n }\\n case 1 {\\n // The stored value fits in the slot, but the combined value\\n // will exceed it.\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\\n\\n // save new length\\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\\n\\n // The contents of the _postBytes array start 32 bytes into\\n // the structure. Our first read should obtain the `submod`\\n // bytes that can fit into the unused space in the last word\\n // of the stored array. To get this, we read 32 bytes starting\\n // from `submod`, so the data we read overlaps with the array\\n // contents by `submod` bytes. Masking the lowest-order\\n // `submod` bytes allows us to add that value directly to the\\n // stored value.\\n\\n let submod := sub(32, slength)\\n let mc := add(_postBytes, submod)\\n let end := add(_postBytes, mlength)\\n let mask := sub(exp(0x100, submod), 1)\\n\\n sstore(\\n sc,\\n add(\\n and(\\n fslot,\\n 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00\\n ),\\n and(mload(mc), mask)\\n )\\n )\\n\\n for {\\n mc := add(mc, 0x20)\\n sc := add(sc, 1)\\n } lt(mc, end) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n sstore(sc, mload(mc))\\n }\\n\\n mask := exp(0x100, sub(mc, end))\\n\\n sstore(sc, mul(div(mload(mc), mask), mask))\\n }\\n default {\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n // Start copying to the last used word of the stored array.\\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\\n\\n // save new length\\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\\n\\n // Copy over the first `submod` bytes of the new data as in\\n // case 1 above.\\n let slengthmod := mod(slength, 32)\\n let submod := sub(32, slengthmod)\\n let mc := add(_postBytes, submod)\\n let end := add(_postBytes, mlength)\\n let mask := sub(exp(0x100, submod), 1)\\n\\n sstore(sc, add(sload(sc), and(mload(mc), mask)))\\n\\n for {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } lt(mc, end) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n sstore(sc, mload(mc))\\n }\\n\\n mask := exp(0x100, sub(mc, end))\\n\\n sstore(sc, mul(div(mload(mc), mask), mask))\\n }\\n }\\n }\\n\\n function equalStorage(bytes storage _preBytes, bytes memory _postBytes)\\n internal\\n view\\n returns (bool)\\n {\\n bool success = true;\\n\\n assembly {\\n // we know _preBytes_offset is 0\\n let fslot := sload(_preBytes.slot)\\n // Decode the length of the stored array like in concatStorage().\\n let slength := div(\\n and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)),\\n 2\\n )\\n let mlength := mload(_postBytes)\\n\\n // if lengths don't match the arrays are not equal\\n switch eq(slength, mlength)\\n case 1 {\\n // slength can contain both the length and contents of the array\\n // if length < 32 bytes so let's prepare for that\\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\\n if iszero(iszero(slength)) {\\n switch lt(slength, 32)\\n case 1 {\\n // blank the last byte which is the length\\n fslot := mul(div(fslot, 0x100), 0x100)\\n\\n if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {\\n // unsuccess:\\n success := 0\\n }\\n }\\n default {\\n // cb is a circuit breaker in the for loop since there's\\n // no said feature for inline assembly loops\\n // cb = 1 - don't breaker\\n // cb = 0 - break\\n let cb := 1\\n\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n let sc := keccak256(0x0, 0x20)\\n\\n let mc := add(_postBytes, 0x20)\\n let end := add(mc, mlength)\\n\\n // the next line is the loop condition:\\n // while(uint(mc < end) + cb == 2)\\n for {\\n\\n } eq(add(lt(mc, end), cb), 2) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n if iszero(eq(sload(sc), mload(mc))) {\\n // unsuccess:\\n success := 0\\n cb := 0\\n }\\n }\\n }\\n }\\n }\\n default {\\n // unsuccess:\\n success := 0\\n }\\n }\\n\\n return success;\\n }\\n\\n function concat(bytes memory _preBytes, bytes memory _postBytes)\\n internal\\n pure\\n returns (bytes memory)\\n {\\n bytes memory tempBytes;\\n\\n assembly {\\n // Get a location of some free memory and store it in tempBytes as\\n // Solidity does for memory variables.\\n tempBytes := mload(0x40)\\n\\n // Store the length of the first bytes array at the beginning of\\n // the memory for tempBytes.\\n let length := mload(_preBytes)\\n mstore(tempBytes, length)\\n\\n // Maintain a memory counter for the current write location in the\\n // temp bytes array by adding the 32 bytes for the array length to\\n // the starting location.\\n let mc := add(tempBytes, 0x20)\\n // Stop copying when the memory counter reaches the length of the\\n // first bytes array.\\n let end := add(mc, length)\\n\\n for {\\n // Initialize a copy counter to the start of the _preBytes data,\\n // 32 bytes into its memory.\\n let cc := add(_preBytes, 0x20)\\n } lt(mc, end) {\\n // Increase both counters by 32 bytes each iteration.\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n // Write the _preBytes data into the tempBytes memory 32 bytes\\n // at a time.\\n mstore(mc, mload(cc))\\n }\\n\\n // Add the length of _postBytes to the current length of tempBytes\\n // and store it as the new length in the first 32 bytes of the\\n // tempBytes memory.\\n length := mload(_postBytes)\\n mstore(tempBytes, add(length, mload(tempBytes)))\\n\\n // Move the memory counter back from a multiple of 0x20 to the\\n // actual end of the _preBytes data.\\n mc := end\\n // Stop copying when the memory counter reaches the new combined\\n // length of the arrays.\\n end := add(mc, length)\\n\\n for {\\n let cc := add(_postBytes, 0x20)\\n } lt(mc, end) {\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n mstore(mc, mload(cc))\\n }\\n\\n // Update the free-memory pointer by padding our last write location\\n // to 32 bytes: add 31 bytes to the end of tempBytes to move to the\\n // next 32 byte block, then round down to the nearest multiple of\\n // 32. If the sum of the length of the two arrays is zero then add\\n // one before rounding down to leave a blank 32 bytes (the length block with 0).\\n mstore(\\n 0x40,\\n and(\\n add(add(end, iszero(add(length, mload(_preBytes)))), 31),\\n not(31) // Round down to the nearest 32 bytes.\\n )\\n )\\n }\\n\\n return tempBytes;\\n }\\n\\n function slice(\\n bytes memory _bytes,\\n uint256 _start,\\n uint256 _length\\n ) internal pure returns (bytes memory res) {\\n uint256 _end = _start + _length;\\n require(_end > _start && _bytes.length >= _end, \\\"Slice out of bounds\\\");\\n\\n assembly {\\n // Alloc bytes array with additional 32 bytes afterspace and assign it's size\\n res := mload(0x40)\\n mstore(0x40, add(add(res, 64), _length))\\n mstore(res, _length)\\n\\n // Compute distance between source and destination pointers\\n let diff := sub(res, add(_bytes, _start))\\n\\n for {\\n let src := add(add(_bytes, 32), _start)\\n let end := add(src, _length)\\n } lt(src, end) {\\n src := add(src, 32)\\n } {\\n mstore(add(src, diff), mload(src))\\n }\\n }\\n }\\n\\n function toAddress(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (address)\\n {\\n uint256 _totalLen = _start + 20;\\n require(\\n _totalLen > _start && _bytes.length >= _totalLen,\\n \\\"Address conversion out of bounds.\\\"\\n );\\n address tempAddress;\\n\\n assembly {\\n tempAddress := div(\\n mload(add(add(_bytes, 0x20), _start)),\\n 0x1000000000000000000000000\\n )\\n }\\n\\n return tempAddress;\\n }\\n\\n function toUint8(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (uint8)\\n {\\n require(\\n _bytes.length >= (_start + 1),\\n \\\"Uint8 conversion out of bounds.\\\"\\n );\\n uint8 tempUint;\\n\\n assembly {\\n tempUint := mload(add(add(_bytes, 0x1), _start))\\n }\\n\\n return tempUint;\\n }\\n\\n function toUint(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (uint256)\\n {\\n uint256 _totalLen = _start + 32;\\n require(\\n _totalLen > _start && _bytes.length >= _totalLen,\\n \\\"Uint conversion out of bounds.\\\"\\n );\\n uint256 tempUint;\\n\\n assembly {\\n tempUint := mload(add(add(_bytes, 0x20), _start))\\n }\\n\\n return tempUint;\\n }\\n\\n function equal(bytes memory _preBytes, bytes memory _postBytes)\\n internal\\n pure\\n returns (bool)\\n {\\n bool success = true;\\n\\n assembly {\\n let length := mload(_preBytes)\\n\\n // if lengths don't match the arrays are not equal\\n switch eq(length, mload(_postBytes))\\n case 1 {\\n // cb is a circuit breaker in the for loop since there's\\n // no said feature for inline assembly loops\\n // cb = 1 - don't breaker\\n // cb = 0 - break\\n let cb := 1\\n\\n let mc := add(_preBytes, 0x20)\\n let end := add(mc, length)\\n\\n for {\\n let cc := add(_postBytes, 0x20)\\n // the next line is the loop condition:\\n // while(uint(mc < end) + cb == 2)\\n } eq(add(lt(mc, end), cb), 2) {\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n // if any of these checks fails then arrays are not equal\\n if iszero(eq(mload(mc), mload(cc))) {\\n // unsuccess:\\n success := 0\\n cb := 0\\n }\\n }\\n }\\n default {\\n // unsuccess:\\n success := 0\\n }\\n }\\n\\n return success;\\n }\\n\\n function toBytes32(bytes memory _source)\\n internal\\n pure\\n returns (bytes32 result)\\n {\\n if (_source.length == 0) {\\n return 0x0;\\n }\\n\\n assembly {\\n result := mload(add(_source, 32))\\n }\\n }\\n\\n function keccak256Slice(\\n bytes memory _bytes,\\n uint256 _start,\\n uint256 _length\\n ) internal pure returns (bytes32 result) {\\n uint256 _end = _start + _length;\\n require(_end > _start && _bytes.length >= _end, \\\"Slice out of bounds\\\");\\n\\n assembly {\\n result := keccak256(add(add(_bytes, 32), _start), _length)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3b76e2fe36eb777440250dcf2ea7a689375e8af22f3cc33521095ff6954becdb\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "storageLayout": { + "storage": [], + "types": null + }, + "userdoc": { + "kind": "user", + "methods": { + "validate((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32),uint256,uint256)": { + "notice": "Performs a full validation of DKG result, including checking the format of fields in the result, declared selected group members, and signatures of operators supporting the result." + }, + "validateFields((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))": { + "notice": "Performs a static validation of DKG result fields: lengths, ranges, and order of arrays." + }, + "validateGroupMembers((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32),uint256)": { + "notice": "Performs validation of group members as declared in DKG result against group members selected by the sortition pool." + }, + "validateMembersHash((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))": { + "notice": "Performs validation of hashed group members that actively took part in DKG." + }, + "validateSignatures((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32),uint256)": { + "notice": "Performs validation of signatures supplied in DKG result. Note that this function does not check if addresses which supplied signatures supporting the result are the ones selected to the group by sortition pool. This function should be used together with `validateGroupMembers`." + } + }, + "notice": "DKGValidator allows performing a full validation of DKG result, including checking the format of fields in the result, declared selected group members, and signatures of operators supporting the result. The operator submitting the result should perform the validation using a free contract call before submitting the result to ensure their result is valid and can not be challenged. All other network operators should perform validation of the submitted result using a free contract call and challenge the result if the validation fails.", + "version": 1 + } +} diff --git a/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/RandomBeacon.sol/RandomBeacon.json b/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/RandomBeacon.sol/RandomBeacon.json new file mode 100644 index 0000000000..763aa87797 --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/RandomBeacon.sol/RandomBeacon.json @@ -0,0 +1,3413 @@ +{ + "contractName": "RandomBeacon", + "sourceName": "contracts/RandomBeacon.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "contract SortitionPool", + "name": "_sortitionPool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "_tToken", + "type": "address" + }, + { + "internalType": "contract IStaking", + "name": "_staking", + "type": "address" + }, + { + "internalType": "contract BeaconDkgValidator", + "name": "_dkgValidator", + "type": "address" + }, + { + "internalType": "contract ReimbursementPool", + "name": "_reimbursementPool", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "AuthorizationDecreaseApproved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "decreasingAt", + "type": "uint64" + } + ], + "name": "AuthorizationDecreaseRequested", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + } + ], + "name": "AuthorizationIncreased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint96", + "name": "minimumAuthorization", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "authorizationDecreaseDelay", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "authorizationDecreaseChangePeriod", + "type": "uint64" + } + ], + "name": "AuthorizationParametersUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "entry", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "entrySubmittedBlock", + "type": "uint256" + } + ], + "name": "CallbackFailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "slashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "maliciousSubmitter", + "type": "address" + } + ], + "name": "DkgMaliciousResultSlashed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "slashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "maliciousSubmitter", + "type": "address" + } + ], + "name": "DkgMaliciousResultSlashingFailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "approver", + "type": "address" + } + ], + "name": "DkgResultApproved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "indexed": false, + "internalType": "string", + "name": "reason", + "type": "string" + } + ], + "name": "DkgResultChallenged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "seed", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "indexed": false, + "internalType": "struct BeaconDkg.Result", + "name": "result", + "type": "tuple" + } + ], + "name": "DkgResultSubmitted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "DkgSeedTimedOut", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "seed", + "type": "uint256" + } + ], + "name": "DkgStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "DkgStateLocked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "DkgTimedOut", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultSubmissionGas", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultApprovalGasOffset", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "notifyOperatorInactivityGasOffset", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntrySubmissionGasOffset", + "type": "uint256" + } + ], + "name": "GasParametersUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldGovernance", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newGovernance", + "type": "address" + } + ], + "name": "GovernanceTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "groupCreationFrequency", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "groupLifetime", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultChallengePeriodLength", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultChallengeExtraGas", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultSubmissionTimeout", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultSubmitterPrecedencePeriodLength", + "type": "uint256" + } + ], + "name": "GroupCreationParametersUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "indexed": true, + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + } + ], + "name": "GroupRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "notifier", + "type": "address" + } + ], + "name": "InactivityClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + } + ], + "name": "InvoluntaryAuthorizationDecreaseFailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "OperatorJoinedSortitionPool", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "OperatorRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "OperatorStatusUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newReimbursementPool", + "type": "address" + } + ], + "name": "ReimbursementPoolUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "slashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "groupMembers", + "type": "address[]" + } + ], + "name": "RelayEntryDelaySlashed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "slashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "groupMembers", + "type": "address[]" + } + ], + "name": "RelayEntryDelaySlashingFailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntrySoftTimeout", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntryHardTimeout", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "callbackGasLimit", + "type": "uint256" + } + ], + "name": "RelayEntryParametersUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "previousEntry", + "type": "bytes" + } + ], + "name": "RelayEntryRequested", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "submitter", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "entry", + "type": "bytes" + } + ], + "name": "RelayEntrySubmitted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "terminatedGroupId", + "type": "uint64" + } + ], + "name": "RelayEntryTimedOut", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "slashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "groupMembers", + "type": "address[]" + } + ], + "name": "RelayEntryTimeoutSlashed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "slashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "groupMembers", + "type": "address[]" + } + ], + "name": "RelayEntryTimeoutSlashingFailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isAuthorized", + "type": "bool" + } + ], + "name": "RequesterAuthorizationUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "sortitionPoolRewardsBanDuration", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntryTimeoutNotificationRewardMultiplier", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "unauthorizedSigningNotificationRewardMultiplier", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "dkgMaliciousResultNotificationRewardMultiplier", + "type": "uint256" + } + ], + "name": "RewardParametersUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "amount", + "type": "uint96" + } + ], + "name": "RewardsWithdrawn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntrySubmissionFailureSlashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "maliciousDkgResultSlashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "unauthorizedSigningSlashingAmount", + "type": "uint256" + } + ], + "name": "SlashingParametersUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "unauthorizedSigningSlashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "groupMembers", + "type": "address[]" + } + ], + "name": "UnauthorizedSigningSlashed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "unauthorizedSigningSlashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "groupMembers", + "type": "address[]" + } + ], + "name": "UnauthorizedSigningSlashingFailed", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "approveAuthorizationDecrease", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct BeaconDkg.Result", + "name": "dkgResult", + "type": "tuple" + } + ], + "name": "approveDkgResult", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + } + ], + "name": "authorizationDecreaseRequested", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + } + ], + "name": "authorizationIncreased", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "authorizationParameters", + "outputs": [ + { + "internalType": "uint96", + "name": "minimumAuthorization", + "type": "uint96" + }, + { + "internalType": "uint64", + "name": "authorizationDecreaseDelay", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "authorizationDecreaseChangePeriod", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "authorizedRequesters", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "availableRewards", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct BeaconDkg.Result", + "name": "dkgResult", + "type": "tuple" + } + ], + "name": "challengeDkgResult", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "eligibleStake", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gasParameters", + "outputs": [ + { + "internalType": "uint256", + "name": "dkgResultSubmissionGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultApprovalGasOffset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "notifyOperatorInactivityGasOffset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "relayEntrySubmissionGasOffset", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "genesis", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + } + ], + "name": "getGroup", + "outputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "registrationBlockNumber", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + }, + { + "internalType": "bool", + "name": "terminated", + "type": "bool" + } + ], + "internalType": "struct Groups.Group", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + } + ], + "name": "getGroup", + "outputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "registrationBlockNumber", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + }, + { + "internalType": "bool", + "name": "terminated", + "type": "bool" + } + ], + "internalType": "struct Groups.Group", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getGroupCreationState", + "outputs": [ + { + "internalType": "enum BeaconDkg.State", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getGroupsRegistry", + "outputs": [ + { + "internalType": "bytes32[]", + "name": "", + "type": "bytes32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "governance", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "groupCreationParameters", + "outputs": [ + { + "internalType": "uint256", + "name": "groupCreationFrequency", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "groupLifetime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultChallengePeriodLength", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultChallengeExtraGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultSubmissionTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgSubmitterPrecedencePeriodLength", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "hasDkgTimedOut", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "name": "inactivityClaimNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + } + ], + "name": "involuntaryAuthorizationDecrease", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isOperatorInPool", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isOperatorUpToDate", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isRelayRequestInProgress", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "joinSortitionPool", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "minimumAuthorization", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "notifyDkgTimeout", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "internalType": "uint256[]", + "name": "inactiveMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + } + ], + "internalType": "struct BeaconInactivity.Claim", + "name": "claim", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint32[]", + "name": "groupMembers", + "type": "uint32[]" + } + ], + "name": "notifyOperatorInactivity", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "operatorToStakingProvider", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "pendingAuthorizationDecrease", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "registerOperator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "reimbursementPool", + "outputs": [ + { + "internalType": "contract ReimbursementPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "relayEntryParameters", + "outputs": [ + { + "internalType": "uint256", + "name": "relayEntrySoftTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "relayEntryHardTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "callbackGasLimit", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "remainingAuthorizationDecreaseDelay", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32[]", + "name": "groupMembers", + "type": "uint32[]" + } + ], + "name": "reportRelayEntryTimeout", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "signedMsgSender", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "internalType": "uint32[]", + "name": "groupMembers", + "type": "uint32[]" + } + ], + "name": "reportUnauthorizedSigning", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IRandomBeaconConsumer", + "name": "callbackContract", + "type": "address" + } + ], + "name": "requestRelayEntry", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "rewardParameters", + "outputs": [ + { + "internalType": "uint256", + "name": "sortitionPoolRewardsBanDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "relayEntryTimeoutNotificationRewardMultiplier", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "unauthorizedSigningNotificationRewardMultiplier", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgMaliciousResultNotificationRewardMultiplier", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "selectGroup", + "outputs": [ + { + "internalType": "uint32[]", + "name": "", + "type": "uint32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "bool", + "name": "isAuthorized", + "type": "bool" + } + ], + "name": "setRequesterAuthorization", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "slashingParameters", + "outputs": [ + { + "internalType": "uint96", + "name": "relayEntrySubmissionFailureSlashingAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "maliciousDkgResultSlashingAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "unauthorizedSigningSlashingAmount", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "sortitionPool", + "outputs": [ + { + "internalType": "contract SortitionPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "staking", + "outputs": [ + { + "internalType": "contract IStaking", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "stakingProviderToOperator", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct BeaconDkg.Result", + "name": "dkgResult", + "type": "tuple" + } + ], + "name": "submitDkgResult", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "entry", + "type": "bytes" + }, + { + "internalType": "uint32[]", + "name": "groupMembers", + "type": "uint32[]" + } + ], + "name": "submitRelayEntry", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "entry", + "type": "bytes" + } + ], + "name": "submitRelayEntry", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "tToken", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newGovernance", + "type": "address" + } + ], + "name": "transferGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "_minimumAuthorization", + "type": "uint96" + }, + { + "internalType": "uint64", + "name": "_authorizationDecreaseDelay", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "_authorizationDecreaseChangePeriod", + "type": "uint64" + } + ], + "name": "updateAuthorizationParameters", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dkgResultSubmissionGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultApprovalGasOffset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "notifyOperatorInactivityGasOffset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "relayEntrySubmissionGasOffset", + "type": "uint256" + } + ], + "name": "updateGasParameters", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "groupCreationFrequency", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "groupLifetime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultChallengePeriodLength", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultChallengeExtraGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultSubmissionTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgSubmitterPrecedencePeriodLength", + "type": "uint256" + } + ], + "name": "updateGroupCreationParameters", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "updateOperatorStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ReimbursementPool", + "name": "_reimbursementPool", + "type": "address" + } + ], + "name": "updateReimbursementPool", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "relayEntrySoftTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "relayEntryHardTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "callbackGasLimit", + "type": "uint256" + } + ], + "name": "updateRelayEntryParameters", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sortitionPoolRewardsBanDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "relayEntryTimeoutNotificationRewardMultiplier", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "unauthorizedSigningNotificationRewardMultiplier", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgMaliciousResultNotificationRewardMultiplier", + "type": "uint256" + } + ], + "name": "updateRewardParameters", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "relayEntrySubmissionFailureSlashingAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "maliciousDkgResultSlashingAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "unauthorizedSigningSlashingAmount", + "type": "uint96" + } + ], + "name": "updateSlashingParameters", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + } + ], + "name": "withdrawIneligibleRewards", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "withdrawRewards", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x60806040523480156200001157600080fd5b5060405162006ab738038062006ab7833981016040819052620000349162000a49565b607180546001600160a01b038088166001600160a01b0319928316811790935560728054888316908416179055607380548783169084161790556032805491851691909216179055620000bd5760405162461bcd60e51b8152602060048201526016602482015260008051602062006a5783398151915260448201526064015b60405180910390fd5b6001600160a01b038416620001045760405162461bcd60e51b8152602060048201526016602482015260008051602062006a578339815191526044820152606401620000b4565b6001600160a01b0383166200014b5760405162461bcd60e51b8152602060048201526016602482015260008051602062006a578339815191526044820152606401620000b4565b6001600160a01b038216620001925760405162461bcd60e51b8152602060048201526016602482015260008051602062006a578339815191526044820152606401620000b4565b6001600160a01b038116620001d95760405162461bcd60e51b8152602060048201526016602482015260008051602062006a578339815191526044820152606401620000b4565b620001f6858360786200038c60201b62003060179092919060201c565b6200020d60886200048560201b620031551760201c565b62000218336200052a565b604051633d36f3fd60e21b815260746004820152690878678326eac90000006024820152623b538060448201819052606482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063f4dbcff49060840160006040518083038186803b1580156200028457600080fd5b505af415801562000299573d6000803e3d6000fd5b5050606680546001600160c01b0319167415af1d78b58c40000000000015af1d78b58c40000017905550620002e7905060886815af1d78b58c4000006200058b602090811b620031e917901c565b6064606a819055606981905560685562127500606755620003206078612d0061c35061050060146200062e602090811b6200327d17901c565b6200034161050061168060886200084860201b62003475179092919060201c565b61fa006064556200036360836203f480620008e6602090811b6200350017901c565b5050600260655550506203a052606b555061a21c606c5561d4e4606d55612bf2606e5562000b32565b82546001600160a01b031615620003f15760405162461bcd60e51b815260206004820152602260248201527f536f72746974696f6e20506f6f6c206164647265737320616c72656164792073604482015261195d60f21b6064820152608401620000b4565b60018301546001600160a01b031615620004585760405162461bcd60e51b815260206004820152602160248201527f444b472056616c696461746f72206164647265737320616c72656164792073656044820152601d60fa1b6064820152608401620000b4565b82546001600160a01b03199081166001600160a01b03938416178455600190930180549093169116179055565b60018101541580156200049a57506002810154155b620004e85760405162461bcd60e51b815260206004820152601e60248201527f5365656420656e74727920616c726561647920696e697469616c697a656400006044820152606401620000b4565b6200051760405180606001604052806040815260200162006a7760409139620008ee60201b620035081760201c565b8051600183015560200151600290910155565b600080546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce80910160405180910390a15050565b620005ab82546801000000000000000090046001600160401b0316151590565b15620005fa5760405162461bcd60e51b815260206004820152601960248201527f52656c6179207265717565737420696e2070726f6772657373000000000000006044820152606401620000b4565b600390910180546001600160601b039092166801000000000000000002600160401b600160a01b0319909216919091179055565b60006200063b8662000974565b60048111156200064f576200064f62000ac9565b146200069e5760405162461bcd60e51b815260206004820152601960248201527f43757272656e74207374617465206973206e6f742049444c45000000000000006044820152606401620000b4565b60008411620007165760405162461bcd60e51b815260206004820152603a60248201527f526573756c74206368616c6c656e676520706572696f64206c656e677468207360448201527f686f756c642062652067726561746572207468616e207a65726f0000000000006064820152608401620000b4565b600082116200078e5760405162461bcd60e51b815260206004820152603560248201527f526573756c74207375626d697373696f6e2074696d656f75742073686f756c6460448201527f2062652067726561746572207468616e207a65726f00000000000000000000006064820152608401620000b4565b8181106200082b5760405162461bcd60e51b815260206004820152605460248201527f5375626d697474657220707265636564656e636520706572696f64206c656e6760448201527f74682073686f756c64206265206c657373207468616e2074686520726573756c60648201527f74207375626d697373696f6e2074696d656f7574000000000000000000000000608482015260a401620000b4565b600285019390935560038401919091556004830155600590910155565b6200086883546801000000000000000090046001600160401b0316151590565b15620008b75760405162461bcd60e51b815260206004820152601960248201527f52656c6179207265717565737420696e2070726f6772657373000000000000006044820152606401620000b4565b6003909201805463ffffffff938416640100000000026001600160401b03199091169390921692909217179055565b600490910155565b60408051808201909152600080825260208201528151604014620009555760405162461bcd60e51b815260206004820152601760248201527f496e76616c6964204731206279746573206c656e6774680000000000000000006044820152606401620000b4565b5060208181015160409283015183518085019094529083529082015290565b805460408051632938b58d60e21b815290516000926001600160a01b03169163a4e2d6349160048083019260209291908290030181865afa158015620009be573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620009e4919062000adf565b1562000a2b575060068101546001901562000a2b57600290506048826006015462000a10919062000b0a565b43111562000a2b5750600a8101546003901562000a2b575060045b919050565b6001600160a01b038116811462000a4657600080fd5b50565b600080600080600060a0868803121562000a6257600080fd5b855162000a6f8162000a30565b602087015190955062000a828162000a30565b604087015190945062000a958162000a30565b606087015190935062000aa88162000a30565b608087015190925062000abb8162000a30565b809150509295509295909350565b634e487b7160e01b600052602160045260246000fd5b60006020828403121562000af257600080fd5b8151801515811462000b0357600080fd5b9392505050565b8082018082111562000b2c57634e487b7160e01b600052601160045260246000fd5b92915050565b615f158062000b426000396000f3fe608060405234801561001057600080fd5b506004361061038e5760003560e01c80637e0049fd116101de578063c35d64ea1161010f578063ded56d45116100ad578063f5ee563f1161007c578063f5ee563f146108fc578063f7186ce01461092a578063f854a27f1461093d578063fd2a47881461095057600080fd5b8063ded56d4514610897578063e03e4535146108c3578063e686440f146108d8578063f0820c92146108eb57600080fd5b8063cb8b3779116100e9578063cb8b377914610854578063ccfd3bbe14610869578063d38bfff41461087c578063d855c6311461088f57600080fd5b8063c35d64ea14610802578063c7c49c9814610815578063c9bacaad1461084157600080fd5b8063a04e29801161017c578063b142f85c11610156578063b142f85c1461078a578063b53dacdf146107c9578063b54a2374146107dc578063c09975cd146107ef57600080fd5b8063a04e29801461075c578063a7f0b3de1461076f578063b0d010d61461077757600080fd5b80638f105e37116101b85780638f105e37146106f1578063985e64871461070b5780639a7d09351461071e5780639c9de0281461073157600080fd5b80637e0049fd146106a25780637e33cba6146106b557806388a59590146106e057600080fd5b80634a07068e116102c3578063663032cd1161026157806375e0ae5a1161023057806375e0ae5a1461060c57806377a5a7bd1461061f5780637b14729e146106325780637b35b4e61461068f57600080fd5b8063663032cd146105ae57806368c34948146105c15780636a7f7a90146105c957806374024ab7146105dc57600080fd5b806355b64bcc1161029d57806355b64bcc1461056257806357665912146105755780635aa6e675146105885780635c5b38701461059b57600080fd5b80634a07068e146104f75780634cf088d91461050a578063529023011461053557600080fd5b8063319ac101116103305780633ea478aa1161030a5780633ea478aa1461048b57806342d86693146104be5780634368ec0c146104d15780634549cc4b146104e457600080fd5b8063319ac10114610445578063339646ac146104655780633682a4501461047857600080fd5b80631872ea941161036c5780631872ea94146103c35780631c5b0762146103e15780631d35fa63146103f4578063313767661461043257600080fd5b80630519e9911461039357806314a85474146103a8578063167f0517146103bb575b600080fd5b6103a66103a1366004614c6d565b610963565b005b6103a66103b6366004614ccd565b610a1b565b6103a6610aeb565b6103cb610b6d565b6040516103d89190614ced565b60405180910390f35b6103a66103ef366004614d31565b610bc8565b608b5460665460408051600160401b9093046001600160601b0390811684528083166020850152600160601b909204909116908201526060016103d8565b6103a6610440366004614d4e565b610c55565b610458610453366004614d9d565b610ed3565b6040516103d89190614e00565b6103a6610473366004614e48565b610fc9565b6103a6610486366004614d31565b611056565b6104ae610499366004614d31565b60706020526000908152604090205460ff1681565b60405190151581526020016103d8565b6103a66104cc366004614d31565b61109d565b6103a66104df366004614d31565b611237565b6104586104f2366004614f2f565b611348565b6103a6610505366004614fae565b611383565b60735461051d906001600160a01b031681565b6040516001600160a01b0390911681526020016103d8565b606754606854606954606a545b6040805194855260208501939093529183015260608201526080016103d8565b6103a6610570366004615030565b6116f1565b6103a661058336600461509b565b611a8a565b60005461051d906001600160a01b031681565b6103a66105a9366004614d4e565b611b93565b6103a66105bc366004614d31565b611d4e565b6104ae611dd3565b6103a66105d7366004614ccd565b611de4565b608b546064546040805163ffffffff808516825264010000000090940490931660208401528201526060016103d8565b6103a661061a366004614d31565b611e6c565b6103a661062d3660046150d0565b611ebf565b6106606074546001600160601b038116916001600160401b03600160601b8304811692600160a01b90041690565b604080516001600160601b0390941684526001600160401b0392831660208501529116908201526060016103d8565b6103a661069d366004614d31565b611f5f565b6103a66106b0366004614d4e565b611fe7565b6106c86106c3366004614d31565b61203a565b6040516001600160601b0390911681526020016103d8565b606b54606c54606d54606e54610542565b608854600160401b90046001600160401b031615156104ae565b6103a6610719366004615121565b6120d3565b6103a661072c36600461515a565b61215c565b61074461073f366004614d31565b6121d5565b6040516001600160401b0390911681526020016103d8565b6103a661076a366004615186565b612259565b6103a6612360565b6103a6610785366004614e48565b612422565b606554608754607a54607b54607c54607d54604080519687526020870195909552938501929092526060840152608083015260a082015260c0016103d8565b6103a66107d73660046151c6565b6124a5565b60715461051d906001600160a01b031681565b60325461051d906001600160a01b031681565b60725461051d906001600160a01b031681565b61051d610823366004614d31565b6001600160a01b039081166000908152607560205260409020541690565b6103a661084f366004614ccd565b612962565b61085c6129ea565b6040516103d8919061523d565b6103a6610877366004615265565b6129f6565b6103a661088a366004614d31565b612ca6565b6103a6612d3d565b61051d6108a5366004614d31565b6001600160a01b039081166000908152607660205260409020541690565b6108cb612dc5565b6040516103d89190615304565b6104ae6108e6366004614d31565b612e49565b6074546001600160601b03166106c8565b61091c61090a366004614d9d565b606f6020526000908152604090205481565b6040519081526020016103d8565b6104ae610938366004614d31565b612ee6565b6106c861094b366004614d31565b612f31565b6106c861095e366004614d31565b613016565b6000546001600160a01b031633146109965760405162461bcd60e51b815260040161098d90615317565b60405180910390fd5b6109a16088846131e9565b606680546001600160601b038481166001600160c01b03199092168217600160601b858316908102919091179093556040805191871682526020820192909252908101919091527f1eda09aaee2b21bbf5571b06eab42dd1b2c2b629a5d6336230ff8b0e1f538276906060015b60405180910390a1505050565b6073546001600160a01b03163314610a455760405162461bcd60e51b815260040161098d9061534e565b60735460715460405163117964a560e21b8152607460048201526001600160a01b039283166024820152908216604482015290841660648201526001600160601b038084166084830152821660a482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__906345e592949060c4015b60006040518083038186803b158015610ace57600080fd5b505af4158015610ae2573d6000803e3d6000fd5b50505050505050565b60735460715460405163520c3d3160e01b8152607460048201526001600160a01b0392831660248201529116604482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063520c3d319060640160006040518083038186803b158015610b5357600080fd5b505af4158015610b67573d6000803e3d6000fd5b50505050565b60606083600101805480602002602001604051908101604052809291908181526020018280548015610bbe57602002820191906000526020600020905b815481526020019060010190808311610baa575b5050505050905090565b60735460715460405163c6e1c83960e01b8152607460048201526001600160a01b0392831660248201529082166044820152908216606482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063c6e1c839906084015b60006040518083038186803b158015610c3a57600080fd5b505af4158015610c4e573d6000803e3d6000fd5b5050505050565b6040516346bf00db60e01b8152600090819073__$852b9611da141be0769f808cc0e4dd5c7d$__906346bf00db90610c949060789087906004016154c5565b6040805180830381865af4158015610cb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd491906155e5565b606654607154604051638871ca5d60e01b815263ffffffff841660048201529395509193506001600160601b0316916000916001600160a01b031690638871ca5d90602401602060405180830381865afa158015610d36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5a919061560a565b60408051600180825281830190925291925060009190602080830190803683375050506001600160a01b038381166000908152607660205260409020549192501681600081518110610dae57610dae615627565b6001600160a01b039283166020918202929092010152607354606a546040516383ddba8f60e01b815291909216916383ddba8f91610df491879133908790600401615676565b600060405180830381600087803b158015610e0e57600080fd5b505af1925050508015610e1f575060015b610e7457604080516001600160601b03851681526001600160a01b038416602082015286917f14621289a12ab59e0737decc388bba91d929c723defb4682d5d19b9a12ecfecb910160405180910390a2610ec1565b604080516001600160601b03851681526001600160a01b038416602082015286917f88f76c659db78142f88e94db3ca791869495394c6c1b3d412ced9022dc97c9e3910160405180910390a25b610ecb607861358c565b505050505050565b604080516080810182526060808252600060208301819052928201839052810191909152610f026083836135e0565b604051806080016040529081600082018054610f1d906156b6565b80601f0160208091040260200160405190810160405280929190818152602001828054610f49906156b6565b8015610f965780601f10610f6b57610100808354040283529160200191610f96565b820191906000526020600020905b815481529060010190602001808311610f7957829003601f168201915b5050509183525050600182015460208201526002820154604082015260039091015460ff16151560609091015292915050565b6000546001600160a01b03163314610ff35760405162461bcd60e51b815260040161098d90615317565b606784905560688390556069829055606a8190556040805185815260208101859052908101839052606081018290527fbe6727aab9b80431985c18deef80d48599397c63884c62e96959f82abd16f16d906080015b60405180910390a150505050565b604051634755926360e01b8152607460048201526001600160a01b038216602482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__90634755926390604401610c22565b6001600160a01b0381811660009081526075602052604090205416806110f85760405162461bcd60e51b815260206004820152601060248201526f2ab735b737bbb71037b832b930ba37b960811b604482015260640161098d565b607354604051632de9480760e01b81526001600160a01b0384811660048301526000921690632de9480790602401606060405180830381865afa158015611143573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116791906156f0565b50607154604051637104c0e560e11b81526001600160a01b03868116600483015280841660248301529294506000935091169063e20981ca906044016020604051808303816000875af11580156111c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e69190615732565b6040516001600160601b03821681529091506001600160a01b038516907f38532b6dea69d7266fa923c7813d190be37625f2454ddfa3d93c45c79482e3fd906020015b60405180910390a250505050565b3360009081526070602052604090205460ff166112965760405162461bcd60e51b815260206004820152601c60248201527f526571756573746572206d75737420626520617574686f72697a656400000000604482015260640161098d565b604080518082019091526089548152608a5460208201526000906112cd906112bd90613627565b8051602090910120608390613661565b90506112da6088826136fe565b608c80546001600160a01b0319166001600160a01b03841617905560655460885461130e91906001600160401b0316615765565b158015611335575060006113226078613863565b600481111561133357611333615227565b145b15611344576113446078613916565b5050565b604080516080810182526060808252600060208084018290528385018290529183018190528451858301208152608390915291909120610f02565b608854600160801b90046001600160401b031660006113a36083836135e0565b905083836040516020016113b8929190615779565b604051602081830303815290604052805190602001208160020154146113f05760405162461bcd60e51b815260040161098d906157c4565b608b54607154604051637bfcd47d60e11b8152600160401b9092046001600160601b0316916000916001600160a01b03169063f7f9a8fa906114389089908990600401615779565b600060405180830381865afa158015611455573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261147d9190810190615816565b9050600081516001600160401b0381111561149a5761149a614e7a565b6040519080825280602002602001820160405280156114c3578160200160208202803683370190505b50905060005b82518110156115495761150d8382815181106114e7576114e7615627565b60200260200101516001600160a01b039081166000908152607660205260409020541690565b82828151811061151f5761151f615627565b6001600160a01b039092166020928302919091019091015280611541816158ca565b9150506114c9565b506073546068546040516383ddba8f60e01b81526001600160a01b03909216916383ddba8f916115829187919033908790600401615676565b600060405180830381600087803b15801561159c57600080fd5b505af19250505080156115ad575060015b61160557608854604051600160401b9091046001600160401b0316907f678dcbc52328cedef940fe45ab75280e81c09ec03fe55df62e67642aa18bc278906115f890869086906158e3565b60405180910390a2611655565b608854604051600160401b9091046001600160401b0316907f6e1369aebaf86903bf1f0ab69c3edd0cadbf0534635f699f57a74a3ce54d37189061164c90869086906158e3565b60405180910390a25b6116606083866139e9565b61166a6083613c1b565b60006116766083613e36565b6001600160401b031611156116bb57604080518082019091526089548152608a5460208201526116a9906112bd90613627565b94506116b6608886613e7e565b610ae2565b6116c56088613fc1565b60016116d16078613863565b60048111156116e2576116e2615227565b03610ae257610ae26078614076565b60005a6088549091506001600160401b03600160401b820481169160009161172491608391600160801b909104166135e0565b90508484604051602001611739929190615779565b604051602081830303815290604052805190602001208160020154146117715760405162461bcd60e51b815260040161098d906157c4565b600061178060888989856140e1565b90506001600160601b0381161561198e57607154604051637bfcd47d60e11b81526000916001600160a01b03169063f7f9a8fa906117c4908a908a90600401615779565b600060405180830381865afa1580156117e1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526118099190810190615816565b9050600081516001600160401b0381111561182657611826614e7a565b60405190808252806020026020018201604052801561184f578160200160208202803683370190505b50905060005b82518110156118af576118738382815181106114e7576114e7615627565b82828151811061188557611885615627565b6001600160a01b0390921660209283029190910190910152806118a7816158ca565b915050611855565b5060735460405163f07f91c560e01b81526001600160a01b039091169063f07f91c5906118e290869085906004016158e3565b600060405180830381600087803b1580156118fc57600080fd5b505af192505050801561190d575060015b61195057847fd3f7d9c595537a55b26b224409f386868056764bc4d55bf8c3d86e20d047afc184846040516119439291906158e3565b60405180910390a261198b565b847f94af8e9c35b4ede2a77f659b202b1efe096bf99f0e6f5dd5905c800978a9a64784846040516119829291906158e3565b60405180910390a25b50505b600161199a6078613863565b60048111156119ab576119ab615227565b036119d4576119d488886040516119c3929190615905565b604051908190039020607890614106565b6119fc88886040516119e7929190615905565b604051908190039020606454608c9190614178565b603254606e546001600160a01b0390911690637ad226dc905a611a1f9088615915565b611a299190615928565b6040516001600160e01b031960e084901b1681526004810191909152336024820152604401600060405180830381600087803b158015611a6857600080fd5b505af1158015611a7c573d6000803e3d6000fd5b505050505050505050505050565b60005a608854909150600090611ab290608390600160801b90046001600160401b03166135e0565b9050611ac16088858584614225565b6001611acd6078613863565b6004811115611ade57611ade615227565b03611af657611af684846040516119c3929190615905565b611b0984846040516119e7929190615905565b603254606e546001600160a01b0390911690637ad226dc905a611b2c9086615915565b611b369190615928565b6040516001600160e01b031960e084901b1681526004810191909152336024820152604401600060405180830381600087803b158015611b7557600080fd5b505af1158015611b89573d6000803e3d6000fd5b5050505050505050565b60005a60405163716ae95760e01b815290915060009073__$852b9611da141be0769f808cc0e4dd5c7d$__9063716ae95790611bd69060789087906004016154c5565b600060405180830381865af4158015611bf3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611c1b919081019061593b565b805190915015611c99576071546067546001600160a01b039091169063942f6892908390611c499042615928565b6040518363ffffffff1660e01b8152600401611c669291906159c9565b600060405180830381600087803b158015611c8057600080fd5b505af1158015611c94573d6000803e3d6000fd5b505050505b611cb7611ca960208501856159eb565b6083919060c0870135614288565b611cc16078614351565b603254606c546001600160a01b0390911690637ad226dc905a611ce49086615915565b606b54611cf19190615928565b611cfb9190615928565b6040516001600160e01b031960e084901b1681526004810191909152336024820152604401600060405180830381600087803b158015611d3a57600080fd5b505af1158015610ae2573d6000803e3d6000fd5b6000546001600160a01b03163314611d785760405162461bcd60e51b815260040161098d90615317565b607154604051632a59250560e21b81526001600160a01b0383811660048301529091169063a964941490602401600060405180830381600087803b158015611dbf57600080fd5b505af1158015610c4e573d6000803e3d6000fd5b6000611ddf60786143b5565b905090565b6073546001600160a01b03163314611e0e5760405162461bcd60e51b815260040161098d9061534e565b604051636dc1282760e11b8152607460048201526001600160a01b03841660248201526001600160601b0380841660448301528216606482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063db82504e90608401610ab6565b6073546040516304a3b6b360e31b8152607460048201526001600160a01b039182166024820152908216604482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063251db59890606401610c22565b6000546001600160a01b03163314611ee95760405162461bcd60e51b815260040161098d90615317565b60658690556087859055611f0160788585858561327d565b6040805187815260208101879052908101859052606081018490526080810183905260a081018290527f88243406f452bee756e4fff4cb19e6855a5d3b7bfab8814ea6838685e08da0939060c00160405180910390a1505050505050565b6000546001600160a01b03163314611f895760405162461bcd60e51b815260040161098d90615317565b6040516001600160a01b03821681527f0e2d2343d31b085b7c4e56d1c8a6ec79f7ab07460386f1c9a1756239fe2533ac9060200160405180910390a1603280546001600160a01b0319166001600160a01b0392909216919091179055565b612000611ff760208301836159eb565b60839190614412565b6040516305149aaf60e51b815273__$852b9611da141be0769f808cc0e4dd5c7d$__9063a29355e090610c229060789085906004016154c5565b607354604051635c359a0f60e11b8152607460048201526001600160a01b039182166024820152908216604482015260009073__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063b86b341e906064015b602060405180830381865af41580156120a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120cd9190615732565b92915050565b6000546001600160a01b031633146120fd5760405162461bcd60e51b815260040161098d90615317565b6001600160a01b038216600081815260706020908152604091829020805460ff191685151590811790915591519182527fb4d9db68405970190721d2b3726fc9f728c1413038755e60518dea67d5545556910160405180910390a25050565b6000546001600160a01b031633146121865760405162461bcd60e51b815260040161098d90615317565b606481905561219760888484613475565b60408051848152602081018490529081018290527fea9006ae23cd9b51dbfbc9d747fc3b0bc77acba4fefba609c76f8e9a9513602e90606001610a0e565b604051624f4ac760e01b8152607460048201526001600160a01b038216602482015260009073__$1150d55cc8540ae1e6a8a840b6e83a829d$__90624f4ac790604401602060405180830381865af4158015612235573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120cd9190615a31565b6000546001600160a01b031633146122835760405162461bcd60e51b815260040161098d90615317565b604051633d36f3fd60e21b8152607460048201526001600160601b03841660248201526001600160401b0380841660448301528216606482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063f4dbcff49060840160006040518083038186803b1580156122f457600080fd5b505af4158015612308573d6000803e3d6000fd5b5050604080516001600160601b03871681526001600160401b0380871660208301528516918101919091527f544b726e42801bb47073854eeedae851903f66fe32a5bd24e626e10b90027b5192506060019050610a0e565b61236a6083613e36565b6001600160401b0316156123b75760405162461bcd60e51b81526020600482015260146024820152734e6f74206177616974696e672067656e6573697360601b604482015260640161098d565b6123c16078613916565b6124207f4574c8c75d6e88acd28f7e467dac97b5c60c3838d9dad993900bdf402152228e43604051602001612400929190918252602082015260400190565b60408051601f198184030181529190528051602090910120607890614106565b565b6000546001600160a01b0316331461244c5760405162461bcd60e51b815260040161098d90615317565b606b849055606c839055606d829055606e8190556040805185815260208101859052908101839052606081018290527feffd28b20afc0bf9349e8d49d5346c7568689b661a6bcd71c26a939b57b0acd190608001611048565b60006124b26083856135e0565b6040518060800160405290816000820180546124cd906156b6565b80601f01602080910402602001604051908101604052809291908181526020018280546124f9906156b6565b80156125465780601f1061251b57610100808354040283529160200191612546565b820191906000526020600020905b81548152906001019060200180831161252957829003601f168201915b5050505050815260200160018201548152602001600282015481526020016003820160009054906101000a900460ff16151515158152505090508282604051602001612593929190615779565b604051602081830303815290604052805190602001208160400151146125cb5760405162461bcd60e51b815260040161098d906157c4565b80606001511561261d5760405162461bcd60e51b815260206004820152601a60248201527f47726f75702063616e6e6f74206265207465726d696e61746564000000000000604482015260640161098d565b8051604080513360601b6bffffffffffffffffffffffff191660208201528151601481830301815260348201928390526339c6c5f160e21b90925273__$b5930e1c3596d61eae714f9835468f05d3$__9263e71b17c492612682928a90603801615a4e565b602060405180830381865af415801561269f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126c39190615a87565b6127035760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b604482015260640161098d565b61270e6083856139e9565b607154604051637bfcd47d60e11b81526000916001600160a01b03169063f7f9a8fa906127419087908790600401615779565b600060405180830381865afa15801561275e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526127869190810190615816565b9050600081516001600160401b038111156127a3576127a3614e7a565b6040519080825280602002602001820160405280156127cc578160200160208202803683370190505b50905060005b825181101561282c576127f08382815181106114e7576114e7615627565b82828151811061280257612802615627565b6001600160a01b039092166020928302919091019091015280612824816158ca565b9150506127d2565b506073546066546069546040516383ddba8f60e01b81526001600160a01b03909316926383ddba8f9261287792600160601b9091046001600160601b03169133908790600401615676565b600060405180830381600087803b15801561289157600080fd5b505af19250505080156128a2575060015b612902576066546040516001600160401b038816917ffd4a5a45de3194b94e2a7954706ac9023b7c9935cf1a25242691da2a94d720d4916128f591600160601b90046001600160601b03169086906158e3565b60405180910390a2610ae2565b6066546040516001600160401b038816917fa311dcb2a3eb32651a722488f4f281b3f8e4ab05abcd8a37a5c7d663bba5a8859161295191600160601b90046001600160601b03169086906158e3565b60405180910390a250505050505050565b6073546001600160a01b0316331461298c5760405162461bcd60e51b815260040161098d9061534e565b604051633558d21760e21b8152607460048201526001600160a01b03841660248201526001600160601b0380841660448301528216606482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063d563485c90608401610ab6565b6000611ddf6078613863565b60005a90506000612a0a6020870187614d9d565b6001600160401b0381166000908152606f60205260409020549091508514612a645760405162461bcd60e51b815260206004820152600d60248201526c496e76616c6964206e6f6e636560981b604482015260640161098d565b612a6f6083826144fb565b612ab15760405162461bcd60e51b815260206004820152601360248201527247726f7570206973206e6f742061637469766560681b604482015260640161098d565b6000612abe6083836135e0565b90508484604051602001612ad3929190615779565b60405160208183030381529060405280519060200120816002015414612b0b5760405162461bcd60e51b815260040161098d906157c4565b60715460405163fc21976b60e01b815260009173__$1ba5315bb273adc70a9cc339490e63eb09$__9163fc21976b91612b5c916001600160a01b03909116908c9087908d908d908d90600401615b21565b600060405180830381865af4158015612b79573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612ba1919081019061593b565b6001600160401b0384166000908152606f60205260408120805492935090612bc8836158ca565b9091555050604080518881523360208201526001600160401b038516917f3ca10b33fda0a4adbc75ac1939659a06e8c332b8f6a2792bedbf8741e4268417910160405180910390a26071546067546001600160a01b039091169063942f6892908390612c349042615928565b6040518363ffffffff1660e01b8152600401612c519291906159c9565b600060405180830381600087803b158015612c6b57600080fd5b505af1158015612c7f573d6000803e3d6000fd5b5050603254606d546001600160a01b039091169250637ad226dc91505a611a1f9088615915565b6000546001600160a01b03163314612cd05760405162461bcd60e51b815260040161098d90615317565b6001600160a01b038116612d315760405162461bcd60e51b815260206004820152602260248201527f4e657720676f7665726e616e636520697320746865207a65726f206164647265604482015261737360f01b606482015260840161098d565b612d3a8161453b565b50565b3360005a9050612d4d607861459c565b6032546001600160a01b0316637ad226dc5a612d699084615915565b6040516001600160e01b031960e084901b16815260048101919091526001600160a01b0385166024820152604401600060405180830381600087803b158015612db157600080fd5b505af1158015610ecb573d6000803e3d6000fd5b607154607f5460408051636c2530b960e01b81526060936001600160a01b031692636c2530b992612e0492909190600401918252602082015260400190565b600060405180830381865afa158015612e21573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611ddf919081019061593b565b60735460715460405163148140a160e21b8152607460048201526001600160a01b0392831660248201529082166044820152908216606482015260009073__$1150d55cc8540ae1e6a8a840b6e83a829d$__90635205028490608401602060405180830381865af4158015612ec2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120cd9190615a87565b6071546040516307b8c36760e51b81526001600160a01b038381166004830152600092169063f7186ce090602401602060405180830381865afa158015612ec2573d6000803e3d6000fd5b600080612f56836001600160a01b039081166000908152607560205260409020541690565b90506001600160a01b038116612fa15760405162461bcd60e51b815260206004820152601060248201526f2ab735b737bbb71037b832b930ba37b960811b604482015260640161098d565b60715460405163439f18fd60e11b81526001600160a01b0383811660048301529091169063873e31fa90602401602060405180830381865afa158015612feb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061300f9190615732565b9392505050565b604051635fc3290960e11b8152607460048201526001600160a01b038216602482015260009073__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063bf8652129060440161208c565b82546001600160a01b0316156130c35760405162461bcd60e51b815260206004820152602260248201527f536f72746974696f6e20506f6f6c206164647265737320616c72656164792073604482015261195d60f21b606482015260840161098d565b60018301546001600160a01b0316156131285760405162461bcd60e51b815260206004820152602160248201527f444b472056616c696461746f72206164647265737320616c72656164792073656044820152601d60fa1b606482015260840161098d565b82546001600160a01b03199081166001600160a01b03938416178455600190930180549093169116179055565b600181015415801561316957506002810154155b6131b55760405162461bcd60e51b815260206004820152601e60248201527f5365656420656e74727920616c726561647920696e697469616c697a65640000604482015260640161098d565b6131d6604051806060016040528060408152602001615ea060409139613508565b8051600183015560200151600290910155565b8154600160401b90046001600160401b0316156132445760405162461bcd60e51b815260206004820152601960248201527852656c6179207265717565737420696e2070726f677265737360381b604482015260640161098d565b600390910180546001600160601b03909216600160401b0273ffffffffffffffffffffffff000000000000000019909216919091179055565b600061328886613863565b600481111561329957613299615227565b146132e25760405162461bcd60e51b815260206004820152601960248201527843757272656e74207374617465206973206e6f742049444c4560381b604482015260640161098d565b600084116133585760405162461bcd60e51b815260206004820152603a60248201527f526573756c74206368616c6c656e676520706572696f64206c656e677468207360448201527f686f756c642062652067726561746572207468616e207a65726f000000000000606482015260840161098d565b600082116133c65760405162461bcd60e51b815260206004820152603560248201527f526573756c74207375626d697373696f6e2074696d656f75742073686f756c646044820152742062652067726561746572207468616e207a65726f60581b606482015260840161098d565b8181106134585760405162461bcd60e51b815260206004820152605460248201527f5375626d697474657220707265636564656e636520706572696f64206c656e6760448201527f74682073686f756c64206265206c657373207468616e2074686520726573756c6064820152731d081cdd589b5a5cdcda5bdb881d1a5b595bdd5d60621b608482015260a40161098d565b600285019390935560038401919091556004830155600590910155565b8254600160401b90046001600160401b0316156134d05760405162461bcd60e51b815260206004820152601960248201527852656c6179207265717565737420696e2070726f677265737360381b604482015260640161098d565b6003909201805463ffffffff9384166401000000000267ffffffffffffffff199091169390921692909217179055565b600490910155565b6040805180820190915260008082526020820152815160401461356d5760405162461bcd60e51b815260206004820152601760248201527f496e76616c6964204731206279746573206c656e677468000000000000000000604482015260640161098d565b5060208181015160409283015183518085019094529083529082015290565b60038101545a1015612d3a5760405162461bcd60e51b815260206004820152601960248201527f4e6f7420656e6f75676820657874726120676173206c65667400000000000000604482015260640161098d565b600082600001600084600101846001600160401b03168154811061360657613606615627565b90600052602060002001548152602001908152602001600020905092915050565b6040805181815260608181018352916000919060208201818036833750508451602095860151958301525060408101939093525090919050565b600061366c83613c1b565b600061367784613e36565b6001600160401b0316116136c05760405162461bcd60e51b815260206004820152601060248201526f4e6f206163746976652067726f75707360801b604482015260640161098d565b60006136cb84613e36565b6136de906001600160401b031684615765565b905060006136f5856136f0878561461b565b614637565b95945050505050565b8154600160401b90046001600160401b0316156137675760405162461bcd60e51b815260206004820152602160248201527f416e6f746865722072656c6179207265717565737420696e2070726f677265736044820152607360f81b606482015260840161098d565b815460009083908290613782906001600160401b0316615c02565b82546101009290920a6001600160401b038181021990931682841691820217909355855477ffffffffffffffffffffffffffffffff00000000000000001916600160401b840267ffffffffffffffff60801b191617600160801b86841602176001600160c01b0316600160c01b43909316929092029190911785556040805180820190915260018601548152600286015460208201529092507fdf86f752d80d21879cbd208ba1d036c03f836b1d7f8f887b0b9e0b63f8a49f5d90849061384890613627565b604051613856929190615c28565b60405180910390a2505050565b805460408051632938b58d60e21b815290516000926001600160a01b03169163a4e2d6349160048083019260209291908290030181865afa1580156138ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138d09190615a87565b1561391157506006810154600190156139115760029050604882600601546138f89190615928565b4311156139115750600a81015460039015613911575060045b919050565b600061392182613863565b600481111561393257613932615227565b1461397b5760405162461bcd60e51b815260206004820152601960248201527843757272656e74207374617465206973206e6f742049444c4560381b604482015260640161098d565b6040517f5c3ed2397d4d21298b2fb5027ac8e2d42e3c9c72bbb55ddb030e2a36a0cdff6b90600090a1805460408051637c1e845d60e11b815290516001600160a01b039092169163f83d08ba9160048082019260009290919082900301818387803b158015611dbf57600080fd5b6139f382826146cd565b15613a4a5760405162461bcd60e51b815260206004820152602160248201527f47726f757020686173206265656e20616c7265616479207465726d696e6174656044820152601960fa1b606482015260840161098d565b600182600001600084600101846001600160401b031681548110613a7057613a70615627565b60009182526020808320919091015483528201929092526040018120600301805460ff1916921515929092179091556002830180546001908101808355918352613ab991615915565b90505b600081118015613b1957506001600160401b03821660028401613ae0600184615915565b81548110613af057613af0615627565b6000918252602090912060048204015460039091166008026101000a90046001600160401b0316115b15613bc75760028301613b2d600183615915565b81548110613b3d57613b3d615627565b90600052602060002090600491828204019190066008029054906101000a90046001600160401b0316836002018281548110613b7b57613b7b615627565b90600052602060002090600491828204019190066008026101000a8154816001600160401b0302191690836001600160401b031602179055508080613bbf90615c4a565b915050613abc565b81836002018281548110613bdd57613bdd615627565b90600052602060002090600491828204019190066008026101000a8154816001600160401b0302191690836001600160401b03160217905550505050565b600181015460038201546001600160401b0316108015613c75575060038101546001820180544392613c7392859290916001600160401b0316908110613c6357613c63615627565b906000526020600020015461471d565b105b15613cbf576003810180546001600160401b0316906000613c9583615c02565b91906101000a8154816001600160401b0302191690836001600160401b0316021790555050613c1b565b60005b600282015481101561134457816002018181548110613ce357613ce3615627565b6000918252602090912060048204015460038481015492166008026101000a90046001600160401b0390811691161115613e2457805b6002830154613d2a90600190615915565b811015613dda5760028301613d40826001615928565b81548110613d5057613d50615627565b90600052602060002090600491828204019190066008029054906101000a90046001600160401b0316836002018281548110613d8e57613d8e615627565b90600052602060002090600491828204019190066008026101000a8154816001600160401b0302191690836001600160401b031602179055508080613dd2906158ca565b915050613d19565b5081600201805480613dee57613dee615c61565b60008281526020902060046000199092019182040180546001600160401b03600860038516026101000a02191690559055613cc2565b80613e2e816158ca565b915050613cc2565b60018101546000908103613e4c57506000919050565b60028201546003830154600184015460009291613e74916001600160401b0390911690615915565b61300f9190615915565b613e878261473f565b613ed35760405162461bcd60e51b815260206004820152601e60248201527f52656c6179207265717565737420646964206e6f742074696d65206f75740000604482015260640161098d565b81546040516001600160401b03600160801b83048116808352600160401b90930416919082907fc28be0fa97c9083fa79881ba8950c1333fb45ec5100d2b893ec0f41544e78bef9060200160405180910390a283546fffffffffffffffffffffffffffffffff16600160801b6001600160401b03858116919091026001600160c01b031691909117600160c01b43831602178555604080518082019091526001860154815260028601546020820152908316907fdf86f752d80d21879cbd208ba1d036c03f836b1d7f8f887b0b9e0b63f8a49f5d908590613fb390613627565b604051611229929190615c28565b613fca8161473f565b6140165760405162461bcd60e51b815260206004820152601e60248201527f52656c6179207265717565737420646964206e6f742074696d65206f75740000604482015260640161098d565b80546040516001600160401b03600160801b830481168252600160401b909204909116907fc28be0fa97c9083fa79881ba8950c1333fb45ec5100d2b893ec0f41544e78bef9060200160405180910390a280546001600160401b03169055565b600161408182613863565b600481111561409257614092615227565b146140af5760405162461bcd60e51b815260040161098d90615c77565b6040517f68c52f05452e81639fa06f379aee3178cddee4725521fff886f244c99e868b5090600090a1612d3a81614351565b6000806140ed866147b3565b90506140fb86868686614848565b90505b949350505050565b600161411183613863565b600481111561412257614122615227565b1461413f5760405162461bcd60e51b815260040161098d90615c77565b60405181907fb2ad26c2940889d79df2ee9c758a8aefa00c5ca90eee119af0e5d795df3b98bb90600090a2436006830155600790910155565b82546001600160a01b031615614220578254604051631bfaf51960e21b8152600481018490524360248201526001600160a01b0390911690636febd464908390604401600060405180830381600088803b1580156141d557600080fd5b5087f1935050505080156141e7575060015b61422057604080518381524360208201527f5e2af61e77ec91022b1cafe282abce475bb18e8cdd47083464caa06583fe39099101610a0e565b505050565b61422e84614b38565b431061427c5760405162461bcd60e51b815260206004820152601f60248201527f52656c617920656e74727920736f66742074696d656f75742070617373656400604482015260640161098d565b610b6784848484614848565b6000838360405161429a929190615905565b60408051918290039091206000818152602088905291909120909150806142c2858783615cff565b50600281018390554360018083019190915586810180549182018155600090815260209020018290556040516142fb9086908690615905565b6040519081900390206001878101546143149190615915565b6001600160401b03167f4c0666db2c51896711b100d1f4f5d20a347c59e6e16ad8f365ed81ff97358b4e60405160405180910390a3505050505050565b600060068201819055600782018190556008820181905560098201819055600a820181905581546040805163a69df4b560e01b815290516001600160a01b039092169263a69df4b59260048084019382900301818387803b158015611dbf57600080fd5b600060036143c283613863565b60048111156143d3576143d3615227565b1480156120cd57506004820154600883015460068401546143f690604890615928565b6144009190615928565b61440a9190615928565b431192915050565b608081146144625760405162461bcd60e51b815260206004820181905260248201527f496e76616c6964206c656e677468206f6620746865207075626c6963206b6579604482015260640161098d565b60008282604051614474929190615905565b604080519182900390912060008181526020879052919091206001015490915015610b675760405162461bcd60e51b815260206004820152603160248201527f47726f757020776974682074686973207075626c6963206b65792077617320616044820152701b1c9958591e481c9959da5cdd195c9959607a1b606482015260840161098d565b6000436145208485600101856001600160401b031681548110613c6357613c63615627565b1015801561300f575061453383836146cd565b159392505050565b600080546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce80910160405180910390a15050565b6145a5816143b5565b6145e95760405162461bcd60e51b81526020600482015260156024820152741112d1c81a185cc81b9bdd081d1a5b5959081bdd5d605a1b604482015260640161098d565b6040517f2852b3e178dd281713b041c3d90b4815bb55b7ec812931d1e8e8d8bb2ed72d3e90600090a1612d3a81614351565b600382015460009061300f9083906001600160401b0316615dbe565b600081815b60028501546001600160401b03821610156146c557816001600160401b031685600201826001600160401b03168154811061467957614679615627565b6000918252602090912060048204015460039091166008026101000a90046001600160401b0316116146b357816146af81615c02565b9250505b806146bd81615c02565b91505061463c565b509392505050565b600082600001600084600101846001600160401b0316815481106146f3576146f3615627565b6000918252602080832090910154835282019290925260400190206003015460ff16905092915050565b6004820154600082815260208490526040812060010154909161300f91615928565b600381015460009081906147639063ffffffff640100000000820481169116615de5565b63ffffffff16905061478683546001600160401b03600160401b90910416151590565b801561300f575082546147aa908290600160c01b90046001600160401b0316615928565b43119392505050565b6000806147bf83614b38565b90508043111561483f5760006147d58243615915565b6003850154909150640100000000900463ffffffff1681111561480757506003830154640100000000900463ffffffff165b6003840154640100000000810463ffffffff169061483590600160401b90046001600160601b031683615e02565b6140fe9190615e19565b50600092915050565b8354600160401b90046001600160401b03166148a65760405162461bcd60e51b815260206004820152601c60248201527f4e6f2072656c6179207265717565737420696e2070726f677265737300000000604482015260640161098d565b6148af8461473f565b156148fc5760405162461bcd60e51b815260206004820152601760248201527f52656c617920726571756573742074696d6564206f7574000000000000000000604482015260640161098d565b73__$b5930e1c3596d61eae714f9835468f05d3$__63b6087a0f6149a8838054614925906156b6565b80601f0160208091040260200160405190810160405280929190818152602001828054614951906156b6565b801561499e5780601f106149735761010080835404028352916020019161499e565b820191906000526020600020905b81548152906001019060200180831161498157829003601f168201915b5050505050614b73565b866001016149eb87878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061350892505050565b6040518463ffffffff1660e01b8152600401614a0993929190615e2d565b602060405180830381865af4158015614a26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a4a9190615a87565b614a865760405162461bcd60e51b815260206004820152600d60248201526c496e76616c696420656e74727960981b604482015260640161098d565b8354604051600160401b9091046001600160401b0316907f087df9fd862e4448d02f8b58e33a18941769c795a8b83cfb95dfaf9c92ca897e90614ace90339087908790615e7a565b60405180910390a2614b1583838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061350892505050565b80516001860155602001516002850155505081546001600160401b031690915550565b60038101548154600091614b649163ffffffff90911690600160c01b90046001600160401b0316615dbe565b6001600160401b031692915050565b614b7b614c14565b8151608014614bcc5760405162461bcd60e51b815260206004820152601760248201527f496e76616c6964204732206279746573206c656e677468000000000000000000604482015260640161098d565b50602081810151604080840151606080860151608096870151845197880185528785019586529187019290925292855281518083019092528152808301919091529082015290565b60408051608081018252600091810182815260608201929092529081908152602001614c53604051806040016040528060008152602001600081525090565b905290565b6001600160601b0381168114612d3a57600080fd5b600080600060608486031215614c8257600080fd5b8335614c8d81614c58565b92506020840135614c9d81614c58565b91506040840135614cad81614c58565b809150509250925092565b6001600160a01b0381168114612d3a57600080fd5b600080600060608486031215614ce257600080fd5b8335614c8d81614cb8565b6020808252825182820181905260009190848201906040850190845b81811015614d2557835183529284019291840191600101614d09565b50909695505050505050565b600060208284031215614d4357600080fd5b813561300f81614cb8565b600060208284031215614d6057600080fd5b81356001600160401b03811115614d7657600080fd5b820160e0818503121561300f57600080fd5b6001600160401b0381168114612d3a57600080fd5b600060208284031215614daf57600080fd5b813561300f81614d88565b6000815180845260005b81811015614de057602081850181015186830182015201614dc4565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000825160806020840152614e1c60a0840182614dba565b905060208401516040840152604084015160608401526060840151151560808401528091505092915050565b60008060008060808587031215614e5e57600080fd5b5050823594602084013594506040840135936060013592509050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715614eb857614eb8614e7a565b604052919050565b600082601f830112614ed157600080fd5b81356001600160401b03811115614eea57614eea614e7a565b614efd601f8201601f1916602001614e90565b818152846020838601011115614f1257600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215614f4157600080fd5b81356001600160401b03811115614f5757600080fd5b6140fe84828501614ec0565b60008083601f840112614f7557600080fd5b5081356001600160401b03811115614f8c57600080fd5b6020830191508360208260051b8501011115614fa757600080fd5b9250929050565b60008060208385031215614fc157600080fd5b82356001600160401b03811115614fd757600080fd5b614fe385828601614f63565b90969095509350505050565b60008083601f84011261500157600080fd5b5081356001600160401b0381111561501857600080fd5b602083019150836020828501011115614fa757600080fd5b6000806000806040858703121561504657600080fd5b84356001600160401b038082111561505d57600080fd5b61506988838901614fef565b9096509450602087013591508082111561508257600080fd5b5061508f87828801614f63565b95989497509550505050565b600080602083850312156150ae57600080fd5b82356001600160401b038111156150c457600080fd5b614fe385828601614fef565b60008060008060008060c087890312156150e957600080fd5b505084359660208601359650604086013595606081013595506080810135945060a0013592509050565b8015158114612d3a57600080fd5b6000806040838503121561513457600080fd5b823561513f81614cb8565b9150602083013561514f81615113565b809150509250929050565b60008060006060848603121561516f57600080fd5b505081359360208301359350604090920135919050565b60008060006060848603121561519b57600080fd5b83356151a681614c58565b925060208401356151b681614d88565b91506040840135614cad81614d88565b600080600080606085870312156151dc57600080fd5b84356001600160401b03808211156151f357600080fd5b6151ff88838901614ec0565b95506020870135915061521182614d88565b9093506040860135908082111561508257600080fd5b634e487b7160e01b600052602160045260246000fd5b602081016005831061525f57634e487b7160e01b600052602160045260246000fd5b91905290565b6000806000806060858703121561527b57600080fd5b84356001600160401b038082111561529257600080fd5b90860190608082890312156152a657600080fd5b909450602086013593506040860135908082111561508257600080fd5b600081518084526020808501945080840160005b838110156152f957815163ffffffff16875295820195908201906001016152d7565b509495945050505050565b60208152600061300f60208301846152c3565b6020808252601c908201527f43616c6c6572206973206e6f742074686520676f7665726e616e636500000000604082015260600190565b60208082526022908201527f43616c6c6572206973206e6f7420746865207374616b696e6720636f6e74726160408201526118dd60f21b606082015260800190565b6000808335601e198436030181126153a757600080fd5b83016020810192503590506001600160401b038111156153c657600080fd5b803603821315614fa757600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000808335601e1984360301811261541557600080fd5b83016020810192503590506001600160401b0381111561543457600080fd5b8060051b3603821315614fa757600080fd5b81835260006001600160fb1b0383111561545f57600080fd5b8260051b80836020870137939093016020019392505050565b63ffffffff81168114612d3a57600080fd5b8183526000602080850194508260005b858110156152f95781356154ad81615478565b63ffffffff168752958201959082019060010161549a565b82815260006020604081840152833560408401526154e581850185615390565b60e060608601526154fb610120860182846153d5565b91505061550b60408601866153fe565b603f19868403810160808801528184529192600092908501835b8381101561555157853560ff811680821461553e578687fd5b8352509486019490860190600101615525565b5061555f60608a018a615390565b96509450818882030160a08901526155788187876153d5565b95505061558860808901896153fe565b94509250808786030160c08801526155a1858585615446565b94506155b060a08901896153fe565b94509250808786030160e088015250506155cb83838361548a565b9250505060c0840135610100840152809150509392505050565b600080604083850312156155f857600080fd5b82519150602083015161514f81615478565b60006020828403121561561c57600080fd5b815161300f81614cb8565b634e487b7160e01b600052603260045260246000fd5b600081518084526020808501945080840160005b838110156152f95781516001600160a01b031687529582019590820190600101615651565b6001600160601b038516815283602082015260018060a01b03831660408201526080606082015260006156ac608083018461563d565b9695505050505050565b600181811c908216806156ca57607f821691505b6020821081036156ea57634e487b7160e01b600052602260045260246000fd5b50919050565b60008060006060848603121561570557600080fd5b835161571081614cb8565b602085015190935061572181614cb8565b6040850151909250614cad81614cb8565b60006020828403121561574457600080fd5b815161300f81614c58565b634e487b7160e01b600052601260045260246000fd5b6000826157745761577461574f565b500690565b60208082528181018390526000908460408401835b868110156157b95782356157a181615478565b63ffffffff168252918301919083019060010161578e565b509695505050505050565b602080825260159082015274496e76616c69642067726f7570206d656d6265727360581b604082015260600190565b60006001600160401b0382111561580c5761580c614e7a565b5060051b60200190565b6000602080838503121561582957600080fd5b82516001600160401b0381111561583f57600080fd5b8301601f8101851361585057600080fd5b805161586361585e826157f3565b614e90565b81815260059190911b8201830190838101908783111561588257600080fd5b928401925b828410156158a957835161589a81614cb8565b82529284019290840190615887565b979650505050505050565b634e487b7160e01b600052601160045260246000fd5b6000600182016158dc576158dc6158b4565b5060010190565b6001600160601b03831681526040602082015260006140fe604083018461563d565b8183823760009101908152919050565b818103818111156120cd576120cd6158b4565b808201808211156120cd576120cd6158b4565b6000602080838503121561594e57600080fd5b82516001600160401b0381111561596457600080fd5b8301601f8101851361597557600080fd5b805161598361585e826157f3565b81815260059190911b820183019083810190878311156159a257600080fd5b928401925b828410156158a95783516159ba81615478565b825292840192908401906159a7565b6040815260006159dc60408301856152c3565b90508260208301529392505050565b6000808335601e19843603018112615a0257600080fd5b8301803591506001600160401b03821115615a1c57600080fd5b602001915036819003821315614fa757600080fd5b600060208284031215615a4357600080fd5b815161300f81614d88565b606081526000615a616060830186614dba565b8281036020840152615a738186614dba565b905082810360408401526156ac8185614dba565b600060208284031215615a9957600080fd5b815161300f81615113565b60008154615ab1816156b6565b808552602060018381168015615ace5760018114615ae857615b16565b60ff1985168884015283151560051b880183019550615b16565b866000528260002060005b85811015615b0e5781548a8201860152908301908401615af3565b890184019650505b505050505092915050565b6001600160a01b038716815260a0602082015260008635615b4181614d88565b6001600160401b031660a0830152615b5c60208801886153fe565b608060c0850152615b7261012085018284615446565b915050615b826040890189615390565b609f19808685030160e0870152615b9a8483856153d5565b9350615ba960608c018c6153fe565b93509150808685030161010087015250615bc4838383615446565b925050508281036040840152615bda8188615aa4565b90508560608401528281036080840152615bf581858761548a565b9998505050505050505050565b60006001600160401b03808316818103615c1e57615c1e6158b4565b6001019392505050565b6001600160401b03831681526040602082015260006140fe6040830184614dba565b600081615c5957615c596158b4565b506000190190565b634e487b7160e01b600052603160045260246000fd5b60208082526022908201527f43757272656e74207374617465206973206e6f74204157414954494e475f5345604082015261115160f21b606082015260800190565b601f82111561422057600081815260208120601f850160051c81016020861015615ce05750805b601f850160051c820191505b81811015610ecb57828155600101615cec565b6001600160401b03831115615d1657615d16614e7a565b615d2a83615d2483546156b6565b83615cb9565b6000601f841160018114615d5e5760008515615d465750838201355b600019600387901b1c1916600186901b178355610c4e565b600083815260209020601f19861690835b82811015615d8f5786850135825560209485019460019092019101615d6f565b5086821015615dac5760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b6001600160401b03818116838216019080821115615dde57615dde6158b4565b5092915050565b63ffffffff818116838216019080821115615dde57615dde6158b4565b80820281158282048414176120cd576120cd6158b4565b600082615e2857615e2861574f565b500490565b835180518252602090810151818301528085015180516040840152810151606083015283546080830152600184015460a0830152825160c083015282015160e082015261010081016140fe565b6001600160a01b03841681526040602082018190526000906136f590830184866153d556fe15c30f4b6cf6dbbcbdcc10fe22f54c8170aea44e198139b776d512d8f027319a1b9e8bfaf1383978231ce98e42bafc8129f473fc993cf60ce327f7d223460663a26469706673582212201e83b5e6a0d35d36568b84271a3808630b95fe28a009d1e00ebcae4df36f5ca864736f6c634300081100335a65726f2d61646472657373207265666572656e63650000000000000000000015c30f4b6cf6dbbcbdcc10fe22f54c8170aea44e198139b776d512d8f027319a1b9e8bfaf1383978231ce98e42bafc8129f473fc993cf60ce327f7d223460663", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061038e5760003560e01c80637e0049fd116101de578063c35d64ea1161010f578063ded56d45116100ad578063f5ee563f1161007c578063f5ee563f146108fc578063f7186ce01461092a578063f854a27f1461093d578063fd2a47881461095057600080fd5b8063ded56d4514610897578063e03e4535146108c3578063e686440f146108d8578063f0820c92146108eb57600080fd5b8063cb8b3779116100e9578063cb8b377914610854578063ccfd3bbe14610869578063d38bfff41461087c578063d855c6311461088f57600080fd5b8063c35d64ea14610802578063c7c49c9814610815578063c9bacaad1461084157600080fd5b8063a04e29801161017c578063b142f85c11610156578063b142f85c1461078a578063b53dacdf146107c9578063b54a2374146107dc578063c09975cd146107ef57600080fd5b8063a04e29801461075c578063a7f0b3de1461076f578063b0d010d61461077757600080fd5b80638f105e37116101b85780638f105e37146106f1578063985e64871461070b5780639a7d09351461071e5780639c9de0281461073157600080fd5b80637e0049fd146106a25780637e33cba6146106b557806388a59590146106e057600080fd5b80634a07068e116102c3578063663032cd1161026157806375e0ae5a1161023057806375e0ae5a1461060c57806377a5a7bd1461061f5780637b14729e146106325780637b35b4e61461068f57600080fd5b8063663032cd146105ae57806368c34948146105c15780636a7f7a90146105c957806374024ab7146105dc57600080fd5b806355b64bcc1161029d57806355b64bcc1461056257806357665912146105755780635aa6e675146105885780635c5b38701461059b57600080fd5b80634a07068e146104f75780634cf088d91461050a578063529023011461053557600080fd5b8063319ac101116103305780633ea478aa1161030a5780633ea478aa1461048b57806342d86693146104be5780634368ec0c146104d15780634549cc4b146104e457600080fd5b8063319ac10114610445578063339646ac146104655780633682a4501461047857600080fd5b80631872ea941161036c5780631872ea94146103c35780631c5b0762146103e15780631d35fa63146103f4578063313767661461043257600080fd5b80630519e9911461039357806314a85474146103a8578063167f0517146103bb575b600080fd5b6103a66103a1366004614c6d565b610963565b005b6103a66103b6366004614ccd565b610a1b565b6103a6610aeb565b6103cb610b6d565b6040516103d89190614ced565b60405180910390f35b6103a66103ef366004614d31565b610bc8565b608b5460665460408051600160401b9093046001600160601b0390811684528083166020850152600160601b909204909116908201526060016103d8565b6103a6610440366004614d4e565b610c55565b610458610453366004614d9d565b610ed3565b6040516103d89190614e00565b6103a6610473366004614e48565b610fc9565b6103a6610486366004614d31565b611056565b6104ae610499366004614d31565b60706020526000908152604090205460ff1681565b60405190151581526020016103d8565b6103a66104cc366004614d31565b61109d565b6103a66104df366004614d31565b611237565b6104586104f2366004614f2f565b611348565b6103a6610505366004614fae565b611383565b60735461051d906001600160a01b031681565b6040516001600160a01b0390911681526020016103d8565b606754606854606954606a545b6040805194855260208501939093529183015260608201526080016103d8565b6103a6610570366004615030565b6116f1565b6103a661058336600461509b565b611a8a565b60005461051d906001600160a01b031681565b6103a66105a9366004614d4e565b611b93565b6103a66105bc366004614d31565b611d4e565b6104ae611dd3565b6103a66105d7366004614ccd565b611de4565b608b546064546040805163ffffffff808516825264010000000090940490931660208401528201526060016103d8565b6103a661061a366004614d31565b611e6c565b6103a661062d3660046150d0565b611ebf565b6106606074546001600160601b038116916001600160401b03600160601b8304811692600160a01b90041690565b604080516001600160601b0390941684526001600160401b0392831660208501529116908201526060016103d8565b6103a661069d366004614d31565b611f5f565b6103a66106b0366004614d4e565b611fe7565b6106c86106c3366004614d31565b61203a565b6040516001600160601b0390911681526020016103d8565b606b54606c54606d54606e54610542565b608854600160401b90046001600160401b031615156104ae565b6103a6610719366004615121565b6120d3565b6103a661072c36600461515a565b61215c565b61074461073f366004614d31565b6121d5565b6040516001600160401b0390911681526020016103d8565b6103a661076a366004615186565b612259565b6103a6612360565b6103a6610785366004614e48565b612422565b606554608754607a54607b54607c54607d54604080519687526020870195909552938501929092526060840152608083015260a082015260c0016103d8565b6103a66107d73660046151c6565b6124a5565b60715461051d906001600160a01b031681565b60325461051d906001600160a01b031681565b60725461051d906001600160a01b031681565b61051d610823366004614d31565b6001600160a01b039081166000908152607560205260409020541690565b6103a661084f366004614ccd565b612962565b61085c6129ea565b6040516103d8919061523d565b6103a6610877366004615265565b6129f6565b6103a661088a366004614d31565b612ca6565b6103a6612d3d565b61051d6108a5366004614d31565b6001600160a01b039081166000908152607660205260409020541690565b6108cb612dc5565b6040516103d89190615304565b6104ae6108e6366004614d31565b612e49565b6074546001600160601b03166106c8565b61091c61090a366004614d9d565b606f6020526000908152604090205481565b6040519081526020016103d8565b6104ae610938366004614d31565b612ee6565b6106c861094b366004614d31565b612f31565b6106c861095e366004614d31565b613016565b6000546001600160a01b031633146109965760405162461bcd60e51b815260040161098d90615317565b60405180910390fd5b6109a16088846131e9565b606680546001600160601b038481166001600160c01b03199092168217600160601b858316908102919091179093556040805191871682526020820192909252908101919091527f1eda09aaee2b21bbf5571b06eab42dd1b2c2b629a5d6336230ff8b0e1f538276906060015b60405180910390a1505050565b6073546001600160a01b03163314610a455760405162461bcd60e51b815260040161098d9061534e565b60735460715460405163117964a560e21b8152607460048201526001600160a01b039283166024820152908216604482015290841660648201526001600160601b038084166084830152821660a482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__906345e592949060c4015b60006040518083038186803b158015610ace57600080fd5b505af4158015610ae2573d6000803e3d6000fd5b50505050505050565b60735460715460405163520c3d3160e01b8152607460048201526001600160a01b0392831660248201529116604482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063520c3d319060640160006040518083038186803b158015610b5357600080fd5b505af4158015610b67573d6000803e3d6000fd5b50505050565b60606083600101805480602002602001604051908101604052809291908181526020018280548015610bbe57602002820191906000526020600020905b815481526020019060010190808311610baa575b5050505050905090565b60735460715460405163c6e1c83960e01b8152607460048201526001600160a01b0392831660248201529082166044820152908216606482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063c6e1c839906084015b60006040518083038186803b158015610c3a57600080fd5b505af4158015610c4e573d6000803e3d6000fd5b5050505050565b6040516346bf00db60e01b8152600090819073__$852b9611da141be0769f808cc0e4dd5c7d$__906346bf00db90610c949060789087906004016154c5565b6040805180830381865af4158015610cb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd491906155e5565b606654607154604051638871ca5d60e01b815263ffffffff841660048201529395509193506001600160601b0316916000916001600160a01b031690638871ca5d90602401602060405180830381865afa158015610d36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5a919061560a565b60408051600180825281830190925291925060009190602080830190803683375050506001600160a01b038381166000908152607660205260409020549192501681600081518110610dae57610dae615627565b6001600160a01b039283166020918202929092010152607354606a546040516383ddba8f60e01b815291909216916383ddba8f91610df491879133908790600401615676565b600060405180830381600087803b158015610e0e57600080fd5b505af1925050508015610e1f575060015b610e7457604080516001600160601b03851681526001600160a01b038416602082015286917f14621289a12ab59e0737decc388bba91d929c723defb4682d5d19b9a12ecfecb910160405180910390a2610ec1565b604080516001600160601b03851681526001600160a01b038416602082015286917f88f76c659db78142f88e94db3ca791869495394c6c1b3d412ced9022dc97c9e3910160405180910390a25b610ecb607861358c565b505050505050565b604080516080810182526060808252600060208301819052928201839052810191909152610f026083836135e0565b604051806080016040529081600082018054610f1d906156b6565b80601f0160208091040260200160405190810160405280929190818152602001828054610f49906156b6565b8015610f965780601f10610f6b57610100808354040283529160200191610f96565b820191906000526020600020905b815481529060010190602001808311610f7957829003601f168201915b5050509183525050600182015460208201526002820154604082015260039091015460ff16151560609091015292915050565b6000546001600160a01b03163314610ff35760405162461bcd60e51b815260040161098d90615317565b606784905560688390556069829055606a8190556040805185815260208101859052908101839052606081018290527fbe6727aab9b80431985c18deef80d48599397c63884c62e96959f82abd16f16d906080015b60405180910390a150505050565b604051634755926360e01b8152607460048201526001600160a01b038216602482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__90634755926390604401610c22565b6001600160a01b0381811660009081526075602052604090205416806110f85760405162461bcd60e51b815260206004820152601060248201526f2ab735b737bbb71037b832b930ba37b960811b604482015260640161098d565b607354604051632de9480760e01b81526001600160a01b0384811660048301526000921690632de9480790602401606060405180830381865afa158015611143573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116791906156f0565b50607154604051637104c0e560e11b81526001600160a01b03868116600483015280841660248301529294506000935091169063e20981ca906044016020604051808303816000875af11580156111c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e69190615732565b6040516001600160601b03821681529091506001600160a01b038516907f38532b6dea69d7266fa923c7813d190be37625f2454ddfa3d93c45c79482e3fd906020015b60405180910390a250505050565b3360009081526070602052604090205460ff166112965760405162461bcd60e51b815260206004820152601c60248201527f526571756573746572206d75737420626520617574686f72697a656400000000604482015260640161098d565b604080518082019091526089548152608a5460208201526000906112cd906112bd90613627565b8051602090910120608390613661565b90506112da6088826136fe565b608c80546001600160a01b0319166001600160a01b03841617905560655460885461130e91906001600160401b0316615765565b158015611335575060006113226078613863565b600481111561133357611333615227565b145b15611344576113446078613916565b5050565b604080516080810182526060808252600060208084018290528385018290529183018190528451858301208152608390915291909120610f02565b608854600160801b90046001600160401b031660006113a36083836135e0565b905083836040516020016113b8929190615779565b604051602081830303815290604052805190602001208160020154146113f05760405162461bcd60e51b815260040161098d906157c4565b608b54607154604051637bfcd47d60e11b8152600160401b9092046001600160601b0316916000916001600160a01b03169063f7f9a8fa906114389089908990600401615779565b600060405180830381865afa158015611455573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261147d9190810190615816565b9050600081516001600160401b0381111561149a5761149a614e7a565b6040519080825280602002602001820160405280156114c3578160200160208202803683370190505b50905060005b82518110156115495761150d8382815181106114e7576114e7615627565b60200260200101516001600160a01b039081166000908152607660205260409020541690565b82828151811061151f5761151f615627565b6001600160a01b039092166020928302919091019091015280611541816158ca565b9150506114c9565b506073546068546040516383ddba8f60e01b81526001600160a01b03909216916383ddba8f916115829187919033908790600401615676565b600060405180830381600087803b15801561159c57600080fd5b505af19250505080156115ad575060015b61160557608854604051600160401b9091046001600160401b0316907f678dcbc52328cedef940fe45ab75280e81c09ec03fe55df62e67642aa18bc278906115f890869086906158e3565b60405180910390a2611655565b608854604051600160401b9091046001600160401b0316907f6e1369aebaf86903bf1f0ab69c3edd0cadbf0534635f699f57a74a3ce54d37189061164c90869086906158e3565b60405180910390a25b6116606083866139e9565b61166a6083613c1b565b60006116766083613e36565b6001600160401b031611156116bb57604080518082019091526089548152608a5460208201526116a9906112bd90613627565b94506116b6608886613e7e565b610ae2565b6116c56088613fc1565b60016116d16078613863565b60048111156116e2576116e2615227565b03610ae257610ae26078614076565b60005a6088549091506001600160401b03600160401b820481169160009161172491608391600160801b909104166135e0565b90508484604051602001611739929190615779565b604051602081830303815290604052805190602001208160020154146117715760405162461bcd60e51b815260040161098d906157c4565b600061178060888989856140e1565b90506001600160601b0381161561198e57607154604051637bfcd47d60e11b81526000916001600160a01b03169063f7f9a8fa906117c4908a908a90600401615779565b600060405180830381865afa1580156117e1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526118099190810190615816565b9050600081516001600160401b0381111561182657611826614e7a565b60405190808252806020026020018201604052801561184f578160200160208202803683370190505b50905060005b82518110156118af576118738382815181106114e7576114e7615627565b82828151811061188557611885615627565b6001600160a01b0390921660209283029190910190910152806118a7816158ca565b915050611855565b5060735460405163f07f91c560e01b81526001600160a01b039091169063f07f91c5906118e290869085906004016158e3565b600060405180830381600087803b1580156118fc57600080fd5b505af192505050801561190d575060015b61195057847fd3f7d9c595537a55b26b224409f386868056764bc4d55bf8c3d86e20d047afc184846040516119439291906158e3565b60405180910390a261198b565b847f94af8e9c35b4ede2a77f659b202b1efe096bf99f0e6f5dd5905c800978a9a64784846040516119829291906158e3565b60405180910390a25b50505b600161199a6078613863565b60048111156119ab576119ab615227565b036119d4576119d488886040516119c3929190615905565b604051908190039020607890614106565b6119fc88886040516119e7929190615905565b604051908190039020606454608c9190614178565b603254606e546001600160a01b0390911690637ad226dc905a611a1f9088615915565b611a299190615928565b6040516001600160e01b031960e084901b1681526004810191909152336024820152604401600060405180830381600087803b158015611a6857600080fd5b505af1158015611a7c573d6000803e3d6000fd5b505050505050505050505050565b60005a608854909150600090611ab290608390600160801b90046001600160401b03166135e0565b9050611ac16088858584614225565b6001611acd6078613863565b6004811115611ade57611ade615227565b03611af657611af684846040516119c3929190615905565b611b0984846040516119e7929190615905565b603254606e546001600160a01b0390911690637ad226dc905a611b2c9086615915565b611b369190615928565b6040516001600160e01b031960e084901b1681526004810191909152336024820152604401600060405180830381600087803b158015611b7557600080fd5b505af1158015611b89573d6000803e3d6000fd5b5050505050505050565b60005a60405163716ae95760e01b815290915060009073__$852b9611da141be0769f808cc0e4dd5c7d$__9063716ae95790611bd69060789087906004016154c5565b600060405180830381865af4158015611bf3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611c1b919081019061593b565b805190915015611c99576071546067546001600160a01b039091169063942f6892908390611c499042615928565b6040518363ffffffff1660e01b8152600401611c669291906159c9565b600060405180830381600087803b158015611c8057600080fd5b505af1158015611c94573d6000803e3d6000fd5b505050505b611cb7611ca960208501856159eb565b6083919060c0870135614288565b611cc16078614351565b603254606c546001600160a01b0390911690637ad226dc905a611ce49086615915565b606b54611cf19190615928565b611cfb9190615928565b6040516001600160e01b031960e084901b1681526004810191909152336024820152604401600060405180830381600087803b158015611d3a57600080fd5b505af1158015610ae2573d6000803e3d6000fd5b6000546001600160a01b03163314611d785760405162461bcd60e51b815260040161098d90615317565b607154604051632a59250560e21b81526001600160a01b0383811660048301529091169063a964941490602401600060405180830381600087803b158015611dbf57600080fd5b505af1158015610c4e573d6000803e3d6000fd5b6000611ddf60786143b5565b905090565b6073546001600160a01b03163314611e0e5760405162461bcd60e51b815260040161098d9061534e565b604051636dc1282760e11b8152607460048201526001600160a01b03841660248201526001600160601b0380841660448301528216606482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063db82504e90608401610ab6565b6073546040516304a3b6b360e31b8152607460048201526001600160a01b039182166024820152908216604482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063251db59890606401610c22565b6000546001600160a01b03163314611ee95760405162461bcd60e51b815260040161098d90615317565b60658690556087859055611f0160788585858561327d565b6040805187815260208101879052908101859052606081018490526080810183905260a081018290527f88243406f452bee756e4fff4cb19e6855a5d3b7bfab8814ea6838685e08da0939060c00160405180910390a1505050505050565b6000546001600160a01b03163314611f895760405162461bcd60e51b815260040161098d90615317565b6040516001600160a01b03821681527f0e2d2343d31b085b7c4e56d1c8a6ec79f7ab07460386f1c9a1756239fe2533ac9060200160405180910390a1603280546001600160a01b0319166001600160a01b0392909216919091179055565b612000611ff760208301836159eb565b60839190614412565b6040516305149aaf60e51b815273__$852b9611da141be0769f808cc0e4dd5c7d$__9063a29355e090610c229060789085906004016154c5565b607354604051635c359a0f60e11b8152607460048201526001600160a01b039182166024820152908216604482015260009073__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063b86b341e906064015b602060405180830381865af41580156120a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120cd9190615732565b92915050565b6000546001600160a01b031633146120fd5760405162461bcd60e51b815260040161098d90615317565b6001600160a01b038216600081815260706020908152604091829020805460ff191685151590811790915591519182527fb4d9db68405970190721d2b3726fc9f728c1413038755e60518dea67d5545556910160405180910390a25050565b6000546001600160a01b031633146121865760405162461bcd60e51b815260040161098d90615317565b606481905561219760888484613475565b60408051848152602081018490529081018290527fea9006ae23cd9b51dbfbc9d747fc3b0bc77acba4fefba609c76f8e9a9513602e90606001610a0e565b604051624f4ac760e01b8152607460048201526001600160a01b038216602482015260009073__$1150d55cc8540ae1e6a8a840b6e83a829d$__90624f4ac790604401602060405180830381865af4158015612235573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120cd9190615a31565b6000546001600160a01b031633146122835760405162461bcd60e51b815260040161098d90615317565b604051633d36f3fd60e21b8152607460048201526001600160601b03841660248201526001600160401b0380841660448301528216606482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063f4dbcff49060840160006040518083038186803b1580156122f457600080fd5b505af4158015612308573d6000803e3d6000fd5b5050604080516001600160601b03871681526001600160401b0380871660208301528516918101919091527f544b726e42801bb47073854eeedae851903f66fe32a5bd24e626e10b90027b5192506060019050610a0e565b61236a6083613e36565b6001600160401b0316156123b75760405162461bcd60e51b81526020600482015260146024820152734e6f74206177616974696e672067656e6573697360601b604482015260640161098d565b6123c16078613916565b6124207f4574c8c75d6e88acd28f7e467dac97b5c60c3838d9dad993900bdf402152228e43604051602001612400929190918252602082015260400190565b60408051601f198184030181529190528051602090910120607890614106565b565b6000546001600160a01b0316331461244c5760405162461bcd60e51b815260040161098d90615317565b606b849055606c839055606d829055606e8190556040805185815260208101859052908101839052606081018290527feffd28b20afc0bf9349e8d49d5346c7568689b661a6bcd71c26a939b57b0acd190608001611048565b60006124b26083856135e0565b6040518060800160405290816000820180546124cd906156b6565b80601f01602080910402602001604051908101604052809291908181526020018280546124f9906156b6565b80156125465780601f1061251b57610100808354040283529160200191612546565b820191906000526020600020905b81548152906001019060200180831161252957829003601f168201915b5050505050815260200160018201548152602001600282015481526020016003820160009054906101000a900460ff16151515158152505090508282604051602001612593929190615779565b604051602081830303815290604052805190602001208160400151146125cb5760405162461bcd60e51b815260040161098d906157c4565b80606001511561261d5760405162461bcd60e51b815260206004820152601a60248201527f47726f75702063616e6e6f74206265207465726d696e61746564000000000000604482015260640161098d565b8051604080513360601b6bffffffffffffffffffffffff191660208201528151601481830301815260348201928390526339c6c5f160e21b90925273__$b5930e1c3596d61eae714f9835468f05d3$__9263e71b17c492612682928a90603801615a4e565b602060405180830381865af415801561269f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126c39190615a87565b6127035760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b604482015260640161098d565b61270e6083856139e9565b607154604051637bfcd47d60e11b81526000916001600160a01b03169063f7f9a8fa906127419087908790600401615779565b600060405180830381865afa15801561275e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526127869190810190615816565b9050600081516001600160401b038111156127a3576127a3614e7a565b6040519080825280602002602001820160405280156127cc578160200160208202803683370190505b50905060005b825181101561282c576127f08382815181106114e7576114e7615627565b82828151811061280257612802615627565b6001600160a01b039092166020928302919091019091015280612824816158ca565b9150506127d2565b506073546066546069546040516383ddba8f60e01b81526001600160a01b03909316926383ddba8f9261287792600160601b9091046001600160601b03169133908790600401615676565b600060405180830381600087803b15801561289157600080fd5b505af19250505080156128a2575060015b612902576066546040516001600160401b038816917ffd4a5a45de3194b94e2a7954706ac9023b7c9935cf1a25242691da2a94d720d4916128f591600160601b90046001600160601b03169086906158e3565b60405180910390a2610ae2565b6066546040516001600160401b038816917fa311dcb2a3eb32651a722488f4f281b3f8e4ab05abcd8a37a5c7d663bba5a8859161295191600160601b90046001600160601b03169086906158e3565b60405180910390a250505050505050565b6073546001600160a01b0316331461298c5760405162461bcd60e51b815260040161098d9061534e565b604051633558d21760e21b8152607460048201526001600160a01b03841660248201526001600160601b0380841660448301528216606482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063d563485c90608401610ab6565b6000611ddf6078613863565b60005a90506000612a0a6020870187614d9d565b6001600160401b0381166000908152606f60205260409020549091508514612a645760405162461bcd60e51b815260206004820152600d60248201526c496e76616c6964206e6f6e636560981b604482015260640161098d565b612a6f6083826144fb565b612ab15760405162461bcd60e51b815260206004820152601360248201527247726f7570206973206e6f742061637469766560681b604482015260640161098d565b6000612abe6083836135e0565b90508484604051602001612ad3929190615779565b60405160208183030381529060405280519060200120816002015414612b0b5760405162461bcd60e51b815260040161098d906157c4565b60715460405163fc21976b60e01b815260009173__$1ba5315bb273adc70a9cc339490e63eb09$__9163fc21976b91612b5c916001600160a01b03909116908c9087908d908d908d90600401615b21565b600060405180830381865af4158015612b79573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612ba1919081019061593b565b6001600160401b0384166000908152606f60205260408120805492935090612bc8836158ca565b9091555050604080518881523360208201526001600160401b038516917f3ca10b33fda0a4adbc75ac1939659a06e8c332b8f6a2792bedbf8741e4268417910160405180910390a26071546067546001600160a01b039091169063942f6892908390612c349042615928565b6040518363ffffffff1660e01b8152600401612c519291906159c9565b600060405180830381600087803b158015612c6b57600080fd5b505af1158015612c7f573d6000803e3d6000fd5b5050603254606d546001600160a01b039091169250637ad226dc91505a611a1f9088615915565b6000546001600160a01b03163314612cd05760405162461bcd60e51b815260040161098d90615317565b6001600160a01b038116612d315760405162461bcd60e51b815260206004820152602260248201527f4e657720676f7665726e616e636520697320746865207a65726f206164647265604482015261737360f01b606482015260840161098d565b612d3a8161453b565b50565b3360005a9050612d4d607861459c565b6032546001600160a01b0316637ad226dc5a612d699084615915565b6040516001600160e01b031960e084901b16815260048101919091526001600160a01b0385166024820152604401600060405180830381600087803b158015612db157600080fd5b505af1158015610ecb573d6000803e3d6000fd5b607154607f5460408051636c2530b960e01b81526060936001600160a01b031692636c2530b992612e0492909190600401918252602082015260400190565b600060405180830381865afa158015612e21573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611ddf919081019061593b565b60735460715460405163148140a160e21b8152607460048201526001600160a01b0392831660248201529082166044820152908216606482015260009073__$1150d55cc8540ae1e6a8a840b6e83a829d$__90635205028490608401602060405180830381865af4158015612ec2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120cd9190615a87565b6071546040516307b8c36760e51b81526001600160a01b038381166004830152600092169063f7186ce090602401602060405180830381865afa158015612ec2573d6000803e3d6000fd5b600080612f56836001600160a01b039081166000908152607560205260409020541690565b90506001600160a01b038116612fa15760405162461bcd60e51b815260206004820152601060248201526f2ab735b737bbb71037b832b930ba37b960811b604482015260640161098d565b60715460405163439f18fd60e11b81526001600160a01b0383811660048301529091169063873e31fa90602401602060405180830381865afa158015612feb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061300f9190615732565b9392505050565b604051635fc3290960e11b8152607460048201526001600160a01b038216602482015260009073__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063bf8652129060440161208c565b82546001600160a01b0316156130c35760405162461bcd60e51b815260206004820152602260248201527f536f72746974696f6e20506f6f6c206164647265737320616c72656164792073604482015261195d60f21b606482015260840161098d565b60018301546001600160a01b0316156131285760405162461bcd60e51b815260206004820152602160248201527f444b472056616c696461746f72206164647265737320616c72656164792073656044820152601d60fa1b606482015260840161098d565b82546001600160a01b03199081166001600160a01b03938416178455600190930180549093169116179055565b600181015415801561316957506002810154155b6131b55760405162461bcd60e51b815260206004820152601e60248201527f5365656420656e74727920616c726561647920696e697469616c697a65640000604482015260640161098d565b6131d6604051806060016040528060408152602001615ea060409139613508565b8051600183015560200151600290910155565b8154600160401b90046001600160401b0316156132445760405162461bcd60e51b815260206004820152601960248201527852656c6179207265717565737420696e2070726f677265737360381b604482015260640161098d565b600390910180546001600160601b03909216600160401b0273ffffffffffffffffffffffff000000000000000019909216919091179055565b600061328886613863565b600481111561329957613299615227565b146132e25760405162461bcd60e51b815260206004820152601960248201527843757272656e74207374617465206973206e6f742049444c4560381b604482015260640161098d565b600084116133585760405162461bcd60e51b815260206004820152603a60248201527f526573756c74206368616c6c656e676520706572696f64206c656e677468207360448201527f686f756c642062652067726561746572207468616e207a65726f000000000000606482015260840161098d565b600082116133c65760405162461bcd60e51b815260206004820152603560248201527f526573756c74207375626d697373696f6e2074696d656f75742073686f756c646044820152742062652067726561746572207468616e207a65726f60581b606482015260840161098d565b8181106134585760405162461bcd60e51b815260206004820152605460248201527f5375626d697474657220707265636564656e636520706572696f64206c656e6760448201527f74682073686f756c64206265206c657373207468616e2074686520726573756c6064820152731d081cdd589b5a5cdcda5bdb881d1a5b595bdd5d60621b608482015260a40161098d565b600285019390935560038401919091556004830155600590910155565b8254600160401b90046001600160401b0316156134d05760405162461bcd60e51b815260206004820152601960248201527852656c6179207265717565737420696e2070726f677265737360381b604482015260640161098d565b6003909201805463ffffffff9384166401000000000267ffffffffffffffff199091169390921692909217179055565b600490910155565b6040805180820190915260008082526020820152815160401461356d5760405162461bcd60e51b815260206004820152601760248201527f496e76616c6964204731206279746573206c656e677468000000000000000000604482015260640161098d565b5060208181015160409283015183518085019094529083529082015290565b60038101545a1015612d3a5760405162461bcd60e51b815260206004820152601960248201527f4e6f7420656e6f75676820657874726120676173206c65667400000000000000604482015260640161098d565b600082600001600084600101846001600160401b03168154811061360657613606615627565b90600052602060002001548152602001908152602001600020905092915050565b6040805181815260608181018352916000919060208201818036833750508451602095860151958301525060408101939093525090919050565b600061366c83613c1b565b600061367784613e36565b6001600160401b0316116136c05760405162461bcd60e51b815260206004820152601060248201526f4e6f206163746976652067726f75707360801b604482015260640161098d565b60006136cb84613e36565b6136de906001600160401b031684615765565b905060006136f5856136f0878561461b565b614637565b95945050505050565b8154600160401b90046001600160401b0316156137675760405162461bcd60e51b815260206004820152602160248201527f416e6f746865722072656c6179207265717565737420696e2070726f677265736044820152607360f81b606482015260840161098d565b815460009083908290613782906001600160401b0316615c02565b82546101009290920a6001600160401b038181021990931682841691820217909355855477ffffffffffffffffffffffffffffffff00000000000000001916600160401b840267ffffffffffffffff60801b191617600160801b86841602176001600160c01b0316600160c01b43909316929092029190911785556040805180820190915260018601548152600286015460208201529092507fdf86f752d80d21879cbd208ba1d036c03f836b1d7f8f887b0b9e0b63f8a49f5d90849061384890613627565b604051613856929190615c28565b60405180910390a2505050565b805460408051632938b58d60e21b815290516000926001600160a01b03169163a4e2d6349160048083019260209291908290030181865afa1580156138ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138d09190615a87565b1561391157506006810154600190156139115760029050604882600601546138f89190615928565b4311156139115750600a81015460039015613911575060045b919050565b600061392182613863565b600481111561393257613932615227565b1461397b5760405162461bcd60e51b815260206004820152601960248201527843757272656e74207374617465206973206e6f742049444c4560381b604482015260640161098d565b6040517f5c3ed2397d4d21298b2fb5027ac8e2d42e3c9c72bbb55ddb030e2a36a0cdff6b90600090a1805460408051637c1e845d60e11b815290516001600160a01b039092169163f83d08ba9160048082019260009290919082900301818387803b158015611dbf57600080fd5b6139f382826146cd565b15613a4a5760405162461bcd60e51b815260206004820152602160248201527f47726f757020686173206265656e20616c7265616479207465726d696e6174656044820152601960fa1b606482015260840161098d565b600182600001600084600101846001600160401b031681548110613a7057613a70615627565b60009182526020808320919091015483528201929092526040018120600301805460ff1916921515929092179091556002830180546001908101808355918352613ab991615915565b90505b600081118015613b1957506001600160401b03821660028401613ae0600184615915565b81548110613af057613af0615627565b6000918252602090912060048204015460039091166008026101000a90046001600160401b0316115b15613bc75760028301613b2d600183615915565b81548110613b3d57613b3d615627565b90600052602060002090600491828204019190066008029054906101000a90046001600160401b0316836002018281548110613b7b57613b7b615627565b90600052602060002090600491828204019190066008026101000a8154816001600160401b0302191690836001600160401b031602179055508080613bbf90615c4a565b915050613abc565b81836002018281548110613bdd57613bdd615627565b90600052602060002090600491828204019190066008026101000a8154816001600160401b0302191690836001600160401b03160217905550505050565b600181015460038201546001600160401b0316108015613c75575060038101546001820180544392613c7392859290916001600160401b0316908110613c6357613c63615627565b906000526020600020015461471d565b105b15613cbf576003810180546001600160401b0316906000613c9583615c02565b91906101000a8154816001600160401b0302191690836001600160401b0316021790555050613c1b565b60005b600282015481101561134457816002018181548110613ce357613ce3615627565b6000918252602090912060048204015460038481015492166008026101000a90046001600160401b0390811691161115613e2457805b6002830154613d2a90600190615915565b811015613dda5760028301613d40826001615928565b81548110613d5057613d50615627565b90600052602060002090600491828204019190066008029054906101000a90046001600160401b0316836002018281548110613d8e57613d8e615627565b90600052602060002090600491828204019190066008026101000a8154816001600160401b0302191690836001600160401b031602179055508080613dd2906158ca565b915050613d19565b5081600201805480613dee57613dee615c61565b60008281526020902060046000199092019182040180546001600160401b03600860038516026101000a02191690559055613cc2565b80613e2e816158ca565b915050613cc2565b60018101546000908103613e4c57506000919050565b60028201546003830154600184015460009291613e74916001600160401b0390911690615915565b61300f9190615915565b613e878261473f565b613ed35760405162461bcd60e51b815260206004820152601e60248201527f52656c6179207265717565737420646964206e6f742074696d65206f75740000604482015260640161098d565b81546040516001600160401b03600160801b83048116808352600160401b90930416919082907fc28be0fa97c9083fa79881ba8950c1333fb45ec5100d2b893ec0f41544e78bef9060200160405180910390a283546fffffffffffffffffffffffffffffffff16600160801b6001600160401b03858116919091026001600160c01b031691909117600160c01b43831602178555604080518082019091526001860154815260028601546020820152908316907fdf86f752d80d21879cbd208ba1d036c03f836b1d7f8f887b0b9e0b63f8a49f5d908590613fb390613627565b604051611229929190615c28565b613fca8161473f565b6140165760405162461bcd60e51b815260206004820152601e60248201527f52656c6179207265717565737420646964206e6f742074696d65206f75740000604482015260640161098d565b80546040516001600160401b03600160801b830481168252600160401b909204909116907fc28be0fa97c9083fa79881ba8950c1333fb45ec5100d2b893ec0f41544e78bef9060200160405180910390a280546001600160401b03169055565b600161408182613863565b600481111561409257614092615227565b146140af5760405162461bcd60e51b815260040161098d90615c77565b6040517f68c52f05452e81639fa06f379aee3178cddee4725521fff886f244c99e868b5090600090a1612d3a81614351565b6000806140ed866147b3565b90506140fb86868686614848565b90505b949350505050565b600161411183613863565b600481111561412257614122615227565b1461413f5760405162461bcd60e51b815260040161098d90615c77565b60405181907fb2ad26c2940889d79df2ee9c758a8aefa00c5ca90eee119af0e5d795df3b98bb90600090a2436006830155600790910155565b82546001600160a01b031615614220578254604051631bfaf51960e21b8152600481018490524360248201526001600160a01b0390911690636febd464908390604401600060405180830381600088803b1580156141d557600080fd5b5087f1935050505080156141e7575060015b61422057604080518381524360208201527f5e2af61e77ec91022b1cafe282abce475bb18e8cdd47083464caa06583fe39099101610a0e565b505050565b61422e84614b38565b431061427c5760405162461bcd60e51b815260206004820152601f60248201527f52656c617920656e74727920736f66742074696d656f75742070617373656400604482015260640161098d565b610b6784848484614848565b6000838360405161429a929190615905565b60408051918290039091206000818152602088905291909120909150806142c2858783615cff565b50600281018390554360018083019190915586810180549182018155600090815260209020018290556040516142fb9086908690615905565b6040519081900390206001878101546143149190615915565b6001600160401b03167f4c0666db2c51896711b100d1f4f5d20a347c59e6e16ad8f365ed81ff97358b4e60405160405180910390a3505050505050565b600060068201819055600782018190556008820181905560098201819055600a820181905581546040805163a69df4b560e01b815290516001600160a01b039092169263a69df4b59260048084019382900301818387803b158015611dbf57600080fd5b600060036143c283613863565b60048111156143d3576143d3615227565b1480156120cd57506004820154600883015460068401546143f690604890615928565b6144009190615928565b61440a9190615928565b431192915050565b608081146144625760405162461bcd60e51b815260206004820181905260248201527f496e76616c6964206c656e677468206f6620746865207075626c6963206b6579604482015260640161098d565b60008282604051614474929190615905565b604080519182900390912060008181526020879052919091206001015490915015610b675760405162461bcd60e51b815260206004820152603160248201527f47726f757020776974682074686973207075626c6963206b65792077617320616044820152701b1c9958591e481c9959da5cdd195c9959607a1b606482015260840161098d565b6000436145208485600101856001600160401b031681548110613c6357613c63615627565b1015801561300f575061453383836146cd565b159392505050565b600080546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce80910160405180910390a15050565b6145a5816143b5565b6145e95760405162461bcd60e51b81526020600482015260156024820152741112d1c81a185cc81b9bdd081d1a5b5959081bdd5d605a1b604482015260640161098d565b6040517f2852b3e178dd281713b041c3d90b4815bb55b7ec812931d1e8e8d8bb2ed72d3e90600090a1612d3a81614351565b600382015460009061300f9083906001600160401b0316615dbe565b600081815b60028501546001600160401b03821610156146c557816001600160401b031685600201826001600160401b03168154811061467957614679615627565b6000918252602090912060048204015460039091166008026101000a90046001600160401b0316116146b357816146af81615c02565b9250505b806146bd81615c02565b91505061463c565b509392505050565b600082600001600084600101846001600160401b0316815481106146f3576146f3615627565b6000918252602080832090910154835282019290925260400190206003015460ff16905092915050565b6004820154600082815260208490526040812060010154909161300f91615928565b600381015460009081906147639063ffffffff640100000000820481169116615de5565b63ffffffff16905061478683546001600160401b03600160401b90910416151590565b801561300f575082546147aa908290600160c01b90046001600160401b0316615928565b43119392505050565b6000806147bf83614b38565b90508043111561483f5760006147d58243615915565b6003850154909150640100000000900463ffffffff1681111561480757506003830154640100000000900463ffffffff165b6003840154640100000000810463ffffffff169061483590600160401b90046001600160601b031683615e02565b6140fe9190615e19565b50600092915050565b8354600160401b90046001600160401b03166148a65760405162461bcd60e51b815260206004820152601c60248201527f4e6f2072656c6179207265717565737420696e2070726f677265737300000000604482015260640161098d565b6148af8461473f565b156148fc5760405162461bcd60e51b815260206004820152601760248201527f52656c617920726571756573742074696d6564206f7574000000000000000000604482015260640161098d565b73__$b5930e1c3596d61eae714f9835468f05d3$__63b6087a0f6149a8838054614925906156b6565b80601f0160208091040260200160405190810160405280929190818152602001828054614951906156b6565b801561499e5780601f106149735761010080835404028352916020019161499e565b820191906000526020600020905b81548152906001019060200180831161498157829003601f168201915b5050505050614b73565b866001016149eb87878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061350892505050565b6040518463ffffffff1660e01b8152600401614a0993929190615e2d565b602060405180830381865af4158015614a26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a4a9190615a87565b614a865760405162461bcd60e51b815260206004820152600d60248201526c496e76616c696420656e74727960981b604482015260640161098d565b8354604051600160401b9091046001600160401b0316907f087df9fd862e4448d02f8b58e33a18941769c795a8b83cfb95dfaf9c92ca897e90614ace90339087908790615e7a565b60405180910390a2614b1583838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061350892505050565b80516001860155602001516002850155505081546001600160401b031690915550565b60038101548154600091614b649163ffffffff90911690600160c01b90046001600160401b0316615dbe565b6001600160401b031692915050565b614b7b614c14565b8151608014614bcc5760405162461bcd60e51b815260206004820152601760248201527f496e76616c6964204732206279746573206c656e677468000000000000000000604482015260640161098d565b50602081810151604080840151606080860151608096870151845197880185528785019586529187019290925292855281518083019092528152808301919091529082015290565b60408051608081018252600091810182815260608201929092529081908152602001614c53604051806040016040528060008152602001600081525090565b905290565b6001600160601b0381168114612d3a57600080fd5b600080600060608486031215614c8257600080fd5b8335614c8d81614c58565b92506020840135614c9d81614c58565b91506040840135614cad81614c58565b809150509250925092565b6001600160a01b0381168114612d3a57600080fd5b600080600060608486031215614ce257600080fd5b8335614c8d81614cb8565b6020808252825182820181905260009190848201906040850190845b81811015614d2557835183529284019291840191600101614d09565b50909695505050505050565b600060208284031215614d4357600080fd5b813561300f81614cb8565b600060208284031215614d6057600080fd5b81356001600160401b03811115614d7657600080fd5b820160e0818503121561300f57600080fd5b6001600160401b0381168114612d3a57600080fd5b600060208284031215614daf57600080fd5b813561300f81614d88565b6000815180845260005b81811015614de057602081850181015186830182015201614dc4565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000825160806020840152614e1c60a0840182614dba565b905060208401516040840152604084015160608401526060840151151560808401528091505092915050565b60008060008060808587031215614e5e57600080fd5b5050823594602084013594506040840135936060013592509050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715614eb857614eb8614e7a565b604052919050565b600082601f830112614ed157600080fd5b81356001600160401b03811115614eea57614eea614e7a565b614efd601f8201601f1916602001614e90565b818152846020838601011115614f1257600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215614f4157600080fd5b81356001600160401b03811115614f5757600080fd5b6140fe84828501614ec0565b60008083601f840112614f7557600080fd5b5081356001600160401b03811115614f8c57600080fd5b6020830191508360208260051b8501011115614fa757600080fd5b9250929050565b60008060208385031215614fc157600080fd5b82356001600160401b03811115614fd757600080fd5b614fe385828601614f63565b90969095509350505050565b60008083601f84011261500157600080fd5b5081356001600160401b0381111561501857600080fd5b602083019150836020828501011115614fa757600080fd5b6000806000806040858703121561504657600080fd5b84356001600160401b038082111561505d57600080fd5b61506988838901614fef565b9096509450602087013591508082111561508257600080fd5b5061508f87828801614f63565b95989497509550505050565b600080602083850312156150ae57600080fd5b82356001600160401b038111156150c457600080fd5b614fe385828601614fef565b60008060008060008060c087890312156150e957600080fd5b505084359660208601359650604086013595606081013595506080810135945060a0013592509050565b8015158114612d3a57600080fd5b6000806040838503121561513457600080fd5b823561513f81614cb8565b9150602083013561514f81615113565b809150509250929050565b60008060006060848603121561516f57600080fd5b505081359360208301359350604090920135919050565b60008060006060848603121561519b57600080fd5b83356151a681614c58565b925060208401356151b681614d88565b91506040840135614cad81614d88565b600080600080606085870312156151dc57600080fd5b84356001600160401b03808211156151f357600080fd5b6151ff88838901614ec0565b95506020870135915061521182614d88565b9093506040860135908082111561508257600080fd5b634e487b7160e01b600052602160045260246000fd5b602081016005831061525f57634e487b7160e01b600052602160045260246000fd5b91905290565b6000806000806060858703121561527b57600080fd5b84356001600160401b038082111561529257600080fd5b90860190608082890312156152a657600080fd5b909450602086013593506040860135908082111561508257600080fd5b600081518084526020808501945080840160005b838110156152f957815163ffffffff16875295820195908201906001016152d7565b509495945050505050565b60208152600061300f60208301846152c3565b6020808252601c908201527f43616c6c6572206973206e6f742074686520676f7665726e616e636500000000604082015260600190565b60208082526022908201527f43616c6c6572206973206e6f7420746865207374616b696e6720636f6e74726160408201526118dd60f21b606082015260800190565b6000808335601e198436030181126153a757600080fd5b83016020810192503590506001600160401b038111156153c657600080fd5b803603821315614fa757600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000808335601e1984360301811261541557600080fd5b83016020810192503590506001600160401b0381111561543457600080fd5b8060051b3603821315614fa757600080fd5b81835260006001600160fb1b0383111561545f57600080fd5b8260051b80836020870137939093016020019392505050565b63ffffffff81168114612d3a57600080fd5b8183526000602080850194508260005b858110156152f95781356154ad81615478565b63ffffffff168752958201959082019060010161549a565b82815260006020604081840152833560408401526154e581850185615390565b60e060608601526154fb610120860182846153d5565b91505061550b60408601866153fe565b603f19868403810160808801528184529192600092908501835b8381101561555157853560ff811680821461553e578687fd5b8352509486019490860190600101615525565b5061555f60608a018a615390565b96509450818882030160a08901526155788187876153d5565b95505061558860808901896153fe565b94509250808786030160c08801526155a1858585615446565b94506155b060a08901896153fe565b94509250808786030160e088015250506155cb83838361548a565b9250505060c0840135610100840152809150509392505050565b600080604083850312156155f857600080fd5b82519150602083015161514f81615478565b60006020828403121561561c57600080fd5b815161300f81614cb8565b634e487b7160e01b600052603260045260246000fd5b600081518084526020808501945080840160005b838110156152f95781516001600160a01b031687529582019590820190600101615651565b6001600160601b038516815283602082015260018060a01b03831660408201526080606082015260006156ac608083018461563d565b9695505050505050565b600181811c908216806156ca57607f821691505b6020821081036156ea57634e487b7160e01b600052602260045260246000fd5b50919050565b60008060006060848603121561570557600080fd5b835161571081614cb8565b602085015190935061572181614cb8565b6040850151909250614cad81614cb8565b60006020828403121561574457600080fd5b815161300f81614c58565b634e487b7160e01b600052601260045260246000fd5b6000826157745761577461574f565b500690565b60208082528181018390526000908460408401835b868110156157b95782356157a181615478565b63ffffffff168252918301919083019060010161578e565b509695505050505050565b602080825260159082015274496e76616c69642067726f7570206d656d6265727360581b604082015260600190565b60006001600160401b0382111561580c5761580c614e7a565b5060051b60200190565b6000602080838503121561582957600080fd5b82516001600160401b0381111561583f57600080fd5b8301601f8101851361585057600080fd5b805161586361585e826157f3565b614e90565b81815260059190911b8201830190838101908783111561588257600080fd5b928401925b828410156158a957835161589a81614cb8565b82529284019290840190615887565b979650505050505050565b634e487b7160e01b600052601160045260246000fd5b6000600182016158dc576158dc6158b4565b5060010190565b6001600160601b03831681526040602082015260006140fe604083018461563d565b8183823760009101908152919050565b818103818111156120cd576120cd6158b4565b808201808211156120cd576120cd6158b4565b6000602080838503121561594e57600080fd5b82516001600160401b0381111561596457600080fd5b8301601f8101851361597557600080fd5b805161598361585e826157f3565b81815260059190911b820183019083810190878311156159a257600080fd5b928401925b828410156158a95783516159ba81615478565b825292840192908401906159a7565b6040815260006159dc60408301856152c3565b90508260208301529392505050565b6000808335601e19843603018112615a0257600080fd5b8301803591506001600160401b03821115615a1c57600080fd5b602001915036819003821315614fa757600080fd5b600060208284031215615a4357600080fd5b815161300f81614d88565b606081526000615a616060830186614dba565b8281036020840152615a738186614dba565b905082810360408401526156ac8185614dba565b600060208284031215615a9957600080fd5b815161300f81615113565b60008154615ab1816156b6565b808552602060018381168015615ace5760018114615ae857615b16565b60ff1985168884015283151560051b880183019550615b16565b866000528260002060005b85811015615b0e5781548a8201860152908301908401615af3565b890184019650505b505050505092915050565b6001600160a01b038716815260a0602082015260008635615b4181614d88565b6001600160401b031660a0830152615b5c60208801886153fe565b608060c0850152615b7261012085018284615446565b915050615b826040890189615390565b609f19808685030160e0870152615b9a8483856153d5565b9350615ba960608c018c6153fe565b93509150808685030161010087015250615bc4838383615446565b925050508281036040840152615bda8188615aa4565b90508560608401528281036080840152615bf581858761548a565b9998505050505050505050565b60006001600160401b03808316818103615c1e57615c1e6158b4565b6001019392505050565b6001600160401b03831681526040602082015260006140fe6040830184614dba565b600081615c5957615c596158b4565b506000190190565b634e487b7160e01b600052603160045260246000fd5b60208082526022908201527f43757272656e74207374617465206973206e6f74204157414954494e475f5345604082015261115160f21b606082015260800190565b601f82111561422057600081815260208120601f850160051c81016020861015615ce05750805b601f850160051c820191505b81811015610ecb57828155600101615cec565b6001600160401b03831115615d1657615d16614e7a565b615d2a83615d2483546156b6565b83615cb9565b6000601f841160018114615d5e5760008515615d465750838201355b600019600387901b1c1916600186901b178355610c4e565b600083815260209020601f19861690835b82811015615d8f5786850135825560209485019460019092019101615d6f565b5086821015615dac5760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b6001600160401b03818116838216019080821115615dde57615dde6158b4565b5092915050565b63ffffffff818116838216019080821115615dde57615dde6158b4565b80820281158282048414176120cd576120cd6158b4565b600082615e2857615e2861574f565b500490565b835180518252602090810151818301528085015180516040840152810151606083015283546080830152600184015460a0830152825160c083015282015160e082015261010081016140fe565b6001600160a01b03841681526040602082018190526000906136f590830184866153d556fe15c30f4b6cf6dbbcbdcc10fe22f54c8170aea44e198139b776d512d8f027319a1b9e8bfaf1383978231ce98e42bafc8129f473fc993cf60ce327f7d223460663a26469706673582212201e83b5e6a0d35d36568b84271a3808630b95fe28a009d1e00ebcae4df36f5ca864736f6c63430008110033", + "linkReferences": { + "contracts/libraries/BLS.sol": { + "BLS": [ + { + "length": 20, + "start": 12700 + }, + { + "length": 20, + "start": 21568 + } + ] + }, + "contracts/libraries/BeaconAuthorization.sol": { + "BeaconAuthorization": [ + { + "length": 20, + "start": 590 + }, + { + "length": 20, + "start": 5594 + }, + { + "length": 20, + "start": 5728 + }, + { + "length": 20, + "start": 5958 + }, + { + "length": 20, + "start": 7101 + }, + { + "length": 20, + "start": 10636 + }, + { + "length": 20, + "start": 10719 + }, + { + "length": 20, + "start": 11184 + }, + { + "length": 20, + "start": 11582 + }, + { + "length": 20, + "start": 11777 + }, + { + "length": 20, + "start": 13578 + }, + { + "length": 20, + "start": 14794 + }, + { + "length": 20, + "start": 15232 + } + ] + }, + "contracts/libraries/BeaconDkg.sol": { + "BeaconDkg": [ + { + "length": 20, + "start": 6059 + }, + { + "length": 20, + "start": 9965 + }, + { + "length": 20, + "start": 11089 + } + ] + }, + "contracts/libraries/BeaconInactivity.sol": { + "BeaconInactivity": [ + { + "length": 20, + "start": 13922 + } + ] + } + }, + "deployedLinkReferences": { + "contracts/libraries/BLS.sol": { + "BLS": [ + { + "length": 20, + "start": 9818 + }, + { + "length": 20, + "start": 18686 + } + ] + }, + "contracts/libraries/BeaconAuthorization.sol": { + "BeaconAuthorization": [ + { + "length": 20, + "start": 2712 + }, + { + "length": 20, + "start": 2846 + }, + { + "length": 20, + "start": 3076 + }, + { + "length": 20, + "start": 4219 + }, + { + "length": 20, + "start": 7754 + }, + { + "length": 20, + "start": 7837 + }, + { + "length": 20, + "start": 8302 + }, + { + "length": 20, + "start": 8700 + }, + { + "length": 20, + "start": 8895 + }, + { + "length": 20, + "start": 10696 + }, + { + "length": 20, + "start": 11912 + }, + { + "length": 20, + "start": 12350 + } + ] + }, + "contracts/libraries/BeaconDkg.sol": { + "BeaconDkg": [ + { + "length": 20, + "start": 3177 + }, + { + "length": 20, + "start": 7083 + }, + { + "length": 20, + "start": 8207 + } + ] + }, + "contracts/libraries/BeaconInactivity.sol": { + "BeaconInactivity": [ + { + "length": 20, + "start": 11040 + } + ] + } + }, + "devdoc": { + "details": "Should be owned by the governance contract controlling Random Beacon parameters.", + "kind": "dev", + "methods": { + "approveDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))": { + "params": { + "dkgResult": "Result to approve. Must match the submitted result stored during `submitDkgResult`." + } + }, + "authorizationDecreaseRequested(address,uint96,uint96)": { + "details": "Can only be called by T staking contract." + }, + "authorizationIncreased(address,uint96,uint96)": { + "details": "Can only be called by T staking contract." + }, + "authorizationParameters()": { + "details": "The minimum authorization is also returned by `minimumAuthorization()` function, as a requirement of `IApplication` interface.", + "returns": { + "authorizationDecreaseChangePeriod": "Authorization decrease change period in seconds. It is the time, before authorization decrease delay end, during which the pending authorization decrease request can be overwritten. If set to 0, pending authorization decrease request can not be overwritten until the entire `authorizationDecreaseDelay` ends. If set to value equal `authorizationDecreaseDelay`, request can always be overwritten.", + "authorizationDecreaseDelay": "Delay in seconds that needs to pass between the time authorization decrease is requested and the time that request gets approved. Protects against free-riders earning rewards and not being active in the network.", + "minimumAuthorization": "The minimum authorization amount required so that operator can participate in the random beacon. This amount is required to execute slashing for providing a malicious DKG result or when a relay entry times out." + } + }, + "challengeDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))": { + "details": "Due to EIP-150 1/64 of the gas is not forwarded to the call, and will be kept to execute the remaining operations in the function after the call inside the try-catch. To eliminate a class of attacks related to the gas limit manipulation, this function requires an extra amount of gas to be left at the end of the execution.", + "params": { + "dkgResult": "Result to challenge. Must match the submitted result stored during `submitDkgResult`." + } + }, + "constructor": { + "details": "Assigns initial values to parameters to make the beacon work safely. These parameters are just proposed defaults and they might be updated with `update*` functions after the contract deployment and before transferring the ownership to the governance contract." + }, + "gasParameters()": { + "returns": { + "dkgResultApprovalGasOffset": "Gas that is meant to balance the DKG result approval's overall cost.", + "dkgResultSubmissionGas": "Calculated gas cost for submitting a DKG result. This will be refunded as part of the DKG approval process.", + "notifyOperatorInactivityGasOffset": "Gas that is meant to balance the operator inactivity notification cost.", + "relayEntrySubmissionGasOffset": "Gas that is meant to balance the relay entry submission cost." + } + }, + "groupCreationParameters()": { + "returns": { + "dkgResultChallengeExtraGas": "The extra gas required to be left at the end of the challenge DKG result transaction.", + "dkgResultChallengePeriodLength": "The number of blocks for which a DKG result can be challenged. Anyone can challenge DKG result for a certain number of blocks before the result is fully accepted and the group registered in the pool of active groups. If the challenge gets accepted, all operators who signed the malicious result get slashed for and the notifier gets rewarded.", + "dkgResultSubmissionTimeout": "Timeout in blocks for a group to submit the DKG result. All members are eligible to submit the DKG result. If `dkgResultSubmissionTimeout` passes without the DKG result submitted, DKG is considered as timed out and no DKG result for this group creation can be submitted anymore.", + "dkgSubmitterPrecedencePeriodLength": "Time during the DKG result approval stage when the submitter of the DKG result takes the precedence to approve the DKG result. After this time passes anyone can approve the DKG result.", + "groupCreationFrequency": "The frequency of a new group creation. Groups are created with a fixed frequency of relay requests.", + "groupLifetime": "Group lifetime in blocks. When a group reached its lifetime, it is no longer selected for new relay requests but may still be responsible for submitting relay entry if relay request assigned to that group is still pending." + } + }, + "hasDkgTimedOut()": { + "returns": { + "_0": "True if DKG timed out, false otherwise." + } + }, + "isRelayRequestInProgress()": { + "returns": { + "_0": "Flag indicating whether a relay entry request is currently in progress." + } + }, + "notifyOperatorInactivity((uint64,uint256[],bytes,uint256[]),uint256,uint32[])": { + "params": { + "claim": "Operator inactivity claim.", + "groupMembers": "Identifiers of group members.", + "nonce": "Current inactivity claim nonce for the given group. Must be the same as the stored one." + } + }, + "relayEntryParameters()": { + "returns": { + "callbackGasLimit": "Relay entry callback gas limit. This is the gas limit with which callback function provided in the relay request transaction is executed. The callback is executed with a new relay entry value in the same transaction the relay entry is submitted.", + "relayEntryHardTimeout": "Hard timeout in blocks for a group to submit the relay entry. After the soft timeout passes without relay entry submitted, all group members start getting slashed. The slashing amount increases linearly until the group submits the relay entry or until `relayEntryHardTimeout` is reached. When the hard timeout is reached, each group member will get slashed for `_relayEntrySubmissionFailureSlashingAmount`.", + "relayEntrySoftTimeout": "Soft timeout in blocks for a group to submit the relay entry. If the soft timeout is reached for submitting the relay entry, the slashing starts." + } + }, + "reportRelayEntryTimeout(uint32[])": { + "params": { + "groupMembers": "Identifiers of group members." + } + }, + "reportUnauthorizedSigning(bytes,uint64,uint32[])": { + "params": { + "groupId": "Group that is being reported for leaking a private key.", + "groupMembers": "Identifiers of group members.", + "signedMsgSender": "Signature of the sender's address as a message." + } + }, + "requestRelayEntry(address)": { + "params": { + "callbackContract": "Beacon consumer callback contract." + } + }, + "rewardParameters()": { + "returns": { + "dkgMaliciousResultNotificationRewardMultiplier": "Percentage of the staking contract malicious behavior notification reward which will be transferred to the notifier reporting about a malicious DKG result. Notifiers are rewarded from a notifiers treasury pool. For example, if notification reward is 1000 and the value of the multiplier is 5, the notifier will receive: 5% of 1000 = 50 per each operator affected.", + "relayEntryTimeoutNotificationRewardMultiplier": "Percentage of the staking contract malicious behavior notification reward which will be transferred to the notifier reporting about relay entry timeout. Notifiers are rewarded from a notifiers treasury pool. For example, if notification reward is 1000 and the value of the multiplier is 5, the notifier will receive: 5% of 1000 = 50 per each operator affected.", + "sortitionPoolRewardsBanDuration": "Duration of the sortition pool rewards ban imposed on operators who misbehaved during DKG by being inactive or disqualified and for operators that were identified by the rest of group members as inactive via `notifyOperatorInactivity`.", + "unauthorizedSigningNotificationRewardMultiplier": "Percentage of the staking contract malicious behavior notification reward which will be transferred to the notifier reporting about unauthorized signing. Notifiers are rewarded from a notifiers treasury pool. For example, if a notification reward is 1000 and the value of the multiplier is 5, the notifier will receive: 5% of 1000 = 50 per each operator affected." + } + }, + "selectGroup()": { + "returns": { + "_0": "IDs of selected group members." + } + }, + "setRequesterAuthorization(address,bool)": { + "details": "Can be called only by the contract guvnor, which should be the random beacon governance contract.", + "params": { + "isAuthorized": "True or false", + "requester": "Requester, can be a contract or EOA" + } + }, + "slashingParameters()": { + "returns": { + "maliciousDkgResultSlashingAmount": "Slashing amount for submitting a malicious DKG result. Every DKG result submitted can be challenged for the time of `dkg.ResultChallengePeriodLength`. If the DKG result submitted is challenged and proven to be malicious, the operator who submitted the malicious result is slashed for `maliciousDkgResultSlashingAmount`.", + "relayEntrySubmissionFailureSlashingAmount": "Slashing amount for not submitting relay entry. When relay entry hard timeout is reached without the relay entry submitted, each group member gets slashed for `relayEntrySubmissionFailureSlashingAmount`. If the relay entry gets submitted after the soft timeout, but before the hard timeout, each group member gets slashed proportionally to `relayEntrySubmissionFailureSlashingAmount` and the time passed since the soft deadline.", + "unauthorizedSigningSlashingAmount": "Slashing amount when an unauthorized signing has been proved, which means the private key leaked and all the group members should be punished." + } + }, + "submitDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))": { + "params": { + "dkgResult": "DKG result." + } + }, + "submitRelayEntry(bytes)": { + "params": { + "entry": "Group BLS signature over the previous entry." + } + }, + "submitRelayEntry(bytes,uint32[])": { + "params": { + "entry": "Group BLS signature over the previous entry.", + "groupMembers": "Identifiers of group members." + } + }, + "updateAuthorizationParameters(uint96,uint64,uint64)": { + "details": "Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.", + "params": { + "_authorizationDecreaseChangePeriod": "New authorization decrease change period in seconds", + "_authorizationDecreaseDelay": "New authorization decrease delay in seconds", + "_minimumAuthorization": "New minimum authorization amount" + } + }, + "updateGasParameters(uint256,uint256,uint256,uint256)": { + "details": "Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.", + "params": { + "dkgResultApprovalGasOffset": "New DKG result approval gas offset", + "dkgResultSubmissionGas": "New DKG result submission gas", + "notifyOperatorInactivityGasOffset": "New operator inactivity notification gas offset", + "relayEntrySubmissionGasOffset": "New relay entry submission gas offset" + } + }, + "updateGroupCreationParameters(uint256,uint256,uint256,uint256,uint256,uint256)": { + "details": "Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.", + "params": { + "dkgResultChallengeExtraGas": "New DKG result challenge extra gas", + "dkgResultChallengePeriodLength": "New DKG result challenge period length", + "dkgResultSubmissionTimeout": "New DKG result submission timeout", + "dkgSubmitterPrecedencePeriodLength": "New DKG result submitter precedence period length", + "groupCreationFrequency": "New group creation frequency", + "groupLifetime": "New group lifetime in blocks" + } + }, + "updateRelayEntryParameters(uint256,uint256,uint256)": { + "details": "Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.", + "params": { + "callbackGasLimit": "New callback gas limit", + "relayEntryHardTimeout": "New relay entry hard timeout", + "relayEntrySoftTimeout": "New relay entry submission soft timeout" + } + }, + "updateRewardParameters(uint256,uint256,uint256,uint256)": { + "details": "Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.", + "params": { + "dkgMaliciousResultNotificationRewardMultiplier": "New value of the DKG malicious result notification reward multiplier", + "relayEntryTimeoutNotificationRewardMultiplier": "New value of the relay entry timeout notification reward multiplier", + "sortitionPoolRewardsBanDuration": "New sortition pool rewards ban duration in seconds.", + "unauthorizedSigningNotificationRewardMultiplier": "New value of the unauthorized signing notification reward multiplier" + } + }, + "updateSlashingParameters(uint96,uint96,uint96)": { + "details": "Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.", + "params": { + "maliciousDkgResultSlashingAmount": "New malicious DKG result slashing amount", + "relayEntrySubmissionFailureSlashingAmount": "New relay entry submission failure amount", + "unauthorizedSigningSlashingAmount": "New unauthorized signing slashing amount" + } + }, + "withdrawIneligibleRewards(address)": { + "details": "Can be called only by the contract guvnor, which should be the random beacon governance contract.", + "params": { + "recipient": "Recipient of withdrawn rewards." + } + }, + "withdrawRewards(address)": { + "details": "Emits `RewardsWithdrawn` event." + } + }, + "title": "Keep Random Beacon", + "version": 1 + }, + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract SortitionPool\",\"name\":\"_sortitionPool\",\"type\":\"address\"},{\"internalType\":\"contract IERC20\",\"name\":\"_tToken\",\"type\":\"address\"},{\"internalType\":\"contract IStaking\",\"name\":\"_staking\",\"type\":\"address\"},{\"internalType\":\"contract BeaconDkgValidator\",\"name\":\"_dkgValidator\",\"type\":\"address\"},{\"internalType\":\"contract ReimbursementPool\",\"name\":\"_reimbursementPool\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"}],\"name\":\"AuthorizationDecreaseApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"fromAmount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"toAmount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"decreasingAt\",\"type\":\"uint64\"}],\"name\":\"AuthorizationDecreaseRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"fromAmount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"toAmount\",\"type\":\"uint96\"}],\"name\":\"AuthorizationIncreased\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"minimumAuthorization\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"authorizationDecreaseDelay\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"authorizationDecreaseChangePeriod\",\"type\":\"uint64\"}],\"name\":\"AuthorizationParametersUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"entry\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"entrySubmittedBlock\",\"type\":\"uint256\"}],\"name\":\"CallbackFailed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"resultHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"slashingAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"maliciousSubmitter\",\"type\":\"address\"}],\"name\":\"DkgMaliciousResultSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"resultHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"slashingAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"maliciousSubmitter\",\"type\":\"address\"}],\"name\":\"DkgMaliciousResultSlashingFailed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"resultHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"approver\",\"type\":\"address\"}],\"name\":\"DkgResultApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"resultHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"reason\",\"type\":\"string\"}],\"name\":\"DkgResultChallenged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"resultHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"submitterMemberIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"},{\"internalType\":\"uint8[]\",\"name\":\"misbehavedMembersIndices\",\"type\":\"uint8[]\"},{\"internalType\":\"bytes\",\"name\":\"signatures\",\"type\":\"bytes\"},{\"internalType\":\"uint256[]\",\"name\":\"signingMembersIndices\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32[]\",\"name\":\"members\",\"type\":\"uint32[]\"},{\"internalType\":\"bytes32\",\"name\":\"membersHash\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"struct BeaconDkg.Result\",\"name\":\"result\",\"type\":\"tuple\"}],\"name\":\"DkgResultSubmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"DkgSeedTimedOut\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"}],\"name\":\"DkgStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"DkgStateLocked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"DkgTimedOut\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgResultSubmissionGas\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgResultApprovalGasOffset\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"notifyOperatorInactivityGasOffset\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"relayEntrySubmissionGasOffset\",\"type\":\"uint256\"}],\"name\":\"GasParametersUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldGovernance\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newGovernance\",\"type\":\"address\"}],\"name\":\"GovernanceTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"groupCreationFrequency\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"groupLifetime\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgResultChallengePeriodLength\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgResultChallengeExtraGas\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgResultSubmissionTimeout\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgResultSubmitterPrecedencePeriodLength\",\"type\":\"uint256\"}],\"name\":\"GroupCreationParametersUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"groupId\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"}],\"name\":\"GroupRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"groupId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"notifier\",\"type\":\"address\"}],\"name\":\"InactivityClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"fromAmount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"toAmount\",\"type\":\"uint96\"}],\"name\":\"InvoluntaryAuthorizationDecreaseFailed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"OperatorJoinedSortitionPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"OperatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"OperatorStatusUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newReimbursementPool\",\"type\":\"address\"}],\"name\":\"ReimbursementPoolUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"slashingAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"groupMembers\",\"type\":\"address[]\"}],\"name\":\"RelayEntryDelaySlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"slashingAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"groupMembers\",\"type\":\"address[]\"}],\"name\":\"RelayEntryDelaySlashingFailed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"relayEntrySoftTimeout\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"relayEntryHardTimeout\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"callbackGasLimit\",\"type\":\"uint256\"}],\"name\":\"RelayEntryParametersUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"groupId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"previousEntry\",\"type\":\"bytes\"}],\"name\":\"RelayEntryRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"entry\",\"type\":\"bytes\"}],\"name\":\"RelayEntrySubmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"terminatedGroupId\",\"type\":\"uint64\"}],\"name\":\"RelayEntryTimedOut\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"slashingAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"groupMembers\",\"type\":\"address[]\"}],\"name\":\"RelayEntryTimeoutSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"slashingAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"groupMembers\",\"type\":\"address[]\"}],\"name\":\"RelayEntryTimeoutSlashingFailed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isAuthorized\",\"type\":\"bool\"}],\"name\":\"RequesterAuthorizationUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"sortitionPoolRewardsBanDuration\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"relayEntryTimeoutNotificationRewardMultiplier\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"unauthorizedSigningNotificationRewardMultiplier\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgMaliciousResultNotificationRewardMultiplier\",\"type\":\"uint256\"}],\"name\":\"RewardParametersUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"RewardsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"relayEntrySubmissionFailureSlashingAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"maliciousDkgResultSlashingAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"unauthorizedSigningSlashingAmount\",\"type\":\"uint256\"}],\"name\":\"SlashingParametersUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"groupId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"unauthorizedSigningSlashingAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"groupMembers\",\"type\":\"address[]\"}],\"name\":\"UnauthorizedSigningSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"groupId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"unauthorizedSigningSlashingAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"groupMembers\",\"type\":\"address[]\"}],\"name\":\"UnauthorizedSigningSlashingFailed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"}],\"name\":\"approveAuthorizationDecrease\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"submitterMemberIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"},{\"internalType\":\"uint8[]\",\"name\":\"misbehavedMembersIndices\",\"type\":\"uint8[]\"},{\"internalType\":\"bytes\",\"name\":\"signatures\",\"type\":\"bytes\"},{\"internalType\":\"uint256[]\",\"name\":\"signingMembersIndices\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32[]\",\"name\":\"members\",\"type\":\"uint32[]\"},{\"internalType\":\"bytes32\",\"name\":\"membersHash\",\"type\":\"bytes32\"}],\"internalType\":\"struct BeaconDkg.Result\",\"name\":\"dkgResult\",\"type\":\"tuple\"}],\"name\":\"approveDkgResult\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"fromAmount\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"toAmount\",\"type\":\"uint96\"}],\"name\":\"authorizationDecreaseRequested\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"fromAmount\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"toAmount\",\"type\":\"uint96\"}],\"name\":\"authorizationIncreased\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"authorizationParameters\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"minimumAuthorization\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"authorizationDecreaseDelay\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"authorizationDecreaseChangePeriod\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"authorizedRequesters\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"}],\"name\":\"availableRewards\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"submitterMemberIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"},{\"internalType\":\"uint8[]\",\"name\":\"misbehavedMembersIndices\",\"type\":\"uint8[]\"},{\"internalType\":\"bytes\",\"name\":\"signatures\",\"type\":\"bytes\"},{\"internalType\":\"uint256[]\",\"name\":\"signingMembersIndices\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32[]\",\"name\":\"members\",\"type\":\"uint32[]\"},{\"internalType\":\"bytes32\",\"name\":\"membersHash\",\"type\":\"bytes32\"}],\"internalType\":\"struct BeaconDkg.Result\",\"name\":\"dkgResult\",\"type\":\"tuple\"}],\"name\":\"challengeDkgResult\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"}],\"name\":\"eligibleStake\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gasParameters\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"dkgResultSubmissionGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgResultApprovalGasOffset\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"notifyOperatorInactivityGasOffset\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"relayEntrySubmissionGasOffset\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"genesis\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"groupId\",\"type\":\"uint64\"}],\"name\":\"getGroup\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"registrationBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"membersHash\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"terminated\",\"type\":\"bool\"}],\"internalType\":\"struct Groups.Group\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"}],\"name\":\"getGroup\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"registrationBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"membersHash\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"terminated\",\"type\":\"bool\"}],\"internalType\":\"struct Groups.Group\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGroupCreationState\",\"outputs\":[{\"internalType\":\"enum BeaconDkg.State\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGroupsRegistry\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governance\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"groupCreationParameters\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"groupCreationFrequency\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"groupLifetime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgResultChallengePeriodLength\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgResultChallengeExtraGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgResultSubmissionTimeout\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgSubmitterPrecedencePeriodLength\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hasDkgTimedOut\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"name\":\"inactivityClaimNonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"fromAmount\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"toAmount\",\"type\":\"uint96\"}],\"name\":\"involuntaryAuthorizationDecrease\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isOperatorInPool\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isOperatorUpToDate\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isRelayRequestInProgress\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"joinSortitionPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minimumAuthorization\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"notifyDkgTimeout\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"groupId\",\"type\":\"uint64\"},{\"internalType\":\"uint256[]\",\"name\":\"inactiveMembersIndices\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"signatures\",\"type\":\"bytes\"},{\"internalType\":\"uint256[]\",\"name\":\"signingMembersIndices\",\"type\":\"uint256[]\"}],\"internalType\":\"struct BeaconInactivity.Claim\",\"name\":\"claim\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint32[]\",\"name\":\"groupMembers\",\"type\":\"uint32[]\"}],\"name\":\"notifyOperatorInactivity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"operatorToStakingProvider\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"}],\"name\":\"pendingAuthorizationDecrease\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"registerOperator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reimbursementPool\",\"outputs\":[{\"internalType\":\"contract ReimbursementPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"relayEntryParameters\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"relayEntrySoftTimeout\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"relayEntryHardTimeout\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callbackGasLimit\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"}],\"name\":\"remainingAuthorizationDecreaseDelay\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32[]\",\"name\":\"groupMembers\",\"type\":\"uint32[]\"}],\"name\":\"reportRelayEntryTimeout\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"signedMsgSender\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"groupId\",\"type\":\"uint64\"},{\"internalType\":\"uint32[]\",\"name\":\"groupMembers\",\"type\":\"uint32[]\"}],\"name\":\"reportUnauthorizedSigning\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IRandomBeaconConsumer\",\"name\":\"callbackContract\",\"type\":\"address\"}],\"name\":\"requestRelayEntry\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardParameters\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"sortitionPoolRewardsBanDuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"relayEntryTimeoutNotificationRewardMultiplier\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unauthorizedSigningNotificationRewardMultiplier\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgMaliciousResultNotificationRewardMultiplier\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"selectGroup\",\"outputs\":[{\"internalType\":\"uint32[]\",\"name\":\"\",\"type\":\"uint32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"isAuthorized\",\"type\":\"bool\"}],\"name\":\"setRequesterAuthorization\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"slashingParameters\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"relayEntrySubmissionFailureSlashingAmount\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"maliciousDkgResultSlashingAmount\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"unauthorizedSigningSlashingAmount\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sortitionPool\",\"outputs\":[{\"internalType\":\"contract SortitionPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"staking\",\"outputs\":[{\"internalType\":\"contract IStaking\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"}],\"name\":\"stakingProviderToOperator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"submitterMemberIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"},{\"internalType\":\"uint8[]\",\"name\":\"misbehavedMembersIndices\",\"type\":\"uint8[]\"},{\"internalType\":\"bytes\",\"name\":\"signatures\",\"type\":\"bytes\"},{\"internalType\":\"uint256[]\",\"name\":\"signingMembersIndices\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32[]\",\"name\":\"members\",\"type\":\"uint32[]\"},{\"internalType\":\"bytes32\",\"name\":\"membersHash\",\"type\":\"bytes32\"}],\"internalType\":\"struct BeaconDkg.Result\",\"name\":\"dkgResult\",\"type\":\"tuple\"}],\"name\":\"submitDkgResult\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"entry\",\"type\":\"bytes\"},{\"internalType\":\"uint32[]\",\"name\":\"groupMembers\",\"type\":\"uint32[]\"}],\"name\":\"submitRelayEntry\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"entry\",\"type\":\"bytes\"}],\"name\":\"submitRelayEntry\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"tToken\",\"outputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newGovernance\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"_minimumAuthorization\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"_authorizationDecreaseDelay\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"_authorizationDecreaseChangePeriod\",\"type\":\"uint64\"}],\"name\":\"updateAuthorizationParameters\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"dkgResultSubmissionGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgResultApprovalGasOffset\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"notifyOperatorInactivityGasOffset\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"relayEntrySubmissionGasOffset\",\"type\":\"uint256\"}],\"name\":\"updateGasParameters\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"groupCreationFrequency\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"groupLifetime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgResultChallengePeriodLength\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgResultChallengeExtraGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgResultSubmissionTimeout\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgSubmitterPrecedencePeriodLength\",\"type\":\"uint256\"}],\"name\":\"updateGroupCreationParameters\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"updateOperatorStatus\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract ReimbursementPool\",\"name\":\"_reimbursementPool\",\"type\":\"address\"}],\"name\":\"updateReimbursementPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"relayEntrySoftTimeout\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"relayEntryHardTimeout\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callbackGasLimit\",\"type\":\"uint256\"}],\"name\":\"updateRelayEntryParameters\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"sortitionPoolRewardsBanDuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"relayEntryTimeoutNotificationRewardMultiplier\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unauthorizedSigningNotificationRewardMultiplier\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgMaliciousResultNotificationRewardMultiplier\",\"type\":\"uint256\"}],\"name\":\"updateRewardParameters\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"relayEntrySubmissionFailureSlashingAmount\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"maliciousDkgResultSlashingAmount\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"unauthorizedSigningSlashingAmount\",\"type\":\"uint96\"}],\"name\":\"updateSlashingParameters\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"withdrawIneligibleRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"}],\"name\":\"withdrawRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Should be owned by the governance contract controlling Random Beacon parameters.\",\"kind\":\"dev\",\"methods\":{\"approveDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))\":{\"params\":{\"dkgResult\":\"Result to approve. Must match the submitted result stored during `submitDkgResult`.\"}},\"authorizationDecreaseRequested(address,uint96,uint96)\":{\"details\":\"Can only be called by T staking contract.\"},\"authorizationIncreased(address,uint96,uint96)\":{\"details\":\"Can only be called by T staking contract.\"},\"authorizationParameters()\":{\"details\":\"The minimum authorization is also returned by `minimumAuthorization()` function, as a requirement of `IApplication` interface.\",\"returns\":{\"authorizationDecreaseChangePeriod\":\"Authorization decrease change period in seconds. It is the time, before authorization decrease delay end, during which the pending authorization decrease request can be overwritten. If set to 0, pending authorization decrease request can not be overwritten until the entire `authorizationDecreaseDelay` ends. If set to value equal `authorizationDecreaseDelay`, request can always be overwritten.\",\"authorizationDecreaseDelay\":\"Delay in seconds that needs to pass between the time authorization decrease is requested and the time that request gets approved. Protects against free-riders earning rewards and not being active in the network.\",\"minimumAuthorization\":\"The minimum authorization amount required so that operator can participate in the random beacon. This amount is required to execute slashing for providing a malicious DKG result or when a relay entry times out.\"}},\"challengeDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))\":{\"details\":\"Due to EIP-150 1/64 of the gas is not forwarded to the call, and will be kept to execute the remaining operations in the function after the call inside the try-catch. To eliminate a class of attacks related to the gas limit manipulation, this function requires an extra amount of gas to be left at the end of the execution.\",\"params\":{\"dkgResult\":\"Result to challenge. Must match the submitted result stored during `submitDkgResult`.\"}},\"constructor\":{\"details\":\"Assigns initial values to parameters to make the beacon work safely. These parameters are just proposed defaults and they might be updated with `update*` functions after the contract deployment and before transferring the ownership to the governance contract.\"},\"gasParameters()\":{\"returns\":{\"dkgResultApprovalGasOffset\":\"Gas that is meant to balance the DKG result approval's overall cost.\",\"dkgResultSubmissionGas\":\"Calculated gas cost for submitting a DKG result. This will be refunded as part of the DKG approval process.\",\"notifyOperatorInactivityGasOffset\":\"Gas that is meant to balance the operator inactivity notification cost.\",\"relayEntrySubmissionGasOffset\":\"Gas that is meant to balance the relay entry submission cost.\"}},\"groupCreationParameters()\":{\"returns\":{\"dkgResultChallengeExtraGas\":\"The extra gas required to be left at the end of the challenge DKG result transaction.\",\"dkgResultChallengePeriodLength\":\"The number of blocks for which a DKG result can be challenged. Anyone can challenge DKG result for a certain number of blocks before the result is fully accepted and the group registered in the pool of active groups. If the challenge gets accepted, all operators who signed the malicious result get slashed for and the notifier gets rewarded.\",\"dkgResultSubmissionTimeout\":\"Timeout in blocks for a group to submit the DKG result. All members are eligible to submit the DKG result. If `dkgResultSubmissionTimeout` passes without the DKG result submitted, DKG is considered as timed out and no DKG result for this group creation can be submitted anymore.\",\"dkgSubmitterPrecedencePeriodLength\":\"Time during the DKG result approval stage when the submitter of the DKG result takes the precedence to approve the DKG result. After this time passes anyone can approve the DKG result.\",\"groupCreationFrequency\":\"The frequency of a new group creation. Groups are created with a fixed frequency of relay requests.\",\"groupLifetime\":\"Group lifetime in blocks. When a group reached its lifetime, it is no longer selected for new relay requests but may still be responsible for submitting relay entry if relay request assigned to that group is still pending.\"}},\"hasDkgTimedOut()\":{\"returns\":{\"_0\":\"True if DKG timed out, false otherwise.\"}},\"isRelayRequestInProgress()\":{\"returns\":{\"_0\":\"Flag indicating whether a relay entry request is currently in progress.\"}},\"notifyOperatorInactivity((uint64,uint256[],bytes,uint256[]),uint256,uint32[])\":{\"params\":{\"claim\":\"Operator inactivity claim.\",\"groupMembers\":\"Identifiers of group members.\",\"nonce\":\"Current inactivity claim nonce for the given group. Must be the same as the stored one.\"}},\"relayEntryParameters()\":{\"returns\":{\"callbackGasLimit\":\"Relay entry callback gas limit. This is the gas limit with which callback function provided in the relay request transaction is executed. The callback is executed with a new relay entry value in the same transaction the relay entry is submitted.\",\"relayEntryHardTimeout\":\"Hard timeout in blocks for a group to submit the relay entry. After the soft timeout passes without relay entry submitted, all group members start getting slashed. The slashing amount increases linearly until the group submits the relay entry or until `relayEntryHardTimeout` is reached. When the hard timeout is reached, each group member will get slashed for `_relayEntrySubmissionFailureSlashingAmount`.\",\"relayEntrySoftTimeout\":\"Soft timeout in blocks for a group to submit the relay entry. If the soft timeout is reached for submitting the relay entry, the slashing starts.\"}},\"reportRelayEntryTimeout(uint32[])\":{\"params\":{\"groupMembers\":\"Identifiers of group members.\"}},\"reportUnauthorizedSigning(bytes,uint64,uint32[])\":{\"params\":{\"groupId\":\"Group that is being reported for leaking a private key.\",\"groupMembers\":\"Identifiers of group members.\",\"signedMsgSender\":\"Signature of the sender's address as a message.\"}},\"requestRelayEntry(address)\":{\"params\":{\"callbackContract\":\"Beacon consumer callback contract.\"}},\"rewardParameters()\":{\"returns\":{\"dkgMaliciousResultNotificationRewardMultiplier\":\"Percentage of the staking contract malicious behavior notification reward which will be transferred to the notifier reporting about a malicious DKG result. Notifiers are rewarded from a notifiers treasury pool. For example, if notification reward is 1000 and the value of the multiplier is 5, the notifier will receive: 5% of 1000 = 50 per each operator affected.\",\"relayEntryTimeoutNotificationRewardMultiplier\":\"Percentage of the staking contract malicious behavior notification reward which will be transferred to the notifier reporting about relay entry timeout. Notifiers are rewarded from a notifiers treasury pool. For example, if notification reward is 1000 and the value of the multiplier is 5, the notifier will receive: 5% of 1000 = 50 per each operator affected.\",\"sortitionPoolRewardsBanDuration\":\"Duration of the sortition pool rewards ban imposed on operators who misbehaved during DKG by being inactive or disqualified and for operators that were identified by the rest of group members as inactive via `notifyOperatorInactivity`.\",\"unauthorizedSigningNotificationRewardMultiplier\":\"Percentage of the staking contract malicious behavior notification reward which will be transferred to the notifier reporting about unauthorized signing. Notifiers are rewarded from a notifiers treasury pool. For example, if a notification reward is 1000 and the value of the multiplier is 5, the notifier will receive: 5% of 1000 = 50 per each operator affected.\"}},\"selectGroup()\":{\"returns\":{\"_0\":\"IDs of selected group members.\"}},\"setRequesterAuthorization(address,bool)\":{\"details\":\"Can be called only by the contract guvnor, which should be the random beacon governance contract.\",\"params\":{\"isAuthorized\":\"True or false\",\"requester\":\"Requester, can be a contract or EOA\"}},\"slashingParameters()\":{\"returns\":{\"maliciousDkgResultSlashingAmount\":\"Slashing amount for submitting a malicious DKG result. Every DKG result submitted can be challenged for the time of `dkg.ResultChallengePeriodLength`. If the DKG result submitted is challenged and proven to be malicious, the operator who submitted the malicious result is slashed for `maliciousDkgResultSlashingAmount`.\",\"relayEntrySubmissionFailureSlashingAmount\":\"Slashing amount for not submitting relay entry. When relay entry hard timeout is reached without the relay entry submitted, each group member gets slashed for `relayEntrySubmissionFailureSlashingAmount`. If the relay entry gets submitted after the soft timeout, but before the hard timeout, each group member gets slashed proportionally to `relayEntrySubmissionFailureSlashingAmount` and the time passed since the soft deadline.\",\"unauthorizedSigningSlashingAmount\":\"Slashing amount when an unauthorized signing has been proved, which means the private key leaked and all the group members should be punished.\"}},\"submitDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))\":{\"params\":{\"dkgResult\":\"DKG result.\"}},\"submitRelayEntry(bytes)\":{\"params\":{\"entry\":\"Group BLS signature over the previous entry.\"}},\"submitRelayEntry(bytes,uint32[])\":{\"params\":{\"entry\":\"Group BLS signature over the previous entry.\",\"groupMembers\":\"Identifiers of group members.\"}},\"updateAuthorizationParameters(uint96,uint64,uint64)\":{\"details\":\"Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.\",\"params\":{\"_authorizationDecreaseChangePeriod\":\"New authorization decrease change period in seconds\",\"_authorizationDecreaseDelay\":\"New authorization decrease delay in seconds\",\"_minimumAuthorization\":\"New minimum authorization amount\"}},\"updateGasParameters(uint256,uint256,uint256,uint256)\":{\"details\":\"Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.\",\"params\":{\"dkgResultApprovalGasOffset\":\"New DKG result approval gas offset\",\"dkgResultSubmissionGas\":\"New DKG result submission gas\",\"notifyOperatorInactivityGasOffset\":\"New operator inactivity notification gas offset\",\"relayEntrySubmissionGasOffset\":\"New relay entry submission gas offset\"}},\"updateGroupCreationParameters(uint256,uint256,uint256,uint256,uint256,uint256)\":{\"details\":\"Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.\",\"params\":{\"dkgResultChallengeExtraGas\":\"New DKG result challenge extra gas\",\"dkgResultChallengePeriodLength\":\"New DKG result challenge period length\",\"dkgResultSubmissionTimeout\":\"New DKG result submission timeout\",\"dkgSubmitterPrecedencePeriodLength\":\"New DKG result submitter precedence period length\",\"groupCreationFrequency\":\"New group creation frequency\",\"groupLifetime\":\"New group lifetime in blocks\"}},\"updateRelayEntryParameters(uint256,uint256,uint256)\":{\"details\":\"Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.\",\"params\":{\"callbackGasLimit\":\"New callback gas limit\",\"relayEntryHardTimeout\":\"New relay entry hard timeout\",\"relayEntrySoftTimeout\":\"New relay entry submission soft timeout\"}},\"updateRewardParameters(uint256,uint256,uint256,uint256)\":{\"details\":\"Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.\",\"params\":{\"dkgMaliciousResultNotificationRewardMultiplier\":\"New value of the DKG malicious result notification reward multiplier\",\"relayEntryTimeoutNotificationRewardMultiplier\":\"New value of the relay entry timeout notification reward multiplier\",\"sortitionPoolRewardsBanDuration\":\"New sortition pool rewards ban duration in seconds.\",\"unauthorizedSigningNotificationRewardMultiplier\":\"New value of the unauthorized signing notification reward multiplier\"}},\"updateSlashingParameters(uint96,uint96,uint96)\":{\"details\":\"Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.\",\"params\":{\"maliciousDkgResultSlashingAmount\":\"New malicious DKG result slashing amount\",\"relayEntrySubmissionFailureSlashingAmount\":\"New relay entry submission failure amount\",\"unauthorizedSigningSlashingAmount\":\"New unauthorized signing slashing amount\"}},\"withdrawIneligibleRewards(address)\":{\"details\":\"Can be called only by the contract guvnor, which should be the random beacon governance contract.\",\"params\":{\"recipient\":\"Recipient of withdrawn rewards.\"}},\"withdrawRewards(address)\":{\"details\":\"Emits `RewardsWithdrawn` event.\"}},\"title\":\"Keep Random Beacon\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"approveAuthorizationDecrease(address)\":{\"notice\":\"Approves the previously registered authorization decrease request. Reverts if authorization decrease delay has not passed yet or if the authorization decrease was not requested for the given staking provider.\"},\"approveDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))\":{\"notice\":\"Approves DKG result. Can be called when the challenge period for the submitted result is finished. Considers the submitted result as valid, bans misbehaved group members from the sortition pool rewards, and completes the group creation by activating the candidate group. For the first `submitterPrecedencePeriodLength` blocks after the end of the challenge period can be called only by the DKG result submitter. After that time, can be called by anyone.\"},\"authorizationDecreaseRequested(address,uint96,uint96)\":{\"notice\":\"Used by T staking contract to inform the beacon that the authorization decrease for the given staking provider has been requested. Reverts if the amount after deauthorization would be non-zero and lower than the minimum authorization. Reverts if another authorization decrease request is pending for the staking provider and not enough time passed since the original request (see `authorizationDecreaseChangePeriod`). If the operator is not known (`registerOperator` was not called) it lets to `approveAuthorizationDecrease` immediately. If the operator is known (`registerOperator` was called), the operator needs to update state of the sortition pool with a call to `joinSortitionPool` or `updateOperatorStatus`. After the sortition pool state is in sync, authorization decrease delay starts. After authorization decrease delay passes, authorization decrease request needs to be approved with a call to `approveAuthorizationDecrease` function. If there is a pending authorization decrease request, it is overwritten, but only if enough time passed since the original request. Otherwise, the function reverts.\"},\"authorizationIncreased(address,uint96,uint96)\":{\"notice\":\"Used by T staking contract to inform the beacon that the authorized stake amount for the given staking provider increased. Reverts if the authorization amount is below the minimum. The function is not updating the sortition pool. Sortition pool state needs to be updated by the operator with a call to `joinSortitionPool` or `updateOperatorStatus`.\"},\"authorizationParameters()\":{\"notice\":\"Returns authorization-related parameters of the beacon.\"},\"authorizedRequesters(address)\":{\"notice\":\"Authorized addresses that can request a relay entry.\"},\"availableRewards(address)\":{\"notice\":\"Returns the amount of rewards available for withdrawal for the given staking provider. Reverts if staking provider has not registered the operator address.\"},\"challengeDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))\":{\"notice\":\"Challenges DKG result. If the submitted result is proved to be invalid it reverts the DKG back to the result submission phase. It removes a candidate group that was previously registered with the DKG result submission.\"},\"eligibleStake(address)\":{\"notice\":\"Returns the current value of the staking provider's eligible stake. Eligible stake is defined as the currently authorized stake minus the pending authorization decrease. Eligible stake is what is used for operator's weight in the sortition pool. If the authorized stake minus the pending authorization decrease is below the minimum authorization, eligible stake is 0.\"},\"gasParameters()\":{\"notice\":\"Returns gas-related parameters of the beacon.\"},\"genesis()\":{\"notice\":\"Triggers group selection if there are no active groups.\"},\"getGroupCreationState()\":{\"notice\":\"Check current group creation state.\"},\"groupCreationParameters()\":{\"notice\":\"Returns group-creation-related parameters of the beacon.\"},\"hasDkgTimedOut()\":{\"notice\":\"Checks if DKG timed out. The DKG timeout period includes time required for off-chain protocol execution and time for the result publication for all group members. After this time result cannot be submitted and DKG can be notified about the timeout.\"},\"inactivityClaimNonce(uint64)\":{\"notice\":\"Stores current operator inactivity claim nonce for given group. Each claim is made with an unique nonce which protects against claim replay.\"},\"involuntaryAuthorizationDecrease(address,uint96,uint96)\":{\"notice\":\"Used by T staking contract to inform the beacon the authorization has been decreased for the given staking provider involuntarily, as a result of slashing. If the operator is not known (`registerOperator` was not called) the function does nothing. The operator was never in a sortition pool so there is nothing to update. If the operator is known, sortition pool is unlocked, and the operator is in the sortition pool, the sortition pool state is updated. If the sortition pool is locked, update needs to be postponed. Every other staker is incentivized to call `updateOperatorStatus` for the problematic operator to increase their own rewards in the pool.\"},\"isOperatorInPool(address)\":{\"notice\":\"Returns true if the given operator is in the sortition pool. Otherwise, returns false.\"},\"isOperatorUpToDate(address)\":{\"notice\":\"Checks if the operator's authorized stake is in sync with operator's weight in the sortition pool. If the operator is not in the sortition pool and their authorized stake is non-zero, function returns false.\"},\"joinSortitionPool()\":{\"notice\":\"Lets the operator join the sortition pool. The operator address must be known - before calling this function, it has to be appointed by the staking provider by calling `registerOperator`. Also, the operator must have the minimum authorization required by the beacon. Function reverts if there is no minimum stake authorized or if the operator is not known. If there was an authorization decrease requested, it is activated by starting the authorization decrease delay.\"},\"minimumAuthorization()\":{\"notice\":\"The minimum authorization amount required so that operator can participate in the random beacon. This amount is required to execute slashing for providing a malicious DKG result or when a relay entry times out.\"},\"notifyDkgTimeout()\":{\"notice\":\"Notifies about DKG timeout.\"},\"notifyOperatorInactivity((uint64,uint256[],bytes,uint256[]),uint256,uint32[])\":{\"notice\":\"Notifies about operators who are inactive. Using this function, a majority of the group can decide about punishing specific group members who constantly fail doing their job. If the provided claim is proved to be valid and signed by sufficient number of group members, operators of members deemed as inactive are banned for sortition pool rewards for duration specified by `_sortitionPoolRewardsBanDuration` parameter. The sender of the claim must be one of the claim signers. This function can be called only for active and non-terminated groups.\"},\"operatorToStakingProvider(address)\":{\"notice\":\"Returns staking provider of the given operator.\"},\"pendingAuthorizationDecrease(address)\":{\"notice\":\"Returns the amount of stake that is pending authorization decrease for the given staking provider. If no authorization decrease has been requested, returns zero.\"},\"registerOperator(address)\":{\"notice\":\"Used by staking provider to set operator address that will operate a node. The given staking provider can set operator address only one time. The operator address can not be changed and must be unique. Reverts if the operator is already set for the staking provider or if the operator address is already in use. Reverts if there is a pending authorization decrease for the staking provider.\"},\"relayEntryParameters()\":{\"notice\":\"Returns relay-entry-related parameters of the beacon.\"},\"remainingAuthorizationDecreaseDelay(address)\":{\"notice\":\"Returns the remaining time in seconds that needs to pass before the requested authorization decrease can be approved. If the sortition pool state was not updated yet by the operator after requesting the authorization decrease, returns `type(uint64).max`.\"},\"reportRelayEntryTimeout(uint32[])\":{\"notice\":\"Reports a relay entry timeout.\"},\"reportUnauthorizedSigning(bytes,uint64,uint32[])\":{\"notice\":\"Reports unauthorized groups signing. Must provide a valid signature of the sender's address as a message. Successful signature verification means the private key has been leaked and all group members should be punished by slashing their tokens. Group has to be active or expired. Unauthorized signing cannot be reported for a terminated group. In case of reporting unauthorized signing for a terminated group, or when the signature is invalid, function reverts.\"},\"requestRelayEntry(address)\":{\"notice\":\"Creates a request to generate a new relay entry, which will include a random number (by signing the previous entry's random number). Requester must be previously authorized by the governance.\"},\"rewardParameters()\":{\"notice\":\"Returns reward-related parameters of the beacon.\"},\"selectGroup()\":{\"notice\":\"Selects a new group of operators. Can only be called when DKG is in progress and the pool is locked. At least one operator has to be registered in the pool, otherwise the function fails reverting the transaction.\"},\"setRequesterAuthorization(address,bool)\":{\"notice\":\"Set authorization for requesters that can request a relay entry.\"},\"slashingParameters()\":{\"notice\":\"Returns slashing-related parameters of the beacon.\"},\"stakingProviderToOperator(address)\":{\"notice\":\"Returns operator registered for the given staking provider.\"},\"submitDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))\":{\"notice\":\"`\\\\x19Ethereum signed message:\\\\n` before signing, so the message to sign is: `\\\\x19Ethereum signed message:\\\\n${keccak256(chainID,groupPubKey,misbehaved,startBlock)}`\"},\"submitRelayEntry(bytes)\":{\"notice\":\"Creates a new relay entry. Gas-optimized version that can be called only before the soft timeout. This should be the majority of cases.\"},\"submitRelayEntry(bytes,uint32[])\":{\"notice\":\"Creates a new relay entry.\"},\"transferGovernance(address)\":{\"notice\":\"Transfers governance of the contract to `newGovernance`.\"},\"updateAuthorizationParameters(uint96,uint64,uint64)\":{\"notice\":\"Updates the values of authorization parameters.\"},\"updateGasParameters(uint256,uint256,uint256,uint256)\":{\"notice\":\"Updates the values of gas parameters.\"},\"updateGroupCreationParameters(uint256,uint256,uint256,uint256,uint256,uint256)\":{\"notice\":\"Updates the values of group creation parameters.\"},\"updateOperatorStatus(address)\":{\"notice\":\"Updates status of the operator in the sortition pool. If there was an authorization decrease requested, it is activated by starting the authorization decrease delay. Function reverts if the operator is not known.\"},\"updateRelayEntryParameters(uint256,uint256,uint256)\":{\"notice\":\"Updates the values of relay entry parameters.\"},\"updateRewardParameters(uint256,uint256,uint256,uint256)\":{\"notice\":\"Updates the values of reward parameters.\"},\"updateSlashingParameters(uint96,uint96,uint96)\":{\"notice\":\"Updates the values of slashing parameters.\"},\"withdrawIneligibleRewards(address)\":{\"notice\":\"Withdraws rewards belonging to operators marked as ineligible for sortition pool rewards.\"},\"withdrawRewards(address)\":{\"notice\":\"Withdraws application rewards for the given staking provider. Rewards are withdrawn to the staking provider's beneficiary address set in the staking contract. Reverts if staking provider has not registered the operator address.\"}},\"notice\":\"Keep Random Beacon contract. It lets to request a new relay entry and validates the new relay entry provided by the network. This contract is in charge of all other Random Beacon activities such as group lifecycle or slashing.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/RandomBeacon.sol\":\"RandomBeacon\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@keep-network/sortition-pools/contracts/Branch.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\n/// @notice The implicit 8-ary trees of the sortition pool\\n/// rely on packing 8 \\\"slots\\\" of 32-bit values into each uint256.\\n/// The Branch library permits efficient calculations on these slots.\\nlibrary Branch {\\n /// @notice Calculate the right shift required\\n /// to make the 32 least significant bits of an uint256\\n /// be the bits of the `position`th slot\\n /// when treating the uint256 as a uint32[8].\\n ///\\n /// @dev Not used for efficiency reasons,\\n /// but left to illustrate the meaning of a common pattern.\\n /// I wish solidity had macros, even C macros.\\n function slotShift(uint256 position) internal pure returns (uint256) {\\n unchecked {\\n return position * Constants.SLOT_WIDTH;\\n }\\n }\\n\\n /// @notice Return the `position`th slot of the `node`,\\n /// treating `node` as a uint32[32].\\n function getSlot(uint256 node, uint256 position)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Doing a bitwise AND with `SLOT_MAX`\\n // clears all but the 32 least significant bits.\\n // Because of the right shift by `slotShift(position)` bits,\\n // those 32 bits contain the 32 bits in the `position`th slot of `node`.\\n return (node >> shiftBits) & Constants.SLOT_MAX;\\n }\\n }\\n\\n /// @notice Return `node` with the `position`th slot set to zero.\\n function clearSlot(uint256 node, uint256 position)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Shifting `SLOT_MAX` left by `slotShift(position)` bits\\n // gives us a number where all bits of the `position`th slot are set,\\n // and all other bits are unset.\\n //\\n // Using a bitwise NOT on this number,\\n // we get a uint256 where all bits are set\\n // except for those of the `position`th slot.\\n //\\n // Bitwise ANDing the original `node` with this number\\n // sets the bits of `position`th slot to zero,\\n // leaving all other bits unchanged.\\n return node & ~(Constants.SLOT_MAX << shiftBits);\\n }\\n }\\n\\n /// @notice Return `node` with the `position`th slot set to `weight`.\\n ///\\n /// @param weight The weight of of the node.\\n /// Safely truncated to a 32-bit number,\\n /// but this should never be called with an overflowing weight regardless.\\n function setSlot(\\n uint256 node,\\n uint256 position,\\n uint256 weight\\n ) internal pure returns (uint256) {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Clear the `position`th slot like in `clearSlot()`.\\n uint256 clearedNode = node & ~(Constants.SLOT_MAX << shiftBits);\\n // Bitwise AND `weight` with `SLOT_MAX`\\n // to clear all but the 32 least significant bits.\\n //\\n // Shift this left by `slotShift(position)` bits\\n // to obtain a uint256 with all bits unset\\n // except in the `position`th slot\\n // which contains the 32-bit value of `weight`.\\n uint256 shiftedWeight = (weight & Constants.SLOT_MAX) << shiftBits;\\n // When we bitwise OR these together,\\n // all other slots except the `position`th one come from the left argument,\\n // and the `position`th gets filled with `weight` from the right argument.\\n return clearedNode | shiftedWeight;\\n }\\n }\\n\\n /// @notice Calculate the summed weight of all slots in the `node`.\\n function sumWeight(uint256 node) internal pure returns (uint256 sum) {\\n unchecked {\\n sum = node & Constants.SLOT_MAX;\\n // Iterate through each slot\\n // by shifting `node` right in increments of 32 bits,\\n // and adding the 32 least significant bits to the `sum`.\\n uint256 newNode = node >> Constants.SLOT_WIDTH;\\n while (newNode > 0) {\\n sum += (newNode & Constants.SLOT_MAX);\\n newNode = newNode >> Constants.SLOT_WIDTH;\\n }\\n return sum;\\n }\\n }\\n\\n /// @notice Pick a slot in `node` that corresponds to `index`.\\n /// Treats the node like an array of virtual stakers,\\n /// the number of virtual stakers in each slot corresponding to its weight,\\n /// and picks which slot contains the `index`th virtual staker.\\n ///\\n /// @dev Requires that `index` be lower than `sumWeight(node)`.\\n /// However, this is not enforced for performance reasons.\\n /// If `index` exceeds the permitted range,\\n /// `pickWeightedSlot()` returns the rightmost slot\\n /// and an excessively high `newIndex`.\\n ///\\n /// @return slot The slot of `node` containing the `index`th virtual staker.\\n ///\\n /// @return newIndex The index of the `index`th virtual staker of `node`\\n /// within the returned slot.\\n function pickWeightedSlot(uint256 node, uint256 index)\\n internal\\n pure\\n returns (uint256 slot, uint256 newIndex)\\n {\\n unchecked {\\n newIndex = index;\\n uint256 newNode = node;\\n uint256 currentSlotWeight = newNode & Constants.SLOT_MAX;\\n while (newIndex >= currentSlotWeight) {\\n newIndex -= currentSlotWeight;\\n slot++;\\n newNode = newNode >> Constants.SLOT_WIDTH;\\n currentSlotWeight = newNode & Constants.SLOT_MAX;\\n }\\n return (slot, newIndex);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa7fb1c9c9789f30493e9a40e24a24f46875dc5e7630b4f67478167759f6d1882\"},\"@keep-network/sortition-pools/contracts/Chaosnet.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\n/// @title Chaosnet\\n/// @notice This is a beta staker program for stakers willing to go the extra\\n/// mile with monitoring, share their logs with the dev team, and allow to more\\n/// carefully monitor the bootstrapping network. As the network matures, the\\n/// beta program will be ended.\\ncontract Chaosnet {\\n /// @notice Indicates if the chaosnet is active. The chaosnet is active\\n /// after the contract deployment and can be ended with a call to\\n /// `deactivateChaosnet()`. Once deactivated chaosnet can not be activated\\n /// again.\\n bool public isChaosnetActive;\\n\\n /// @notice Indicates if the given operator is a beta operator for chaosnet.\\n mapping(address => bool) public isBetaOperator;\\n\\n /// @notice Address controlling chaosnet status and beta operator addresses.\\n address public chaosnetOwner;\\n\\n event BetaOperatorsAdded(address[] operators);\\n\\n event ChaosnetOwnerRoleTransferred(\\n address oldChaosnetOwner,\\n address newChaosnetOwner\\n );\\n\\n event ChaosnetDeactivated();\\n\\n constructor() {\\n _transferChaosnetOwner(msg.sender);\\n isChaosnetActive = true;\\n }\\n\\n modifier onlyChaosnetOwner() {\\n require(msg.sender == chaosnetOwner, \\\"Not the chaosnet owner\\\");\\n _;\\n }\\n\\n modifier onlyOnChaosnet() {\\n require(isChaosnetActive, \\\"Chaosnet is not active\\\");\\n _;\\n }\\n\\n /// @notice Adds beta operator to chaosnet. Can be called only by the\\n /// chaosnet owner when the chaosnet is active. Once the operator is added\\n /// as a beta operator, it can not be removed.\\n function addBetaOperators(address[] calldata operators)\\n public\\n onlyOnChaosnet\\n onlyChaosnetOwner\\n {\\n for (uint256 i = 0; i < operators.length; i++) {\\n isBetaOperator[operators[i]] = true;\\n }\\n\\n emit BetaOperatorsAdded(operators);\\n }\\n\\n /// @notice Deactivates the chaosnet. Can be called only by the chaosnet\\n /// owner. Once deactivated chaosnet can not be activated again.\\n function deactivateChaosnet() public onlyOnChaosnet onlyChaosnetOwner {\\n isChaosnetActive = false;\\n emit ChaosnetDeactivated();\\n }\\n\\n /// @notice Transfers the chaosnet owner role to another non-zero address.\\n function transferChaosnetOwnerRole(address newChaosnetOwner)\\n public\\n onlyChaosnetOwner\\n {\\n require(\\n newChaosnetOwner != address(0),\\n \\\"New chaosnet owner must not be zero address\\\"\\n );\\n _transferChaosnetOwner(newChaosnetOwner);\\n }\\n\\n function _transferChaosnetOwner(address newChaosnetOwner) internal {\\n address oldChaosnetOwner = chaosnetOwner;\\n chaosnetOwner = newChaosnetOwner;\\n emit ChaosnetOwnerRoleTransferred(oldChaosnetOwner, newChaosnetOwner);\\n }\\n}\\n\",\"keccak256\":\"0xeaf7bdd5626f88c329793a012621039692ce1b6e1f13013997ddb13d7e3032df\"},\"@keep-network/sortition-pools/contracts/Constants.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nlibrary Constants {\\n ////////////////////////////////////////////////////////////////////////////\\n // Parameters for configuration\\n\\n // How many bits a position uses per level of the tree;\\n // each branch of the tree contains 2**SLOT_BITS slots.\\n uint256 constant SLOT_BITS = 3;\\n uint256 constant LEVELS = 7;\\n ////////////////////////////////////////////////////////////////////////////\\n\\n ////////////////////////////////////////////////////////////////////////////\\n // Derived constants, do not touch\\n uint256 constant SLOT_COUNT = 2**SLOT_BITS;\\n uint256 constant SLOT_WIDTH = 256 / SLOT_COUNT;\\n uint256 constant LAST_SLOT = SLOT_COUNT - 1;\\n uint256 constant SLOT_MAX = (2**SLOT_WIDTH) - 1;\\n uint256 constant POOL_CAPACITY = SLOT_COUNT**LEVELS;\\n\\n uint256 constant ID_WIDTH = SLOT_WIDTH;\\n uint256 constant ID_MAX = SLOT_MAX;\\n\\n uint256 constant BLOCKHEIGHT_WIDTH = 96 - ID_WIDTH;\\n uint256 constant BLOCKHEIGHT_MAX = (2**BLOCKHEIGHT_WIDTH) - 1;\\n\\n uint256 constant SLOT_POINTER_MAX = (2**SLOT_BITS) - 1;\\n uint256 constant LEAF_FLAG = 1 << 255;\\n\\n uint256 constant WEIGHT_WIDTH = 256 / SLOT_COUNT;\\n ////////////////////////////////////////////////////////////////////////////\\n}\\n\",\"keccak256\":\"0xaef690ced707935745ff1482b7bb9bd9eb77bf6a39c717465e64cf12db8a7d39\"},\"@keep-network/sortition-pools/contracts/Leaf.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary Leaf {\\n function make(\\n address _operator,\\n uint256 _creationBlock,\\n uint256 _id\\n ) internal pure returns (uint256) {\\n assert(_creationBlock <= type(uint64).max);\\n assert(_id <= type(uint32).max);\\n // Converting a bytesX type into a larger type\\n // adds zero bytes on the right.\\n uint256 op = uint256(bytes32(bytes20(_operator)));\\n // Bitwise AND the id to erase\\n // all but the 32 least significant bits\\n uint256 uid = _id & Constants.ID_MAX;\\n // Erase all but the 64 least significant bits,\\n // then shift left by 32 bits to make room for the id\\n uint256 cb = (_creationBlock & Constants.BLOCKHEIGHT_MAX) <<\\n Constants.ID_WIDTH;\\n // Bitwise OR them all together to get\\n // [address operator || uint64 creationBlock || uint32 id]\\n return (op | cb | uid);\\n }\\n\\n function operator(uint256 leaf) internal pure returns (address) {\\n // Converting a bytesX type into a smaller type\\n // truncates it on the right.\\n return address(bytes20(bytes32(leaf)));\\n }\\n\\n /// @notice Return the block number the leaf was created in.\\n function creationBlock(uint256 leaf) internal pure returns (uint256) {\\n return ((leaf >> Constants.ID_WIDTH) & Constants.BLOCKHEIGHT_MAX);\\n }\\n\\n function id(uint256 leaf) internal pure returns (uint32) {\\n // Id is stored in the 32 least significant bits.\\n // Bitwise AND ensures that we only get the contents of those bits.\\n return uint32(leaf & Constants.ID_MAX);\\n }\\n}\\n\",\"keccak256\":\"0xbd107a1a43e48884885e5e966ffcbcd8fa5e89863715d717bb4006e9f89cdc2b\"},\"@keep-network/sortition-pools/contracts/Position.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary Position {\\n // Return the last 3 bits of a position number,\\n // corresponding to its slot in its parent\\n function slot(uint256 a) internal pure returns (uint256) {\\n return a & Constants.SLOT_POINTER_MAX;\\n }\\n\\n // Return the parent of a position number\\n function parent(uint256 a) internal pure returns (uint256) {\\n return a >> Constants.SLOT_BITS;\\n }\\n\\n // Return the location of the child of a at the given slot\\n function child(uint256 a, uint256 s) internal pure returns (uint256) {\\n return (a << Constants.SLOT_BITS) | (s & Constants.SLOT_POINTER_MAX); // slot(s)\\n }\\n\\n // Return the uint p as a flagged position uint:\\n // the least significant 21 bits contain the position\\n // and the 22nd bit is set as a flag\\n // to distinguish the position 0x000000 from an empty field.\\n function setFlag(uint256 p) internal pure returns (uint256) {\\n return p | Constants.LEAF_FLAG;\\n }\\n\\n // Turn a flagged position into an unflagged position\\n // by removing the flag at the 22nd least significant bit.\\n //\\n // We shouldn't _actually_ need this\\n // as all position-manipulating code should ignore non-position bits anyway\\n // but it's cheap to call so might as well do it.\\n function unsetFlag(uint256 p) internal pure returns (uint256) {\\n return p & (~Constants.LEAF_FLAG);\\n }\\n}\\n\",\"keccak256\":\"0xd3a927908080ac21353a92a6bce3d69e94a5c30f6b51f16b271b6cc679f110e2\"},\"@keep-network/sortition-pools/contracts/RNG.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Leaf.sol\\\";\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary RNG {\\n /// @notice Get an index in the range `[0 .. range-1]`\\n /// and the new state of the RNG,\\n /// using the provided `state` of the RNG.\\n ///\\n /// @param range The upper bound of the index, exclusive.\\n ///\\n /// @param state The previous state of the RNG.\\n /// The initial state needs to be obtained\\n /// from a trusted randomness oracle (the random beacon),\\n /// or from a chain of earlier calls to `RNG.getIndex()`\\n /// on an originally trusted seed.\\n ///\\n /// @dev Calculates the number of bits required for the desired range,\\n /// takes the least significant bits of `state`\\n /// and checks if the obtained index is within the desired range.\\n /// The original state is hashed with `keccak256` to get a new state.\\n /// If the index is outside the range,\\n /// the function retries until it gets a suitable index.\\n ///\\n /// @return index A random integer between `0` and `range - 1`, inclusive.\\n ///\\n /// @return newState The new state of the RNG.\\n /// When `getIndex()` is called one or more times,\\n /// care must be taken to always use the output `state`\\n /// of the most recent call as the input `state` of a subsequent call.\\n /// At the end of a transaction calling `RNG.getIndex()`,\\n /// the previous stored state must be overwritten with the latest output.\\n function getIndex(\\n uint256 range,\\n bytes32 state,\\n uint256 bits\\n ) internal view returns (uint256, bytes32) {\\n bool found = false;\\n uint256 index = 0;\\n bytes32 newState = state;\\n while (!found) {\\n index = truncate(bits, uint256(newState));\\n newState = keccak256(abi.encodePacked(newState, address(this)));\\n if (index < range) {\\n found = true;\\n }\\n }\\n return (index, newState);\\n }\\n\\n /// @notice Calculate how many bits are required\\n /// for an index in the range `[0 .. range-1]`.\\n ///\\n /// @param range The upper bound of the desired range, exclusive.\\n ///\\n /// @return uint The smallest number of bits\\n /// that can contain the number `range-1`.\\n function bitsRequired(uint256 range) internal pure returns (uint256) {\\n unchecked {\\n if (range == 1) {\\n return 0;\\n }\\n\\n uint256 bits = Constants.WEIGHT_WIDTH - 1;\\n\\n // Left shift by `bits`,\\n // so we have a 1 in the (bits + 1)th least significant bit\\n // and 0 in other bits.\\n // If this number is equal or greater than `range`,\\n // the range [0, range-1] fits in `bits` bits.\\n //\\n // Because we loop from high bits to low bits,\\n // we find the highest number of bits that doesn't fit the range,\\n // and return that number + 1.\\n while (1 << bits >= range) {\\n bits--;\\n }\\n\\n return bits + 1;\\n }\\n }\\n\\n /// @notice Truncate `input` to the `bits` least significant bits.\\n function truncate(uint256 bits, uint256 input)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n return input & ((1 << bits) - 1);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x67f87f589cd5123ffa32f883ea2f09b0e56258508bae82b8c655b3c27c71eb5e\"},\"@keep-network/sortition-pools/contracts/Rewards.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\n/// @title Rewards\\n/// @notice Rewards are allocated proportionally to operators\\n/// present in the pool at payout based on their weight in the pool.\\n///\\n/// To facilitate this, we use a global accumulator value\\n/// to track the total rewards one unit of weight would've earned\\n/// since the creation of the pool.\\n///\\n/// Whenever a reward is paid, the accumulator is increased\\n/// by the size of the reward divided by the total weight\\n/// of all eligible operators in the pool.\\n///\\n/// Each operator has an individual accumulator value,\\n/// set to equal the global accumulator when the operator joins the pool.\\n/// This accumulator reflects the amount of rewards\\n/// that have already been accounted for with that operator.\\n///\\n/// Whenever an operator's weight in the pool changes,\\n/// we can update the amount of rewards the operator has earned\\n/// by subtracting the operator's accumulator from the global accumulator.\\n/// This gives us the amount of rewards one unit of weight has earned\\n/// since the last time the operator's rewards have been updated.\\n/// Then we multiply that by the operator's previous (pre-change) weight\\n/// to determine how much rewards in total the operator has earned,\\n/// and add this to the operator's earned rewards.\\n/// Finally, we set the operator's accumulator to the global accumulator value.\\ncontract Rewards {\\n struct OperatorRewards {\\n // The state of the global accumulator\\n // when the operator's rewards were last updated\\n uint96 accumulated;\\n // The amount of rewards collected by the operator after the latest update.\\n // The amount the operator could withdraw may equal `available`\\n // or it may be greater, if more rewards have been paid in since then.\\n // To evaulate the most recent amount including rewards potentially paid\\n // since the last update, use `availableRewards` function.\\n uint96 available;\\n // If nonzero, the operator is ineligible for rewards\\n // and may only re-enable rewards after the specified timestamp.\\n // XXX: unsigned 32-bit integer unix seconds, will break around 2106\\n uint32 ineligibleUntil;\\n // Locally cached weight of the operator,\\n // used to reduce the cost of setting operators ineligible.\\n uint32 weight;\\n }\\n\\n // The global accumulator of how much rewards\\n // a hypothetical operator of weight 1 would have earned\\n // since the creation of the pool.\\n uint96 internal globalRewardAccumulator;\\n // If the amount of reward tokens paid in\\n // does not divide cleanly by pool weight,\\n // the difference is recorded as rounding dust\\n // and added to the next reward.\\n uint96 internal rewardRoundingDust;\\n\\n // The amount of rewards that would've been earned by ineligible operators\\n // had they not been ineligible.\\n uint96 public ineligibleEarnedRewards;\\n\\n // Ineligibility times are calculated from this offset,\\n // set at contract creation.\\n uint256 internal immutable ineligibleOffsetStart;\\n\\n mapping(uint32 => OperatorRewards) internal operatorRewards;\\n\\n constructor() {\\n // solhint-disable-next-line not-rely-on-time\\n ineligibleOffsetStart = block.timestamp;\\n }\\n\\n /// @notice Return whether the operator is eligible for rewards or not.\\n function isEligibleForRewards(uint32 operator) internal view returns (bool) {\\n return operatorRewards[operator].ineligibleUntil == 0;\\n }\\n\\n /// @notice Return the time the operator's reward eligibility can be restored.\\n function rewardsEligibilityRestorableAt(uint32 operator)\\n internal\\n view\\n returns (uint256)\\n {\\n uint32 until = operatorRewards[operator].ineligibleUntil;\\n require(until != 0, \\\"Operator already eligible\\\");\\n return (uint256(until) + ineligibleOffsetStart);\\n }\\n\\n /// @notice Return whether the operator is able to restore their eligibility\\n /// for rewards right away.\\n function canRestoreRewardEligibility(uint32 operator)\\n internal\\n view\\n returns (bool)\\n {\\n // solhint-disable-next-line not-rely-on-time\\n return rewardsEligibilityRestorableAt(operator) <= block.timestamp;\\n }\\n\\n /// @notice Internal function for updating the global state of rewards.\\n function addRewards(uint96 rewardAmount, uint32 currentPoolWeight) internal {\\n require(currentPoolWeight > 0, \\\"No recipients in pool\\\");\\n\\n uint96 totalAmount = rewardAmount + rewardRoundingDust;\\n uint96 perWeightReward = totalAmount / currentPoolWeight;\\n uint96 newRoundingDust = totalAmount % currentPoolWeight;\\n\\n globalRewardAccumulator += perWeightReward;\\n rewardRoundingDust = newRoundingDust;\\n }\\n\\n /// @notice Internal function for updating the operator's reward state.\\n function updateOperatorRewards(uint32 operator, uint32 newWeight) internal {\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n if (o.ineligibleUntil == 0) {\\n // If operator is not ineligible, update their earned rewards\\n o.available += accruedRewards;\\n } else {\\n // If ineligible, put the rewards into the ineligible pot\\n ineligibleEarnedRewards += accruedRewards;\\n }\\n // In any case, update their accumulator and weight\\n o.accumulated = acc;\\n o.weight = newWeight;\\n operatorRewards[operator] = o;\\n }\\n\\n /// @notice Set the amount of withdrawable tokens to zero\\n /// and return the previous withdrawable amount.\\n /// @dev Does not update the withdrawable amount,\\n /// but should usually be accompanied by an update.\\n function withdrawOperatorRewards(uint32 operator)\\n internal\\n returns (uint96 withdrawable)\\n {\\n OperatorRewards storage o = operatorRewards[operator];\\n withdrawable = o.available;\\n o.available = 0;\\n }\\n\\n /// @notice Set the amount of ineligible-earned tokens to zero\\n /// and return the previous amount.\\n function withdrawIneligibleRewards() internal returns (uint96 withdrawable) {\\n withdrawable = ineligibleEarnedRewards;\\n ineligibleEarnedRewards = 0;\\n }\\n\\n /// @notice Set the given operators as ineligible for rewards.\\n /// The operators can restore their eligibility at the given time.\\n function setIneligible(uint32[] memory operators, uint256 until) internal {\\n OperatorRewards memory o = OperatorRewards(0, 0, 0, 0);\\n uint96 globalAcc = globalRewardAccumulator;\\n uint96 accrued = 0;\\n // Record ineligibility as seconds after contract creation\\n uint32 _until = uint32(until - ineligibleOffsetStart);\\n\\n for (uint256 i = 0; i < operators.length; i++) {\\n uint32 operator = operators[i];\\n OperatorRewards storage r = operatorRewards[operator];\\n o.available = r.available;\\n o.accumulated = r.accumulated;\\n o.ineligibleUntil = r.ineligibleUntil;\\n o.weight = r.weight;\\n\\n if (o.ineligibleUntil != 0) {\\n // If operator is already ineligible,\\n // don't earn rewards or shorten its ineligibility\\n if (o.ineligibleUntil < _until) {\\n o.ineligibleUntil = _until;\\n }\\n } else {\\n // The operator becomes ineligible -> earn rewards\\n o.ineligibleUntil = _until;\\n accrued = (globalAcc - o.accumulated) * uint96(o.weight);\\n o.available += accrued;\\n }\\n o.accumulated = globalAcc;\\n\\n r.available = o.available;\\n r.accumulated = o.accumulated;\\n r.ineligibleUntil = o.ineligibleUntil;\\n r.weight = o.weight;\\n }\\n }\\n\\n /// @notice Restore the given operator's eligibility for rewards.\\n function restoreEligibility(uint32 operator) internal {\\n // solhint-disable-next-line not-rely-on-time\\n require(canRestoreRewardEligibility(operator), \\\"Operator still ineligible\\\");\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n ineligibleEarnedRewards += accruedRewards;\\n o.accumulated = acc;\\n o.ineligibleUntil = 0;\\n operatorRewards[operator] = o;\\n }\\n\\n /// @notice Returns the amount of rewards currently available for withdrawal\\n /// for the given operator.\\n function availableRewards(uint32 operator) internal view returns (uint96) {\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n if (o.ineligibleUntil == 0) {\\n // If operator is not ineligible, calculate newly accrued rewards and add\\n // them to the available ones, calculated during the last update.\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n return o.available + accruedRewards;\\n } else {\\n // If ineligible, return only the rewards calculated during the last\\n // update.\\n return o.available;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3a10abb408b44335a092387b2c7ee01db3b27997f1f2c888d9b7a2d92934c4e2\"},\"@keep-network/sortition-pools/contracts/SortitionPool.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"@thesis/solidity-contracts/contracts/token/IERC20WithPermit.sol\\\";\\nimport \\\"@thesis/solidity-contracts/contracts/token/IReceiveApproval.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\nimport \\\"./RNG.sol\\\";\\nimport \\\"./SortitionTree.sol\\\";\\nimport \\\"./Rewards.sol\\\";\\nimport \\\"./Chaosnet.sol\\\";\\n\\n/// @title Sortition Pool\\n/// @notice A logarithmic data structure used to store the pool of eligible\\n/// operators weighted by their stakes. It allows to select a group of operators\\n/// based on the provided pseudo-random seed.\\ncontract SortitionPool is\\n SortitionTree,\\n Rewards,\\n Ownable,\\n Chaosnet,\\n IReceiveApproval\\n{\\n using Branch for uint256;\\n using Leaf for uint256;\\n using Position for uint256;\\n\\n IERC20WithPermit public immutable rewardToken;\\n\\n uint256 public immutable poolWeightDivisor;\\n\\n bool public isLocked;\\n\\n event IneligibleForRewards(uint32[] ids, uint256 until);\\n\\n event RewardEligibilityRestored(address indexed operator, uint32 indexed id);\\n\\n /// @notice Reverts if called while pool is locked.\\n modifier onlyUnlocked() {\\n require(!isLocked, \\\"Sortition pool locked\\\");\\n _;\\n }\\n\\n /// @notice Reverts if called while pool is unlocked.\\n modifier onlyLocked() {\\n require(isLocked, \\\"Sortition pool unlocked\\\");\\n _;\\n }\\n\\n constructor(IERC20WithPermit _rewardToken, uint256 _poolWeightDivisor) {\\n rewardToken = _rewardToken;\\n poolWeightDivisor = _poolWeightDivisor;\\n }\\n\\n function receiveApproval(\\n address sender,\\n uint256 amount,\\n address token,\\n bytes calldata\\n ) external override {\\n require(token == address(rewardToken), \\\"Unsupported token\\\");\\n rewardToken.transferFrom(sender, address(this), amount);\\n Rewards.addRewards(uint96(amount), uint32(root.sumWeight()));\\n }\\n\\n /// @notice Withdraws all available rewards for the given operator to the\\n /// given beneficiary.\\n /// @dev Can be called only be the owner. Does not validate if the provided\\n /// beneficiary is associated with the provided operator - this needs to\\n /// be done by the owner calling this function.\\n /// @return The amount of rewards withdrawn in this call.\\n function withdrawRewards(address operator, address beneficiary)\\n public\\n onlyOwner\\n returns (uint96)\\n {\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(getPoolWeight(operator)));\\n uint96 earned = Rewards.withdrawOperatorRewards(id);\\n rewardToken.transfer(beneficiary, uint256(earned));\\n return earned;\\n }\\n\\n /// @notice Withdraws rewards not allocated to operators marked as ineligible\\n /// to the given recipient address.\\n /// @dev Can be called only by the owner.\\n function withdrawIneligible(address recipient) public onlyOwner {\\n uint96 earned = Rewards.withdrawIneligibleRewards();\\n rewardToken.transfer(recipient, uint256(earned));\\n }\\n\\n /// @notice Locks the sortition pool. In locked state, members cannot be\\n /// inserted and removed from the pool. Members statuses cannot\\n /// be updated as well.\\n /// @dev Can be called only by the contract owner.\\n function lock() public onlyOwner {\\n isLocked = true;\\n }\\n\\n /// @notice Unlocks the sortition pool. Removes all restrictions set by\\n /// the `lock` method.\\n /// @dev Can be called only by the contract owner.\\n function unlock() public onlyOwner {\\n isLocked = false;\\n }\\n\\n /// @notice Inserts an operator to the pool. Reverts if the operator is\\n /// already present. Reverts if the operator is not eligible because of their\\n /// authorized stake. Reverts if the chaosnet is active and the operator is\\n /// not a beta operator.\\n /// @dev Can be called only by the contract owner.\\n /// @param operator Address of the inserted operator.\\n /// @param authorizedStake Inserted operator's authorized stake for the application.\\n function insertOperator(address operator, uint256 authorizedStake)\\n public\\n onlyOwner\\n onlyUnlocked\\n {\\n uint256 weight = getWeight(authorizedStake);\\n require(weight > 0, \\\"Operator not eligible\\\");\\n\\n if (isChaosnetActive) {\\n require(isBetaOperator[operator], \\\"Not beta operator for chaosnet\\\");\\n }\\n\\n _insertOperator(operator, weight);\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(weight));\\n }\\n\\n /// @notice Update the operator's weight if present and eligible,\\n /// or remove from the pool if present and ineligible.\\n /// @dev Can be called only by the contract owner.\\n /// @param operator Address of the updated operator.\\n /// @param authorizedStake Operator's authorized stake for the application.\\n function updateOperatorStatus(address operator, uint256 authorizedStake)\\n public\\n onlyOwner\\n onlyUnlocked\\n {\\n uint256 weight = getWeight(authorizedStake);\\n\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(weight));\\n\\n if (weight == 0) {\\n _removeOperator(operator);\\n } else {\\n updateOperator(operator, weight);\\n }\\n }\\n\\n /// @notice Set the given operators as ineligible for rewards.\\n /// The operators can restore their eligibility at the given time.\\n function setRewardIneligibility(uint32[] calldata operators, uint256 until)\\n public\\n onlyOwner\\n {\\n Rewards.setIneligible(operators, until);\\n emit IneligibleForRewards(operators, until);\\n }\\n\\n /// @notice Restores reward eligibility for the operator.\\n function restoreRewardEligibility(address operator) public {\\n uint32 id = getOperatorID(operator);\\n Rewards.restoreEligibility(id);\\n emit RewardEligibilityRestored(operator, id);\\n }\\n\\n /// @notice Returns whether the operator is eligible for rewards or not.\\n function isEligibleForRewards(address operator) public view returns (bool) {\\n uint32 id = getOperatorID(operator);\\n return Rewards.isEligibleForRewards(id);\\n }\\n\\n /// @notice Returns the time the operator's reward eligibility can be restored.\\n function rewardsEligibilityRestorableAt(address operator)\\n public\\n view\\n returns (uint256)\\n {\\n uint32 id = getOperatorID(operator);\\n return Rewards.rewardsEligibilityRestorableAt(id);\\n }\\n\\n /// @notice Returns whether the operator is able to restore their eligibility\\n /// for rewards right away.\\n function canRestoreRewardEligibility(address operator)\\n public\\n view\\n returns (bool)\\n {\\n uint32 id = getOperatorID(operator);\\n return Rewards.canRestoreRewardEligibility(id);\\n }\\n\\n /// @notice Returns the amount of rewards withdrawable for the given operator.\\n function getAvailableRewards(address operator) public view returns (uint96) {\\n uint32 id = getOperatorID(operator);\\n return availableRewards(id);\\n }\\n\\n /// @notice Return whether the operator is present in the pool.\\n function isOperatorInPool(address operator) public view returns (bool) {\\n return getFlaggedLeafPosition(operator) != 0;\\n }\\n\\n /// @notice Return whether the operator's weight in the pool\\n /// matches their eligible weight.\\n function isOperatorUpToDate(address operator, uint256 authorizedStake)\\n public\\n view\\n returns (bool)\\n {\\n return getWeight(authorizedStake) == getPoolWeight(operator);\\n }\\n\\n /// @notice Return the weight of the operator in the pool,\\n /// which may or may not be out of date.\\n function getPoolWeight(address operator) public view returns (uint256) {\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n if (flaggedPosition == 0) {\\n return 0;\\n } else {\\n uint256 leafPosition = flaggedPosition.unsetFlag();\\n uint256 leafWeight = getLeafWeight(leafPosition);\\n return leafWeight;\\n }\\n }\\n\\n /// @notice Selects a new group of operators of the provided size based on\\n /// the provided pseudo-random seed. At least one operator has to be\\n /// registered in the pool, otherwise the function fails reverting the\\n /// transaction.\\n /// @param groupSize Size of the requested group\\n /// @param seed Pseudo-random number used to select operators to group\\n /// @return selected Members of the selected group\\n function selectGroup(uint256 groupSize, bytes32 seed)\\n public\\n view\\n onlyLocked\\n returns (uint32[] memory)\\n {\\n uint256 _root = root;\\n\\n bytes32 rngState = seed;\\n uint256 rngRange = _root.sumWeight();\\n require(rngRange > 0, \\\"Not enough operators in pool\\\");\\n uint256 currentIndex;\\n\\n uint256 bits = RNG.bitsRequired(rngRange);\\n\\n uint32[] memory selected = new uint32[](groupSize);\\n\\n for (uint256 i = 0; i < groupSize; i++) {\\n (currentIndex, rngState) = RNG.getIndex(rngRange, rngState, bits);\\n\\n uint256 leafPosition = pickWeightedLeaf(currentIndex, _root);\\n\\n uint256 leaf = leaves[leafPosition];\\n selected[i] = leaf.id();\\n }\\n return selected;\\n }\\n\\n function getWeight(uint256 authorization) internal view returns (uint256) {\\n return authorization / poolWeightDivisor;\\n }\\n}\\n\",\"keccak256\":\"0xab42e7c5b1828f42a73f699eb2dc96d4f793572a6323b8b1fbd7c5e0c065bda7\"},\"@keep-network/sortition-pools/contracts/SortitionTree.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Branch.sol\\\";\\nimport \\\"./Position.sol\\\";\\nimport \\\"./Leaf.sol\\\";\\nimport \\\"./Constants.sol\\\";\\n\\ncontract SortitionTree {\\n using Branch for uint256;\\n using Position for uint256;\\n using Leaf for uint256;\\n\\n // implicit tree\\n // root 8\\n // level2 64\\n // level3 512\\n // level4 4k\\n // level5 32k\\n // level6 256k\\n // level7 2M\\n uint256 internal root;\\n\\n // A 2-index mapping from layer => (index (0-index) => branch). For example,\\n // to access the 6th branch in the 2nd layer (right below the root node; the\\n // first branch layer), call branches[2][5]. Mappings are used in place of\\n // arrays for efficiency. The root is the first layer, the branches occupy\\n // layers 2 through 7, and layer 8 is for the leaves. Following this\\n // convention, the first index in `branches` is `2`, and the last index is\\n // `7`.\\n mapping(uint256 => mapping(uint256 => uint256)) internal branches;\\n\\n // A 0-index mapping from index => leaf, acting as an array. For example, to\\n // access the 42nd leaf, call leaves[41].\\n mapping(uint256 => uint256) internal leaves;\\n\\n // the flagged (see setFlag() and unsetFlag() in Position.sol) positions\\n // of all operators present in the pool\\n mapping(address => uint256) internal flaggedLeafPosition;\\n\\n // the leaf after the rightmost occupied leaf of each stack\\n uint256 internal rightmostLeaf;\\n\\n // the empty leaves in each stack\\n // between 0 and the rightmost occupied leaf\\n uint256[] internal emptyLeaves;\\n\\n // Each operator has an uint32 ID number\\n // which is allocated when they first join the pool\\n // and remains unchanged even if they leave and rejoin the pool.\\n mapping(address => uint32) internal operatorID;\\n\\n // The idAddress array records the address corresponding to each ID number.\\n // The ID number 0 is initialized with a zero address and is not used.\\n address[] internal idAddress;\\n\\n constructor() {\\n root = 0;\\n rightmostLeaf = 0;\\n idAddress.push();\\n }\\n\\n /// @notice Return the ID number of the given operator address. An ID number\\n /// of 0 means the operator has not been allocated an ID number yet.\\n /// @param operator Address of the operator.\\n /// @return the ID number of the given operator address\\n function getOperatorID(address operator) public view returns (uint32) {\\n return operatorID[operator];\\n }\\n\\n /// @notice Get the operator address corresponding to the given ID number. A\\n /// zero address means the ID number has not been allocated yet.\\n /// @param id ID of the operator\\n /// @return the address of the operator\\n function getIDOperator(uint32 id) public view returns (address) {\\n return idAddress.length > id ? idAddress[id] : address(0);\\n }\\n\\n /// @notice Gets the operator addresses corresponding to the given ID\\n /// numbers. A zero address means the ID number has not been allocated yet.\\n /// This function works just like getIDOperator except that it allows to fetch\\n /// operator addresses for multiple IDs in one call.\\n /// @param ids the array of the operator ids\\n /// @return an array of the associated operator addresses\\n function getIDOperators(uint32[] calldata ids)\\n public\\n view\\n returns (address[] memory)\\n {\\n uint256 idCount = idAddress.length;\\n\\n address[] memory operators = new address[](ids.length);\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint32 id = ids[i];\\n operators[i] = idCount > id ? idAddress[id] : address(0);\\n }\\n return operators;\\n }\\n\\n /// @notice Checks if operator is already registered in the pool.\\n /// @param operator the address of the operator\\n /// @return whether or not the operator is already registered in the pool\\n function isOperatorRegistered(address operator) public view returns (bool) {\\n return getFlaggedLeafPosition(operator) != 0;\\n }\\n\\n /// @notice Sum the number of operators in each trunk.\\n /// @return the number of operators in the pool\\n function operatorsInPool() public view returns (uint256) {\\n // Get the number of leaves that might be occupied;\\n // if `rightmostLeaf` equals `firstLeaf()` the tree must be empty,\\n // otherwise the difference between these numbers\\n // gives the number of leaves that may be occupied.\\n uint256 nPossiblyUsedLeaves = rightmostLeaf;\\n // Get the number of empty leaves\\n // not accounted for by the `rightmostLeaf`\\n uint256 nEmptyLeaves = emptyLeaves.length;\\n\\n return (nPossiblyUsedLeaves - nEmptyLeaves);\\n }\\n\\n /// @notice Convenience method to return the total weight of the pool\\n /// @return the total weight of the pool\\n function totalWeight() public view returns (uint256) {\\n return root.sumWeight();\\n }\\n\\n /// @notice Give the operator a new ID number.\\n /// Does not check if the operator already has an ID number.\\n /// @param operator the address of the operator\\n /// @return a new ID for that operator\\n function allocateOperatorID(address operator) internal returns (uint256) {\\n uint256 id = idAddress.length;\\n\\n require(id <= type(uint32).max, \\\"Pool capacity exceeded\\\");\\n\\n operatorID[operator] = uint32(id);\\n idAddress.push(operator);\\n return id;\\n }\\n\\n /// @notice Inserts an operator into the sortition pool\\n /// @param operator the address of an operator to insert\\n /// @param weight how much weight that operator has in the pool\\n function _insertOperator(address operator, uint256 weight) internal {\\n require(\\n !isOperatorRegistered(operator),\\n \\\"Operator is already registered in the pool\\\"\\n );\\n\\n // Fetch the operator's ID, and if they don't have one, allocate them one.\\n uint256 id = getOperatorID(operator);\\n if (id == 0) {\\n id = allocateOperatorID(operator);\\n }\\n\\n // Determine which leaf to insert them into\\n uint256 position = getEmptyLeafPosition();\\n // Record the block the operator was inserted in\\n uint256 theLeaf = Leaf.make(operator, block.number, id);\\n\\n // Update the leaf, and propagate the weight changes all the way up to the\\n // root.\\n root = setLeaf(position, theLeaf, weight, root);\\n\\n // Without position flags,\\n // the position 0x000000 would be treated as empty\\n flaggedLeafPosition[operator] = position.setFlag();\\n }\\n\\n /// @notice Remove an operator (and their weight) from the pool.\\n /// @param operator the address of the operator to remove\\n function _removeOperator(address operator) internal {\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n require(flaggedPosition != 0, \\\"Operator is not registered in the pool\\\");\\n uint256 unflaggedPosition = flaggedPosition.unsetFlag();\\n\\n // Update the leaf, and propagate the weight changes all the way up to the\\n // root.\\n root = removeLeaf(unflaggedPosition, root);\\n removeLeafPositionRecord(operator);\\n }\\n\\n /// @notice Update an operator's weight in the pool.\\n /// @param operator the address of the operator to update\\n /// @param weight the new weight\\n function updateOperator(address operator, uint256 weight) internal {\\n require(\\n isOperatorRegistered(operator),\\n \\\"Operator is not registered in the pool\\\"\\n );\\n\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n uint256 unflaggedPosition = flaggedPosition.unsetFlag();\\n root = updateLeaf(unflaggedPosition, weight, root);\\n }\\n\\n /// @notice Helper method to remove a leaf position record for an operator.\\n /// @param operator the address of the operator to remove the record for\\n function removeLeafPositionRecord(address operator) internal {\\n flaggedLeafPosition[operator] = 0;\\n }\\n\\n /// @notice Removes the data and weight from a particular leaf.\\n /// @param position the leaf index to remove\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function removeLeaf(uint256 position, uint256 _root)\\n internal\\n returns (uint256)\\n {\\n uint256 rightmostSubOne = rightmostLeaf - 1;\\n bool isRightmost = position == rightmostSubOne;\\n\\n // Clears out the data in the leaf node, and then propagates the weight\\n // changes all the way up to the root.\\n uint256 newRoot = setLeaf(position, 0, 0, _root);\\n\\n // Infer if need to fall back on emptyLeaves yet\\n if (isRightmost) {\\n rightmostLeaf = rightmostSubOne;\\n } else {\\n emptyLeaves.push(position);\\n }\\n return newRoot;\\n }\\n\\n /// @notice Updates the tree to give a particular leaf a new weight.\\n /// @param position the index of the leaf to update\\n /// @param weight the new weight\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function updateLeaf(\\n uint256 position,\\n uint256 weight,\\n uint256 _root\\n ) internal returns (uint256) {\\n if (getLeafWeight(position) != weight) {\\n return updateTree(position, weight, _root);\\n } else {\\n return _root;\\n }\\n }\\n\\n /// @notice Places a leaf into a particular position, with a given weight and\\n /// propagates that change.\\n /// @param position the index to place the leaf in\\n /// @param theLeaf the new leaf to place in the position\\n /// @param leafWeight the weight of the leaf\\n /// @param _root the root containing the new leaf\\n /// @return the updated root node\\n function setLeaf(\\n uint256 position,\\n uint256 theLeaf,\\n uint256 leafWeight,\\n uint256 _root\\n ) internal returns (uint256) {\\n // set leaf\\n leaves[position] = theLeaf;\\n\\n return (updateTree(position, leafWeight, _root));\\n }\\n\\n /// @notice Propagates a weight change at a position through the tree,\\n /// eventually returning the updated root.\\n /// @param position the index of leaf to update\\n /// @param weight the new weight of the leaf\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function updateTree(\\n uint256 position,\\n uint256 weight,\\n uint256 _root\\n ) internal returns (uint256) {\\n uint256 childSlot;\\n uint256 treeNode;\\n uint256 newNode;\\n uint256 nodeWeight = weight;\\n\\n uint256 parent = position;\\n // set levels 7 to 2\\n for (uint256 level = Constants.LEVELS; level >= 2; level--) {\\n childSlot = parent.slot();\\n parent = parent.parent();\\n treeNode = branches[level][parent];\\n newNode = treeNode.setSlot(childSlot, nodeWeight);\\n branches[level][parent] = newNode;\\n nodeWeight = newNode.sumWeight();\\n }\\n\\n // set level Root\\n childSlot = parent.slot();\\n return _root.setSlot(childSlot, nodeWeight);\\n }\\n\\n /// @notice Retrieves the next available empty leaf position. Tries to fill\\n /// left to right first, ignoring leaf removals, and then fills\\n /// most-recent-removals first.\\n /// @return the position of the empty leaf\\n function getEmptyLeafPosition() internal returns (uint256) {\\n uint256 rLeaf = rightmostLeaf;\\n bool spaceOnRight = (rLeaf + 1) < Constants.POOL_CAPACITY;\\n if (spaceOnRight) {\\n rightmostLeaf = rLeaf + 1;\\n return rLeaf;\\n } else {\\n uint256 emptyLeafCount = emptyLeaves.length;\\n require(emptyLeafCount > 0, \\\"Pool is full\\\");\\n uint256 emptyLeaf = emptyLeaves[emptyLeafCount - 1];\\n emptyLeaves.pop();\\n return emptyLeaf;\\n }\\n }\\n\\n /// @notice Gets the flagged leaf position for an operator.\\n /// @param operator the address of the operator\\n /// @return the leaf position of that operator\\n function getFlaggedLeafPosition(address operator)\\n internal\\n view\\n returns (uint256)\\n {\\n return flaggedLeafPosition[operator];\\n }\\n\\n /// @notice Gets the weight of a leaf at a particular position.\\n /// @param position the index of the leaf\\n /// @return the weight of the leaf at that position\\n function getLeafWeight(uint256 position) internal view returns (uint256) {\\n uint256 slot = position.slot();\\n uint256 parent = position.parent();\\n\\n // A leaf's weight information is stored a 32-bit slot in the branch layer\\n // directly above the leaf layer. To access it, we calculate that slot and\\n // parent position, and always know the hard-coded layer index.\\n uint256 node = branches[Constants.LEVELS][parent];\\n return node.getSlot(slot);\\n }\\n\\n /// @notice Picks a leaf given a random index.\\n /// @param index a number in `[0, _root.totalWeight())` used to decide\\n /// between leaves\\n /// @param _root the root of the tree\\n function pickWeightedLeaf(uint256 index, uint256 _root)\\n internal\\n view\\n returns (uint256 leafPosition)\\n {\\n uint256 currentIndex = index;\\n uint256 currentNode = _root;\\n uint256 currentPosition = 0;\\n uint256 currentSlot;\\n\\n require(index < currentNode.sumWeight(), \\\"Index exceeds weight\\\");\\n\\n // get root slot\\n (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex);\\n\\n // get slots from levels 2 to 7\\n for (uint256 level = 2; level <= Constants.LEVELS; level++) {\\n currentPosition = currentPosition.child(currentSlot);\\n currentNode = branches[level][currentPosition];\\n (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex);\\n }\\n\\n // get leaf position\\n leafPosition = currentPosition.child(currentSlot);\\n }\\n}\\n\",\"keccak256\":\"0x51daeca62ef52be78a1a9de4d2a1c5900c873165f59eda14d5965d7d7da90a03\"},\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/security/ReentrancyGuard.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Contract module that helps prevent reentrant calls to a function.\\n *\\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\\n * available, which can be applied to functions to make sure there are no nested\\n * (reentrant) calls to them.\\n *\\n * Note that because there is a single `nonReentrant` guard, functions marked as\\n * `nonReentrant` may not call one another. This can be worked around by making\\n * those functions `private`, and then adding `external` `nonReentrant` entry\\n * points to them.\\n *\\n * TIP: If you would like to learn more about reentrancy and alternative ways\\n * to protect against it, check out our blog post\\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\\n */\\nabstract contract ReentrancyGuard {\\n // Booleans are more expensive than uint256 or any type that takes up a full\\n // word because each write operation emits an extra SLOAD to first read the\\n // slot's contents, replace the bits taken up by the boolean, and then write\\n // back. This is the compiler's defense against contract upgrades and\\n // pointer aliasing, and it cannot be disabled.\\n\\n // The values being non-zero value makes deployment a bit more expensive,\\n // but in exchange the refund on every call to nonReentrant will be lower in\\n // amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to\\n // increase the likelihood of the full refund coming into effect.\\n uint256 private constant _NOT_ENTERED = 1;\\n uint256 private constant _ENTERED = 2;\\n\\n uint256 private _status;\\n\\n constructor() {\\n _status = _NOT_ENTERED;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and making it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_status != _ENTERED, \\\"ReentrancyGuard: reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n _status = _ENTERED;\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _status = _NOT_ENTERED;\\n }\\n}\\n\",\"keccak256\":\"0x0e9621f60b2faabe65549f7ed0f24e8853a45c1b7990d47e8160e523683f3935\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n uint8 private constant _ADDRESS_LENGTH = 20;\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\\n */\\n function toHexString(address addr) internal pure returns (string memory) {\\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\\n }\\n}\\n\",\"keccak256\":\"0xaf159a8b1923ad2a26d516089bceca9bdeaeacd04be50983ea00ba63070f08a3\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.3) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n /// @solidity memory-safe-assembly\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0xdb7f5c28fc61cda0bd8ab60ce288e206b791643bcd3ba464a70cbec18895a2f5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\n /**\\n * @dev Returns the largest of two numbers.\\n */\\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a >= b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the smallest of two numbers.\\n */\\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a < b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the average of two numbers. The result is rounded towards\\n * zero.\\n */\\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b) / 2 can overflow.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1);\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. It the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`.\\n // We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`.\\n // This gives `2**k < a <= 2**(k+1)` \\u2192 `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`.\\n // Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a\\n // good first aproximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1;\\n uint256 x = a;\\n if (x >> 128 > 0) {\\n x >>= 128;\\n result <<= 64;\\n }\\n if (x >> 64 > 0) {\\n x >>= 64;\\n result <<= 32;\\n }\\n if (x >> 32 > 0) {\\n x >>= 32;\\n result <<= 16;\\n }\\n if (x >> 16 > 0) {\\n x >>= 16;\\n result <<= 8;\\n }\\n if (x >> 8 > 0) {\\n x >>= 8;\\n result <<= 4;\\n }\\n if (x >> 4 > 0) {\\n x >>= 4;\\n result <<= 2;\\n }\\n if (x >> 2 > 0) {\\n result <<= 1;\\n }\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n uint256 result = sqrt(a);\\n if (rounding == Rounding.Up && result * result < a) {\\n result += 1;\\n }\\n return result;\\n }\\n}\\n\",\"keccak256\":\"0xd15c3e400531f00203839159b2b8e7209c5158b35618f570c695b7e47f12e9f0\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IApproveAndCall.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\n/// @notice An interface that should be implemented by tokens supporting\\n/// `approveAndCall`/`receiveApproval` pattern.\\ninterface IApproveAndCall {\\n /// @notice Executes `receiveApproval` function on spender as specified in\\n /// `IReceiveApproval` interface. Approves spender to withdraw from\\n /// the caller multiple times, up to the `amount`. If this\\n /// function is called again, it overwrites the current allowance\\n /// with `amount`. Reverts if the approval reverted or if\\n /// `receiveApproval` call on the spender reverted.\\n function approveAndCall(\\n address spender,\\n uint256 amount,\\n bytes memory extraData\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x393d18ef81a57dcc96fff4c340cc2945deaebb37b9796c322cf2bc96872c3df8\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IERC20WithPermit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\\\";\\n\\nimport \\\"./IApproveAndCall.sol\\\";\\n\\n/// @title IERC20WithPermit\\n/// @notice Burnable ERC20 token with EIP2612 permit functionality. User can\\n/// authorize a transfer of their token with a signature conforming\\n/// EIP712 standard instead of an on-chain transaction from their\\n/// address. Anyone can submit this signature on the user's behalf by\\n/// calling the permit function, as specified in EIP2612 standard,\\n/// paying gas fees, and possibly performing other actions in the same\\n/// transaction.\\ninterface IERC20WithPermit is IERC20, IERC20Metadata, IApproveAndCall {\\n /// @notice EIP2612 approval made with secp256k1 signature.\\n /// Users can authorize a transfer of their tokens with a signature\\n /// conforming EIP712 standard, rather than an on-chain transaction\\n /// from their address. Anyone can submit this signature on the\\n /// user's behalf by calling the permit function, paying gas fees,\\n /// and possibly performing other actions in the same transaction.\\n /// @dev The deadline argument can be set to `type(uint256).max to create\\n /// permits that effectively never expire.\\n function permit(\\n address owner,\\n address spender,\\n uint256 amount,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /// @notice Destroys `amount` tokens from the caller.\\n function burn(uint256 amount) external;\\n\\n /// @notice Destroys `amount` of tokens from `account`, deducting the amount\\n /// from caller's allowance.\\n function burnFrom(address account, uint256 amount) external;\\n\\n /// @notice Returns hash of EIP712 Domain struct with the token name as\\n /// a signing domain and token contract as a verifying contract.\\n /// Used to construct EIP2612 signature provided to `permit`\\n /// function.\\n /* solhint-disable-next-line func-name-mixedcase */\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n\\n /// @notice Returns the current nonce for EIP2612 permission for the\\n /// provided token owner for a replay protection. Used to construct\\n /// EIP2612 signature provided to `permit` function.\\n function nonce(address owner) external view returns (uint256);\\n\\n /// @notice Returns EIP2612 Permit message hash. Used to construct EIP2612\\n /// signature provided to `permit` function.\\n /* solhint-disable-next-line func-name-mixedcase */\\n function PERMIT_TYPEHASH() external pure returns (bytes32);\\n}\\n\",\"keccak256\":\"0xdac9a5086c19a7128b505a7be1ab0ac1aa314f6989cb88d2417e9d7383f89fa9\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IReceiveApproval.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\n/// @notice An interface that should be implemented by contracts supporting\\n/// `approveAndCall`/`receiveApproval` pattern.\\ninterface IReceiveApproval {\\n /// @notice Receives approval to spend tokens. Called as a result of\\n /// `approveAndCall` call on the token.\\n function receiveApproval(\\n address from,\\n uint256 amount,\\n address token,\\n bytes calldata extraData\\n ) external;\\n}\\n\",\"keccak256\":\"0x6a30d83ad230548b1e7839737affc8489a035314209de14b89dbef7fb0f66395\",\"license\":\"MIT\"},\"@threshold-network/solidity-contracts/contracts/staking/IApplication.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-or-later\\n\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n\\npragma solidity ^0.8.9;\\n\\n/// @title Application interface for Threshold Network applications\\n/// @notice Generic interface for an application. Application is an external\\n/// smart contract or a set of smart contracts utilizing functionalities\\n/// offered by Threshold Network. Applications authorized for the given\\n/// staking provider are eligible to slash the stake delegated to that\\n/// staking provider.\\ninterface IApplication {\\n /// @dev Event emitted by `withdrawRewards` function.\\n event RewardsWithdrawn(address indexed stakingProvider, uint96 amount);\\n\\n /// @notice Withdraws application rewards for the given staking provider.\\n /// Rewards are withdrawn to the staking provider's beneficiary\\n /// address set in the staking contract.\\n /// @dev Emits `RewardsWithdrawn` event.\\n function withdrawRewards(address stakingProvider) external;\\n\\n /// @notice Used by T staking contract to inform the application that the\\n /// authorized amount for the given staking provider increased.\\n /// The application may do any necessary housekeeping. The\\n /// application must revert the transaction in case the\\n /// authorization is below the minimum required.\\n function authorizationIncreased(\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external;\\n\\n /// @notice Used by T staking contract to inform the application that the\\n /// authorization decrease for the given staking provider has been\\n /// requested. The application should mark the authorization as\\n /// pending decrease and respond to the staking contract with\\n /// `approveAuthorizationDecrease` at its discretion. It may\\n /// happen right away but it also may happen several months later.\\n /// If there is already a pending authorization decrease request\\n /// for the application, and the application does not agree for\\n /// overwriting it, the function should revert.\\n function authorizationDecreaseRequested(\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external;\\n\\n /// @notice Used by T staking contract to inform the application the\\n /// authorization has been decreased for the given staking provider\\n /// involuntarily, as a result of slashing. Lets the application to\\n /// do any housekeeping neccessary. Called with 250k gas limit and\\n /// does not revert the transaction if\\n /// `involuntaryAuthorizationDecrease` call failed.\\n function involuntaryAuthorizationDecrease(\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external;\\n\\n /// @notice Returns the amount of application rewards available for\\n /// withdrawal for the given staking provider.\\n function availableRewards(address stakingProvider)\\n external\\n view\\n returns (uint96);\\n\\n /// @notice The minimum authorization amount required for the staking\\n /// provider so that they can participate in the application.\\n function minimumAuthorization() external view returns (uint96);\\n}\\n\",\"keccak256\":\"0x43d707dccc548bf48ad316d9652450cb297203234d251132cdc6b97508eb44c5\",\"license\":\"GPL-3.0-or-later\"},\"@threshold-network/solidity-contracts/contracts/staking/IStaking.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-or-later\\n\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n\\npragma solidity ^0.8.9;\\n\\n/// @title Interface of Threshold Network staking contract\\n/// @notice The staking contract enables T owners to have their wallets offline\\n/// and their stake managed by staking providers on their behalf.\\n/// The staking contract does not define operator role. The operator\\n/// responsible for running off-chain client software is appointed by\\n/// the staking provider in the particular application utilizing the\\n/// staking contract. All off-chain client software should be able\\n/// to run without exposing operator's or staking provider\\u2019s private\\n/// key and should not require any owner\\u2019s keys at all. The stake\\n/// delegation optimizes the network throughput without compromising the\\n/// security of the owners\\u2019 stake.\\ninterface IStaking {\\n enum StakeType {\\n NU,\\n KEEP,\\n T\\n }\\n\\n //\\n //\\n // Delegating a stake\\n //\\n //\\n\\n /// @notice Creates a delegation with `msg.sender` owner with the given\\n /// staking provider, beneficiary, and authorizer. Transfers the\\n /// given amount of T to the staking contract.\\n /// @dev The owner of the delegation needs to have the amount approved to\\n /// transfer to the staking contract.\\n function stake(\\n address stakingProvider,\\n address payable beneficiary,\\n address authorizer,\\n uint96 amount\\n ) external;\\n\\n /// @notice Allows the Governance to set the minimum required stake amount.\\n /// This amount is required to protect against griefing the staking\\n /// contract and individual applications are allowed to require\\n /// higher minimum stakes if necessary.\\n function setMinimumStakeAmount(uint96 amount) external;\\n\\n //\\n //\\n // Authorizing an application\\n //\\n //\\n\\n /// @notice Allows the Governance to approve the particular application\\n /// before individual stake authorizers are able to authorize it.\\n function approveApplication(address application) external;\\n\\n /// @notice Increases the authorization of the given staking provider for\\n /// the given application by the given amount. Can only be called by\\n /// the authorizer for that staking provider.\\n /// @dev Calls `authorizationIncreased(address stakingProvider, uint256 amount)`\\n /// on the given application to notify the application about\\n /// authorization change. See `IApplication`.\\n function increaseAuthorization(\\n address stakingProvider,\\n address application,\\n uint96 amount\\n ) external;\\n\\n /// @notice Requests decrease of the authorization for the given staking\\n /// provider on the given application by the provided amount.\\n /// It may not change the authorized amount immediatelly. When\\n /// it happens depends on the application. Can only be called by the\\n /// given staking provider\\u2019s authorizer. Overwrites pending\\n /// authorization decrease for the given staking provider and\\n /// application if the application agrees for that. If the\\n /// application does not agree for overwriting, the function\\n /// reverts.\\n /// @dev Calls `authorizationDecreaseRequested(address stakingProvider, uint256 amount)`\\n /// on the given application. See `IApplication`.\\n function requestAuthorizationDecrease(\\n address stakingProvider,\\n address application,\\n uint96 amount\\n ) external;\\n\\n /// @notice Requests decrease of all authorizations for the given staking\\n /// provider on all applications by all authorized amount.\\n /// It may not change the authorized amount immediatelly. When\\n /// it happens depends on the application. Can only be called by the\\n /// given staking provider\\u2019s authorizer. Overwrites pending\\n /// authorization decrease for the given staking provider and\\n /// application.\\n /// @dev Calls `authorizationDecreaseRequested(address stakingProvider, uint256 amount)`\\n /// for each authorized application. See `IApplication`.\\n function requestAuthorizationDecrease(address stakingProvider) external;\\n\\n /// @notice Called by the application at its discretion to approve the\\n /// previously requested authorization decrease request. Can only be\\n /// called by the application that was previously requested to\\n /// decrease the authorization for that staking provider.\\n /// Returns resulting authorized amount for the application.\\n function approveAuthorizationDecrease(address stakingProvider)\\n external\\n returns (uint96);\\n\\n /// @notice Decreases the authorization for the given `stakingProvider` on\\n /// the given disabled `application`, for all authorized amount.\\n /// Can be called by anyone.\\n function forceDecreaseAuthorization(\\n address stakingProvider,\\n address application\\n ) external;\\n\\n /// @notice Pauses the given application\\u2019s eligibility to slash stakes.\\n /// Besides that stakers can't change authorization to the application.\\n /// Can be called only by the Panic Button of the particular\\n /// application. The paused application can not slash stakes until\\n /// it is approved again by the Governance using `approveApplication`\\n /// function. Should be used only in case of an emergency.\\n function pauseApplication(address application) external;\\n\\n /// @notice Disables the given application. The disabled application can't\\n /// slash stakers. Also stakers can't increase authorization to that\\n /// application but can decrease without waiting by calling\\n /// `requestAuthorizationDecrease` at any moment. Can be called only\\n /// by the governance. The disabled application can't be approved\\n /// again. Should be used only in case of an emergency.\\n function disableApplication(address application) external;\\n\\n /// @notice Sets the Panic Button role for the given application to the\\n /// provided address. Can only be called by the Governance. If the\\n /// Panic Button for the given application should be disabled, the\\n /// role address should be set to 0x0 address.\\n function setPanicButton(address application, address panicButton) external;\\n\\n /// @notice Sets the maximum number of applications one staking provider can\\n /// have authorized. Used to protect against DoSing slashing queue.\\n /// Can only be called by the Governance.\\n function setAuthorizationCeiling(uint256 ceiling) external;\\n\\n //\\n //\\n // Stake top-up\\n //\\n //\\n\\n /// @notice Increases the amount of the stake for the given staking provider.\\n /// If `autoIncrease` flag is true then the amount will be added for\\n /// all authorized applications.\\n /// @dev The sender of this transaction needs to have the amount approved to\\n /// transfer to the staking contract.\\n function topUp(address stakingProvider, uint96 amount) external;\\n\\n /// @notice Toggle `autoIncrease` flag. If true then the complete amount\\n /// in top-up will be added to already authorized applications.\\n function toggleAutoAuthorizationIncrease(address stakingProvider) external;\\n\\n //\\n //\\n // Undelegating a stake (unstaking)\\n //\\n //\\n\\n /// @notice Reduces the liquid T stake amount by the provided amount and\\n /// withdraws T to the owner. Reverts if there is at least one\\n /// authorization higher than the sum of the legacy stake and\\n /// remaining liquid T stake or if the unstake amount is higher than\\n /// the liquid T stake amount. Can be called only by the delegation\\n /// owner or the staking provider.\\n function unstakeT(address stakingProvider, uint96 amount) external;\\n\\n /// @notice Sets the legacy KEEP staking contract active stake amount cached\\n /// in T staking contract to 0. Reverts if the amount of liquid T\\n /// staked in T staking contract is lower than the highest\\n /// application authorization. This function allows to unstake from\\n /// KEEP staking contract and still being able to operate in T\\n /// network and earning rewards based on the liquid T staked. Can be\\n /// called only by the delegation owner or the staking provider.\\n function unstakeKeep(address stakingProvider) external;\\n\\n /// @notice Sets to 0 the amount of T that is cached from the legacy\\n /// NU staking contract. Reverts if there is at least one\\n /// authorization higher than the sum of remaining legacy NU stake\\n /// and native T stake for that staking provider or if the unstaked\\n /// amount is higher than the cached legacy stake amount. If succeeded,\\n /// the legacy NU stake can be partially or fully undelegated on\\n /// the legacy NU staking contract. This function allows to unstake\\n /// from NU staking contract while still being able to operate in\\n /// T network and earning rewards based on the native T staked.\\n /// Can be called only by the stake owner or the staking provider.\\n function unstakeNu(address stakingProvider) external;\\n\\n /// @notice Sets cached legacy stake amount to 0, sets the liquid T stake\\n /// amount to 0 and withdraws all liquid T from the stake to the\\n /// owner. Reverts if there is at least one non-zero authorization.\\n /// Can be called only by the delegation owner or the staking\\n /// provider.\\n function unstakeAll(address stakingProvider) external;\\n\\n //\\n //\\n // Keeping information in sync\\n //\\n //\\n\\n /// @notice Sets reward in T tokens for notification of misbehaviour\\n /// of one staking provider. Can only be called by the governance.\\n function setNotificationReward(uint96 reward) external;\\n\\n /// @notice Transfer some amount of T tokens as reward for notifications\\n /// of misbehaviour\\n function pushNotificationReward(uint96 reward) external;\\n\\n /// @notice Withdraw some amount of T tokens from notifiers treasury.\\n /// Can only be called by the governance.\\n function withdrawNotificationReward(address recipient, uint96 amount)\\n external;\\n\\n /// @notice Adds staking providers to the slashing queue along with the\\n /// amount that should be slashed from each one of them. Can only be\\n /// called by application authorized for all staking providers in\\n /// the array.\\n function slash(uint96 amount, address[] memory stakingProviders) external;\\n\\n /// @notice Adds staking providers to the slashing queue along with the\\n /// amount. The notifier will receive reward per each staking\\n /// provider from notifiers treasury. Can only be called by\\n /// application authorized for all staking providers in the array.\\n function seize(\\n uint96 amount,\\n uint256 rewardMultipier,\\n address notifier,\\n address[] memory stakingProviders\\n ) external;\\n\\n /// @notice Takes the given number of queued slashing operations and\\n /// processes them. Receives 5% of the slashed amount.\\n /// Executes `involuntaryAllocationDecrease` function on each\\n /// affected application.\\n function processSlashing(uint256 count) external;\\n\\n //\\n //\\n // Auxiliary functions\\n //\\n //\\n\\n /// @notice Returns the authorized stake amount of the staking provider for\\n /// the application.\\n function authorizedStake(address stakingProvider, address application)\\n external\\n view\\n returns (uint96);\\n\\n /// @notice Returns staked amount of T, Keep and Nu for the specified\\n /// staking provider.\\n /// @dev All values are in T denomination\\n function stakes(address stakingProvider)\\n external\\n view\\n returns (\\n uint96 tStake,\\n uint96 keepInTStake,\\n uint96 nuInTStake\\n );\\n\\n /// @notice Returns start staking timestamp.\\n /// @dev This value is set at most once.\\n function getStartStakingTimestamp(address stakingProvider)\\n external\\n view\\n returns (uint256);\\n\\n /// @notice Returns auto-increase flag.\\n function getAutoIncreaseFlag(address stakingProvider)\\n external\\n view\\n returns (bool);\\n\\n /// @notice Returns staked amount of NU for the specified staking provider.\\n function stakedNu(address stakingProvider) external view returns (uint256);\\n\\n /// @notice Gets the stake owner, the beneficiary and the authorizer\\n /// for the specified staking provider address.\\n /// @return owner Stake owner address.\\n /// @return beneficiary Beneficiary address.\\n /// @return authorizer Authorizer address.\\n function rolesOf(address stakingProvider)\\n external\\n view\\n returns (\\n address owner,\\n address payable beneficiary,\\n address authorizer\\n );\\n\\n /// @notice Returns length of application array\\n function getApplicationsLength() external view returns (uint256);\\n\\n /// @notice Returns length of slashing queue\\n function getSlashingQueueLength() external view returns (uint256);\\n\\n /// @notice Returns minimum possible stake for T, KEEP or NU in T\\n /// denomination.\\n /// @dev For example, suppose the given staking provider has 10 T, 20 T worth\\n /// of KEEP, and 30 T worth of NU all staked, and the maximum\\n /// application authorization is 40 T, then `getMinStaked` for\\n /// that staking provider returns:\\n /// * 0 T if KEEP stake type specified i.e.\\n /// min = 40 T max - (10 T) = 30 T\\n /// * 10 T if NU stake type specified i.e.\\n /// min = 40 T max - (10 T) = 30 T\\n /// * 0 T if T stake type specified i.e.\\n /// min = 40 T max = 40 T\\n /// In other words, the minimum stake amount for the specified\\n /// stake type is the minimum amount of stake of the given type\\n /// needed to satisfy the maximum application authorization given\\n /// the staked amounts of the T stake types for that staking provider.\\n function getMinStaked(address stakingProvider, StakeType stakeTypes)\\n external\\n view\\n returns (uint96);\\n\\n /// @notice Returns available amount to authorize for the specified application\\n function getAvailableToAuthorize(\\n address stakingProvider,\\n address application\\n ) external view returns (uint96);\\n}\\n\",\"keccak256\":\"0xc8fbea45ba10de0383d6e7b2dd0f3931971e1b702e4a308ff8325bb23fdff81c\",\"license\":\"GPL-3.0-or-later\"},\"contracts/BeaconDkgValidator.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\nimport \\\"./libraries/BytesLib.sol\\\";\\nimport {BeaconDkg as DKG} from \\\"./libraries/BeaconDkg.sol\\\";\\n\\n/// @title DKG result validator\\n/// @notice DKGValidator allows performing a full validation of DKG result,\\n/// including checking the format of fields in the result, declared\\n/// selected group members, and signatures of operators supporting the\\n/// result. The operator submitting the result should perform the\\n/// validation using a free contract call before submitting the result\\n/// to ensure their result is valid and can not be challenged. All other\\n/// network operators should perform validation of the submitted result\\n/// using a free contract call and challenge the result if the\\n/// validation fails.\\ncontract BeaconDkgValidator {\\n using BytesLib for bytes;\\n using ECDSA for bytes32;\\n\\n /// @dev Size of a group in the threshold relay.\\n uint256 public constant groupSize = 64;\\n\\n /// @dev The minimum number of group members needed to interact according to\\n /// the protocol to produce a relay entry. The adversary can not learn\\n /// anything about the key as long as it does not break into\\n /// groupThreshold+1 of members.\\n uint256 public constant groupThreshold = 33;\\n\\n /// @dev The minimum number of active and properly behaving group members\\n /// during the DKG needed to accept the result. This number is higher\\n /// than `groupThreshold` to keep a safety margin for members becoming\\n /// inactive after DKG so that the group can still produce a relay\\n /// entry.\\n uint256 public constant activeThreshold = 58; // 90% of groupSize\\n\\n /// @dev Size in bytes of a single signature produced by operator supporting\\n /// DKG result.\\n uint256 public constant signatureByteSize = 65;\\n\\n SortitionPool public immutable sortitionPool;\\n\\n constructor(SortitionPool _sortitionPool) {\\n require(\\n address(_sortitionPool) != address(0),\\n \\\"Zero-address reference\\\"\\n );\\n\\n sortitionPool = _sortitionPool;\\n }\\n\\n /// @notice Performs a full validation of DKG result, including checking the\\n /// format of fields in the result, declared selected group members,\\n /// and signatures of operators supporting the result.\\n /// @param seed seed used to start the DKG and select group members\\n /// @param startBlock DKG start block\\n /// @return isValid true if the result is valid, false otherwise\\n /// @return errorMsg validation error message; empty for a valid result\\n function validate(\\n DKG.Result calldata result,\\n uint256 seed,\\n uint256 startBlock\\n ) external view returns (bool isValid, string memory errorMsg) {\\n (bool hasValidFields, string memory error) = validateFields(result);\\n if (!hasValidFields) {\\n return (false, error);\\n }\\n\\n if (!validateSignatures(result, startBlock)) {\\n return (false, \\\"Invalid signatures\\\");\\n }\\n\\n if (!validateGroupMembers(result, seed)) {\\n return (false, \\\"Invalid group members\\\");\\n }\\n\\n // At this point all group members and mishbehaved members were verified\\n if (!validateMembersHash(result)) {\\n return (false, \\\"Invalid members hash\\\");\\n }\\n\\n return (true, \\\"\\\");\\n }\\n\\n /// @notice Performs a static validation of DKG result fields: lengths,\\n /// ranges, and order of arrays.\\n /// @return isValid true if the result is valid, false otherwise\\n /// @return errorMsg validation error message; empty for a valid result\\n function validateFields(DKG.Result calldata result)\\n public\\n pure\\n returns (bool isValid, string memory errorMsg)\\n {\\n // Group public key needs to be 128 bytes long.\\n if (result.groupPubKey.length != 128) {\\n return (false, \\\"Malformed group public key\\\");\\n }\\n\\n // The number of misbehaved members can not exceed the threshold.\\n // Misbehaved member indices needs to be unique, between [1, groupSize],\\n // and sorted in ascending order.\\n uint8[] calldata misbehavedMembersIndices = result\\n .misbehavedMembersIndices;\\n if (groupSize - misbehavedMembersIndices.length < activeThreshold) {\\n return (false, \\\"Too many members misbehaving during DKG\\\");\\n }\\n if (misbehavedMembersIndices.length > 1) {\\n if (\\n misbehavedMembersIndices[0] < 1 ||\\n misbehavedMembersIndices[misbehavedMembersIndices.length - 1] >\\n groupSize\\n ) {\\n return (false, \\\"Corrupted misbehaved members indices\\\");\\n }\\n for (uint256 i = 1; i < misbehavedMembersIndices.length; i++) {\\n if (\\n misbehavedMembersIndices[i - 1] >=\\n misbehavedMembersIndices[i]\\n ) {\\n return (false, \\\"Corrupted misbehaved members indices\\\");\\n }\\n }\\n }\\n\\n // Each signature needs to have a correct length and signatures need to\\n // be provided.\\n uint256 signaturesCount = result.signatures.length / signatureByteSize;\\n if (result.signatures.length == 0) {\\n return (false, \\\"No signatures provided\\\");\\n }\\n if (result.signatures.length % signatureByteSize != 0) {\\n return (false, \\\"Malformed signatures array\\\");\\n }\\n\\n // We expect the same amount of signatures as the number of declared\\n // group member indices that signed the result.\\n uint256[] calldata signingMembersIndices = result.signingMembersIndices;\\n if (signaturesCount != signingMembersIndices.length) {\\n return (false, \\\"Unexpected signatures count\\\");\\n }\\n if (signaturesCount < groupThreshold) {\\n return (false, \\\"Too few signatures\\\");\\n }\\n if (signaturesCount > groupSize) {\\n return (false, \\\"Too many signatures\\\");\\n }\\n\\n // Signing member indices needs to be unique, between [1,groupSize],\\n // and sorted in ascending order.\\n if (\\n signingMembersIndices[0] < 1 ||\\n signingMembersIndices[signingMembersIndices.length - 1] > groupSize\\n ) {\\n return (false, \\\"Corrupted signing member indices\\\");\\n }\\n for (uint256 i = 1; i < signingMembersIndices.length; i++) {\\n if (signingMembersIndices[i - 1] >= signingMembersIndices[i]) {\\n return (false, \\\"Corrupted signing member indices\\\");\\n }\\n }\\n\\n return (true, \\\"\\\");\\n }\\n\\n /// @notice Performs validation of group members as declared in DKG\\n /// result against group members selected by the sortition pool.\\n /// @param seed seed used to start the DKG and select group members\\n /// @return true if group members matches; false otherwise\\n function validateGroupMembers(DKG.Result calldata result, uint256 seed)\\n public\\n view\\n returns (bool)\\n {\\n uint32[] calldata resultMembers = result.members;\\n uint32[] memory actualGroupMembers = sortitionPool.selectGroup(\\n groupSize,\\n bytes32(seed)\\n );\\n if (resultMembers.length != actualGroupMembers.length) {\\n return false;\\n }\\n for (uint256 i = 0; i < resultMembers.length; i++) {\\n if (resultMembers[i] != actualGroupMembers[i]) {\\n return false;\\n }\\n }\\n return true;\\n }\\n\\n /// @notice Performs validation of signatures supplied in DKG result.\\n /// Note that this function does not check if addresses which\\n /// supplied signatures supporting the result are the ones selected\\n /// to the group by sortition pool. This function should be used\\n /// together with `validateGroupMembers`.\\n /// @param startBlock DKG start block\\n /// @return true if group members matches; false otherwise\\n function validateSignatures(DKG.Result calldata result, uint256 startBlock)\\n public\\n view\\n returns (bool)\\n {\\n bytes32 hash = keccak256(\\n abi.encode(\\n block.chainid,\\n result.groupPubKey,\\n result.misbehavedMembersIndices,\\n startBlock\\n )\\n ).toEthSignedMessageHash();\\n\\n uint256[] calldata signingMembersIndices = result.signingMembersIndices;\\n uint32[] memory signingMemberIds = new uint32[](\\n signingMembersIndices.length\\n );\\n for (uint256 i = 0; i < signingMembersIndices.length; i++) {\\n signingMemberIds[i] = result.members[signingMembersIndices[i] - 1];\\n }\\n\\n address[] memory signingMemberAddresses = sortitionPool.getIDOperators(\\n signingMemberIds\\n );\\n\\n bytes memory current; // Current signature to be checked.\\n\\n uint256 signaturesCount = result.signatures.length / signatureByteSize;\\n for (uint256 i = 0; i < signaturesCount; i++) {\\n current = result.signatures.slice(\\n signatureByteSize * i,\\n signatureByteSize\\n );\\n address recoveredAddress = hash.recover(current);\\n\\n if (signingMemberAddresses[i] != recoveredAddress) {\\n return false;\\n }\\n }\\n\\n return true;\\n }\\n\\n /// @notice Performs validation of hashed group members that actively took\\n /// part in DKG.\\n /// @param result DKG result\\n /// @return true if result's group members hash matches with the one that is\\n /// challenged.\\n function validateMembersHash(DKG.Result calldata result)\\n public\\n pure\\n returns (bool)\\n {\\n if (result.misbehavedMembersIndices.length > 0) {\\n // members that generated a group signing key\\n uint32[] memory groupMembers = new uint32[](\\n result.members.length - result.misbehavedMembersIndices.length\\n );\\n uint256 k = 0; // misbehaved members counter\\n uint256 j = 0; // group members counter\\n for (uint256 i = 0; i < result.members.length; i++) {\\n // misbehaved member indices start from 1, so we need to -1 on misbehaved\\n if (i != result.misbehavedMembersIndices[k] - 1) {\\n groupMembers[j] = result.members[i];\\n j++;\\n } else if (k < result.misbehavedMembersIndices.length - 1) {\\n k++;\\n }\\n }\\n\\n return keccak256(abi.encode(groupMembers)) == result.membersHash;\\n }\\n\\n return keccak256(abi.encode(result.members)) == result.membersHash;\\n }\\n}\\n\",\"keccak256\":\"0xaacb5961dc3181238036f1e747b3d1935f356ca5ff27bd9c9c1c0c22dee6630c\",\"license\":\"GPL-3.0-only\"},\"contracts/Governable.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\n/// @notice Governable contract.\\n/// @dev A constructor is not defined, which makes the contract compatible with\\n/// upgradable proxies. This requires calling explicitly `_transferGovernance`\\n/// function in a child contract.\\nabstract contract Governable {\\n // Governance of the contract\\n // The variable should be initialized by the implementing contract.\\n // slither-disable-next-line uninitialized-state\\n address public governance;\\n\\n // Reserved storage space in case we need to add more variables,\\n // since there are upgradeable contracts that inherit from this one.\\n // See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\\n // slither-disable-next-line unused-state\\n uint256[49] private __gap;\\n\\n event GovernanceTransferred(address oldGovernance, address newGovernance);\\n\\n modifier onlyGovernance() virtual {\\n require(governance == msg.sender, \\\"Caller is not the governance\\\");\\n _;\\n }\\n\\n /// @notice Transfers governance of the contract to `newGovernance`.\\n function transferGovernance(address newGovernance)\\n external\\n virtual\\n onlyGovernance\\n {\\n require(\\n newGovernance != address(0),\\n \\\"New governance is the zero address\\\"\\n );\\n _transferGovernance(newGovernance);\\n }\\n\\n function _transferGovernance(address newGovernance) internal virtual {\\n address oldGovernance = governance;\\n governance = newGovernance;\\n emit GovernanceTransferred(oldGovernance, newGovernance);\\n }\\n}\\n\",\"keccak256\":\"0xcc6a0fe8fdf05a805d2874dc7dd76dede1eb16e3ab77f2d0069dbb92272ab0a3\",\"license\":\"GPL-3.0-only\"},\"contracts/RandomBeacon.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./api/IRandomBeacon.sol\\\";\\nimport \\\"./libraries/Groups.sol\\\";\\nimport \\\"./libraries/Relay.sol\\\";\\nimport \\\"./libraries/Groups.sol\\\";\\nimport \\\"./libraries/Callback.sol\\\";\\nimport \\\"./Reimbursable.sol\\\";\\nimport \\\"./Governable.sol\\\";\\nimport {BeaconInactivity as Inactivity} from \\\"./libraries/BeaconInactivity.sol\\\";\\nimport {BeaconAuthorization as Authorization} from \\\"./libraries/BeaconAuthorization.sol\\\";\\nimport {BeaconDkg as DKG} from \\\"./libraries/BeaconDkg.sol\\\";\\nimport {BeaconDkgValidator as DKGValidator} from \\\"./BeaconDkgValidator.sol\\\";\\n\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\nimport \\\"@threshold-network/solidity-contracts/contracts/staking/IApplication.sol\\\";\\nimport \\\"@threshold-network/solidity-contracts/contracts/staking/IStaking.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/Math.sol\\\";\\n\\n/// @title Keep Random Beacon\\n/// @notice Keep Random Beacon contract. It lets to request a new\\n/// relay entry and validates the new relay entry provided by the\\n/// network. This contract is in charge of all other Random Beacon\\n/// activities such as group lifecycle or slashing.\\n/// @dev Should be owned by the governance contract controlling Random Beacon\\n/// parameters.\\ncontract RandomBeacon is IRandomBeacon, IApplication, Governable, Reimbursable {\\n using SafeERC20 for IERC20;\\n using Authorization for Authorization.Data;\\n using DKG for DKG.Data;\\n using Groups for Groups.Data;\\n using Relay for Relay.Data;\\n using Callback for Callback.Data;\\n\\n // Constant parameters\\n\\n /// @notice Seed value used for the genesis group selection.\\n /// https://www.wolframalpha.com/input/?i=pi+to+78+digits\\n uint256 internal constant genesisSeed =\\n 31415926535897932384626433832795028841971693993751058209749445923078164062862;\\n\\n // Governable parameters\\n\\n /// @notice Relay entry callback gas limit. This is the gas limit with which\\n /// callback function provided in the relay request transaction is\\n /// executed. The callback is executed with a new relay entry value\\n /// in the same transaction the relay entry is submitted.\\n uint256 internal _callbackGasLimit;\\n\\n /// @notice The frequency of new group creation. Groups are created with\\n /// a fixed frequency of relay requests.\\n uint256 internal _groupCreationFrequency;\\n\\n /// @notice Slashing amount for submitting a malicious DKG result. Every\\n /// DKG result submitted can be challenged for the time of\\n /// `dkg.ResultChallengePeriodLength`. If the DKG result submitted\\n /// is challenged and proven to be malicious, the operator who\\n /// submitted the malicious result is slashed for\\n /// `_maliciousDkgResultSlashingAmount`.\\n uint96 internal _maliciousDkgResultSlashingAmount;\\n\\n /// @notice Slashing amount when an unauthorized signing has been proved,\\n /// which means the private key leaked and all the group members\\n /// should be punished.\\n uint96 internal _unauthorizedSigningSlashingAmount;\\n\\n /// @notice Duration of the sortition pool rewards ban imposed on operators\\n /// who misbehaved during DKG by being inactive or disqualified and\\n /// for operators that were identified by the rest of group members\\n /// as inactive via `notifyOperatorInactivity`.\\n uint256 internal _sortitionPoolRewardsBanDuration;\\n\\n /// @notice Percentage of the staking contract malicious behavior\\n /// notification reward which will be transferred to the notifier\\n /// reporting about relay entry timeout. Notifiers are rewarded\\n /// from a notifiers treasury pool. For example, if\\n /// notification reward is 1000 and the value of the multiplier is\\n /// 5, the notifier will receive: 5% of 1000 = 50 per each\\n /// operator affected.\\n uint256 internal _relayEntryTimeoutNotificationRewardMultiplier;\\n\\n /// @notice Percentage of the staking contract malicious behavior\\n /// notification reward which will be transferred to the notifier\\n /// reporting about unauthorized signing. Notifiers are rewarded\\n /// from a notifiers treasury pool. For example, if a\\n /// notification reward is 1000 and the value of the multiplier is\\n /// 5, the notifier will receive: 5% of 1000 = 50 per each\\n /// operator affected.\\n uint256 internal _unauthorizedSigningNotificationRewardMultiplier;\\n\\n /// @notice Percentage of the staking contract malicious behavior\\n /// notification reward which will be transferred to the notifier\\n /// reporting about a malicious DKG result. Notifiers are rewarded\\n /// from a notifiers treasury pool. For example, if\\n /// notification reward is 1000 and the value of the multiplier is\\n /// 5, the notifier will receive: 5% of 1000 = 50 per each\\n /// operator affected.\\n uint256 internal _dkgMaliciousResultNotificationRewardMultiplier;\\n\\n /// @notice Calculated gas cost for submitting a DKG result. This will\\n /// be refunded as part of the DKG approval process. It is in the\\n /// submitter's interest to not skip his priority turn on the approval,\\n /// otherwise the refund of the DKG submission will be refunded to\\n /// another group member that will call the DKG approve function.\\n uint256 internal _dkgResultSubmissionGas;\\n\\n /// @notice Gas that is meant to balance the DKG result approval's overall\\n /// cost. Can be updated by the governance based on the current\\n /// market conditions.\\n uint256 internal _dkgResultApprovalGasOffset;\\n\\n /// @notice Gas that is meant to balance the operator inactivity notification\\n /// cost. Can be updated by the governance based on the current\\n /// market conditions.\\n uint256 internal _notifyOperatorInactivityGasOffset;\\n\\n /// @notice Gas that is meant to balance the relay entry submission cost.\\n /// Can be updated by the governance based on the current market\\n /// conditions.\\n uint256 internal _relayEntrySubmissionGasOffset;\\n\\n // Other parameters\\n\\n /// @notice Stores current operator inactivity claim nonce for given group.\\n /// Each claim is made with an unique nonce which protects\\n /// against claim replay.\\n mapping(uint64 => uint256) public inactivityClaimNonce; // groupId -> nonce\\n\\n /// @notice Authorized addresses that can request a relay entry.\\n mapping(address => bool) public authorizedRequesters;\\n\\n // External dependencies\\n\\n SortitionPool public sortitionPool;\\n IERC20 public tToken;\\n IStaking public staking;\\n\\n // Libraries data storages\\n\\n Authorization.Data internal authorization;\\n DKG.Data internal dkg;\\n Groups.Data internal groups;\\n Relay.Data internal relay;\\n Callback.Data internal callback;\\n\\n // Events\\n\\n event AuthorizationParametersUpdated(\\n uint96 minimumAuthorization,\\n uint64 authorizationDecreaseDelay,\\n uint64 authorizationDecreaseChangePeriod\\n );\\n\\n event RelayEntryParametersUpdated(\\n uint256 relayEntrySoftTimeout,\\n uint256 relayEntryHardTimeout,\\n uint256 callbackGasLimit\\n );\\n\\n event GroupCreationParametersUpdated(\\n uint256 groupCreationFrequency,\\n uint256 groupLifetime,\\n uint256 dkgResultChallengePeriodLength,\\n uint256 dkgResultChallengeExtraGas,\\n uint256 dkgResultSubmissionTimeout,\\n uint256 dkgResultSubmitterPrecedencePeriodLength\\n );\\n\\n event RewardParametersUpdated(\\n uint256 sortitionPoolRewardsBanDuration,\\n uint256 relayEntryTimeoutNotificationRewardMultiplier,\\n uint256 unauthorizedSigningNotificationRewardMultiplier,\\n uint256 dkgMaliciousResultNotificationRewardMultiplier\\n );\\n\\n event SlashingParametersUpdated(\\n uint256 relayEntrySubmissionFailureSlashingAmount,\\n uint256 maliciousDkgResultSlashingAmount,\\n uint256 unauthorizedSigningSlashingAmount\\n );\\n\\n event GasParametersUpdated(\\n uint256 dkgResultSubmissionGas,\\n uint256 dkgResultApprovalGasOffset,\\n uint256 notifyOperatorInactivityGasOffset,\\n uint256 relayEntrySubmissionGasOffset\\n );\\n\\n event RequesterAuthorizationUpdated(\\n address indexed requester,\\n bool isAuthorized\\n );\\n\\n event DkgStarted(uint256 indexed seed);\\n\\n event DkgResultSubmitted(\\n bytes32 indexed resultHash,\\n uint256 indexed seed,\\n DKG.Result result\\n );\\n\\n event DkgTimedOut();\\n\\n event DkgResultApproved(\\n bytes32 indexed resultHash,\\n address indexed approver\\n );\\n\\n event DkgResultChallenged(\\n bytes32 indexed resultHash,\\n address indexed challenger,\\n string reason\\n );\\n\\n event DkgMaliciousResultSlashed(\\n bytes32 indexed resultHash,\\n uint256 slashingAmount,\\n address maliciousSubmitter\\n );\\n\\n event DkgMaliciousResultSlashingFailed(\\n bytes32 indexed resultHash,\\n uint256 slashingAmount,\\n address maliciousSubmitter\\n );\\n\\n event DkgStateLocked();\\n\\n event DkgSeedTimedOut();\\n\\n event GroupRegistered(uint64 indexed groupId, bytes indexed groupPubKey);\\n\\n event RelayEntryRequested(\\n uint256 indexed requestId,\\n uint64 groupId,\\n bytes previousEntry\\n );\\n\\n event RelayEntrySubmitted(\\n uint256 indexed requestId,\\n address submitter,\\n bytes entry\\n );\\n\\n event RelayEntryTimedOut(\\n uint256 indexed requestId,\\n uint64 terminatedGroupId\\n );\\n\\n event RelayEntryDelaySlashed(\\n uint256 indexed requestId,\\n uint256 slashingAmount,\\n address[] groupMembers\\n );\\n\\n event RelayEntryDelaySlashingFailed(\\n uint256 indexed requestId,\\n uint256 slashingAmount,\\n address[] groupMembers\\n );\\n\\n event RelayEntryTimeoutSlashed(\\n uint256 indexed requestId,\\n uint256 slashingAmount,\\n address[] groupMembers\\n );\\n\\n event RelayEntryTimeoutSlashingFailed(\\n uint256 indexed requestId,\\n uint256 slashingAmount,\\n address[] groupMembers\\n );\\n\\n event UnauthorizedSigningSlashed(\\n uint64 indexed groupId,\\n uint256 unauthorizedSigningSlashingAmount,\\n address[] groupMembers\\n );\\n\\n event UnauthorizedSigningSlashingFailed(\\n uint64 indexed groupId,\\n uint256 unauthorizedSigningSlashingAmount,\\n address[] groupMembers\\n );\\n\\n event CallbackFailed(uint256 entry, uint256 entrySubmittedBlock);\\n\\n event InactivityClaimed(\\n uint64 indexed groupId,\\n uint256 nonce,\\n address notifier\\n );\\n\\n event OperatorRegistered(\\n address indexed stakingProvider,\\n address indexed operator\\n );\\n\\n event AuthorizationIncreased(\\n address indexed stakingProvider,\\n address indexed operator,\\n uint96 fromAmount,\\n uint96 toAmount\\n );\\n\\n event AuthorizationDecreaseRequested(\\n address indexed stakingProvider,\\n address indexed operator,\\n uint96 fromAmount,\\n uint96 toAmount,\\n uint64 decreasingAt\\n );\\n\\n event AuthorizationDecreaseApproved(address indexed stakingProvider);\\n\\n event InvoluntaryAuthorizationDecreaseFailed(\\n address indexed stakingProvider,\\n address indexed operator,\\n uint96 fromAmount,\\n uint96 toAmount\\n );\\n\\n event OperatorJoinedSortitionPool(\\n address indexed stakingProvider,\\n address indexed operator\\n );\\n\\n event OperatorStatusUpdated(\\n address indexed stakingProvider,\\n address indexed operator\\n );\\n\\n /// @dev Assigns initial values to parameters to make the beacon work\\n /// safely. These parameters are just proposed defaults and they might\\n /// be updated with `update*` functions after the contract deployment\\n /// and before transferring the ownership to the governance contract.\\n constructor(\\n SortitionPool _sortitionPool,\\n IERC20 _tToken,\\n IStaking _staking,\\n DKGValidator _dkgValidator,\\n ReimbursementPool _reimbursementPool\\n ) {\\n sortitionPool = _sortitionPool;\\n tToken = _tToken;\\n staking = _staking;\\n reimbursementPool = _reimbursementPool;\\n\\n require(\\n address(_sortitionPool) != address(0),\\n \\\"Zero-address reference\\\"\\n );\\n require(address(_tToken) != address(0), \\\"Zero-address reference\\\");\\n require(address(_staking) != address(0), \\\"Zero-address reference\\\");\\n require(address(_dkgValidator) != address(0), \\\"Zero-address reference\\\");\\n require(\\n address(_reimbursementPool) != address(0),\\n \\\"Zero-address reference\\\"\\n );\\n\\n dkg.init(_sortitionPool, _dkgValidator);\\n relay.initSeedEntry();\\n\\n _transferGovernance(msg.sender);\\n\\n //\\n // All parameters set in the constructor are initial ones, used at the\\n // moment contracts were deployed for the first time. Parameters are\\n // governable and values assigned in the constructor do not need to\\n // reflect the current ones.\\n //\\n\\n // Minimum authorization is 40k T.\\n //\\n // Authorization decrease delay is 45 days.\\n //\\n // Authorization decrease change period is 45 days. It means pending\\n // authorization decrease can be overwritten all the time.\\n authorization.setParameters(40_000e18, 3_888_000, 3_888_000);\\n\\n // Malicious DKG result slashing amount is set initially to 1% of the\\n // minimum authorization (400 T). This values needs to be increased\\n // significantly once the system is fully launched.\\n //\\n // Unauthorized signing slashing amount is set initially to 1% of the\\n // minimum authorization (400 T). This values needs to be increased\\n // significantly once the system is fully launched.\\n //\\n // Slashing amount for not providing relay entry on time is set\\n // initially to 1% of the minimum authorization (400 T). This values\\n // needs to be increased significantly once the system is fully launched.\\n //\\n // Inactive operators are set as ineligible for rewards for 2 weeks.\\n _maliciousDkgResultSlashingAmount = 400e18;\\n _unauthorizedSigningSlashingAmount = 400e18;\\n relay.setRelayEntrySubmissionFailureSlashingAmount(400e18);\\n\\n // Notifier of a malicious DKG result receives 100% of the notifier\\n // reward from the staking contract.\\n //\\n // Notifier of unauthorized signing receives 100% of the notifier\\n // reward from the staking contract.\\n //\\n // Notifier of relay entry timeout receives 100% of the notifier\\n // reward from the staking contract.\\n _dkgMaliciousResultNotificationRewardMultiplier = 100;\\n _unauthorizedSigningNotificationRewardMultiplier = 100;\\n _relayEntryTimeoutNotificationRewardMultiplier = 100;\\n\\n // Inactive operators are set as ineligible for rewards for 2 weeks.\\n _sortitionPoolRewardsBanDuration = 2 weeks;\\n\\n // DKG result challenge period length is set to 48h, assuming\\n // 15s block time.\\n //\\n // The extra gas required for DKG result challenge is 50k units.\\n //\\n // DKG result submission timeout, gives each member 20 blocks to submit\\n // the result. Assuming 15s block time, it is ~8h to submit the result\\n // in the pessimistic case.\\n //\\n // The original DKG result submitter has 20 blocks to approve it before\\n // anyone else can do that.\\n //\\n // With these parameters, the happy path takes no more than 56 hours.\\n // In practice, it should take about 48 hours (just the challenge time).\\n dkg.setParameters(11_520, 50_000, 1_280, 20);\\n\\n // Relay entry soft timeout gives each of 64 members 20 blocks to submit\\n // the result.\\n //\\n // Relay entry hard timeout is set to ~48h assuming 15s block time.\\n relay.setTimeouts(1_280, 5_760);\\n\\n // Callback gas limit is set to 56k units of gas. As of April 2022, it\\n // is enough to store new entry and block number on-chain.\\n // If the cost of EVM opcodes change over time, these parameters will\\n // have to be updated.\\n _callbackGasLimit = 64_000;\\n\\n // Group lifetime is set to 45 days assuming 15s block time.\\n //\\n // New group is created every 2 relay requests.\\n //\\n // This way, even if ECDSA WalletRegistry is the only consumer of the\\n // beacon initially, and relay request is executed every week, we should\\n // have 2 active groups in the system all the time.\\n groups.setGroupLifetime(259_200);\\n _groupCreationFrequency = 2;\\n\\n // Gas parameters were adjusted based on Ethereum state in April 2022.\\n // If the cost of EVM opcodes change over time, these parameters will\\n // have to be updated.\\n _dkgResultSubmissionGas = 237_650;\\n _dkgResultApprovalGasOffset = 41_500;\\n _notifyOperatorInactivityGasOffset = 54_500;\\n _relayEntrySubmissionGasOffset = 11_250;\\n }\\n\\n modifier onlyStakingContract() {\\n require(\\n msg.sender == address(staking),\\n \\\"Caller is not the staking contract\\\"\\n );\\n _;\\n }\\n\\n modifier onlyReimbursableAdmin() override {\\n require(governance == msg.sender, \\\"Caller is not the governance\\\");\\n _;\\n }\\n\\n /// @notice Updates the values of authorization parameters.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract. The caller is responsible for\\n /// validating parameters.\\n /// @param _minimumAuthorization New minimum authorization amount\\n /// @param _authorizationDecreaseDelay New authorization decrease delay in\\n /// seconds\\n /// @param _authorizationDecreaseChangePeriod New authorization decrease\\n /// change period in seconds\\n function updateAuthorizationParameters(\\n uint96 _minimumAuthorization,\\n uint64 _authorizationDecreaseDelay,\\n uint64 _authorizationDecreaseChangePeriod\\n ) external onlyGovernance {\\n authorization.setParameters(\\n _minimumAuthorization,\\n _authorizationDecreaseDelay,\\n _authorizationDecreaseChangePeriod\\n );\\n\\n emit AuthorizationParametersUpdated(\\n _minimumAuthorization,\\n _authorizationDecreaseDelay,\\n _authorizationDecreaseChangePeriod\\n );\\n }\\n\\n /// @notice Updates the values of relay entry parameters.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract. The caller is responsible for\\n /// validating parameters.\\n /// @param relayEntrySoftTimeout New relay entry submission soft timeout\\n /// @param relayEntryHardTimeout New relay entry hard timeout\\n /// @param callbackGasLimit New callback gas limit\\n function updateRelayEntryParameters(\\n uint256 relayEntrySoftTimeout,\\n uint256 relayEntryHardTimeout,\\n uint256 callbackGasLimit\\n ) external onlyGovernance {\\n _callbackGasLimit = callbackGasLimit;\\n relay.setTimeouts(relayEntrySoftTimeout, relayEntryHardTimeout);\\n\\n emit RelayEntryParametersUpdated(\\n relayEntrySoftTimeout,\\n relayEntryHardTimeout,\\n callbackGasLimit\\n );\\n }\\n\\n /// @notice Updates the values of group creation parameters.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract. The caller is responsible for\\n /// validating parameters.\\n /// @param groupCreationFrequency New group creation frequency\\n /// @param groupLifetime New group lifetime in blocks\\n /// @param dkgResultChallengePeriodLength New DKG result challenge period\\n /// length\\n /// @param dkgResultChallengeExtraGas New DKG result challenge extra gas\\n /// @param dkgResultSubmissionTimeout New DKG result submission timeout\\n /// @param dkgSubmitterPrecedencePeriodLength New DKG result submitter\\n /// precedence period length\\n function updateGroupCreationParameters(\\n uint256 groupCreationFrequency,\\n uint256 groupLifetime,\\n uint256 dkgResultChallengePeriodLength,\\n uint256 dkgResultChallengeExtraGas,\\n uint256 dkgResultSubmissionTimeout,\\n uint256 dkgSubmitterPrecedencePeriodLength\\n ) external onlyGovernance {\\n _groupCreationFrequency = groupCreationFrequency;\\n groups.setGroupLifetime(groupLifetime);\\n dkg.setParameters(\\n dkgResultChallengePeriodLength,\\n dkgResultChallengeExtraGas,\\n dkgResultSubmissionTimeout,\\n dkgSubmitterPrecedencePeriodLength\\n );\\n\\n emit GroupCreationParametersUpdated(\\n groupCreationFrequency,\\n groupLifetime,\\n dkgResultChallengePeriodLength,\\n dkgResultChallengeExtraGas,\\n dkgResultSubmissionTimeout,\\n dkgSubmitterPrecedencePeriodLength\\n );\\n }\\n\\n /// @notice Updates the values of reward parameters.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract. The caller is responsible for\\n /// validating parameters.\\n /// @param sortitionPoolRewardsBanDuration New sortition pool rewards\\n /// ban duration in seconds.\\n /// @param relayEntryTimeoutNotificationRewardMultiplier New value of the\\n /// relay entry timeout notification reward multiplier\\n /// @param unauthorizedSigningNotificationRewardMultiplier New value of the\\n /// unauthorized signing notification reward multiplier\\n /// @param dkgMaliciousResultNotificationRewardMultiplier New value of the\\n /// DKG malicious result notification reward multiplier\\n function updateRewardParameters(\\n uint256 sortitionPoolRewardsBanDuration,\\n uint256 relayEntryTimeoutNotificationRewardMultiplier,\\n uint256 unauthorizedSigningNotificationRewardMultiplier,\\n uint256 dkgMaliciousResultNotificationRewardMultiplier\\n ) external onlyGovernance {\\n _sortitionPoolRewardsBanDuration = sortitionPoolRewardsBanDuration;\\n _relayEntryTimeoutNotificationRewardMultiplier = relayEntryTimeoutNotificationRewardMultiplier;\\n _unauthorizedSigningNotificationRewardMultiplier = unauthorizedSigningNotificationRewardMultiplier;\\n _dkgMaliciousResultNotificationRewardMultiplier = dkgMaliciousResultNotificationRewardMultiplier;\\n emit RewardParametersUpdated(\\n sortitionPoolRewardsBanDuration,\\n relayEntryTimeoutNotificationRewardMultiplier,\\n unauthorizedSigningNotificationRewardMultiplier,\\n dkgMaliciousResultNotificationRewardMultiplier\\n );\\n }\\n\\n /// @notice Updates the values of slashing parameters.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract. The caller is responsible for\\n /// validating parameters.\\n /// @param relayEntrySubmissionFailureSlashingAmount New relay entry\\n /// submission failure amount\\n /// @param maliciousDkgResultSlashingAmount New malicious DKG result\\n /// slashing amount\\n /// @param unauthorizedSigningSlashingAmount New unauthorized signing\\n /// slashing amount\\n function updateSlashingParameters(\\n uint96 relayEntrySubmissionFailureSlashingAmount,\\n uint96 maliciousDkgResultSlashingAmount,\\n uint96 unauthorizedSigningSlashingAmount\\n ) external onlyGovernance {\\n relay.setRelayEntrySubmissionFailureSlashingAmount(\\n relayEntrySubmissionFailureSlashingAmount\\n );\\n _maliciousDkgResultSlashingAmount = maliciousDkgResultSlashingAmount;\\n _unauthorizedSigningSlashingAmount = unauthorizedSigningSlashingAmount;\\n emit SlashingParametersUpdated(\\n relayEntrySubmissionFailureSlashingAmount,\\n maliciousDkgResultSlashingAmount,\\n unauthorizedSigningSlashingAmount\\n );\\n }\\n\\n /// @notice Updates the values of gas parameters.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract. The caller is responsible for\\n /// validating parameters.\\n /// @param dkgResultSubmissionGas New DKG result submission gas\\n /// @param dkgResultApprovalGasOffset New DKG result approval gas offset\\n /// @param notifyOperatorInactivityGasOffset New operator inactivity\\n /// notification gas offset\\n /// @param relayEntrySubmissionGasOffset New relay entry submission gas\\n /// offset\\n function updateGasParameters(\\n uint256 dkgResultSubmissionGas,\\n uint256 dkgResultApprovalGasOffset,\\n uint256 notifyOperatorInactivityGasOffset,\\n uint256 relayEntrySubmissionGasOffset\\n ) external onlyGovernance {\\n _dkgResultSubmissionGas = dkgResultSubmissionGas;\\n _dkgResultApprovalGasOffset = dkgResultApprovalGasOffset;\\n _notifyOperatorInactivityGasOffset = notifyOperatorInactivityGasOffset;\\n _relayEntrySubmissionGasOffset = relayEntrySubmissionGasOffset;\\n\\n emit GasParametersUpdated(\\n dkgResultSubmissionGas,\\n dkgResultApprovalGasOffset,\\n notifyOperatorInactivityGasOffset,\\n relayEntrySubmissionGasOffset\\n );\\n }\\n\\n /// @notice Set authorization for requesters that can request a relay\\n /// entry.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract.\\n /// @param requester Requester, can be a contract or EOA\\n /// @param isAuthorized True or false\\n function setRequesterAuthorization(address requester, bool isAuthorized)\\n external\\n onlyGovernance\\n {\\n authorizedRequesters[requester] = isAuthorized;\\n\\n emit RequesterAuthorizationUpdated(requester, isAuthorized);\\n }\\n\\n /// @notice Withdraws application rewards for the given staking provider.\\n /// Rewards are withdrawn to the staking provider's beneficiary\\n /// address set in the staking contract. Reverts if staking provider\\n /// has not registered the operator address.\\n /// @dev Emits `RewardsWithdrawn` event.\\n function withdrawRewards(address stakingProvider) external {\\n address operator = stakingProviderToOperator(stakingProvider);\\n require(operator != address(0), \\\"Unknown operator\\\");\\n (, address beneficiary, ) = staking.rolesOf(stakingProvider);\\n uint96 amount = sortitionPool.withdrawRewards(operator, beneficiary);\\n // slither-disable-next-line reentrancy-events\\n emit RewardsWithdrawn(stakingProvider, amount);\\n }\\n\\n /// @notice Withdraws rewards belonging to operators marked as ineligible\\n /// for sortition pool rewards.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract.\\n /// @param recipient Recipient of withdrawn rewards.\\n function withdrawIneligibleRewards(address recipient)\\n external\\n onlyGovernance\\n {\\n sortitionPool.withdrawIneligible(recipient);\\n }\\n\\n /// @notice Used by staking provider to set operator address that will\\n /// operate a node. The given staking provider can set operator\\n /// address only one time. The operator address can not be changed\\n /// and must be unique. Reverts if the operator is already set for\\n /// the staking provider or if the operator address is already in\\n /// use. Reverts if there is a pending authorization decrease for\\n /// the staking provider.\\n function registerOperator(address operator) external {\\n authorization.registerOperator(operator);\\n }\\n\\n /// @notice Lets the operator join the sortition pool. The operator address\\n /// must be known - before calling this function, it has to be\\n /// appointed by the staking provider by calling `registerOperator`.\\n /// Also, the operator must have the minimum authorization required\\n /// by the beacon. Function reverts if there is no minimum stake\\n /// authorized or if the operator is not known. If there was an\\n /// authorization decrease requested, it is activated by starting\\n /// the authorization decrease delay.\\n function joinSortitionPool() external {\\n authorization.joinSortitionPool(staking, sortitionPool);\\n }\\n\\n /// @notice Updates status of the operator in the sortition pool. If there\\n /// was an authorization decrease requested, it is activated by\\n /// starting the authorization decrease delay.\\n /// Function reverts if the operator is not known.\\n function updateOperatorStatus(address operator) external {\\n authorization.updateOperatorStatus(staking, sortitionPool, operator);\\n }\\n\\n /// @notice Used by T staking contract to inform the beacon that the\\n /// authorized stake amount for the given staking provider increased.\\n ///\\n /// Reverts if the authorization amount is below the minimum.\\n ///\\n /// The function is not updating the sortition pool. Sortition pool\\n /// state needs to be updated by the operator with a call to\\n /// `joinSortitionPool` or `updateOperatorStatus`.\\n ///\\n /// @dev Can only be called by T staking contract.\\n function authorizationIncreased(\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external onlyStakingContract {\\n authorization.authorizationIncreased(\\n stakingProvider,\\n fromAmount,\\n toAmount\\n );\\n }\\n\\n /// @notice Used by T staking contract to inform the beacon that the\\n /// authorization decrease for the given staking provider has been\\n /// requested.\\n ///\\n /// Reverts if the amount after deauthorization would be non-zero\\n /// and lower than the minimum authorization.\\n ///\\n /// Reverts if another authorization decrease request is pending for\\n /// the staking provider and not enough time passed since the\\n /// original request (see `authorizationDecreaseChangePeriod`).\\n ///\\n /// If the operator is not known (`registerOperator` was not called)\\n /// it lets to `approveAuthorizationDecrease` immediately. If the\\n /// operator is known (`registerOperator` was called), the operator\\n /// needs to update state of the sortition pool with a call to\\n /// `joinSortitionPool` or `updateOperatorStatus`. After the\\n /// sortition pool state is in sync, authorization decrease delay\\n /// starts.\\n ///\\n /// After authorization decrease delay passes, authorization\\n /// decrease request needs to be approved with a call to\\n /// `approveAuthorizationDecrease` function.\\n ///\\n /// If there is a pending authorization decrease request, it is\\n /// overwritten, but only if enough time passed since the original\\n /// request. Otherwise, the function reverts.\\n ///\\n /// @dev Can only be called by T staking contract.\\n function authorizationDecreaseRequested(\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external onlyStakingContract {\\n authorization.authorizationDecreaseRequested(\\n stakingProvider,\\n fromAmount,\\n toAmount\\n );\\n }\\n\\n /// @notice Approves the previously registered authorization decrease\\n /// request. Reverts if authorization decrease delay has not passed\\n /// yet or if the authorization decrease was not requested for the\\n /// given staking provider.\\n function approveAuthorizationDecrease(address stakingProvider) external {\\n authorization.approveAuthorizationDecrease(staking, stakingProvider);\\n }\\n\\n /// @notice Used by T staking contract to inform the beacon the\\n /// authorization has been decreased for the given staking provider\\n /// involuntarily, as a result of slashing.\\n ///\\n /// If the operator is not known (`registerOperator` was not called)\\n /// the function does nothing. The operator was never in a sortition\\n /// pool so there is nothing to update.\\n ///\\n /// If the operator is known, sortition pool is unlocked, and the\\n /// operator is in the sortition pool, the sortition pool state is\\n /// updated. If the sortition pool is locked, update needs to be\\n /// postponed. Every other staker is incentivized to call\\n /// `updateOperatorStatus` for the problematic operator to increase\\n /// their own rewards in the pool.\\n function involuntaryAuthorizationDecrease(\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external onlyStakingContract {\\n authorization.involuntaryAuthorizationDecrease(\\n staking,\\n sortitionPool,\\n stakingProvider,\\n fromAmount,\\n toAmount\\n );\\n }\\n\\n /// @notice Triggers group selection if there are no active groups.\\n function genesis() external {\\n require(groups.numberOfActiveGroups() == 0, \\\"Not awaiting genesis\\\");\\n\\n dkg.lockState();\\n dkg.start(\\n uint256(keccak256(abi.encodePacked(genesisSeed, block.number)))\\n );\\n }\\n\\n /// @notice Submits result of DKG protocol. It is on-chain part of phase 14 of\\n /// the protocol. The DKG result consists of result submitting member\\n /// index, calculated group public key, bytes array of misbehaved\\n /// members, concatenation of signatures from group members,\\n /// indices of members corresponding to each signature and\\n /// the list of group members.\\n /// When the result is verified successfully it gets registered and\\n /// waits for an approval. A result can be challenged to verify the\\n /// members list corresponds to the expected set of members determined\\n /// by the sortition pool.\\n /// A candidate group is registered based on the submitted DKG result\\n /// details.\\n /// @dev The message to be signed by each member is keccak256 hash of the\\n /// chain ID, calculated group public key, misbehaved members as bytes\\n /// and DKG start block. The calculated hash should be prefixed with\\n // prefixed with\\n /// `\\\\x19Ethereum signed message:\\\\n` before signing, so the message to\\n /// sign is:\\n /// `\\\\x19Ethereum signed message:\\\\n${keccak256(chainID,groupPubKey,misbehaved,startBlock)}`\\n /// @param dkgResult DKG result.\\n function submitDkgResult(DKG.Result calldata dkgResult) external {\\n groups.validatePublicKey(dkgResult.groupPubKey);\\n dkg.submitResult(dkgResult);\\n }\\n\\n /// @notice Notifies about DKG timeout.\\n function notifyDkgTimeout() external refundable(msg.sender) {\\n dkg.notifyTimeout();\\n }\\n\\n /// @notice Approves DKG result. Can be called when the challenge period for\\n /// the submitted result is finished. Considers the submitted result\\n /// as valid, bans misbehaved group members from the sortition pool\\n /// rewards, and completes the group creation by activating the\\n /// candidate group. For the first `submitterPrecedencePeriodLength`\\n /// blocks after the end of the challenge period can be called only\\n /// by the DKG result submitter. After that time, can be called by\\n /// anyone.\\n /// @param dkgResult Result to approve. Must match the submitted result\\n /// stored during `submitDkgResult`.\\n function approveDkgResult(DKG.Result calldata dkgResult) external {\\n uint256 gasStart = gasleft();\\n\\n uint32[] memory misbehavedMembers = dkg.approveResult(dkgResult);\\n\\n if (misbehavedMembers.length > 0) {\\n sortitionPool.setRewardIneligibility(\\n misbehavedMembers,\\n // solhint-disable-next-line not-rely-on-time\\n block.timestamp + _sortitionPoolRewardsBanDuration\\n );\\n }\\n\\n groups.addGroup(dkgResult.groupPubKey, dkgResult.membersHash);\\n dkg.complete();\\n\\n // Refund msg.sender's ETH for DKG result submission and result approval\\n reimbursementPool.refund(\\n _dkgResultSubmissionGas +\\n (gasStart - gasleft()) +\\n _dkgResultApprovalGasOffset,\\n msg.sender\\n );\\n }\\n\\n /// @notice Challenges DKG result. If the submitted result is proved to be\\n /// invalid it reverts the DKG back to the result submission phase.\\n /// It removes a candidate group that was previously registered with\\n /// the DKG result submission.\\n /// @param dkgResult Result to challenge. Must match the submitted result\\n /// stored during `submitDkgResult`.\\n /// @dev Due to EIP-150 1/64 of the gas is not forwarded to the call, and\\n /// will be kept to execute the remaining operations in the function\\n /// after the call inside the try-catch. To eliminate a class of\\n /// attacks related to the gas limit manipulation, this function\\n /// requires an extra amount of gas to be left at the end of the\\n /// execution.\\n function challengeDkgResult(DKG.Result calldata dkgResult) external {\\n (bytes32 maliciousResultHash, uint32 maliciousSubmitter) = dkg\\n .challengeResult(dkgResult);\\n\\n uint96 slashingAmount = _maliciousDkgResultSlashingAmount;\\n address maliciousSubmitterAddresses = sortitionPool.getIDOperator(\\n maliciousSubmitter\\n );\\n\\n address[] memory stakingProviderWrapper = new address[](1);\\n stakingProviderWrapper[0] = operatorToStakingProvider(\\n maliciousSubmitterAddresses\\n );\\n try\\n staking.seize(\\n slashingAmount,\\n _dkgMaliciousResultNotificationRewardMultiplier,\\n msg.sender,\\n stakingProviderWrapper\\n )\\n {\\n // slither-disable-next-line reentrancy-events\\n emit DkgMaliciousResultSlashed(\\n maliciousResultHash,\\n slashingAmount,\\n maliciousSubmitterAddresses\\n );\\n } catch {\\n // Should never happen but we want to ensure a non-critical path\\n // failure from an external contract does not stop the challenge\\n // to complete.\\n emit DkgMaliciousResultSlashingFailed(\\n maliciousResultHash,\\n slashingAmount,\\n maliciousSubmitterAddresses\\n );\\n }\\n\\n // Due to EIP-150, 1/64 of the gas is not forwarded to the call, and\\n // will be kept to execute the remaining operations in the function\\n // after the call inside the try-catch.\\n //\\n // To ensure there is no way for the caller to manipulate gas limit in\\n // such a way that the call inside try-catch fails with out-of-gas and\\n // the rest of the function is executed with the remaining 1/64 of gas,\\n // we require an extra gas amount to be left at the end of the call to\\n // `challengeDkgResult`.\\n dkg.requireChallengeExtraGas();\\n }\\n\\n /// @notice Check current group creation state.\\n function getGroupCreationState() external view returns (DKG.State) {\\n return dkg.currentState();\\n }\\n\\n /// @notice Checks if DKG timed out. The DKG timeout period includes time required\\n /// for off-chain protocol execution and time for the result publication\\n /// for all group members. After this time result cannot be submitted\\n /// and DKG can be notified about the timeout.\\n /// @return True if DKG timed out, false otherwise.\\n function hasDkgTimedOut() external view returns (bool) {\\n return dkg.hasDkgTimedOut();\\n }\\n\\n function getGroupsRegistry() external view returns (bytes32[] memory) {\\n return groups.groupsRegistry;\\n }\\n\\n function getGroup(uint64 groupId)\\n external\\n view\\n returns (Groups.Group memory)\\n {\\n return groups.getGroup(groupId);\\n }\\n\\n function getGroup(bytes memory groupPubKey)\\n external\\n view\\n returns (Groups.Group memory)\\n {\\n return groups.getGroup(groupPubKey);\\n }\\n\\n /// @notice Creates a request to generate a new relay entry, which will\\n /// include a random number (by signing the previous entry's\\n /// random number). Requester must be previously authorized by the\\n /// governance.\\n /// @param callbackContract Beacon consumer callback contract.\\n function requestRelayEntry(IRandomBeaconConsumer callbackContract)\\n external\\n {\\n require(\\n authorizedRequesters[msg.sender],\\n \\\"Requester must be authorized\\\"\\n );\\n\\n uint64 groupId = groups.selectGroup(\\n uint256(keccak256(AltBn128.g1Marshal(relay.previousEntry)))\\n );\\n\\n relay.requestEntry(groupId);\\n\\n callback.setCallbackContract(callbackContract);\\n\\n // If the current request should trigger group creation we need to lock\\n // DKG state (lock sortition pool) to prevent operators from changing\\n // its state before relay entry is known. That entry will be used as a\\n // group selection seed.\\n if (\\n relay.requestCount % _groupCreationFrequency == 0 &&\\n dkg.currentState() == DKG.State.IDLE\\n ) {\\n dkg.lockState();\\n }\\n }\\n\\n /// @notice Creates a new relay entry. Gas-optimized version that can be\\n /// called only before the soft timeout. This should be the majority\\n /// of cases.\\n /// @param entry Group BLS signature over the previous entry.\\n function submitRelayEntry(bytes calldata entry) external {\\n uint256 gasStart = gasleft();\\n\\n Groups.Group storage group = groups.getGroup(\\n relay.currentRequestGroupID\\n );\\n\\n relay.submitEntryBeforeSoftTimeout(entry, group.groupPubKey);\\n\\n // If DKG is awaiting a seed, that means the we should start the actual\\n // group creation process.\\n if (dkg.currentState() == DKG.State.AWAITING_SEED) {\\n dkg.start(uint256(keccak256(entry)));\\n }\\n\\n callback.executeCallback(uint256(keccak256(entry)), _callbackGasLimit);\\n\\n reimbursementPool.refund(\\n (gasStart - gasleft()) + _relayEntrySubmissionGasOffset,\\n msg.sender\\n );\\n }\\n\\n /// @notice Creates a new relay entry.\\n /// @param entry Group BLS signature over the previous entry.\\n /// @param groupMembers Identifiers of group members.\\n function submitRelayEntry(\\n bytes calldata entry,\\n uint32[] calldata groupMembers\\n ) external {\\n uint256 gasStart = gasleft();\\n uint256 currentRequestId = relay.currentRequestID;\\n\\n Groups.Group storage group = groups.getGroup(\\n relay.currentRequestGroupID\\n );\\n\\n require(\\n group.membersHash == keccak256(abi.encode(groupMembers)),\\n \\\"Invalid group members\\\"\\n );\\n\\n uint96 slashingAmount = relay.submitEntry(entry, group.groupPubKey);\\n\\n if (slashingAmount > 0) {\\n address[] memory groupMembersAddresses = sortitionPool\\n .getIDOperators(groupMembers);\\n\\n address[] memory stakingProvidersAddresses = new address[](\\n groupMembersAddresses.length\\n );\\n for (uint256 i = 0; i < groupMembersAddresses.length; i++) {\\n stakingProvidersAddresses[i] = operatorToStakingProvider(\\n groupMembersAddresses[i]\\n );\\n }\\n\\n try staking.slash(slashingAmount, stakingProvidersAddresses) {\\n // slither-disable-next-line reentrancy-events\\n emit RelayEntryDelaySlashed(\\n currentRequestId,\\n slashingAmount,\\n groupMembersAddresses\\n );\\n } catch {\\n // Should never happen but we want to ensure a non-critical path\\n // failure from an external contract does not stop group members\\n // from submitting a valid relay entry.\\n emit RelayEntryDelaySlashingFailed(\\n currentRequestId,\\n slashingAmount,\\n groupMembersAddresses\\n );\\n }\\n }\\n\\n // If DKG is awaiting a seed, that means the we should start the actual\\n // group creation process.\\n if (dkg.currentState() == DKG.State.AWAITING_SEED) {\\n dkg.start(uint256(keccak256(entry)));\\n }\\n\\n callback.executeCallback(uint256(keccak256(entry)), _callbackGasLimit);\\n reimbursementPool.refund(\\n (gasStart - gasleft()) + _relayEntrySubmissionGasOffset,\\n msg.sender\\n );\\n }\\n\\n /// @notice Reports a relay entry timeout.\\n /// @param groupMembers Identifiers of group members.\\n function reportRelayEntryTimeout(uint32[] calldata groupMembers) external {\\n uint64 groupId = relay.currentRequestGroupID;\\n Groups.Group storage group = groups.getGroup(groupId);\\n\\n require(\\n group.membersHash == keccak256(abi.encode(groupMembers)),\\n \\\"Invalid group members\\\"\\n );\\n\\n uint96 slashingAmount = relay.relayEntrySubmissionFailureSlashingAmount;\\n address[] memory groupMembersAddresses = sortitionPool.getIDOperators(\\n groupMembers\\n );\\n\\n address[] memory stakingProvidersAddresses = new address[](\\n groupMembersAddresses.length\\n );\\n for (uint256 i = 0; i < groupMembersAddresses.length; i++) {\\n stakingProvidersAddresses[i] = operatorToStakingProvider(\\n groupMembersAddresses[i]\\n );\\n }\\n\\n try\\n staking.seize(\\n slashingAmount,\\n _relayEntryTimeoutNotificationRewardMultiplier,\\n msg.sender,\\n stakingProvidersAddresses\\n )\\n {\\n // slither-disable-next-line reentrancy-events\\n emit RelayEntryTimeoutSlashed(\\n relay.currentRequestID,\\n slashingAmount,\\n groupMembersAddresses\\n );\\n } catch {\\n // Should never happen but we want to ensure a non-critical path\\n // failure from an external contract does not stop the challenge\\n // to complete.\\n emit RelayEntryTimeoutSlashingFailed(\\n relay.currentRequestID,\\n slashingAmount,\\n groupMembersAddresses\\n );\\n }\\n\\n groups.terminateGroup(groupId);\\n groups.expireOldGroups();\\n\\n if (groups.numberOfActiveGroups() > 0) {\\n groupId = groups.selectGroup(\\n uint256(keccak256(AltBn128.g1Marshal(relay.previousEntry)))\\n );\\n relay.retryOnEntryTimeout(groupId);\\n } else {\\n relay.cleanupOnEntryTimeout();\\n\\n // If DKG is awaiting a seed, we should notify about its timeout to\\n // avoid blocking the future group creation.\\n if (dkg.currentState() == DKG.State.AWAITING_SEED) {\\n dkg.notifySeedTimedOut();\\n }\\n }\\n }\\n\\n /// @notice Reports unauthorized groups signing. Must provide a valid signature\\n /// of the sender's address as a message. Successful signature\\n /// verification means the private key has been leaked and all group\\n /// members should be punished by slashing their tokens. Group has\\n /// to be active or expired. Unauthorized signing cannot be reported\\n /// for a terminated group. In case of reporting unauthorized\\n /// signing for a terminated group, or when the signature is invalid,\\n /// function reverts.\\n /// @param signedMsgSender Signature of the sender's address as a message.\\n /// @param groupId Group that is being reported for leaking a private key.\\n /// @param groupMembers Identifiers of group members.\\n function reportUnauthorizedSigning(\\n bytes memory signedMsgSender,\\n uint64 groupId,\\n uint32[] calldata groupMembers\\n ) external {\\n Groups.Group memory group = groups.getGroup(groupId);\\n\\n require(\\n group.membersHash == keccak256(abi.encode(groupMembers)),\\n \\\"Invalid group members\\\"\\n );\\n\\n require(!group.terminated, \\\"Group cannot be terminated\\\");\\n\\n require(\\n BLS.verifyBytes(\\n group.groupPubKey,\\n abi.encodePacked(msg.sender),\\n signedMsgSender\\n ),\\n \\\"Invalid signature\\\"\\n );\\n\\n groups.terminateGroup(groupId);\\n\\n address[] memory groupMembersAddresses = sortitionPool.getIDOperators(\\n groupMembers\\n );\\n\\n address[] memory stakingProvidersAddresses = new address[](\\n groupMembersAddresses.length\\n );\\n for (uint256 i = 0; i < groupMembersAddresses.length; i++) {\\n stakingProvidersAddresses[i] = operatorToStakingProvider(\\n groupMembersAddresses[i]\\n );\\n }\\n\\n try\\n staking.seize(\\n _unauthorizedSigningSlashingAmount,\\n _unauthorizedSigningNotificationRewardMultiplier,\\n msg.sender,\\n stakingProvidersAddresses\\n )\\n {\\n // slither-disable-next-line reentrancy-events\\n emit UnauthorizedSigningSlashed(\\n groupId,\\n _unauthorizedSigningSlashingAmount,\\n groupMembersAddresses\\n );\\n } catch {\\n // Should never happen but we want to ensure a non-critical path\\n // failure from an external contract does not stop the challenge\\n // to complete.\\n emit UnauthorizedSigningSlashingFailed(\\n groupId,\\n _unauthorizedSigningSlashingAmount,\\n groupMembersAddresses\\n );\\n }\\n }\\n\\n /// @notice Notifies about operators who are inactive. Using this function,\\n /// a majority of the group can decide about punishing specific\\n /// group members who constantly fail doing their job. If the provided\\n /// claim is proved to be valid and signed by sufficient number\\n /// of group members, operators of members deemed as inactive are\\n /// banned for sortition pool rewards for duration specified by\\n /// `_sortitionPoolRewardsBanDuration` parameter. The sender of\\n /// the claim must be one of the claim signers. This function can be\\n /// called only for active and non-terminated groups.\\n /// @param claim Operator inactivity claim.\\n /// @param nonce Current inactivity claim nonce for the given group. Must\\n /// be the same as the stored one.\\n /// @param groupMembers Identifiers of group members.\\n function notifyOperatorInactivity(\\n Inactivity.Claim calldata claim,\\n uint256 nonce,\\n uint32[] calldata groupMembers\\n ) external {\\n uint256 gasStart = gasleft();\\n uint64 groupId = claim.groupId;\\n\\n require(nonce == inactivityClaimNonce[groupId], \\\"Invalid nonce\\\");\\n\\n require(groups.isGroupActive(groupId), \\\"Group is not active\\\");\\n\\n Groups.Group storage group = groups.getGroup(groupId);\\n\\n require(\\n group.membersHash == keccak256(abi.encode(groupMembers)),\\n \\\"Invalid group members\\\"\\n );\\n\\n uint32[] memory ineligibleOperators = Inactivity.verifyClaim(\\n sortitionPool,\\n claim,\\n group.groupPubKey,\\n nonce,\\n groupMembers\\n );\\n\\n inactivityClaimNonce[groupId]++;\\n\\n emit InactivityClaimed(groupId, nonce, msg.sender);\\n\\n sortitionPool.setRewardIneligibility(\\n ineligibleOperators,\\n // solhint-disable-next-line not-rely-on-time\\n block.timestamp + _sortitionPoolRewardsBanDuration\\n );\\n\\n reimbursementPool.refund(\\n (gasStart - gasleft()) + _notifyOperatorInactivityGasOffset,\\n msg.sender\\n );\\n }\\n\\n /// @notice The minimum authorization amount required so that operator can\\n /// participate in the random beacon. This amount is required to\\n /// execute slashing for providing a malicious DKG result or when\\n /// a relay entry times out.\\n function minimumAuthorization() external view returns (uint96) {\\n return authorization.parameters.minimumAuthorization;\\n }\\n\\n /// @return Flag indicating whether a relay entry request is currently\\n /// in progress.\\n function isRelayRequestInProgress() external view returns (bool) {\\n return relay.isRequestInProgress();\\n }\\n\\n /// @notice Returns the current value of the staking provider's eligible\\n /// stake. Eligible stake is defined as the currently authorized\\n /// stake minus the pending authorization decrease. Eligible stake\\n /// is what is used for operator's weight in the sortition pool.\\n /// If the authorized stake minus the pending authorization decrease\\n /// is below the minimum authorization, eligible stake is 0.\\n function eligibleStake(address stakingProvider)\\n external\\n view\\n returns (uint96)\\n {\\n return authorization.eligibleStake(staking, stakingProvider);\\n }\\n\\n /// @notice Returns the amount of rewards available for withdrawal for the\\n /// given staking provider. Reverts if staking provider has not\\n /// registered the operator address.\\n function availableRewards(address stakingProvider)\\n external\\n view\\n returns (uint96)\\n {\\n address operator = stakingProviderToOperator(stakingProvider);\\n require(operator != address(0), \\\"Unknown operator\\\");\\n return sortitionPool.getAvailableRewards(operator);\\n }\\n\\n /// @notice Returns the amount of stake that is pending authorization\\n /// decrease for the given staking provider. If no authorization\\n /// decrease has been requested, returns zero.\\n function pendingAuthorizationDecrease(address stakingProvider)\\n external\\n view\\n returns (uint96)\\n {\\n return authorization.pendingAuthorizationDecrease(stakingProvider);\\n }\\n\\n /// @notice Returns the remaining time in seconds that needs to pass before\\n /// the requested authorization decrease can be approved.\\n /// If the sortition pool state was not updated yet by the operator\\n /// after requesting the authorization decrease, returns\\n /// `type(uint64).max`.\\n function remainingAuthorizationDecreaseDelay(address stakingProvider)\\n external\\n view\\n returns (uint64)\\n {\\n return\\n authorization.remainingAuthorizationDecreaseDelay(stakingProvider);\\n }\\n\\n /// @notice Returns operator registered for the given staking provider.\\n function stakingProviderToOperator(address stakingProvider)\\n public\\n view\\n returns (address)\\n {\\n return authorization.stakingProviderToOperator[stakingProvider];\\n }\\n\\n /// @notice Returns staking provider of the given operator.\\n function operatorToStakingProvider(address operator)\\n public\\n view\\n returns (address)\\n {\\n return authorization.operatorToStakingProvider[operator];\\n }\\n\\n /// @notice Checks if the operator's authorized stake is in sync with\\n /// operator's weight in the sortition pool.\\n /// If the operator is not in the sortition pool and their\\n /// authorized stake is non-zero, function returns false.\\n function isOperatorUpToDate(address operator) external view returns (bool) {\\n return\\n authorization.isOperatorUpToDate(staking, sortitionPool, operator);\\n }\\n\\n /// @notice Returns true if the given operator is in the sortition pool.\\n /// Otherwise, returns false.\\n function isOperatorInPool(address operator) external view returns (bool) {\\n return sortitionPool.isOperatorInPool(operator);\\n }\\n\\n /// @notice Selects a new group of operators. Can only be called when DKG\\n /// is in progress and the pool is locked.\\n /// At least one operator has to be registered in the pool,\\n /// otherwise the function fails reverting the transaction.\\n /// @return IDs of selected group members.\\n function selectGroup() external view returns (uint32[] memory) {\\n return sortitionPool.selectGroup(DKG.groupSize, bytes32(dkg.seed));\\n }\\n\\n /// @notice Returns authorization-related parameters of the beacon.\\n /// @dev The minimum authorization is also returned by `minimumAuthorization()`\\n /// function, as a requirement of `IApplication` interface.\\n /// @return minimumAuthorization The minimum authorization amount required\\n /// so that operator can participate in the random beacon. This\\n /// amount is required to execute slashing for providing a malicious\\n /// DKG result or when a relay entry times out.\\n /// @return authorizationDecreaseDelay Delay in seconds that needs to pass\\n /// between the time authorization decrease is requested and the\\n /// time that request gets approved. Protects against free-riders\\n /// earning rewards and not being active in the network.\\n /// @return authorizationDecreaseChangePeriod Authorization decrease change\\n /// period in seconds. It is the time, before authorization decrease\\n /// delay end, during which the pending authorization decrease\\n /// request can be overwritten.\\n /// If set to 0, pending authorization decrease request can not be\\n /// overwritten until the entire `authorizationDecreaseDelay` ends.\\n /// If set to value equal `authorizationDecreaseDelay`, request can\\n /// always be overwritten.\\n function authorizationParameters()\\n external\\n view\\n returns (\\n uint96 minimumAuthorization,\\n uint64 authorizationDecreaseDelay,\\n uint64 authorizationDecreaseChangePeriod\\n )\\n {\\n return (\\n authorization.parameters.minimumAuthorization,\\n authorization.parameters.authorizationDecreaseDelay,\\n authorization.parameters.authorizationDecreaseChangePeriod\\n );\\n }\\n\\n /// @notice Returns relay-entry-related parameters of the beacon.\\n /// @return relayEntrySoftTimeout Soft timeout in blocks for a group to\\n /// submit the relay entry. If the soft timeout is reached for\\n /// submitting the relay entry, the slashing starts.\\n /// @return relayEntryHardTimeout Hard timeout in blocks for a group to\\n /// submit the relay entry. After the soft timeout passes without\\n /// relay entry submitted, all group members start getting slashed.\\n /// The slashing amount increases linearly until the group submits\\n /// the relay entry or until `relayEntryHardTimeout` is reached.\\n /// When the hard timeout is reached, each group member will get\\n /// slashed for `_relayEntrySubmissionFailureSlashingAmount`.\\n /// @return callbackGasLimit Relay entry callback gas limit. This is the gas\\n /// limit with which callback function provided in the relay request\\n /// transaction is executed. The callback is executed with a new\\n /// relay entry value in the same transaction the relay entry is\\n /// submitted.\\n function relayEntryParameters()\\n external\\n view\\n returns (\\n uint256 relayEntrySoftTimeout,\\n uint256 relayEntryHardTimeout,\\n uint256 callbackGasLimit\\n )\\n {\\n return (\\n relay.relayEntrySoftTimeout,\\n relay.relayEntryHardTimeout,\\n _callbackGasLimit\\n );\\n }\\n\\n /// @notice Returns group-creation-related parameters of the beacon.\\n /// @return groupCreationFrequency The frequency of a new group creation.\\n /// Groups are created with a fixed frequency of relay requests.\\n /// @return groupLifetime Group lifetime in blocks. When a group reached its\\n /// lifetime, it is no longer selected for new relay requests but\\n /// may still be responsible for submitting relay entry if relay\\n /// request assigned to that group is still pending.\\n /// @return dkgResultChallengePeriodLength The number of blocks for which\\n /// a DKG result can be challenged. Anyone can challenge DKG result\\n /// for a certain number of blocks before the result is fully\\n /// accepted and the group registered in the pool of active groups.\\n /// If the challenge gets accepted, all operators who signed the\\n /// malicious result get slashed for and the notifier gets rewarded.\\n /// @return dkgResultChallengeExtraGas The extra gas required to be left at\\n /// the end of the challenge DKG result transaction.\\n /// @return dkgResultSubmissionTimeout Timeout in blocks for a group to\\n /// submit the DKG result. All members are eligible to submit the\\n /// DKG result. If `dkgResultSubmissionTimeout` passes without the\\n /// DKG result submitted, DKG is considered as timed out and no DKG\\n /// result for this group creation can be submitted anymore.\\n /// @return dkgSubmitterPrecedencePeriodLength Time during the DKG result\\n /// approval stage when the submitter of the DKG result takes the\\n /// precedence to approve the DKG result. After this time passes\\n /// anyone can approve the DKG result.\\n function groupCreationParameters()\\n external\\n view\\n returns (\\n uint256 groupCreationFrequency,\\n uint256 groupLifetime,\\n uint256 dkgResultChallengePeriodLength,\\n uint256 dkgResultChallengeExtraGas,\\n uint256 dkgResultSubmissionTimeout,\\n uint256 dkgSubmitterPrecedencePeriodLength\\n )\\n {\\n return (\\n _groupCreationFrequency,\\n groups.groupLifetime,\\n dkg.parameters.resultChallengePeriodLength,\\n dkg.parameters.resultChallengeExtraGas,\\n dkg.parameters.resultSubmissionTimeout,\\n dkg.parameters.submitterPrecedencePeriodLength\\n );\\n }\\n\\n /// @notice Returns reward-related parameters of the beacon.\\n /// @return sortitionPoolRewardsBanDuration Duration of the sortition pool\\n /// rewards ban imposed on operators who misbehaved during DKG by\\n /// being inactive or disqualified and for operators that were\\n /// identified by the rest of group members as inactive via\\n /// `notifyOperatorInactivity`.\\n /// @return relayEntryTimeoutNotificationRewardMultiplier Percentage of the\\n /// staking contract malicious behavior notification reward which\\n /// will be transferred to the notifier reporting about relay entry\\n /// timeout. Notifiers are rewarded from a notifiers treasury pool.\\n /// For example, if notification reward is 1000 and the value of the\\n /// multiplier is 5, the notifier will receive: 5% of 1000 = 50 per\\n /// each operator affected.\\n /// @return unauthorizedSigningNotificationRewardMultiplier Percentage of the\\n /// staking contract malicious behavior notification reward which\\n /// will be transferred to the notifier reporting about unauthorized\\n /// signing. Notifiers are rewarded from a notifiers treasury pool.\\n /// For example, if a notification reward is 1000 and the value of\\n /// the multiplier is 5, the notifier will receive: 5% of 1000 = 50\\n /// per each operator affected.\\n /// @return dkgMaliciousResultNotificationRewardMultiplier Percentage of the\\n /// staking contract malicious behavior notification reward which\\n /// will be transferred to the notifier reporting about a malicious\\n /// DKG result. Notifiers are rewarded from a notifiers treasury\\n /// pool. For example, if notification reward is 1000 and the value\\n /// of the multiplier is 5, the notifier will receive:\\n /// 5% of 1000 = 50 per each operator affected.\\n function rewardParameters()\\n external\\n view\\n returns (\\n uint256 sortitionPoolRewardsBanDuration,\\n uint256 relayEntryTimeoutNotificationRewardMultiplier,\\n uint256 unauthorizedSigningNotificationRewardMultiplier,\\n uint256 dkgMaliciousResultNotificationRewardMultiplier\\n )\\n {\\n return (\\n _sortitionPoolRewardsBanDuration,\\n _relayEntryTimeoutNotificationRewardMultiplier,\\n _unauthorizedSigningNotificationRewardMultiplier,\\n _dkgMaliciousResultNotificationRewardMultiplier\\n );\\n }\\n\\n /// @notice Returns slashing-related parameters of the beacon.\\n /// @return relayEntrySubmissionFailureSlashingAmount Slashing amount for\\n /// not submitting relay entry. When relay entry hard timeout is\\n /// reached without the relay entry submitted, each group member\\n /// gets slashed for `relayEntrySubmissionFailureSlashingAmount`.\\n /// If the relay entry gets submitted after the soft timeout, but\\n /// before the hard timeout, each group member gets slashed\\n /// proportionally to `relayEntrySubmissionFailureSlashingAmount`\\n /// and the time passed since the soft deadline.\\n /// @return maliciousDkgResultSlashingAmount Slashing amount for submitting\\n /// a malicious DKG result. Every DKG result submitted can be\\n /// challenged for the time of `dkg.ResultChallengePeriodLength`.\\n /// If the DKG result submitted is challenged and proven to be\\n /// malicious, the operator who submitted the malicious result is\\n /// slashed for `maliciousDkgResultSlashingAmount`.\\n /// @return unauthorizedSigningSlashingAmount Slashing amount when an\\n /// unauthorized signing has been proved, which means the private\\n /// key leaked and all the group members should be punished.\\n function slashingParameters()\\n external\\n view\\n returns (\\n uint96 relayEntrySubmissionFailureSlashingAmount,\\n uint96 maliciousDkgResultSlashingAmount,\\n uint96 unauthorizedSigningSlashingAmount\\n )\\n {\\n return (\\n relay.relayEntrySubmissionFailureSlashingAmount,\\n _maliciousDkgResultSlashingAmount,\\n _unauthorizedSigningSlashingAmount\\n );\\n }\\n\\n /// @notice Returns gas-related parameters of the beacon.\\n /// @return dkgResultSubmissionGas Calculated gas cost for submitting a DKG\\n /// result. This will be refunded as part of the DKG approval\\n /// process.\\n /// @return dkgResultApprovalGasOffset Gas that is meant to balance the DKG\\n /// result approval's overall cost.\\n /// @return notifyOperatorInactivityGasOffset Gas that is meant to balance\\n /// the operator inactivity notification cost.\\n /// @return relayEntrySubmissionGasOffset Gas that is meant to balance the\\n /// relay entry submission cost.\\n function gasParameters()\\n external\\n view\\n returns (\\n uint256 dkgResultSubmissionGas,\\n uint256 dkgResultApprovalGasOffset,\\n uint256 notifyOperatorInactivityGasOffset,\\n uint256 relayEntrySubmissionGasOffset\\n )\\n {\\n return (\\n _dkgResultSubmissionGas,\\n _dkgResultApprovalGasOffset,\\n _notifyOperatorInactivityGasOffset,\\n _relayEntrySubmissionGasOffset\\n );\\n }\\n}\\n\",\"keccak256\":\"0x50e6572ce7e51404a9918bf80d13004c4f4fd2a41fbc898f8aac84fa71423917\",\"license\":\"GPL-3.0-only\"},\"contracts/Reimbursable.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./ReimbursementPool.sol\\\";\\n\\nabstract contract Reimbursable {\\n // The variable should be initialized by the implementing contract.\\n // slither-disable-next-line uninitialized-state\\n ReimbursementPool public reimbursementPool;\\n\\n // Reserved storage space in case we need to add more variables,\\n // since there are upgradeable contracts that inherit from this one.\\n // See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\\n // slither-disable-next-line unused-state\\n uint256[49] private __gap;\\n\\n event ReimbursementPoolUpdated(address newReimbursementPool);\\n\\n modifier refundable(address receiver) {\\n uint256 gasStart = gasleft();\\n _;\\n reimbursementPool.refund(gasStart - gasleft(), receiver);\\n }\\n\\n modifier onlyReimbursableAdmin() virtual {\\n _;\\n }\\n\\n function updateReimbursementPool(ReimbursementPool _reimbursementPool)\\n external\\n onlyReimbursableAdmin\\n {\\n emit ReimbursementPoolUpdated(address(_reimbursementPool));\\n\\n reimbursementPool = _reimbursementPool;\\n }\\n}\\n\",\"keccak256\":\"0x6b01344c1ec13aaab1dc432d3afabe08d6dd0d1a9248be8b36a0747ac22e5d9f\",\"license\":\"GPL-3.0-only\"},\"contracts/ReimbursementPool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/security/ReentrancyGuard.sol\\\";\\n\\ncontract ReimbursementPool is Ownable, ReentrancyGuard {\\n /// @notice Authorized contracts that can interact with the reimbursment pool.\\n /// Authorization can be granted and removed by the owner.\\n mapping(address => bool) public isAuthorized;\\n\\n /// @notice Static gas includes:\\n /// - cost of the refund function\\n /// - base transaction cost\\n uint256 public staticGas;\\n\\n /// @notice Max gas price used to reimburse a transaction submitter. Protects\\n /// against malicious operator-miners.\\n uint256 public maxGasPrice;\\n\\n event StaticGasUpdated(uint256 newStaticGas);\\n\\n event MaxGasPriceUpdated(uint256 newMaxGasPrice);\\n\\n event SendingEtherFailed(uint256 refundAmount, address receiver);\\n\\n event AuthorizedContract(address thirdPartyContract);\\n\\n event UnauthorizedContract(address thirdPartyContract);\\n\\n event FundsWithdrawn(uint256 withdrawnAmount, address receiver);\\n\\n constructor(uint256 _staticGas, uint256 _maxGasPrice) {\\n staticGas = _staticGas;\\n maxGasPrice = _maxGasPrice;\\n }\\n\\n /// @notice Receive ETH\\n receive() external payable {}\\n\\n /// @notice Refunds ETH to a spender for executing specific transactions.\\n /// @dev Ignoring the result of sending ETH to a receiver is made on purpose.\\n /// For EOA receiving ETH should always work. If a receiver is a smart\\n /// contract, then we do not want to fail a transaction, because in some\\n /// cases the refund is done at the very end of multiple calls where all\\n /// the previous calls were already paid off. It is a receiver's smart\\n /// contract resposibility to make sure it can receive ETH.\\n /// @dev Only authorized contracts are allowed calling this function.\\n /// @param gasSpent Gas spent on a transaction that needs to be reimbursed.\\n /// @param receiver Address where the reimbursment is sent.\\n function refund(uint256 gasSpent, address receiver) external nonReentrant {\\n require(\\n isAuthorized[msg.sender],\\n \\\"Contract is not authorized for a refund\\\"\\n );\\n require(receiver != address(0), \\\"Receiver's address cannot be zero\\\");\\n\\n uint256 gasPrice = tx.gasprice < maxGasPrice\\n ? tx.gasprice\\n : maxGasPrice;\\n\\n uint256 refundAmount = (gasSpent + staticGas) * gasPrice;\\n\\n /* solhint-disable avoid-low-level-calls */\\n // slither-disable-next-line low-level-calls,unchecked-lowlevel\\n (bool sent, ) = receiver.call{value: refundAmount}(\\\"\\\");\\n /* solhint-enable avoid-low-level-calls */\\n if (!sent) {\\n // slither-disable-next-line reentrancy-events\\n emit SendingEtherFailed(refundAmount, receiver);\\n }\\n }\\n\\n /// @notice Authorize a contract that can interact with this reimbursment pool.\\n /// Can be authorized by the owner only.\\n /// @param _contract Authorized contract.\\n function authorize(address _contract) external onlyOwner {\\n isAuthorized[_contract] = true;\\n\\n emit AuthorizedContract(_contract);\\n }\\n\\n /// @notice Unauthorize a contract that was previously authorized to interact\\n /// with this reimbursment pool. Can be unauthorized by the\\n /// owner only.\\n /// @param _contract Authorized contract.\\n function unauthorize(address _contract) external onlyOwner {\\n delete isAuthorized[_contract];\\n\\n emit UnauthorizedContract(_contract);\\n }\\n\\n /// @notice Setting a static gas cost for executing a transaction. Can be set\\n /// by the owner only.\\n /// @param _staticGas Static gas cost.\\n function setStaticGas(uint256 _staticGas) external onlyOwner {\\n staticGas = _staticGas;\\n\\n emit StaticGasUpdated(_staticGas);\\n }\\n\\n /// @notice Setting a max gas price for transactions. Can be set by the\\n /// owner only.\\n /// @param _maxGasPrice Max gas price used to reimburse tx submitters.\\n function setMaxGasPrice(uint256 _maxGasPrice) external onlyOwner {\\n maxGasPrice = _maxGasPrice;\\n\\n emit MaxGasPriceUpdated(_maxGasPrice);\\n }\\n\\n /// @notice Withdraws all ETH from this pool which are sent to a given\\n /// address. Can be set by the owner only.\\n /// @param receiver An address where ETH is sent.\\n function withdrawAll(address receiver) external onlyOwner {\\n withdraw(address(this).balance, receiver);\\n }\\n\\n /// @notice Withdraws ETH amount from this pool which are sent to a given\\n /// address. Can be set by the owner only.\\n /// @param amount Amount to withdraw from the pool.\\n /// @param receiver An address where ETH is sent.\\n function withdraw(uint256 amount, address receiver) public onlyOwner {\\n require(\\n address(this).balance >= amount,\\n \\\"Insufficient contract balance\\\"\\n );\\n require(receiver != address(0), \\\"Receiver's address cannot be zero\\\");\\n\\n emit FundsWithdrawn(amount, receiver);\\n\\n /* solhint-disable avoid-low-level-calls */\\n // slither-disable-next-line low-level-calls,arbitrary-send\\n (bool sent, ) = receiver.call{value: amount}(\\\"\\\");\\n /* solhint-enable avoid-low-level-calls */\\n require(sent, \\\"Failed to send Ether\\\");\\n }\\n}\\n\",\"keccak256\":\"0xd6c24368cc4c6349b8b614e878ca961cad8254b8e8db1cc0abe452a70022ce50\",\"license\":\"GPL-3.0-only\"},\"contracts/api/IRandomBeacon.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IRandomBeaconConsumer.sol\\\";\\n\\n/// @title Random Beacon interface\\ninterface IRandomBeacon {\\n /// @notice Creates a request to generate a new relay entry. Requires a\\n /// request fee denominated in T token.\\n /// @param callbackContract Beacon consumer callback contract.\\n function requestRelayEntry(IRandomBeaconConsumer callbackContract) external;\\n}\\n\",\"keccak256\":\"0xc5f6ddbf69b2f2e2c03fe78b3857a1f038982e858679f520101f53c4ebe2f4bf\",\"license\":\"GPL-3.0-only\"},\"contracts/api/IRandomBeaconConsumer.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\ninterface IRandomBeaconConsumer {\\n /// @notice Receives relay entry produced by Keep Random Beacon. This function\\n /// should be called only by Keep Random Beacon.\\n ///\\n /// @param relayEntry Relay entry (random number) produced by Keep Random\\n /// Beacon.\\n /// @param blockNumber Block number at which the relay entry was submitted\\n /// to the chain.\\n function __beaconCallback(uint256 relayEntry, uint256 blockNumber) external;\\n}\\n\",\"keccak256\":\"0x84ce236b4eeb664ccb02782777a05c6ebb410be9b9e586a123a1205437a2ed9f\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/AltBn128.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./ModUtils.sol\\\";\\n\\n/// @title Operations on alt_bn128\\n/// @dev Implementations of common elliptic curve operations on Ethereum's\\n/// (poorly named) alt_bn128 curve. Whenever possible, use post-Byzantium\\n/// pre-compiled contracts to offset gas costs. Note that these\\n/// pre-compiles might not be available on all (eg private) chains.\\nlibrary AltBn128 {\\n using ModUtils for uint256;\\n\\n // G1Point implements a point in G1 group.\\n struct G1Point {\\n uint256 x;\\n uint256 y;\\n }\\n\\n // gfP2 implements a field of size p\\u00b2 as a quadratic extension of the base\\n // field.\\n struct gfP2 {\\n uint256 x;\\n uint256 y;\\n }\\n\\n // G2Point implements a point in G2 group.\\n struct G2Point {\\n gfP2 x;\\n gfP2 y;\\n }\\n\\n // p is a prime over which we form a basic field\\n // Taken from go-ethereum/crypto/bn256/cloudflare/constants.go\\n uint256 internal constant p =\\n 21888242871839275222246405745257275088696311157297823662689037894645226208583;\\n\\n /// @dev Gets generator of G1 group.\\n /// Taken from go-ethereum/crypto/bn256/cloudflare/curve.go\\n uint256 internal constant g1x = 1;\\n uint256 internal constant g1y = 2;\\n\\n /// @dev Gets generator of G2 group.\\n /// Taken from go-ethereum/crypto/bn256/cloudflare/twist.go\\n uint256 internal constant g2xx =\\n 11559732032986387107991004021392285783925812861821192530917403151452391805634;\\n uint256 internal constant g2xy =\\n 10857046999023057135944570762232829481370756359578518086990519993285655852781;\\n uint256 internal constant g2yx =\\n 4082367875863433681332203403145435568316851327593401208105741076214120093531;\\n uint256 internal constant g2yy =\\n 8495653923123431417604973247489272438418190587263600148770280649306958101930;\\n\\n /// @dev Gets twist curve B constant.\\n /// Taken from go-ethereum/crypto/bn256/cloudflare/twist.go\\n uint256 internal constant twistBx =\\n 266929791119991161246907387137283842545076965332900288569378510910307636690;\\n uint256 internal constant twistBy =\\n 19485874751759354771024239261021720505790618469301721065564631296452457478373;\\n\\n /// @dev Gets root of the point where x and y are equal.\\n uint256 internal constant hexRootX =\\n 21573744529824266246521972077326577680729363968861965890554801909984373949499;\\n uint256 internal constant hexRootY =\\n 16854739155576650954933913186877292401521110422362946064090026408937773542853;\\n\\n /// @dev g1YFromX computes a Y value for a G1 point based on an X value.\\n /// This computation is simply evaluating the curve equation for Y on a\\n /// given X, and allows a point on the curve to be represented by just\\n /// an X value + a sign bit.\\n function g1YFromX(uint256 x) internal view returns (uint256) {\\n return ((x.modExp(3, p) + 3) % p).modSqrt(p);\\n }\\n\\n /// @dev Hash a byte array message, m, and map it deterministically to a\\n /// point on G1. Note that this approach was chosen for its simplicity\\n /// and lower gas cost on the EVM, rather than good distribution of\\n /// points on G1.\\n function g1HashToPoint(bytes memory m)\\n internal\\n view\\n returns (G1Point memory)\\n {\\n unchecked {\\n bytes32 h = sha256(m);\\n uint256 x = uint256(h) % p;\\n uint256 y;\\n\\n while (true) {\\n y = g1YFromX(x);\\n if (y > 0) {\\n return G1Point(x, y);\\n }\\n x += 1;\\n }\\n }\\n }\\n\\n /// @dev Decompress a point on G1 from a single uint256.\\n function g1Decompress(bytes32 m) internal view returns (G1Point memory) {\\n unchecked {\\n bytes32 mX = bytes32(0);\\n bytes1 leadX = m[0] & 0x7f;\\n // slither-disable-next-line incorrect-shift\\n uint256 mask = 0xff << (31 * 8);\\n mX = (m & ~bytes32(mask)) | (leadX >> 0);\\n\\n uint256 x = uint256(mX);\\n uint256 y = g1YFromX(x);\\n\\n if (parity(y) != (m[0] & 0x80) >> 7) {\\n y = p - y;\\n }\\n\\n require(\\n isG1PointOnCurve(G1Point(x, y)),\\n \\\"Malformed bn256.G1 point.\\\"\\n );\\n\\n return G1Point(x, y);\\n }\\n }\\n\\n /// @dev Wraps the point addition pre-compile introduced in Byzantium.\\n /// Returns the sum of two points on G1. Revert if the provided points\\n /// are not on the curve.\\n function g1Add(G1Point memory a, G1Point memory b)\\n internal\\n view\\n returns (G1Point memory c)\\n {\\n assembly {\\n let arg := mload(0x40)\\n mstore(arg, mload(a))\\n mstore(add(arg, 0x20), mload(add(a, 0x20)))\\n mstore(add(arg, 0x40), mload(b))\\n mstore(add(arg, 0x60), mload(add(b, 0x20)))\\n // 0x60 is the ECADD precompile address\\n if iszero(staticcall(not(0), 0x06, arg, 0x80, c, 0x40)) {\\n revert(0, 0)\\n }\\n }\\n }\\n\\n /// @dev Returns true if G1 point is on the curve.\\n function isG1PointOnCurve(G1Point memory point)\\n internal\\n view\\n returns (bool)\\n {\\n return point.y.modExp(2, p) == (point.x.modExp(3, p) + 3) % p;\\n }\\n\\n /// @dev Wraps the scalar point multiplication pre-compile introduced in\\n /// Byzantium. The result of a point from G1 multiplied by a scalar\\n /// should match the point added to itself the same number of times.\\n /// Revert if the provided point isn't on the curve.\\n function scalarMultiply(G1Point memory p_1, uint256 scalar)\\n internal\\n view\\n returns (G1Point memory p_2)\\n {\\n assembly {\\n let arg := mload(0x40)\\n mstore(arg, mload(p_1))\\n mstore(add(arg, 0x20), mload(add(p_1, 0x20)))\\n mstore(add(arg, 0x40), scalar)\\n // 0x07 is the ECMUL precompile address\\n if iszero(staticcall(not(0), 0x07, arg, 0x60, p_2, 0x40)) {\\n revert(0, 0)\\n }\\n }\\n }\\n\\n /// @dev Wraps the pairing check pre-compile introduced in Byzantium.\\n /// Returns the result of a pairing check of 2 pairs\\n /// (G1 p1, G2 p2) (G1 p3, G2 p4)\\n function pairing(\\n G1Point memory p1,\\n G2Point memory p2,\\n G1Point memory p3,\\n G2Point memory p4\\n ) internal view returns (bool result) {\\n uint256 _c;\\n assembly {\\n let c := mload(0x40)\\n let arg := add(c, 0x20)\\n\\n mstore(arg, mload(p1))\\n mstore(add(arg, 0x20), mload(add(p1, 0x20)))\\n\\n let p2x := mload(p2)\\n mstore(add(arg, 0x40), mload(p2x))\\n mstore(add(arg, 0x60), mload(add(p2x, 0x20)))\\n\\n let p2y := mload(add(p2, 0x20))\\n mstore(add(arg, 0x80), mload(p2y))\\n mstore(add(arg, 0xa0), mload(add(p2y, 0x20)))\\n\\n mstore(add(arg, 0xc0), mload(p3))\\n mstore(add(arg, 0xe0), mload(add(p3, 0x20)))\\n\\n let p4x := mload(p4)\\n mstore(add(arg, 0x100), mload(p4x))\\n mstore(add(arg, 0x120), mload(add(p4x, 0x20)))\\n\\n let p4y := mload(add(p4, 0x20))\\n mstore(add(arg, 0x140), mload(p4y))\\n mstore(add(arg, 0x160), mload(add(p4y, 0x20)))\\n\\n // call(gasLimit, to, value, inputOffset, inputSize, outputOffset, outputSize)\\n if iszero(staticcall(not(0), 0x08, arg, 0x180, c, 0x20)) {\\n revert(0, 0)\\n }\\n _c := mload(c)\\n }\\n return _c != 0;\\n }\\n\\n function getP() internal pure returns (uint256) {\\n return p;\\n }\\n\\n function g1() internal pure returns (G1Point memory) {\\n return G1Point(g1x, g1y);\\n }\\n\\n function g2() internal pure returns (G2Point memory) {\\n return G2Point(gfP2(g2xx, g2xy), gfP2(g2yx, g2yy));\\n }\\n\\n /// @dev g2YFromX computes a Y value for a G2 point based on an X value.\\n /// This computation is simply evaluating the curve equation for Y on a\\n /// given X, and allows a point on the curve to be represented by just\\n /// an X value + a sign bit.\\n function g2YFromX(gfP2 memory _x) internal pure returns (gfP2 memory y) {\\n (uint256 xx, uint256 xy) = _gfP2CubeAddTwistB(_x.x, _x.y);\\n\\n // Using formula y = x ^ (p^2 + 15) / 32 from\\n // https://github.com/ethereum/beacon_chain/blob/master/beacon_chain/utils/bls.py\\n // (p^2 + 15) / 32 results into a big 512bit value, so breaking it to two uint256 as (a * a + b)\\n uint256 a = 3869331240733915743250440106392954448556483137451914450067252501901456824595;\\n uint256 b = 146360017852723390495514512480590656176144969185739259173561346299185050597;\\n\\n (uint256 xbx, uint256 xby) = _gfP2Pow(xx, xy, b);\\n (uint256 yax, uint256 yay) = _gfP2Pow(xx, xy, a);\\n (uint256 ya2x, uint256 ya2y) = _gfP2Pow(yax, yay, a);\\n (y.x, y.y) = _gfP2Multiply(ya2x, ya2y, xbx, xby);\\n\\n // Multiply y by hexRoot constant to find correct y.\\n while (!_g2X2y(xx, xy, y.x, y.y)) {\\n (y.x, y.y) = _gfP2Multiply(y.x, y.y, hexRootX, hexRootY);\\n }\\n }\\n\\n /// @dev Compress a point on G1 to a single uint256 for serialization.\\n function g1Compress(G1Point memory point) internal pure returns (bytes32) {\\n bytes32 m = bytes32(point.x);\\n\\n bytes1 leadM = m[0] | (parity(point.y) << 7);\\n // slither-disable-next-line incorrect-shift\\n uint256 mask = 0xff << (31 * 8);\\n m = (m & ~bytes32(mask)) | (leadM >> 0);\\n\\n return m;\\n }\\n\\n /// @dev Compress a point on G2 to a pair of uint256 for serialization.\\n function g2Compress(G2Point memory point)\\n internal\\n pure\\n returns (bytes memory)\\n {\\n bytes32 m = bytes32(point.x.x);\\n\\n bytes1 leadM = m[0] | (parity(point.y.x) << 7);\\n // slither-disable-next-line incorrect-shift\\n uint256 mask = 0xff << (31 * 8);\\n m = (m & ~bytes32(mask)) | (leadM >> 0);\\n\\n return abi.encodePacked(m, bytes32(point.x.y));\\n }\\n\\n /// @dev Unmarshals a point on G1 from bytes in an uncompressed form.\\n function g1Unmarshal(bytes memory m)\\n internal\\n pure\\n returns (G1Point memory)\\n {\\n require(m.length == 64, \\\"Invalid G1 bytes length\\\");\\n\\n bytes32 x;\\n bytes32 y;\\n\\n assembly {\\n x := mload(add(m, 0x20))\\n y := mload(add(m, 0x40))\\n }\\n\\n return G1Point(uint256(x), uint256(y));\\n }\\n\\n /// @dev Marshals a point on G1 to bytes form.\\n function g1Marshal(G1Point memory point)\\n internal\\n pure\\n returns (bytes memory)\\n {\\n bytes memory m = new bytes(64);\\n bytes32 x = bytes32(point.x);\\n bytes32 y = bytes32(point.y);\\n\\n assembly {\\n mstore(add(m, 32), x)\\n mstore(add(m, 64), y)\\n }\\n\\n return m;\\n }\\n\\n /// @dev Unmarshals a point on G2 from bytes in an uncompressed form.\\n function g2Unmarshal(bytes memory m)\\n internal\\n pure\\n returns (G2Point memory)\\n {\\n require(m.length == 128, \\\"Invalid G2 bytes length\\\");\\n\\n uint256 xx;\\n uint256 xy;\\n uint256 yx;\\n uint256 yy;\\n\\n assembly {\\n xx := mload(add(m, 0x20))\\n xy := mload(add(m, 0x40))\\n yx := mload(add(m, 0x60))\\n yy := mload(add(m, 0x80))\\n }\\n\\n return G2Point(gfP2(xx, xy), gfP2(yx, yy));\\n }\\n\\n /// @dev Decompress a point on G2 from a pair of uint256.\\n function g2Decompress(bytes memory m)\\n internal\\n pure\\n returns (G2Point memory)\\n {\\n require(m.length == 64, \\\"Invalid G2 compressed bytes length\\\");\\n\\n bytes32 x1;\\n bytes32 x2;\\n uint256 temp;\\n\\n // Extract two bytes32 from bytes array\\n assembly {\\n temp := add(m, 32)\\n x1 := mload(temp)\\n temp := add(m, 64)\\n x2 := mload(temp)\\n }\\n\\n bytes32 mX = bytes32(0);\\n bytes1 leadX = x1[0] & 0x7f;\\n // slither-disable-next-line incorrect-shift\\n uint256 mask = 0xff << (31 * 8);\\n mX = (x1 & ~bytes32(mask)) | (leadX >> 0);\\n\\n gfP2 memory x = gfP2(uint256(mX), uint256(x2));\\n gfP2 memory y = g2YFromX(x);\\n\\n if (parity(y.x) != (m[0] & 0x80) >> 7) {\\n y.x = p - y.x;\\n y.y = p - y.y;\\n }\\n\\n return G2Point(x, y);\\n }\\n\\n /// @dev Returns the sum of two gfP2 field elements.\\n function gfP2Add(gfP2 memory a, gfP2 memory b)\\n internal\\n pure\\n returns (gfP2 memory)\\n {\\n return gfP2(addmod(a.x, b.x, p), addmod(a.y, b.y, p));\\n }\\n\\n /// @dev Returns multiplication of two gfP2 field elements.\\n function gfP2Multiply(gfP2 memory a, gfP2 memory b)\\n internal\\n pure\\n returns (gfP2 memory)\\n {\\n return\\n gfP2(\\n addmod(mulmod(a.x, b.y, p), mulmod(b.x, a.y, p), p),\\n addmod(mulmod(a.y, b.y, p), p - mulmod(a.x, b.x, p), p)\\n );\\n }\\n\\n /// @dev Returns gfP2 element to the power of the provided exponent.\\n function gfP2Pow(gfP2 memory _a, uint256 _exp)\\n internal\\n pure\\n returns (gfP2 memory result)\\n {\\n (uint256 x, uint256 y) = _gfP2Pow(_a.x, _a.y, _exp);\\n return gfP2(x, y);\\n }\\n\\n function gfP2Square(gfP2 memory a) internal pure returns (gfP2 memory) {\\n return gfP2Multiply(a, a);\\n }\\n\\n function gfP2Cube(gfP2 memory a) internal pure returns (gfP2 memory) {\\n return gfP2Multiply(a, gfP2Square(a));\\n }\\n\\n function gfP2CubeAddTwistB(gfP2 memory a)\\n internal\\n pure\\n returns (gfP2 memory)\\n {\\n (uint256 x, uint256 y) = _gfP2CubeAddTwistB(a.x, a.y);\\n return gfP2(x, y);\\n }\\n\\n /// @dev Returns true if G2 point's y^2 equals x.\\n function g2X2y(gfP2 memory x, gfP2 memory y) internal pure returns (bool) {\\n gfP2 memory y2;\\n y2 = gfP2Square(y);\\n\\n return (y2.x == x.x && y2.y == x.y);\\n }\\n\\n /// @dev Returns true if G2 point is on the curve.\\n function isG2PointOnCurve(G2Point memory point)\\n internal\\n pure\\n returns (bool)\\n {\\n (uint256 y2x, uint256 y2y) = _gfP2Square(point.y.x, point.y.y);\\n (uint256 x3x, uint256 x3y) = _gfP2CubeAddTwistB(point.x.x, point.x.y);\\n\\n return (y2x == x3x && y2y == x3y);\\n }\\n\\n function twistB() private pure returns (gfP2 memory) {\\n return gfP2(twistBx, twistBy);\\n }\\n\\n function hexRoot() private pure returns (gfP2 memory) {\\n return gfP2(hexRootX, hexRootY);\\n }\\n\\n /// @dev Calculates whether the provided number is even or odd.\\n /// @return 0x01 if y is an even number and 0x00 if it's odd.\\n function parity(uint256 value) private pure returns (bytes1) {\\n return bytes32(value)[31] & 0x01;\\n }\\n\\n function _gfP2Add(\\n uint256 ax,\\n uint256 ay,\\n uint256 bx,\\n uint256 by\\n ) private pure returns (uint256 x, uint256 y) {\\n x = addmod(ax, bx, p);\\n y = addmod(ay, by, p);\\n }\\n\\n function _gfP2Multiply(\\n uint256 ax,\\n uint256 ay,\\n uint256 bx,\\n uint256 by\\n ) private pure returns (uint256 x, uint256 y) {\\n x = addmod(mulmod(ax, by, p), mulmod(bx, ay, p), p);\\n y = addmod(mulmod(ay, by, p), p - mulmod(ax, bx, p), p);\\n }\\n\\n function _gfP2CubeAddTwistB(uint256 ax, uint256 ay)\\n private\\n pure\\n returns (uint256 x, uint256 y)\\n {\\n (uint256 a3x, uint256 a3y) = _gfP2Cube(ax, ay);\\n return _gfP2Add(a3x, a3y, twistBx, twistBy);\\n }\\n\\n function _gfP2Pow(\\n uint256 _ax,\\n uint256 _ay,\\n uint256 _exp\\n ) private pure returns (uint256 x, uint256 y) {\\n uint256 exp = _exp;\\n x = 0;\\n y = 1;\\n uint256 ax = _ax;\\n uint256 ay = _ay;\\n\\n // Reduce exp dividing by 2 gradually to 0 while computing final\\n // result only when exp is an odd number.\\n while (exp > 0) {\\n if (parity(exp) == 0x01) {\\n (x, y) = _gfP2Multiply(x, y, ax, ay);\\n }\\n\\n unchecked {\\n exp = exp / 2;\\n }\\n (ax, ay) = _gfP2Multiply(ax, ay, ax, ay);\\n }\\n }\\n\\n function _gfP2Square(uint256 _ax, uint256 _ay)\\n private\\n pure\\n returns (uint256 x, uint256 y)\\n {\\n return _gfP2Multiply(_ax, _ay, _ax, _ay);\\n }\\n\\n function _gfP2Cube(uint256 _ax, uint256 _ay)\\n private\\n pure\\n returns (uint256 x, uint256 y)\\n {\\n (uint256 _bx, uint256 _by) = _gfP2Square(_ax, _ay);\\n return _gfP2Multiply(_ax, _ay, _bx, _by);\\n }\\n\\n function _g2X2y(\\n uint256 xx,\\n uint256 xy,\\n uint256 yx,\\n uint256 yy\\n ) private pure returns (bool) {\\n (uint256 y2x, uint256 y2y) = _gfP2Square(yx, yy);\\n\\n return (y2x == xx && y2y == xy);\\n }\\n}\\n\",\"keccak256\":\"0x8a100028820ff5c424f4bb780fbedec1da2576fbc6d5aa4e7309d986b730a319\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BLS.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./AltBn128.sol\\\";\\n\\n/// @title BLS signatures verification\\n/// @dev Library for verification of 2-pairing-check BLS signatures, including\\n/// basic, aggregated, or reconstructed threshold BLS signatures, generated\\n/// using the AltBn128 curve.\\nlibrary BLS {\\n /// @dev Creates a signature over message using the provided secret key.\\n function sign(bytes memory message, uint256 secretKey)\\n external\\n view\\n returns (bytes memory)\\n {\\n AltBn128.G1Point memory p_1 = AltBn128.g1HashToPoint(message);\\n AltBn128.G1Point memory p_2 = AltBn128.scalarMultiply(p_1, secretKey);\\n\\n return AltBn128.g1Marshal(p_2);\\n }\\n\\n /// @dev Wraps the functionality of BLS.verify, but hashes a message to\\n /// a point on G1 and marshal to bytes first to allow raw bytes\\n /// verification.\\n function verifyBytes(\\n bytes memory publicKey,\\n bytes memory message,\\n bytes memory signature\\n ) external view returns (bool) {\\n AltBn128.G1Point memory point = AltBn128.g1HashToPoint(message);\\n bytes memory messageAsPoint = AltBn128.g1Marshal(point);\\n\\n return verify(publicKey, messageAsPoint, signature);\\n }\\n\\n /// @dev Verify performs the pairing operation to check if the signature\\n /// is correct for the provided message and the corresponding public\\n /// key. Public key must be a valid point on G2 curve in an\\n /// uncompressed format. Message must be a valid point on G1 curve in\\n /// an uncompressed format. Signature must be a valid point on G1\\n /// curve in an uncompressed format.\\n function verify(\\n bytes memory publicKey,\\n bytes memory message,\\n bytes memory signature\\n ) public view returns (bool) {\\n AltBn128.G1Point memory _signature = AltBn128.g1Unmarshal(signature);\\n\\n return\\n _verify(\\n AltBn128.g2Unmarshal(publicKey),\\n AltBn128.g1Unmarshal(message),\\n _signature\\n );\\n }\\n\\n function _verify(\\n AltBn128.G2Point memory publicKey,\\n AltBn128.G1Point memory message,\\n AltBn128.G1Point memory signature\\n ) public view returns (bool) {\\n return\\n AltBn128.pairing(\\n AltBn128.G1Point(signature.x, AltBn128.getP() - signature.y),\\n AltBn128.g2(),\\n message,\\n publicKey\\n );\\n }\\n}\\n\",\"keccak256\":\"0x08c7e739c63c31f5f45fb390695eca9e98a9525589ace41526f25060f46e43d4\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BeaconAuthorization.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\n// Initial version copied from Keep Network ECDSA Wallets:\\n// https://github.com/keep-network/keep-core/blob/5286ebc8ff99b2aa6569f9dd97fd6995f25b4630/solidity/ecdsa/contracts/libraries/EcdsaAuthorization.sol\\n//\\n// With the following differences:\\n// - functions' visibility was changed to public/external to deploy it as a linked\\n// library.\\n// - documentation was updated to be more generic.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\nimport \\\"@threshold-network/solidity-contracts/contracts/staking/IStaking.sol\\\";\\n\\n/// @notice Library managing the state of stake authorizations for the operator\\n/// contract and the presence of operators in the sortition\\n/// pool based on the stake authorized for them.\\nlibrary BeaconAuthorization {\\n struct Parameters {\\n // The minimum authorization required by the beacon so that\\n // operator can join the sortition pool and do the work.\\n uint96 minimumAuthorization;\\n // Authorization decrease delay in seconds between the time\\n // authorization decrease is requested and the time the authorization\\n // decrease can be approved. It is always the same value, no matter if\\n // authorization decrease amount is small, significant, or if it is\\n // a decrease to zero.\\n uint64 authorizationDecreaseDelay;\\n // The time period before the authorization decrease delay end,\\n // during which the authorization decrease request can be overwritten.\\n //\\n // When the request is overwritten, the authorization decrease delay is\\n // reset.\\n //\\n // For example, if `authorizationDecraseChangePeriod` is set to 4\\n // days, `authorizationDecreaseDelay` is set to 14 days, and someone\\n // requested authorization decrease, it means they can not\\n // request another decrease for the first 10 days. After 10 days pass,\\n // they can request again and overwrite the previous authorization\\n // decrease request. The delay time will reset for them and they\\n // will have to wait another 10 days to alter it and 14 days to\\n // approve it.\\n //\\n // This value protects against malicious operators who manipulate\\n // their weight by overwriting authorization decrease request, and\\n // lowering or increasing their eligible stake this way.\\n //\\n // If set to a value equal to `authorizationDecreaseDelay, it means\\n // that authorization decrease request can be always overwritten.\\n // If set to zero, it means authorization decrease request can not be\\n // overwritten until the delay end, and one needs to wait for the entire\\n // authorization decrease delay to approve their decrease and request\\n // for another one or to overwrite the pending one.\\n //\\n // (1) authorization decrease requested timestamp\\n // (2) from this moment authorization decrease request can be\\n // overwritten\\n // (3) from this moment authorization decrease request can be\\n // approved, assuming it was NOT overwritten in (2)\\n //\\n // (1) (2) (3)\\n // --x------------------------------x--------------------------x---->\\n // | \\\\________________________/\\n // | authorizationDecreaseChangePeriod\\n // \\\\______________________________________________________/\\n // authorizationDecreaseDelay\\n //\\n uint64 authorizationDecreaseChangePeriod;\\n }\\n\\n struct AuthorizationDecrease {\\n uint96 decreasingBy; // amount\\n uint64 decreasingAt; // timestamp\\n }\\n\\n struct Data {\\n Parameters parameters;\\n mapping(address => address) stakingProviderToOperator;\\n mapping(address => address) operatorToStakingProvider;\\n mapping(address => AuthorizationDecrease) pendingDecreases;\\n }\\n\\n event OperatorRegistered(\\n address indexed stakingProvider,\\n address indexed operator\\n );\\n\\n event AuthorizationIncreased(\\n address indexed stakingProvider,\\n address indexed operator,\\n uint96 fromAmount,\\n uint96 toAmount\\n );\\n\\n event AuthorizationDecreaseRequested(\\n address indexed stakingProvider,\\n address indexed operator,\\n uint96 fromAmount,\\n uint96 toAmount,\\n uint64 decreasingAt\\n );\\n\\n event AuthorizationDecreaseApproved(address indexed stakingProvider);\\n\\n event InvoluntaryAuthorizationDecreaseFailed(\\n address indexed stakingProvider,\\n address indexed operator,\\n uint96 fromAmount,\\n uint96 toAmount\\n );\\n\\n event OperatorJoinedSortitionPool(\\n address indexed stakingProvider,\\n address indexed operator\\n );\\n\\n event OperatorStatusUpdated(\\n address indexed stakingProvider,\\n address indexed operator\\n );\\n\\n /// @notice Updates authorization-related parameters.\\n /// @param _minimumAuthorization New value of the minimum authorization for\\n /// the beacon. Without at least the minimum authorization, staking\\n /// provider is not eligible to join and operate in the network.\\n /// @param _authorizationDecreaseDelay New value of the authorization\\n /// decrease delay. It is the time in seconds that needs to pass\\n /// between the time authorization decrease is requested and the time\\n /// the authorization decrease can be approved, no matter the\\n /// authorization decrease amount.\\n /// @param _authorizationDecreaseChangePeriod New value of the authorization\\n /// decrease change period. It is the time in seconds, before\\n /// authorization decrease delay end, during which the pending\\n /// authorization decrease request can be overwritten.\\n /// If set to 0, pending authorization decrease request can not be\\n /// overwritten until the entire `authorizationDecreaseDelay` ends.\\n /// If set to value equal `authorizationDecreaseDelay`, request can\\n /// always be overwritten.\\n function setParameters(\\n Data storage self,\\n uint96 _minimumAuthorization,\\n uint64 _authorizationDecreaseDelay,\\n uint64 _authorizationDecreaseChangePeriod\\n ) external {\\n self.parameters.minimumAuthorization = _minimumAuthorization;\\n self\\n .parameters\\n .authorizationDecreaseDelay = _authorizationDecreaseDelay;\\n self\\n .parameters\\n .authorizationDecreaseChangePeriod = _authorizationDecreaseChangePeriod;\\n }\\n\\n /// @notice Used by staking provider to set operator address that will\\n /// operate a node. The given staking provider can set operator\\n /// address only one time. The operator address can not be changed\\n /// and must be unique. Reverts if the operator is already set for\\n /// the staking provider or if the operator address is already in\\n /// use. Reverts if there is a pending authorization decrease for\\n /// the staking provider.\\n function registerOperator(Data storage self, address operator) public {\\n address stakingProvider = msg.sender;\\n\\n require(operator != address(0), \\\"Operator can not be zero address\\\");\\n require(\\n self.stakingProviderToOperator[stakingProvider] == address(0),\\n \\\"Operator already set for the staking provider\\\"\\n );\\n require(\\n self.operatorToStakingProvider[operator] == address(0),\\n \\\"Operator address already in use\\\"\\n );\\n\\n // Authorization request for a staking provider who has not yet\\n // registered their operator can be approved immediately.\\n // We need to make sure that the approval happens before operator\\n // is registered to do not let the operator join the sortition pool\\n // with an unresolved authorization decrease request that can be\\n // approved at any point.\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n require(\\n decrease.decreasingAt == 0,\\n \\\"There is a pending authorization decrease request\\\"\\n );\\n\\n emit OperatorRegistered(stakingProvider, operator);\\n\\n self.stakingProviderToOperator[stakingProvider] = operator;\\n self.operatorToStakingProvider[operator] = stakingProvider;\\n }\\n\\n /// @notice Used by T staking contract to inform the beacon that the\\n /// authorized stake amount for the given staking provider increased.\\n ///\\n /// Reverts if the authorization amount is below the minimum.\\n ///\\n /// The function is not updating the sortition pool. Sortition pool\\n /// state needs to be updated by the operator with a call to\\n /// `joinSortitionPool` or `updateOperatorStatus`.\\n ///\\n /// @dev Should only be callable by T staking contract.\\n function authorizationIncreased(\\n Data storage self,\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external {\\n require(\\n toAmount >= self.parameters.minimumAuthorization,\\n \\\"Authorization below the minimum\\\"\\n );\\n\\n // Note that this function does not require the operator address to be\\n // set for the given staking provider. This allows the stake owner\\n // who is also an authorizer to increase the authorization before the\\n // staking provider sets the operator. This allows delegating stake\\n // and increasing authorization immediately one after another without\\n // having to wait for the staking provider to do their part.\\n\\n address operator = self.stakingProviderToOperator[stakingProvider];\\n emit AuthorizationIncreased(\\n stakingProvider,\\n operator,\\n fromAmount,\\n toAmount\\n );\\n }\\n\\n /// @notice Used by T staking contract to inform the beacon that the\\n /// authorization decrease for the given staking provider has been\\n /// requested.\\n ///\\n /// Reverts if the amount after deauthorization would be non-zero\\n /// and lower than the minimum authorization.\\n ///\\n /// Reverts if another authorization decrease request is pending for\\n /// the staking provider and not enough time passed since the\\n /// original request (see `authorizationDecreaseChangePeriod`).\\n ///\\n /// If the operator is not known (`registerOperator` was not called)\\n /// it lets to `approveAuthorizationDecrease` immediately. If the\\n /// operator is known (`registerOperator` was called), the operator\\n /// needs to update state of the sortition pool with a call to\\n /// `joinSortitionPool` or `updateOperatorStatus`. After the\\n /// sortition pool state is in sync, authorization decrease delay\\n /// starts.\\n ///\\n /// After authorization decrease delay passes, authorization\\n /// decrease request needs to be approved with a call to\\n /// `approveAuthorizationDecrease` function.\\n ///\\n /// If there is a pending authorization decrease request, it is\\n /// overwritten, but only if enough time passed since the original\\n /// request. Otherwise, the function reverts.\\n ///\\n /// @dev Should only be callable by T staking contract.\\n function authorizationDecreaseRequested(\\n Data storage self,\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) public {\\n require(\\n toAmount == 0 || toAmount >= self.parameters.minimumAuthorization,\\n \\\"Authorization amount should be 0 or above the minimum\\\"\\n );\\n\\n address operator = self.stakingProviderToOperator[stakingProvider];\\n\\n uint64 decreasingAt;\\n\\n if (operator == address(0)) {\\n // Operator is not known. It means `registerOperator` was not\\n // called yet, and there is no chance the operator could\\n // call `joinSortitionPool`. We can let to approve authorization\\n // decrease immediately because that operator was never in the\\n // sortition pool.\\n\\n // solhint-disable-next-line not-rely-on-time\\n decreasingAt = uint64(block.timestamp);\\n } else {\\n // Operator is known. It means that this operator is or was in\\n // the sortition pool. Before authorization decrease delay starts,\\n // the operator needs to update the state of the sortition pool\\n // with a call to `joinSortitionPool` or `updateOperatorStatus`.\\n // For now, we set `decreasingAt` as \\\"never decreasing\\\" and let\\n // it be updated by `joinSortitionPool` or `updateOperatorStatus`\\n // once we know the sortition pool is in sync.\\n decreasingAt = type(uint64).max;\\n }\\n\\n uint96 decreasingBy = fromAmount - toAmount;\\n\\n AuthorizationDecrease storage decreaseRequest = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n uint64 pendingDecreaseAt = decreaseRequest.decreasingAt;\\n if (pendingDecreaseAt != 0 && pendingDecreaseAt != type(uint64).max) {\\n // If there is already a pending authorization decrease request for\\n // this staking provider and that request has been activated\\n // (sortition pool was updated), require enough time to pass before\\n // it can be overwritten.\\n require(\\n // solhint-disable-next-line not-rely-on-time\\n block.timestamp >=\\n pendingDecreaseAt -\\n self.parameters.authorizationDecreaseChangePeriod,\\n \\\"Not enough time passed since the original request\\\"\\n );\\n }\\n\\n decreaseRequest.decreasingBy = decreasingBy;\\n decreaseRequest.decreasingAt = decreasingAt;\\n\\n emit AuthorizationDecreaseRequested(\\n stakingProvider,\\n operator,\\n fromAmount,\\n toAmount,\\n decreasingAt\\n );\\n }\\n\\n /// @notice Approves the previously registered authorization decrease\\n /// request. Reverts if authorization decrease delay have not passed\\n /// yet or if the authorization decrease was not requested for the\\n /// given staking provider.\\n function approveAuthorizationDecrease(\\n Data storage self,\\n IStaking tokenStaking,\\n address stakingProvider\\n ) public {\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n require(\\n decrease.decreasingAt > 0,\\n \\\"Authorization decrease not requested\\\"\\n );\\n require(\\n decrease.decreasingAt != type(uint64).max,\\n \\\"Authorization decrease request not activated\\\"\\n );\\n require(\\n // solhint-disable-next-line not-rely-on-time\\n block.timestamp >= decrease.decreasingAt,\\n \\\"Authorization decrease delay not passed\\\"\\n );\\n\\n emit AuthorizationDecreaseApproved(stakingProvider);\\n\\n // slither-disable-next-line unused-return\\n tokenStaking.approveAuthorizationDecrease(stakingProvider);\\n delete self.pendingDecreases[stakingProvider];\\n }\\n\\n /// @notice Used by T staking contract to inform the beacon the\\n /// authorization has been decreased for the given staking provider\\n /// involuntarily, as a result of slashing.\\n ///\\n /// If the operator is not known (`registerOperator` was not called)\\n /// the function does nothing. The operator was never in a sortition\\n /// pool so there is nothing to update.\\n ///\\n /// If the operator is known, sortition pool is unlocked, and the\\n /// operator is in the sortition pool, the sortition pool state is\\n /// updated. If the sortition pool is locked, update needs to be\\n /// postponed. Every other staker is incentivized to call\\n /// `updateOperatorStatus` for the problematic operator to increase\\n /// their own rewards in the pool.\\n ///\\n /// @dev Should only be callable by T staking contract.\\n function involuntaryAuthorizationDecrease(\\n Data storage self,\\n IStaking tokenStaking,\\n SortitionPool sortitionPool,\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external {\\n address operator = self.stakingProviderToOperator[stakingProvider];\\n\\n if (operator == address(0)) {\\n // Operator is not known. It means `registerOperator` was not\\n // called yet, and there is no chance the operator could\\n // call `joinSortitionPool`. We can just ignore this update because\\n // operator was never in the sortition pool.\\n return;\\n } else {\\n // Operator is known. It means that this operator is or was in the\\n // sortition pool and the sortition pool may need to be updated.\\n //\\n // If the sortition pool is not locked and the operator is in the\\n // sortition pool, we are updating it.\\n //\\n // To keep stakes synchronized between applications when staking\\n // providers are slashed, without the risk of running out of gas,\\n // the staking contract queues up slashings and let users process\\n // the transactions. When an application slashes one or more staking\\n // providers, it adds them to the slashing queue on the staking\\n // contract. A queue entry contains the staking provider\\u2019s address\\n // and the amount they are due to be slashed.\\n //\\n // When there is at least one staking provider in the slashing\\n // queue, any account can submit a transaction processing one or\\n // more staking providers' slashings, and collecting a reward for\\n // doing so. A queued slashing is processed by updating the staking\\n // provider\\u2019s stake to the post-slashing amount, updating authorized\\n // amount for each affected application, and notifying all affected\\n // applications that the staking provider\\u2019s authorized stake has\\n // been reduced due to slashing.\\n //\\n // The entire idea is that the process transaction is expensive\\n // because each application needs to be updated, so the reward for\\n // the processor is hefty and comes from the slashed tokens.\\n // Practically, it means that if the sortition pool is unlocked, and\\n // can be updated, it should be updated because we already paid\\n // someone for updating it.\\n //\\n // If the sortition pool is locked, update needs to wait. Other\\n // sortition pool members are incentivized to call\\n // `updateOperatorStatus` for the problematic operator because they\\n // will increase their rewards this way.\\n if (sortitionPool.isOperatorInPool(operator)) {\\n if (sortitionPool.isLocked()) {\\n emit InvoluntaryAuthorizationDecreaseFailed(\\n stakingProvider,\\n operator,\\n fromAmount,\\n toAmount\\n );\\n } else {\\n updateOperatorStatus(\\n self,\\n tokenStaking,\\n sortitionPool,\\n operator\\n );\\n }\\n }\\n }\\n }\\n\\n /// @notice Lets the operator join the sortition pool. The operator address\\n /// must be known - before calling this function, it has to be\\n /// appointed by the staking provider by calling `registerOperator`.\\n /// Also, the operator must have the minimum authorization required\\n /// by the beacon. Function reverts if there is no minimum stake\\n /// authorized or if the operator is not known. If there was an\\n /// authorization decrease requested, it is activated by starting\\n /// the authorization decrease delay.\\n function joinSortitionPool(\\n Data storage self,\\n IStaking tokenStaking,\\n SortitionPool sortitionPool\\n ) public {\\n address operator = msg.sender;\\n\\n address stakingProvider = self.operatorToStakingProvider[operator];\\n require(stakingProvider != address(0), \\\"Unknown operator\\\");\\n\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n uint96 _eligibleStake = eligibleStake(\\n self,\\n tokenStaking,\\n stakingProvider,\\n decrease.decreasingBy\\n );\\n\\n require(_eligibleStake != 0, \\\"Authorization below the minimum\\\");\\n\\n emit OperatorJoinedSortitionPool(stakingProvider, operator);\\n\\n sortitionPool.insertOperator(operator, _eligibleStake);\\n\\n // If there is a pending authorization decrease request, activate it.\\n // At this point, the sortition pool state is up to date so the\\n // authorization decrease delay can start counting.\\n if (decrease.decreasingAt == type(uint64).max) {\\n decrease.decreasingAt =\\n // solhint-disable-next-line not-rely-on-time\\n uint64(block.timestamp) +\\n self.parameters.authorizationDecreaseDelay;\\n }\\n }\\n\\n /// @notice Updates status of the operator in the sortition pool. If there\\n /// was an authorization decrease requested, it is activated by\\n /// starting the authorization decrease delay.\\n /// Function reverts if the operator is not known.\\n function updateOperatorStatus(\\n Data storage self,\\n IStaking tokenStaking,\\n SortitionPool sortitionPool,\\n address operator\\n ) public {\\n address stakingProvider = self.operatorToStakingProvider[operator];\\n require(stakingProvider != address(0), \\\"Unknown operator\\\");\\n\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n emit OperatorStatusUpdated(stakingProvider, operator);\\n\\n if (sortitionPool.isOperatorInPool(operator)) {\\n uint96 _eligibleStake = eligibleStake(\\n self,\\n tokenStaking,\\n stakingProvider,\\n decrease.decreasingBy\\n );\\n\\n sortitionPool.updateOperatorStatus(operator, _eligibleStake);\\n }\\n\\n // If there is a pending authorization decrease request, activate it.\\n // At this point, the sortition pool state is up to date so the\\n // authorization decrease delay can start counting.\\n if (decrease.decreasingAt == type(uint64).max) {\\n decrease.decreasingAt =\\n // solhint-disable-next-line not-rely-on-time\\n uint64(block.timestamp) +\\n self.parameters.authorizationDecreaseDelay;\\n }\\n }\\n\\n /// @notice Checks if the operator's authorized stake is in sync with\\n /// operator's weight in the sortition pool.\\n /// If the operator is not in the sortition pool and their\\n /// authorized stake is non-zero, function returns false.\\n function isOperatorUpToDate(\\n Data storage self,\\n IStaking tokenStaking,\\n SortitionPool sortitionPool,\\n address operator\\n ) external view returns (bool) {\\n address stakingProvider = self.operatorToStakingProvider[operator];\\n require(stakingProvider != address(0), \\\"Unknown operator\\\");\\n\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n uint96 _eligibleStake = eligibleStake(\\n self,\\n tokenStaking,\\n stakingProvider,\\n decrease.decreasingBy\\n );\\n\\n if (!sortitionPool.isOperatorInPool(operator)) {\\n return _eligibleStake == 0;\\n } else {\\n return sortitionPool.isOperatorUpToDate(operator, _eligibleStake);\\n }\\n }\\n\\n /// @notice Returns the current value of the staking provider's eligible\\n /// stake. Eligible stake is defined as the currently authorized\\n /// stake minus the pending authorization decrease. Eligible stake\\n /// is what is used for operator's weight in the pool. If the\\n /// authorized stake minus the pending authorization decrease is\\n /// below the minimum authorization, eligible stake is 0.\\n /// @dev This function can be exposed to the public in contrast to the\\n /// second variant accepting `decreasingBy` as a parameter.\\n function eligibleStake(\\n Data storage self,\\n IStaking tokenStaking,\\n address stakingProvider\\n ) external view returns (uint96) {\\n return\\n eligibleStake(\\n self,\\n tokenStaking,\\n stakingProvider,\\n pendingAuthorizationDecrease(self, stakingProvider)\\n );\\n }\\n\\n /// @notice Returns the current value of the staking provider's eligible\\n /// stake. Eligible stake is defined as the currently authorized\\n /// stake minus the pending authorization decrease. Eligible stake\\n /// is what is used for operator's weight in the pool. If the\\n /// authorized stake minus the pending authorization decrease is\\n /// below the minimum authorization, eligible stake is 0.\\n /// @dev This function is not intended to be exposes to the public.\\n /// `decreasingBy` must be fetched from `pendingDecreases` mapping and\\n /// it is passed as a parameter to optimize gas usage of functions that\\n /// call `eligibleStake` and need to use `AuthorizationDecrease`\\n /// fetched from `pendingDecreases` for some additional logic.\\n function eligibleStake(\\n Data storage self,\\n IStaking tokenStaking,\\n address stakingProvider,\\n uint96 decreasingBy\\n ) public view returns (uint96) {\\n uint96 authorizedStake = tokenStaking.authorizedStake(\\n stakingProvider,\\n address(this)\\n );\\n\\n uint96 _eligibleStake = authorizedStake > decreasingBy\\n ? authorizedStake - decreasingBy\\n : 0;\\n\\n if (_eligibleStake < self.parameters.minimumAuthorization) {\\n return 0;\\n } else {\\n return _eligibleStake;\\n }\\n }\\n\\n /// @notice Returns the amount of stake that is pending authorization\\n /// decrease for the given staking provider. If no authorization\\n /// decrease has been requested, returns zero.\\n function pendingAuthorizationDecrease(\\n Data storage self,\\n address stakingProvider\\n ) public view returns (uint96) {\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n return decrease.decreasingBy;\\n }\\n\\n /// @notice Returns the remaining time in seconds that needs to pass before\\n /// the requested authorization decrease can be approved.\\n /// If the sortition pool state was not updated yet by the operator\\n /// after requesting the authorization decrease, returns\\n /// `type(uint64).max`.\\n function remainingAuthorizationDecreaseDelay(\\n Data storage self,\\n address stakingProvider\\n ) external view returns (uint64) {\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n if (decrease.decreasingAt == type(uint64).max) {\\n return type(uint64).max;\\n }\\n\\n // solhint-disable-next-line not-rely-on-time\\n uint64 _now = uint64(block.timestamp);\\n return _now > decrease.decreasingAt ? 0 : decrease.decreasingAt - _now;\\n }\\n}\\n\",\"keccak256\":\"0xe146f4a3c662e971317d0189b2fca613f9f83a163ef682ed1e536e6c1f919a08\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BeaconDkg.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\nimport \\\"./BytesLib.sol\\\";\\nimport {BeaconDkgValidator as DKGValidator} from \\\"../BeaconDkgValidator.sol\\\";\\n\\nlibrary BeaconDkg {\\n using BytesLib for bytes;\\n using ECDSA for bytes32;\\n\\n struct Parameters {\\n // Time in blocks during which a submitted result can be challenged.\\n uint256 resultChallengePeriodLength;\\n // Extra gas required to be left at the end of the challenge DKG result\\n // transaction.\\n uint256 resultChallengeExtraGas;\\n // Time in blocks during which a result is expected to be submitted.\\n uint256 resultSubmissionTimeout;\\n // Time in blocks during which only the result submitter is allowed to\\n // approve it. Once this period ends and the submitter have not approved\\n // the result, anyone can do it.\\n uint256 submitterPrecedencePeriodLength;\\n }\\n\\n struct Data {\\n // Address of the Sortition Pool contract.\\n SortitionPool sortitionPool;\\n // Address of the DKGValidator contract.\\n DKGValidator dkgValidator;\\n // DKG parameters. The parameters should persist between DKG executions.\\n // They should be updated with dedicated set functions only when DKG is not\\n // in progress.\\n Parameters parameters;\\n // Time in blocks at which DKG started.\\n uint256 startBlock;\\n // Seed used to start DKG.\\n uint256 seed;\\n // Time in blocks that should be added to result submission period calculation.\\n // It is used in case of a challenge to adjust DKG timeout calculation.\\n uint256 resultSubmissionStartBlockOffset;\\n // Hash of submitted DKG result.\\n bytes32 submittedResultHash;\\n // Block number from the moment of the DKG result submission.\\n uint256 submittedResultBlock;\\n }\\n\\n /// @notice DKG result.\\n struct Result {\\n // Claimed submitter candidate group member index.\\n // Must be in range [1, groupSize].\\n uint256 submitterMemberIndex;\\n // Generated candidate group public key\\n bytes groupPubKey;\\n // Array of misbehaved members indices (disqualified or inactive).\\n // Indices must be in range [1, groupSize], unique, and sorted in ascending\\n // order.\\n uint8[] misbehavedMembersIndices;\\n // Concatenation of signatures from members supporting the result.\\n // The message to be signed by each member is keccak256 hash of the\\n // calculated group public key, misbehaved members indices and DKG\\n // start block. The calculated hash should be prefixed with prefixed with\\n // `\\\\x19Ethereum signed message:\\\\n` before signing, so the message to\\n // sign is:\\n // `\\\\x19Ethereum signed message:\\\\n${keccak256(\\n // groupPubKey, misbehavedMembersIndices, dkgStartBlock\\n // )}`\\n bytes signatures;\\n // Indices of members corresponding to each signature. Indices must be\\n // be in range [1, groupSize], unique, and sorted in ascending order.\\n uint256[] signingMembersIndices;\\n // Identifiers of candidate group members as outputted by the group\\n // selection protocol.\\n uint32[] members;\\n // Keccak256 hash of group members identifiers that actively took part\\n // in DKG (excluding IA/DQ members).\\n bytes32 membersHash;\\n }\\n\\n /// @notice States for phases of group creation. The states doesn't include\\n /// timeouts which should be tracked and notified individually.\\n enum State {\\n // Group creation is not in progress. It is a state set after group creation\\n // completion either by timeout or by a result approval.\\n IDLE,\\n // Group creation is awaiting the seed and sortition pool is locked.\\n AWAITING_SEED,\\n // Off-chain DKG protocol execution is in progress. A result is being calculated\\n // by the clients in this state. It's not yet possible to submit the result.\\n KEY_GENERATION,\\n // After off-chain DKG protocol execution the contract awaits result submission.\\n // This is a state to which group creation returns in case of a result\\n // challenge notification.\\n AWAITING_RESULT,\\n // DKG result was submitted and awaits an approval or a challenge. If a result\\n // gets challenge the state returns to `AWAITING_RESULT`. If a result gets\\n // approval the state changes to `IDLE`.\\n CHALLENGE\\n }\\n\\n /// @dev Size of a group in the threshold relay.\\n uint256 public constant groupSize = 64;\\n\\n /// @notice Time in blocks after which DKG result is complete and ready to be\\n // published by clients.\\n uint256 public constant offchainDkgTime = 5 * (1 + 5) + 2 * (1 + 10) + 20;\\n\\n event DkgStarted(uint256 indexed seed);\\n\\n // To recreate the members that actively took part in dkg, the selected members\\n // array should be filtered out from misbehavedMembersIndices.\\n event DkgResultSubmitted(\\n bytes32 indexed resultHash,\\n uint256 indexed seed,\\n Result result\\n );\\n\\n event DkgTimedOut();\\n\\n event DkgResultApproved(\\n bytes32 indexed resultHash,\\n address indexed approver\\n );\\n\\n event DkgResultChallenged(\\n bytes32 indexed resultHash,\\n address indexed challenger,\\n string reason\\n );\\n\\n event DkgStateLocked();\\n\\n event DkgSeedTimedOut();\\n\\n /// @notice Initializes SortitionPool and DKGValidator addresses.\\n /// Can be performed only once.\\n /// @param _sortitionPool Sortition Pool reference\\n /// @param _dkgValidator DKGValidator reference\\n function init(\\n Data storage self,\\n SortitionPool _sortitionPool,\\n DKGValidator _dkgValidator\\n ) internal {\\n require(\\n address(self.sortitionPool) == address(0),\\n \\\"Sortition Pool address already set\\\"\\n );\\n\\n require(\\n address(self.dkgValidator) == address(0),\\n \\\"DKG Validator address already set\\\"\\n );\\n\\n self.sortitionPool = _sortitionPool;\\n self.dkgValidator = _dkgValidator;\\n }\\n\\n /// @notice Determines the current state of group creation. It doesn't take\\n /// timeouts into consideration. The timeouts should be tracked and\\n /// notified separately.\\n function currentState(Data storage self)\\n internal\\n view\\n returns (State state)\\n {\\n state = State.IDLE;\\n\\n if (self.sortitionPool.isLocked()) {\\n state = State.AWAITING_SEED;\\n\\n if (self.startBlock > 0) {\\n state = State.KEY_GENERATION;\\n\\n if (block.number > self.startBlock + offchainDkgTime) {\\n state = State.AWAITING_RESULT;\\n\\n if (self.submittedResultBlock > 0) {\\n state = State.CHALLENGE;\\n }\\n }\\n }\\n }\\n }\\n\\n /// @notice Locks the sortition pool and starts awaiting for the\\n /// group creation seed.\\n function lockState(Data storage self) internal {\\n require(currentState(self) == State.IDLE, \\\"Current state is not IDLE\\\");\\n\\n emit DkgStateLocked();\\n\\n self.sortitionPool.lock();\\n }\\n\\n function start(Data storage self, uint256 seed) internal {\\n require(\\n currentState(self) == State.AWAITING_SEED,\\n \\\"Current state is not AWAITING_SEED\\\"\\n );\\n\\n emit DkgStarted(seed);\\n\\n self.startBlock = block.number;\\n self.seed = seed;\\n }\\n\\n /// @notice Allows to submit a DKG result. The submitted result does not go\\n /// through a validation and before it gets accepted, it needs to\\n /// wait through the challenge period during which everyone has\\n /// a chance to challenge the result as invalid one. Submitter of\\n /// the result needs to be in the sortition pool and if the result\\n /// gets challenged, the submitter will get slashed.\\n function submitResult(Data storage self, Result calldata result) external {\\n require(\\n currentState(self) == State.AWAITING_RESULT,\\n \\\"Current state is not AWAITING_RESULT\\\"\\n );\\n require(!hasDkgTimedOut(self), \\\"DKG timeout already passed\\\");\\n\\n SortitionPool sortitionPool = self.sortitionPool;\\n\\n // Submitter must be an operator in the sortition pool.\\n // Declared submitter's member index in the DKG result needs to match\\n // the address calling this function.\\n require(\\n sortitionPool.isOperatorInPool(msg.sender),\\n \\\"Submitter not in the sortition pool\\\"\\n );\\n require(\\n sortitionPool.getIDOperator(\\n result.members[result.submitterMemberIndex - 1]\\n ) == msg.sender,\\n \\\"Unexpected submitter index\\\"\\n );\\n\\n self.submittedResultHash = keccak256(abi.encode(result));\\n self.submittedResultBlock = block.number;\\n\\n emit DkgResultSubmitted(self.submittedResultHash, self.seed, result);\\n }\\n\\n /// @notice Checks if DKG timed out. The DKG timeout period includes time required\\n /// for off-chain protocol execution and time for the result publication.\\n /// After this time a result cannot be submitted and DKG can be notified\\n /// about the timeout. DKG period is adjusted by result submission\\n /// offset that include blocks that were mined while invalid result\\n /// has been registered until it got challenged.\\n /// @return True if DKG timed out, false otherwise.\\n function hasDkgTimedOut(Data storage self) internal view returns (bool) {\\n return\\n currentState(self) == State.AWAITING_RESULT &&\\n block.number >\\n (self.startBlock +\\n offchainDkgTime +\\n self.resultSubmissionStartBlockOffset +\\n self.parameters.resultSubmissionTimeout);\\n }\\n\\n /// @notice Notifies about DKG timeout.\\n function notifyTimeout(Data storage self) internal {\\n require(hasDkgTimedOut(self), \\\"DKG has not timed out\\\");\\n\\n emit DkgTimedOut();\\n\\n complete(self);\\n }\\n\\n /// @notice Notifies about the seed was not delivered and restores the\\n /// initial DKG state (IDLE).\\n function notifySeedTimedOut(Data storage self) internal {\\n require(\\n currentState(self) == State.AWAITING_SEED,\\n \\\"Current state is not AWAITING_SEED\\\"\\n );\\n\\n emit DkgSeedTimedOut();\\n\\n complete(self);\\n }\\n\\n /// @notice Approves DKG result. Can be called when the challenge period for\\n /// the submitted result is finished. Considers the submitted result\\n /// as valid. For the first `submitterPrecedencePeriodLength`\\n /// blocks after the end of the challenge period can be called only\\n /// by the DKG result submitter. After that time, can be called by\\n /// anyone.\\n /// @dev Can be called after a challenge period for the submitted result.\\n /// @param result Result to approve. Must match the submitted result stored\\n /// during `submitResult`.\\n /// @return misbehavedMembers Identifiers of members who misbehaved during DKG.\\n function approveResult(Data storage self, Result calldata result)\\n external\\n returns (uint32[] memory misbehavedMembers)\\n {\\n require(\\n currentState(self) == State.CHALLENGE,\\n \\\"Current state is not CHALLENGE\\\"\\n );\\n\\n uint256 challengePeriodEnd = self.submittedResultBlock +\\n self.parameters.resultChallengePeriodLength;\\n\\n require(\\n block.number > challengePeriodEnd,\\n \\\"Challenge period has not passed yet\\\"\\n );\\n\\n require(\\n keccak256(abi.encode(result)) == self.submittedResultHash,\\n \\\"Result under approval is different than the submitted one\\\"\\n );\\n\\n // Extract submitter member address. Submitter member index is in\\n // range [1, groupSize] so we need to -1 when fetching identifier from members\\n // array.\\n address submitterMember = self.sortitionPool.getIDOperator(\\n result.members[result.submitterMemberIndex - 1]\\n );\\n\\n require(\\n msg.sender == submitterMember ||\\n block.number >\\n challengePeriodEnd +\\n self.parameters.submitterPrecedencePeriodLength,\\n \\\"Only the DKG result submitter can approve the result at this moment\\\"\\n );\\n\\n // Extract misbehaved members identifiers. Misbehaved members indices\\n // are in range [1, groupSize], so we need to -1 when fetching identifiers from\\n // members array.\\n misbehavedMembers = new uint32[](\\n result.misbehavedMembersIndices.length\\n );\\n for (uint256 i = 0; i < result.misbehavedMembersIndices.length; i++) {\\n misbehavedMembers[i] = result.members[\\n result.misbehavedMembersIndices[i] - 1\\n ];\\n }\\n\\n emit DkgResultApproved(self.submittedResultHash, msg.sender);\\n\\n return misbehavedMembers;\\n }\\n\\n /// @notice Challenges DKG result. If the submitted result is proved to be\\n /// invalid it reverts the DKG back to the result submission phase.\\n /// @dev Can be called during a challenge period for the submitted result.\\n /// @param result Result to challenge. Must match the submitted result\\n /// stored during `submitResult`.\\n /// @return maliciousResultHash Hash of the malicious result.\\n /// @return maliciousSubmitter Identifier of the malicious submitter.\\n function challengeResult(Data storage self, Result calldata result)\\n external\\n returns (bytes32 maliciousResultHash, uint32 maliciousSubmitter)\\n {\\n require(\\n currentState(self) == State.CHALLENGE,\\n \\\"Current state is not CHALLENGE\\\"\\n );\\n\\n require(\\n block.number <=\\n self.submittedResultBlock +\\n self.parameters.resultChallengePeriodLength,\\n \\\"Challenge period has already passed\\\"\\n );\\n\\n require(\\n keccak256(abi.encode(result)) == self.submittedResultHash,\\n \\\"Result under challenge is different than the submitted one\\\"\\n );\\n\\n // https://github.com/crytic/slither/issues/982\\n // slither-disable-next-line unused-return\\n try\\n self.dkgValidator.validate(result, self.seed, self.startBlock)\\n returns (\\n // slither-disable-next-line uninitialized-local,variable-scope\\n bool isValid,\\n // slither-disable-next-line uninitialized-local,variable-scope\\n string memory errorMsg\\n ) {\\n if (isValid) {\\n revert(\\\"unjustified challenge\\\");\\n }\\n\\n emit DkgResultChallenged(\\n self.submittedResultHash,\\n msg.sender,\\n errorMsg\\n );\\n } catch {\\n // if the validation reverted we consider the DKG result as invalid\\n emit DkgResultChallenged(\\n self.submittedResultHash,\\n msg.sender,\\n \\\"validation reverted\\\"\\n );\\n }\\n\\n // Consider result hash as malicious.\\n maliciousResultHash = self.submittedResultHash;\\n maliciousSubmitter = result.members[result.submitterMemberIndex - 1];\\n\\n // Adjust DKG result submission block start, so submission stage starts\\n // from the beginning.\\n self.resultSubmissionStartBlockOffset =\\n block.number -\\n self.startBlock -\\n offchainDkgTime;\\n\\n submittedResultCleanup(self);\\n\\n return (maliciousResultHash, maliciousSubmitter);\\n }\\n\\n /// @notice Due to EIP150, 1/64 of the gas is not forwarded to the call, and\\n /// will be kept to execute the remaining operations in the function\\n /// after the call inside the try-catch.\\n ///\\n /// To ensure there is no way for the caller to manipulate gas limit\\n /// in such a way that the call inside try-catch fails with out-of-gas\\n /// and the rest of the function is executed with the remaining\\n /// 1/64 of gas, we require an extra gas amount to be left at the\\n /// end of the call to the function challenging DKG result and\\n /// wrapping the call to BeaconDkgValidator and TokenStaking\\n /// contracts inside a try-catch.\\n function requireChallengeExtraGas(Data storage self) internal view {\\n require(\\n gasleft() >= self.parameters.resultChallengeExtraGas,\\n \\\"Not enough extra gas left\\\"\\n );\\n }\\n\\n /// @notice Updates DKG-related parameters\\n /// @param _resultChallengePeriodLength New value of the result challenge\\n /// period length. It is the number of blocks for which a DKG result\\n /// can be challenged.\\n /// @param _resultChallengeExtraGas New value of the result challenge extra\\n /// gas. It is the extra gas required to be left at the end of the\\n /// challenge DKG result transaction.\\n /// @param _resultSubmissionTimeout New value of the result submission\\n /// timeout in seconds. It is a timeout for a group to provide a DKG\\n /// result.\\n /// @param _submitterPrecedencePeriodLength New value of the submitter\\n /// precedence period length in blocks. It is the time during which\\n /// only the original DKG result submitter can approve it.\\n function setParameters(\\n Data storage self,\\n uint256 _resultChallengePeriodLength,\\n uint256 _resultChallengeExtraGas,\\n uint256 _resultSubmissionTimeout,\\n uint256 _submitterPrecedencePeriodLength\\n ) internal {\\n require(currentState(self) == State.IDLE, \\\"Current state is not IDLE\\\");\\n\\n require(\\n _resultChallengePeriodLength > 0,\\n \\\"Result challenge period length should be greater than zero\\\"\\n );\\n require(\\n _resultSubmissionTimeout > 0,\\n \\\"Result submission timeout should be greater than zero\\\"\\n );\\n require(\\n _submitterPrecedencePeriodLength < _resultSubmissionTimeout,\\n \\\"Submitter precedence period length should be less than the result submission timeout\\\"\\n );\\n\\n self\\n .parameters\\n .resultChallengePeriodLength = _resultChallengePeriodLength;\\n self.parameters.resultChallengeExtraGas = _resultChallengeExtraGas;\\n self.parameters.resultSubmissionTimeout = _resultSubmissionTimeout;\\n self\\n .parameters\\n .submitterPrecedencePeriodLength = _submitterPrecedencePeriodLength;\\n }\\n\\n /// @notice Completes DKG by cleaning up state.\\n /// @dev Should be called after DKG times out or a result is approved.\\n function complete(Data storage self) internal {\\n delete self.startBlock;\\n delete self.seed;\\n delete self.resultSubmissionStartBlockOffset;\\n submittedResultCleanup(self);\\n self.sortitionPool.unlock();\\n }\\n\\n /// @notice Cleans up submitted result state either after DKG completion\\n /// (as part of `complete` method) or after justified challenge.\\n function submittedResultCleanup(Data storage self) private {\\n delete self.submittedResultHash;\\n delete self.submittedResultBlock;\\n }\\n}\\n\",\"keccak256\":\"0x86bea35ab775ec969bc91208305f6f85aa9dd49bb74f8e57e7d453797e8ad98e\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BeaconInactivity.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./BytesLib.sol\\\";\\nimport \\\"./Groups.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\n\\nlibrary BeaconInactivity {\\n using BytesLib for bytes;\\n using ECDSA for bytes32;\\n\\n struct Claim {\\n // ID of the group raising the inactivity claim.\\n uint64 groupId;\\n // Indices of members accused of being inactive. Indices must be in\\n // range [1, groupMembers.length], unique, and sorted in ascending order.\\n uint256[] inactiveMembersIndices;\\n // Concatenation of signatures from members supporting the claim.\\n // The message to be signed by each member is keccak256 hash of the\\n // concatenation of the chain ID, inactivity claim nonce for the given\\n // group, group public key, and inactive members indices. The calculated\\n // hash should be prefixed with `\\\\x19Ethereum signed message:\\\\n` before\\n // signing, so the message to sign is:\\n // `\\\\x19Ethereum signed message:\\\\n${keccak256(\\n // chainID | nonce | groupPubKey | inactiveMembersIndices\\n // )}`\\n bytes signatures;\\n // Indices of members corresponding to each signature. Indices must be\\n // in range [1, groupMembers.length], unique, and sorted in ascending\\n // order.\\n uint256[] signingMembersIndices;\\n }\\n\\n /// @notice The minimum number of group members needed to interact according\\n /// to the protocol to produce a valid inactivity claim.\\n uint256 public constant groupThreshold = 33;\\n\\n /// @notice Size in bytes of a single signature produced by member\\n /// supporting the inactivity claim.\\n uint256 public constant signatureByteSize = 65;\\n\\n /// @notice Verifies the inactivity claim according to the rules defined in\\n /// `Claim` struct documentation. Reverts if verification fails.\\n /// @dev Group members hash is validated upstream in\\n /// RandomBeacon.notifyOperatorInactivity()\\n /// @param sortitionPool Sortition pool reference\\n /// @param claim Inactivity claim\\n /// @param groupPubKey Public key of the group raising the claim\\n /// @param nonce Current nonce for group used in the claim\\n /// @param groupMembers Identifiers of group members\\n /// @return inactiveMembers Identifiers of members who are inactive\\n function verifyClaim(\\n SortitionPool sortitionPool,\\n Claim calldata claim,\\n bytes memory groupPubKey,\\n uint256 nonce,\\n uint32[] calldata groupMembers\\n ) external view returns (uint32[] memory inactiveMembers) {\\n // Validate inactive members indices. Maximum indices count is equal to\\n // the group size and is not limited deliberately to leave a theoretical\\n // possibility to accuse more members than `groupSize - groupThreshold`.\\n validateMembersIndices(\\n claim.inactiveMembersIndices,\\n groupMembers.length\\n );\\n\\n // Validate signatures array is properly formed and number of\\n // signatures and signers is correct.\\n uint256 signaturesCount = claim.signatures.length / signatureByteSize;\\n require(claim.signatures.length != 0, \\\"No signatures provided\\\");\\n require(\\n claim.signatures.length % signatureByteSize == 0,\\n \\\"Malformed signatures array\\\"\\n );\\n require(\\n signaturesCount == claim.signingMembersIndices.length,\\n \\\"Unexpected signatures count\\\"\\n );\\n require(signaturesCount >= groupThreshold, \\\"Too few signatures\\\");\\n require(signaturesCount <= groupMembers.length, \\\"Too many signatures\\\");\\n\\n // Validate signing members indices. Note that `signingMembersIndices`\\n // were already partially validated during `signatures` parameter\\n // validation.\\n validateMembersIndices(\\n claim.signingMembersIndices,\\n groupMembers.length\\n );\\n\\n // Usage of group public key and not group ID is important because it\\n // provides uniqueness of signed messages and prevent against reusing\\n // them in future in case some other application has a group with the\\n // same ID and subset of members.\\n bytes32 signedMessageHash = keccak256(\\n abi.encode(\\n block.chainid,\\n nonce,\\n groupPubKey,\\n claim.inactiveMembersIndices\\n )\\n ).toEthSignedMessageHash();\\n\\n address[] memory groupMembersAddresses = sortitionPool.getIDOperators(\\n groupMembers\\n );\\n\\n // Verify each signature.\\n bytes memory checkedSignature;\\n bool senderSignatureExists = false;\\n for (uint256 i = 0; i < signaturesCount; i++) {\\n uint256 memberIndex = claim.signingMembersIndices[i];\\n checkedSignature = claim.signatures.slice(\\n signatureByteSize * i,\\n signatureByteSize\\n );\\n address recoveredAddress = signedMessageHash.recover(\\n checkedSignature\\n );\\n\\n require(\\n groupMembersAddresses[memberIndex - 1] == recoveredAddress,\\n \\\"Invalid signature\\\"\\n );\\n\\n if (!senderSignatureExists && msg.sender == recoveredAddress) {\\n senderSignatureExists = true;\\n }\\n }\\n\\n require(senderSignatureExists, \\\"Sender must be claim signer\\\");\\n\\n inactiveMembers = new uint32[](claim.inactiveMembersIndices.length);\\n for (uint256 i = 0; i < claim.inactiveMembersIndices.length; i++) {\\n uint256 memberIndex = claim.inactiveMembersIndices[i];\\n inactiveMembers[i] = groupMembers[memberIndex - 1];\\n }\\n\\n return inactiveMembers;\\n }\\n\\n /// @notice Validates members indices array. Array is considered valid\\n /// if its size and each single index are in [1, groupSize] range,\\n /// indexes are unique, and sorted in an ascending order.\\n /// Reverts if validation fails.\\n /// @param indices Array to validate\\n /// @param groupSize Group size used as reference\\n function validateMembersIndices(\\n uint256[] calldata indices,\\n uint256 groupSize\\n ) internal pure {\\n require(\\n indices.length > 0 && indices.length <= groupSize,\\n \\\"Corrupted members indices\\\"\\n );\\n\\n // Check if first and last indices are in range [1, groupSize].\\n // This check combined with the loop below makes sure every single\\n // index is in the correct range.\\n require(\\n indices[0] > 0 && indices[indices.length - 1] <= groupSize,\\n \\\"Corrupted members indices\\\"\\n );\\n\\n for (uint256 i = 0; i < indices.length - 1; i++) {\\n // Check whether given index is smaller than the next one. This\\n // way we are sure indexes are ordered in the ascending order\\n // and there are no duplicates.\\n require(indices[i] < indices[i + 1], \\\"Corrupted members indices\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x8dffb20eb4ffd2e388080c5fbcb648e33480aca3dab4be2254cf30c5e72413bf\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BytesLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\n/*\\nVersion pulled from keep-core v1:\\nhttps://github.com/keep-network/keep-core/blob/f297202db00c027978ad8e7103a356503de5773c/solidity-v1/contracts/utils/BytesLib.sol\\n\\nTo compile it with solidity 0.8 `_preBytes_slot` was replaced with `_preBytes.slot`.\\n*/\\n\\n/*\\nhttps://github.com/GNSPS/solidity-bytes-utils/\\nThis is free and unencumbered software released into the public domain.\\nAnyone is free to copy, modify, publish, use, compile, sell, or\\ndistribute this software, either in source code form or as a compiled\\nbinary, for any purpose, commercial or non-commercial, and by any\\nmeans.\\nIn jurisdictions that recognize copyright laws, the author or authors\\nof this software dedicate any and all copyright interest in the\\nsoftware to the public domain. We make this dedication for the benefit\\nof the public at large and to the detriment of our heirs and\\nsuccessors. We intend this dedication to be an overt act of\\nrelinquishment in perpetuity of all present and future rights to this\\nsoftware under copyright law.\\nTHE SOFTWARE IS PROVIDED \\\"AS IS\\\", WITHOUT WARRANTY OF ANY KIND,\\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\\nIN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\\nOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\\nOTHER DEALINGS IN THE SOFTWARE.\\nFor more information, please refer to \\n*/\\n\\n/** @title BytesLib **/\\n/** @author https://github.com/GNSPS **/\\n\\nlibrary BytesLib {\\n function concatStorage(bytes storage _preBytes, bytes memory _postBytes)\\n internal\\n {\\n assembly {\\n // Read the first 32 bytes of _preBytes storage, which is the length\\n // of the array. (We don't need to use the offset into the slot\\n // because arrays use the entire slot.)\\n let fslot := sload(_preBytes.slot)\\n // Arrays of 31 bytes or less have an even value in their slot,\\n // while longer arrays have an odd value. The actual length is\\n // the slot divided by two for odd values, and the lowest order\\n // byte divided by two for even values.\\n // If the slot is even, bitwise and the slot with 255 and divide by\\n // two to get the length. If the slot is odd, bitwise and the slot\\n // with -1 and divide by two.\\n let slength := div(\\n and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)),\\n 2\\n )\\n let mlength := mload(_postBytes)\\n let newlength := add(slength, mlength)\\n // slength can contain both the length and contents of the array\\n // if length < 32 bytes so let's prepare for that\\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\\n switch add(lt(slength, 32), lt(newlength, 32))\\n case 2 {\\n // Since the new array still fits in the slot, we just need to\\n // update the contents of the slot.\\n // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length\\n sstore(\\n _preBytes.slot,\\n // all the modifications to the slot are inside this\\n // next block\\n add(\\n // we can just add to the slot contents because the\\n // bytes we want to change are the LSBs\\n fslot,\\n add(\\n mul(\\n div(\\n // load the bytes from memory\\n mload(add(_postBytes, 0x20)),\\n // zero all bytes to the right\\n exp(0x100, sub(32, mlength))\\n ),\\n // and now shift left the number of bytes to\\n // leave space for the length in the slot\\n exp(0x100, sub(32, newlength))\\n ),\\n // increase length by the double of the memory\\n // bytes length\\n mul(mlength, 2)\\n )\\n )\\n )\\n }\\n case 1 {\\n // The stored value fits in the slot, but the combined value\\n // will exceed it.\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\\n\\n // save new length\\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\\n\\n // The contents of the _postBytes array start 32 bytes into\\n // the structure. Our first read should obtain the `submod`\\n // bytes that can fit into the unused space in the last word\\n // of the stored array. To get this, we read 32 bytes starting\\n // from `submod`, so the data we read overlaps with the array\\n // contents by `submod` bytes. Masking the lowest-order\\n // `submod` bytes allows us to add that value directly to the\\n // stored value.\\n\\n let submod := sub(32, slength)\\n let mc := add(_postBytes, submod)\\n let end := add(_postBytes, mlength)\\n let mask := sub(exp(0x100, submod), 1)\\n\\n sstore(\\n sc,\\n add(\\n and(\\n fslot,\\n 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00\\n ),\\n and(mload(mc), mask)\\n )\\n )\\n\\n for {\\n mc := add(mc, 0x20)\\n sc := add(sc, 1)\\n } lt(mc, end) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n sstore(sc, mload(mc))\\n }\\n\\n mask := exp(0x100, sub(mc, end))\\n\\n sstore(sc, mul(div(mload(mc), mask), mask))\\n }\\n default {\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n // Start copying to the last used word of the stored array.\\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\\n\\n // save new length\\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\\n\\n // Copy over the first `submod` bytes of the new data as in\\n // case 1 above.\\n let slengthmod := mod(slength, 32)\\n let submod := sub(32, slengthmod)\\n let mc := add(_postBytes, submod)\\n let end := add(_postBytes, mlength)\\n let mask := sub(exp(0x100, submod), 1)\\n\\n sstore(sc, add(sload(sc), and(mload(mc), mask)))\\n\\n for {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } lt(mc, end) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n sstore(sc, mload(mc))\\n }\\n\\n mask := exp(0x100, sub(mc, end))\\n\\n sstore(sc, mul(div(mload(mc), mask), mask))\\n }\\n }\\n }\\n\\n function equalStorage(bytes storage _preBytes, bytes memory _postBytes)\\n internal\\n view\\n returns (bool)\\n {\\n bool success = true;\\n\\n assembly {\\n // we know _preBytes_offset is 0\\n let fslot := sload(_preBytes.slot)\\n // Decode the length of the stored array like in concatStorage().\\n let slength := div(\\n and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)),\\n 2\\n )\\n let mlength := mload(_postBytes)\\n\\n // if lengths don't match the arrays are not equal\\n switch eq(slength, mlength)\\n case 1 {\\n // slength can contain both the length and contents of the array\\n // if length < 32 bytes so let's prepare for that\\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\\n if iszero(iszero(slength)) {\\n switch lt(slength, 32)\\n case 1 {\\n // blank the last byte which is the length\\n fslot := mul(div(fslot, 0x100), 0x100)\\n\\n if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {\\n // unsuccess:\\n success := 0\\n }\\n }\\n default {\\n // cb is a circuit breaker in the for loop since there's\\n // no said feature for inline assembly loops\\n // cb = 1 - don't breaker\\n // cb = 0 - break\\n let cb := 1\\n\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n let sc := keccak256(0x0, 0x20)\\n\\n let mc := add(_postBytes, 0x20)\\n let end := add(mc, mlength)\\n\\n // the next line is the loop condition:\\n // while(uint(mc < end) + cb == 2)\\n for {\\n\\n } eq(add(lt(mc, end), cb), 2) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n if iszero(eq(sload(sc), mload(mc))) {\\n // unsuccess:\\n success := 0\\n cb := 0\\n }\\n }\\n }\\n }\\n }\\n default {\\n // unsuccess:\\n success := 0\\n }\\n }\\n\\n return success;\\n }\\n\\n function concat(bytes memory _preBytes, bytes memory _postBytes)\\n internal\\n pure\\n returns (bytes memory)\\n {\\n bytes memory tempBytes;\\n\\n assembly {\\n // Get a location of some free memory and store it in tempBytes as\\n // Solidity does for memory variables.\\n tempBytes := mload(0x40)\\n\\n // Store the length of the first bytes array at the beginning of\\n // the memory for tempBytes.\\n let length := mload(_preBytes)\\n mstore(tempBytes, length)\\n\\n // Maintain a memory counter for the current write location in the\\n // temp bytes array by adding the 32 bytes for the array length to\\n // the starting location.\\n let mc := add(tempBytes, 0x20)\\n // Stop copying when the memory counter reaches the length of the\\n // first bytes array.\\n let end := add(mc, length)\\n\\n for {\\n // Initialize a copy counter to the start of the _preBytes data,\\n // 32 bytes into its memory.\\n let cc := add(_preBytes, 0x20)\\n } lt(mc, end) {\\n // Increase both counters by 32 bytes each iteration.\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n // Write the _preBytes data into the tempBytes memory 32 bytes\\n // at a time.\\n mstore(mc, mload(cc))\\n }\\n\\n // Add the length of _postBytes to the current length of tempBytes\\n // and store it as the new length in the first 32 bytes of the\\n // tempBytes memory.\\n length := mload(_postBytes)\\n mstore(tempBytes, add(length, mload(tempBytes)))\\n\\n // Move the memory counter back from a multiple of 0x20 to the\\n // actual end of the _preBytes data.\\n mc := end\\n // Stop copying when the memory counter reaches the new combined\\n // length of the arrays.\\n end := add(mc, length)\\n\\n for {\\n let cc := add(_postBytes, 0x20)\\n } lt(mc, end) {\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n mstore(mc, mload(cc))\\n }\\n\\n // Update the free-memory pointer by padding our last write location\\n // to 32 bytes: add 31 bytes to the end of tempBytes to move to the\\n // next 32 byte block, then round down to the nearest multiple of\\n // 32. If the sum of the length of the two arrays is zero then add\\n // one before rounding down to leave a blank 32 bytes (the length block with 0).\\n mstore(\\n 0x40,\\n and(\\n add(add(end, iszero(add(length, mload(_preBytes)))), 31),\\n not(31) // Round down to the nearest 32 bytes.\\n )\\n )\\n }\\n\\n return tempBytes;\\n }\\n\\n function slice(\\n bytes memory _bytes,\\n uint256 _start,\\n uint256 _length\\n ) internal pure returns (bytes memory res) {\\n uint256 _end = _start + _length;\\n require(_end > _start && _bytes.length >= _end, \\\"Slice out of bounds\\\");\\n\\n assembly {\\n // Alloc bytes array with additional 32 bytes afterspace and assign it's size\\n res := mload(0x40)\\n mstore(0x40, add(add(res, 64), _length))\\n mstore(res, _length)\\n\\n // Compute distance between source and destination pointers\\n let diff := sub(res, add(_bytes, _start))\\n\\n for {\\n let src := add(add(_bytes, 32), _start)\\n let end := add(src, _length)\\n } lt(src, end) {\\n src := add(src, 32)\\n } {\\n mstore(add(src, diff), mload(src))\\n }\\n }\\n }\\n\\n function toAddress(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (address)\\n {\\n uint256 _totalLen = _start + 20;\\n require(\\n _totalLen > _start && _bytes.length >= _totalLen,\\n \\\"Address conversion out of bounds.\\\"\\n );\\n address tempAddress;\\n\\n assembly {\\n tempAddress := div(\\n mload(add(add(_bytes, 0x20), _start)),\\n 0x1000000000000000000000000\\n )\\n }\\n\\n return tempAddress;\\n }\\n\\n function toUint8(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (uint8)\\n {\\n require(\\n _bytes.length >= (_start + 1),\\n \\\"Uint8 conversion out of bounds.\\\"\\n );\\n uint8 tempUint;\\n\\n assembly {\\n tempUint := mload(add(add(_bytes, 0x1), _start))\\n }\\n\\n return tempUint;\\n }\\n\\n function toUint(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (uint256)\\n {\\n uint256 _totalLen = _start + 32;\\n require(\\n _totalLen > _start && _bytes.length >= _totalLen,\\n \\\"Uint conversion out of bounds.\\\"\\n );\\n uint256 tempUint;\\n\\n assembly {\\n tempUint := mload(add(add(_bytes, 0x20), _start))\\n }\\n\\n return tempUint;\\n }\\n\\n function equal(bytes memory _preBytes, bytes memory _postBytes)\\n internal\\n pure\\n returns (bool)\\n {\\n bool success = true;\\n\\n assembly {\\n let length := mload(_preBytes)\\n\\n // if lengths don't match the arrays are not equal\\n switch eq(length, mload(_postBytes))\\n case 1 {\\n // cb is a circuit breaker in the for loop since there's\\n // no said feature for inline assembly loops\\n // cb = 1 - don't breaker\\n // cb = 0 - break\\n let cb := 1\\n\\n let mc := add(_preBytes, 0x20)\\n let end := add(mc, length)\\n\\n for {\\n let cc := add(_postBytes, 0x20)\\n // the next line is the loop condition:\\n // while(uint(mc < end) + cb == 2)\\n } eq(add(lt(mc, end), cb), 2) {\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n // if any of these checks fails then arrays are not equal\\n if iszero(eq(mload(mc), mload(cc))) {\\n // unsuccess:\\n success := 0\\n cb := 0\\n }\\n }\\n }\\n default {\\n // unsuccess:\\n success := 0\\n }\\n }\\n\\n return success;\\n }\\n\\n function toBytes32(bytes memory _source)\\n internal\\n pure\\n returns (bytes32 result)\\n {\\n if (_source.length == 0) {\\n return 0x0;\\n }\\n\\n assembly {\\n result := mload(add(_source, 32))\\n }\\n }\\n\\n function keccak256Slice(\\n bytes memory _bytes,\\n uint256 _start,\\n uint256 _length\\n ) internal pure returns (bytes32 result) {\\n uint256 _end = _start + _length;\\n require(_end > _start && _bytes.length >= _end, \\\"Slice out of bounds\\\");\\n\\n assembly {\\n result := keccak256(add(add(_bytes, 32), _start), _length)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3b76e2fe36eb777440250dcf2ea7a689375e8af22f3cc33521095ff6954becdb\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/Callback.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../api/IRandomBeaconConsumer.sol\\\";\\n\\n/// @title Callback library\\n/// @dev Library for handling calls to random beacon consumer.\\nlibrary Callback {\\n struct Data {\\n IRandomBeaconConsumer callbackContract;\\n }\\n\\n event CallbackFailed(uint256 entry, uint256 entrySubmittedBlock);\\n\\n /// @notice Sets callback contract.\\n /// @param callbackContract Callback contract.\\n function setCallbackContract(\\n Data storage self,\\n IRandomBeaconConsumer callbackContract\\n ) internal {\\n self.callbackContract = callbackContract;\\n }\\n\\n /// @notice Executes consumer specified callback for the relay entry request.\\n /// @param entry The generated random number.\\n /// @param callbackGasLimit Callback gas limit.\\n function executeCallback(\\n Data storage self,\\n uint256 entry,\\n uint256 callbackGasLimit\\n ) internal {\\n if (address(self.callbackContract) != address(0)) {\\n try\\n self.callbackContract.__beaconCallback{gas: callbackGasLimit}(\\n entry,\\n block.number\\n )\\n {} catch {\\n // slither-disable-next-line reentrancy-events\\n emit CallbackFailed(entry, block.number);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x258d635d74d8906c73d1c2d0929f033c7e548cdaf9c9a71a7e82b4ab70e5ad29\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/Groups.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\n/// @notice This library is used as a registry of created groups.\\n/// @dev This library should be used along with DKG library that ensures linear\\n/// groups creation (only one group creation happens at a time). A candidate\\n/// group has to be popped or activated before adding a new candidate group.\\nlibrary Groups {\\n struct Group {\\n bytes groupPubKey;\\n uint256 registrationBlockNumber;\\n // Keccak256 hash of group members identifiers array. Group members do not\\n // include operators selected by the sortition pool that misbehaved during DKG.\\n // See how `misbehavedMembersIndices` are used in `hashGroupMembers` function.\\n bytes32 membersHash;\\n // When selected group does not create a relay entry on-time it should\\n // be marked as terminated.\\n bool terminated;\\n }\\n\\n struct Data {\\n // Mapping of keccak256 hashes of group public keys to groups details.\\n mapping(bytes32 => Group) groupsData;\\n // Holds keccak256 hashes of group public keys in the order of registration.\\n bytes32[] groupsRegistry;\\n // Group ids that were active but failed creating a relay entry. When an\\n // active-terminated group qualifies to become 'expired', then it will\\n // be removed from this array.\\n uint64[] activeTerminatedGroups;\\n // Points to the first active group, it is also the expired groups counter.\\n uint64 expiredGroupOffset;\\n // Group lifetime in blocks. When a group reached its lifetime, it\\n // is no longer selected for new relay requests but may still be\\n // responsible for submitting relay entry if relay request assigned\\n // to that group is still pending.\\n uint256 groupLifetime;\\n }\\n\\n event GroupRegistered(uint64 indexed groupId, bytes indexed groupPubKey);\\n\\n /// @notice Performs preliminary validation of a new group public key.\\n /// The group public key must be unique and have 128 bytes in length.\\n /// If the validation fails, the function reverts. This function\\n /// must be called first for a public key of a group added with\\n /// `addGroup` function.\\n /// @param groupPubKey Candidate group public key\\n function validatePublicKey(Data storage self, bytes calldata groupPubKey)\\n internal\\n view\\n {\\n require(groupPubKey.length == 128, \\\"Invalid length of the public key\\\");\\n\\n bytes32 groupPubKeyHash = keccak256(groupPubKey);\\n\\n require(\\n self.groupsData[groupPubKeyHash].registrationBlockNumber == 0,\\n \\\"Group with this public key was already registered\\\"\\n );\\n }\\n\\n /// @notice Adds a new candidate group. The group is stored with group public\\n /// key and group members, but is not yet activated.\\n /// @dev The group members list is stored with all misbehaved members filtered out.\\n /// The code calling this function should ensure that the number of\\n /// candidate (not activated) groups is never more than one.\\n /// @param groupPubKey Generated candidate group public key\\n /// @param membersHash Keccak256 hash of members that actively took part in DKG.\\n function addGroup(\\n Data storage self,\\n bytes calldata groupPubKey,\\n bytes32 membersHash\\n ) internal {\\n bytes32 groupPubKeyHash = keccak256(groupPubKey);\\n\\n // We use group from storage that is assumed to be a struct set to the\\n // default values. We need to remember to overwrite fields in case a\\n // candidate group was already registered before and popped.\\n Group storage group = self.groupsData[groupPubKeyHash];\\n group.groupPubKey = groupPubKey;\\n group.membersHash = membersHash;\\n group.registrationBlockNumber = block.number;\\n\\n self.groupsRegistry.push(groupPubKeyHash);\\n\\n emit GroupRegistered(\\n uint64(self.groupsRegistry.length - 1),\\n groupPubKey\\n );\\n }\\n\\n /// @notice Goes through groups starting from the oldest one that is still\\n /// active and checks if it hasn't expired. If so, updates the information\\n /// about expired groups so that all expired groups are marked as such.\\n function expireOldGroups(Data storage self) internal {\\n // Move expiredGroupOffset as long as there are some groups that should\\n // be marked as expired. It is possible that expired group offset will\\n // move out of the groups array by one position. It means that all groups\\n // are expired (it points to the first active group) and that place in\\n // groups array - currently empty - will be possibly filled later by\\n // a new group.\\n while (\\n self.expiredGroupOffset < self.groupsRegistry.length &&\\n groupLifetimeOf(\\n self,\\n self.groupsRegistry[self.expiredGroupOffset]\\n ) <\\n block.number\\n ) {\\n self.expiredGroupOffset++;\\n }\\n\\n // Go through all activeTerminatedGroups and if some of the terminated\\n // groups are expired, remove them from activeTerminatedGroups collection\\n // and rearrange the array to preserve the original order.\\n // This is needed because we evaluate the shift of selected group index\\n // based on how many non-expired groups have been terminated. Hence it is\\n // important that a number of terminated groups matches the length of\\n // activeTerminatedGroups[].\\n uint256 i = 0;\\n while (i < self.activeTerminatedGroups.length) {\\n if (self.expiredGroupOffset > self.activeTerminatedGroups[i]) {\\n // When 'i'th group qualifies for expiration, we need to remove\\n // it from the activeTerminatedGroups array manually by rearranging\\n // the order starting from 'i'th group.\\n for (\\n uint256 j = i;\\n j < self.activeTerminatedGroups.length - 1;\\n j++\\n ) {\\n self.activeTerminatedGroups[j] = self\\n .activeTerminatedGroups[j + 1];\\n }\\n // Resizing the array length by 1. The last element was copied\\n // over in the loop above to an index \\\"second to last\\\". This is\\n // why we can safely remove it from here.\\n self.activeTerminatedGroups.pop();\\n } else {\\n i++;\\n }\\n }\\n }\\n\\n /// @notice Terminates group with the provided index. Reverts if the group\\n /// is already terminated.\\n /// @param groupId Index in the groupRegistry array.\\n function terminateGroup(Data storage self, uint64 groupId) internal {\\n require(\\n !isGroupTerminated(self, groupId),\\n \\\"Group has been already terminated\\\"\\n );\\n self.groupsData[self.groupsRegistry[groupId]].terminated = true;\\n // Expanding array for a new terminated group that is added below during\\n // sortition in ascending order.\\n self.activeTerminatedGroups.push();\\n\\n // Sorting activeTerminatedGroups by groupId in ascending order so a\\n // non-terminated group is properly selected.\\n uint256 i;\\n for (\\n i = self.activeTerminatedGroups.length - 1;\\n i > 0 && self.activeTerminatedGroups[i - 1] > groupId;\\n i--\\n ) {\\n self.activeTerminatedGroups[i] = self.activeTerminatedGroups[i - 1];\\n }\\n self.activeTerminatedGroups[i] = groupId;\\n }\\n\\n /// @notice Returns an index of a randomly selected active group. Terminated\\n /// and expired groups are not considered as active.\\n /// Before new group is selected, information about expired groups\\n /// is updated. At least one active group needs to be present for this\\n /// function to succeed.\\n /// @param seed Random number used as a group selection seed.\\n function selectGroup(Data storage self, uint256 seed)\\n internal\\n returns (uint64)\\n {\\n expireOldGroups(self);\\n\\n require(numberOfActiveGroups(self) > 0, \\\"No active groups\\\");\\n\\n uint64 selectedGroup = uint64(seed % numberOfActiveGroups(self));\\n uint64 result = shiftByTerminatedGroups(\\n self,\\n shiftByExpiredGroups(self, selectedGroup)\\n );\\n return result;\\n }\\n\\n /// @notice Setter for group lifetime.\\n /// @param lifetime Lifetime of a group in blocks.\\n function setGroupLifetime(Data storage self, uint256 lifetime) internal {\\n self.groupLifetime = lifetime;\\n }\\n\\n /// @notice Checks if group with the given index is terminated.\\n function isGroupTerminated(Data storage self, uint64 groupId)\\n internal\\n view\\n returns (bool)\\n {\\n return self.groupsData[self.groupsRegistry[groupId]].terminated;\\n }\\n\\n /// @notice Gets the cutoff time until which the given group is considered\\n /// to be active assuming it hasn't been terminated before.\\n function groupLifetimeOf(Data storage self, bytes32 groupPubKeyHash)\\n internal\\n view\\n returns (uint256)\\n {\\n return\\n self.groupsData[groupPubKeyHash].registrationBlockNumber +\\n self.groupLifetime;\\n }\\n\\n /// @notice Checks if group with the given index is active and non-terminated.\\n function isGroupActive(Data storage self, uint64 groupId)\\n internal\\n view\\n returns (bool)\\n {\\n return\\n groupLifetimeOf(self, self.groupsRegistry[groupId]) >=\\n block.number &&\\n !isGroupTerminated(self, groupId);\\n }\\n\\n function getGroup(Data storage self, uint64 groupId)\\n internal\\n view\\n returns (Group storage)\\n {\\n return self.groupsData[self.groupsRegistry[groupId]];\\n }\\n\\n function getGroup(Data storage self, bytes memory groupPubKey)\\n internal\\n view\\n returns (Group storage)\\n {\\n return self.groupsData[keccak256(groupPubKey)];\\n }\\n\\n /// @notice Gets the number of active groups. Expired and terminated\\n /// groups are not counted as active.\\n function numberOfActiveGroups(Data storage self)\\n internal\\n view\\n returns (uint64)\\n {\\n if (self.groupsRegistry.length == 0) {\\n return 0;\\n }\\n\\n uint256 activeGroups = self.groupsRegistry.length -\\n self.expiredGroupOffset -\\n self.activeTerminatedGroups.length;\\n\\n return uint64(activeGroups);\\n }\\n\\n /// @notice Evaluates the shift of a selected group index based on the number\\n /// of expired groups.\\n function shiftByExpiredGroups(Data storage self, uint64 selectedIndex)\\n internal\\n view\\n returns (uint64)\\n {\\n return self.expiredGroupOffset + selectedIndex;\\n }\\n\\n /// @notice Evaluates the shift of a selected group index based on the number\\n /// of non-expired but terminated groups.\\n function shiftByTerminatedGroups(Data storage self, uint64 selectedIndex)\\n internal\\n view\\n returns (uint64)\\n {\\n uint64 shiftedIndex = selectedIndex;\\n for (uint64 i = 0; i < self.activeTerminatedGroups.length; i++) {\\n if (self.activeTerminatedGroups[i] <= shiftedIndex) {\\n shiftedIndex++;\\n }\\n }\\n\\n return shiftedIndex;\\n }\\n}\\n\",\"keccak256\":\"0x27a3cee268e5afa5ee3a00089aa82faffff7c3882aa94919499de4ef55dcfb0c\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/ModUtils.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\nlibrary ModUtils {\\n /// @dev Wraps the modular exponent pre-compile introduced in Byzantium.\\n /// Returns base^exponent mod p.\\n function modExp(\\n uint256 base,\\n uint256 exponent,\\n uint256 p\\n ) internal view returns (uint256 o) {\\n assembly {\\n // Args for the precompile: [ \\n // ]\\n let output := mload(0x40)\\n let args := add(output, 0x20)\\n mstore(args, 0x20)\\n mstore(add(args, 0x20), 0x20)\\n mstore(add(args, 0x40), 0x20)\\n mstore(add(args, 0x60), base)\\n mstore(add(args, 0x80), exponent)\\n mstore(add(args, 0xa0), p)\\n\\n // 0x05 is the modular exponent contract address\\n if iszero(staticcall(not(0), 0x05, args, 0xc0, output, 0x20)) {\\n revert(0, 0)\\n }\\n o := mload(output)\\n }\\n }\\n\\n /// @dev Calculates and returns the square root of a mod p if such a square\\n /// root exists. The modulus p must be an odd prime. If a square root\\n /// does not exist, function returns 0.\\n function modSqrt(uint256 a, uint256 p) internal view returns (uint256) {\\n unchecked {\\n if (legendre(a, p) != 1) {\\n return 0;\\n }\\n\\n if (a == 0) {\\n return 0;\\n }\\n\\n if (p % 4 == 3) {\\n return modExp(a, (p + 1) / 4, p);\\n }\\n\\n uint256 s = p - 1;\\n uint256 e = 0;\\n\\n while (s % 2 == 0) {\\n s = s / 2;\\n e = e + 1;\\n }\\n\\n // Note the smaller int- finding n with Legendre symbol or -1\\n // should be quick\\n uint256 n = 2;\\n while (legendre(n, p) != -1) {\\n n = n + 1;\\n }\\n\\n uint256 x = modExp(a, (s + 1) / 2, p);\\n uint256 b = modExp(a, s, p);\\n uint256 g = modExp(n, s, p);\\n uint256 r = e;\\n uint256 gs = 0;\\n uint256 m = 0;\\n uint256 t = b;\\n\\n while (true) {\\n t = b;\\n m = 0;\\n\\n for (m = 0; m < r; m++) {\\n if (t == 1) {\\n break;\\n }\\n t = modExp(t, 2, p);\\n }\\n\\n if (m == 0) {\\n return x;\\n }\\n\\n gs = modExp(g, uint256(2)**(r - m - 1), p);\\n g = (gs * gs) % p;\\n x = (x * gs) % p;\\n b = (b * g) % p;\\n r = m;\\n }\\n }\\n }\\n\\n /// @dev Calculates the Legendre symbol of the given a mod p.\\n /// @return Returns 1 if a is a quadratic residue mod p, -1 if it is\\n /// a non-quadratic residue, and 0 if a is 0.\\n function legendre(uint256 a, uint256 p) internal view returns (int256) {\\n unchecked {\\n uint256 raised = modExp(a, (p - 1) / uint256(2), p);\\n\\n if (raised == 0 || raised == 1) {\\n return int256(raised);\\n } else if (raised == p - 1) {\\n return -1;\\n }\\n\\n require(false, \\\"Failed to calculate legendre.\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x57bb4ab4f257715c6daafa1a4e4bc6dd9edfe45afca797e5b8e98db577826505\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/Relay.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"./AltBn128.sol\\\";\\nimport \\\"./BLS.sol\\\";\\nimport \\\"./Groups.sol\\\";\\n\\nlibrary Relay {\\n using SafeERC20 for IERC20;\\n\\n struct Data {\\n // Total count of all requests.\\n uint64 requestCount;\\n // Data of current request.\\n // Request identifier.\\n uint64 currentRequestID;\\n // Identifier of group responsible for signing.\\n uint64 currentRequestGroupID;\\n // Request start block.\\n uint64 currentRequestStartBlock;\\n // Previous entry value.\\n AltBn128.G1Point previousEntry;\\n // Time in blocks during which a result is expected to be submitted.\\n uint32 relayEntrySoftTimeout;\\n // Hard timeout in blocks for a group to submit the relay entry.\\n uint32 relayEntryHardTimeout;\\n // Slashing amount for not submitting relay entry\\n uint96 relayEntrySubmissionFailureSlashingAmount;\\n }\\n\\n /// @notice Seed used as the first relay entry value.\\n /// It's a G1 point G * PI =\\n /// G * 31415926535897932384626433832795028841971693993751058209749445923078164062862\\n /// Where G is the generator of G1 abstract cyclic group.\\n bytes public constant relaySeed =\\n hex\\\"15c30f4b6cf6dbbcbdcc10fe22f54c8170aea44e198139b776d512d8f027319a1b9e8bfaf1383978231ce98e42bafc8129f473fc993cf60ce327f7d223460663\\\";\\n\\n event RelayEntryRequested(\\n uint256 indexed requestId,\\n uint64 groupId,\\n bytes previousEntry\\n );\\n\\n event RelayEntrySubmitted(\\n uint256 indexed requestId,\\n address submitter,\\n bytes entry\\n );\\n\\n event RelayEntryTimedOut(\\n uint256 indexed requestId,\\n uint64 terminatedGroupId\\n );\\n\\n /// @notice Initializes the very first `previousEntry` with an initial\\n /// `relaySeed` value. Can be performed only once.\\n function initSeedEntry(Data storage self) internal {\\n require(\\n self.previousEntry.x == 0 && self.previousEntry.y == 0,\\n \\\"Seed entry already initialized\\\"\\n );\\n self.previousEntry = AltBn128.g1Unmarshal(relaySeed);\\n }\\n\\n /// @notice Creates a request to generate a new relay entry, which will\\n /// include a random number (by signing the previous entry's\\n /// random number).\\n /// @param groupId Identifier of the group chosen to handle the request.\\n function requestEntry(Data storage self, uint64 groupId) internal {\\n require(\\n !isRequestInProgress(self),\\n \\\"Another relay request in progress\\\"\\n );\\n\\n uint64 currentRequestId = ++self.requestCount;\\n\\n self.currentRequestID = currentRequestId;\\n self.currentRequestGroupID = groupId;\\n self.currentRequestStartBlock = uint64(block.number);\\n\\n emit RelayEntryRequested(\\n currentRequestId,\\n groupId,\\n AltBn128.g1Marshal(self.previousEntry)\\n );\\n }\\n\\n /// @notice Creates a new relay entry. Gas-optimized version that can be\\n /// called only before the soft timeout. This should be the majority\\n /// of cases.\\n /// @param entry Group BLS signature over the previous entry.\\n /// @param groupPubKey Public key of the group which signed the relay entry.\\n function submitEntryBeforeSoftTimeout(\\n Data storage self,\\n bytes calldata entry,\\n bytes storage groupPubKey\\n ) internal {\\n require(\\n block.number < softTimeoutBlock(self),\\n \\\"Relay entry soft timeout passed\\\"\\n );\\n _submitEntry(self, entry, groupPubKey);\\n }\\n\\n /// @notice Creates a new relay entry. Can be called at any time.\\n /// In case the soft timeout has not been exceeded, it is more\\n /// gas-efficient to call the second variation of `submitEntry`.\\n /// @param entry Group BLS signature over the previous entry.\\n /// @param groupPubKey Public key of the group which signed the relay entry.\\n /// @return slashingAmount Amount by which group members should be slashed\\n /// in case the relay entry was submitted after the soft timeout.\\n /// The value is zero if entry was submitted on time.\\n function submitEntry(\\n Data storage self,\\n bytes calldata entry,\\n bytes storage groupPubKey\\n ) internal returns (uint96) {\\n // If the soft timeout has been exceeded apply stake slashing for\\n // all group members. Otherwise, no slashing.\\n uint96 slashingAmount = calculateSlashingAmount(self);\\n\\n _submitEntry(self, entry, groupPubKey);\\n\\n return slashingAmount;\\n }\\n\\n function _submitEntry(\\n Data storage self,\\n bytes calldata entry,\\n bytes storage groupPubKey\\n ) internal {\\n require(isRequestInProgress(self), \\\"No relay request in progress\\\");\\n require(!hasRequestTimedOut(self), \\\"Relay request timed out\\\");\\n\\n require(\\n BLS._verify(\\n AltBn128.g2Unmarshal(groupPubKey),\\n self.previousEntry,\\n AltBn128.g1Unmarshal(entry)\\n ),\\n \\\"Invalid entry\\\"\\n );\\n\\n emit RelayEntrySubmitted(self.currentRequestID, msg.sender, entry);\\n\\n self.previousEntry = AltBn128.g1Unmarshal(entry);\\n self.currentRequestID = 0;\\n self.currentRequestGroupID = 0;\\n self.currentRequestStartBlock = 0;\\n }\\n\\n /// @notice Calculates the slashing amount for all group members.\\n /// @dev Must be used when a soft timeout was hit.\\n /// @return Amount by which group members should be slashed\\n /// in case the relay entry was submitted after the soft timeout.\\n function calculateSlashingAmount(Data storage self)\\n internal\\n view\\n returns (uint96)\\n {\\n uint256 softTimeout = softTimeoutBlock(self);\\n\\n if (block.number > softTimeout) {\\n uint256 submissionDelay = block.number - softTimeout;\\n // The slashing amount is a result of a calculated portion of the submission\\n // delay blocks. The max delay can be set up to relayEntryHardTimeout, which\\n // in consequence sets the max slashing amount.\\n if (submissionDelay > self.relayEntryHardTimeout) {\\n submissionDelay = self.relayEntryHardTimeout;\\n }\\n\\n return\\n uint96(\\n (submissionDelay *\\n self.relayEntrySubmissionFailureSlashingAmount) /\\n self.relayEntryHardTimeout\\n );\\n }\\n\\n return 0;\\n }\\n\\n /// @notice Updates relay-related parameters\\n /// @param _relayEntrySoftTimeout New relay entry soft timeout value.\\n /// It is the time in blocks during which a result is expected to be\\n /// submitted so that the group is not slashed.\\n /// @param _relayEntryHardTimeout New relay entry hard timeout value.\\n /// It is the time in blocks for a group to submit the relay entry\\n /// before slashing for the full slashing amount happens.\\n function setTimeouts(\\n Data storage self,\\n uint256 _relayEntrySoftTimeout,\\n uint256 _relayEntryHardTimeout\\n ) internal {\\n require(!isRequestInProgress(self), \\\"Relay request in progress\\\");\\n\\n self.relayEntrySoftTimeout = uint32(_relayEntrySoftTimeout);\\n self.relayEntryHardTimeout = uint32(_relayEntryHardTimeout);\\n }\\n\\n /// @notice Set relayEntrySubmissionFailureSlashingAmount parameter.\\n /// @param newRelayEntrySubmissionFailureSlashingAmount New value of\\n /// the parameter.\\n function setRelayEntrySubmissionFailureSlashingAmount(\\n Data storage self,\\n uint96 newRelayEntrySubmissionFailureSlashingAmount\\n ) internal {\\n require(!isRequestInProgress(self), \\\"Relay request in progress\\\");\\n\\n self\\n .relayEntrySubmissionFailureSlashingAmount = newRelayEntrySubmissionFailureSlashingAmount;\\n }\\n\\n /// @notice Retries the current relay request in case a relay entry\\n /// timeout was reported.\\n /// @param newGroupId ID of the group chosen to retry the current request.\\n function retryOnEntryTimeout(Data storage self, uint64 newGroupId)\\n internal\\n {\\n require(hasRequestTimedOut(self), \\\"Relay request did not time out\\\");\\n\\n uint64 currentRequestId = self.currentRequestID;\\n uint64 previousGroupId = self.currentRequestGroupID;\\n\\n emit RelayEntryTimedOut(currentRequestId, previousGroupId);\\n\\n self.currentRequestGroupID = newGroupId;\\n self.currentRequestStartBlock = uint64(block.number);\\n\\n emit RelayEntryRequested(\\n currentRequestId,\\n newGroupId,\\n AltBn128.g1Marshal(self.previousEntry)\\n );\\n }\\n\\n /// @notice Cleans up the current relay request in case a relay entry\\n /// timeout was reported.\\n function cleanupOnEntryTimeout(Data storage self) internal {\\n require(hasRequestTimedOut(self), \\\"Relay request did not time out\\\");\\n\\n emit RelayEntryTimedOut(\\n self.currentRequestID,\\n self.currentRequestGroupID\\n );\\n\\n self.currentRequestID = 0;\\n self.currentRequestGroupID = 0;\\n self.currentRequestStartBlock = 0;\\n }\\n\\n /// @notice Returns whether a relay entry request is currently in progress.\\n /// @return True if there is a request in progress. False otherwise.\\n function isRequestInProgress(Data storage self)\\n internal\\n view\\n returns (bool)\\n {\\n return self.currentRequestID != 0;\\n }\\n\\n /// @notice Returns whether the current relay request has timed out.\\n /// @return True if the request timed out. False otherwise.\\n function hasRequestTimedOut(Data storage self)\\n internal\\n view\\n returns (bool)\\n {\\n uint256 _relayEntryTimeout = self.relayEntrySoftTimeout +\\n self.relayEntryHardTimeout;\\n\\n return\\n isRequestInProgress(self) &&\\n block.number > self.currentRequestStartBlock + _relayEntryTimeout;\\n }\\n\\n /// @notice Calculates soft timeout block for the pending relay request.\\n /// @return The soft timeout block\\n function softTimeoutBlock(Data storage self)\\n internal\\n view\\n returns (uint256)\\n {\\n return self.currentRequestStartBlock + self.relayEntrySoftTimeout;\\n }\\n}\\n\",\"keccak256\":\"0x0ff1513ef6dceda503d19d1798d9de97510ec3c033b9a59aa240ce2a3052e6d3\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "storageLayout": { + "storage": [ + { + "astId": 9704, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "governance", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 9708, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)49_storage" + }, + { + "astId": 14668, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "reimbursementPool", + "offset": 0, + "slot": "50", + "type": "t_contract(ReimbursementPool)14998" + }, + { + "astId": 14672, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)49_storage" + }, + { + "astId": 9832, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "_callbackGasLimit", + "offset": 0, + "slot": "100", + "type": "t_uint256" + }, + { + "astId": 9835, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "_groupCreationFrequency", + "offset": 0, + "slot": "101", + "type": "t_uint256" + }, + { + "astId": 9838, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "_maliciousDkgResultSlashingAmount", + "offset": 0, + "slot": "102", + "type": "t_uint96" + }, + { + "astId": 9841, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "_unauthorizedSigningSlashingAmount", + "offset": 12, + "slot": "102", + "type": "t_uint96" + }, + { + "astId": 9844, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "_sortitionPoolRewardsBanDuration", + "offset": 0, + "slot": "103", + "type": "t_uint256" + }, + { + "astId": 9847, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "_relayEntryTimeoutNotificationRewardMultiplier", + "offset": 0, + "slot": "104", + "type": "t_uint256" + }, + { + "astId": 9850, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "_unauthorizedSigningNotificationRewardMultiplier", + "offset": 0, + "slot": "105", + "type": "t_uint256" + }, + { + "astId": 9853, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "_dkgMaliciousResultNotificationRewardMultiplier", + "offset": 0, + "slot": "106", + "type": "t_uint256" + }, + { + "astId": 9856, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "_dkgResultSubmissionGas", + "offset": 0, + "slot": "107", + "type": "t_uint256" + }, + { + "astId": 9859, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "_dkgResultApprovalGasOffset", + "offset": 0, + "slot": "108", + "type": "t_uint256" + }, + { + "astId": 9862, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "_notifyOperatorInactivityGasOffset", + "offset": 0, + "slot": "109", + "type": "t_uint256" + }, + { + "astId": 9865, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "_relayEntrySubmissionGasOffset", + "offset": 0, + "slot": "110", + "type": "t_uint256" + }, + { + "astId": 9870, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "inactivityClaimNonce", + "offset": 0, + "slot": "111", + "type": "t_mapping(t_uint64,t_uint256)" + }, + { + "astId": 9875, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "authorizedRequesters", + "offset": 0, + "slot": "112", + "type": "t_mapping(t_address,t_bool)" + }, + { + "astId": 9878, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "sortitionPool", + "offset": 0, + "slot": "113", + "type": "t_contract(SortitionPool)1980" + }, + { + "astId": 9881, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "tToken", + "offset": 0, + "slot": "114", + "type": "t_contract(IERC20)4111" + }, + { + "astId": 9884, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "staking", + "offset": 0, + "slot": "115", + "type": "t_contract(IStaking)9039" + }, + { + "astId": 9887, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "authorization", + "offset": 0, + "slot": "116", + "type": "t_struct(Data)16593_storage" + }, + { + "astId": 9890, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "dkg", + "offset": 0, + "slot": "120", + "type": "t_struct(Data)17523_storage" + }, + { + "astId": 9893, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "groups", + "offset": 0, + "slot": "131", + "type": "t_struct(Data)19026_storage" + }, + { + "astId": 9896, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "relay", + "offset": 0, + "slot": "136", + "type": "t_struct(Data)19920_storage" + }, + { + "astId": 9899, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "callback", + "offset": 0, + "slot": "140", + "type": "t_struct(Data)18930_storage" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_bytes32)dyn_storage": { + "base": "t_bytes32", + "encoding": "dynamic_array", + "label": "bytes32[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)49_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint64)dyn_storage": { + "base": "t_uint64", + "encoding": "dynamic_array", + "label": "uint64[]", + "numberOfBytes": "32" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "encoding": "inplace", + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_bytes_storage": { + "encoding": "bytes", + "label": "bytes", + "numberOfBytes": "32" + }, + "t_contract(BeaconDkgValidator)9699": { + "encoding": "inplace", + "label": "contract BeaconDkgValidator", + "numberOfBytes": "20" + }, + "t_contract(IERC20)4111": { + "encoding": "inplace", + "label": "contract IERC20", + "numberOfBytes": "20" + }, + "t_contract(IRandomBeaconConsumer)15021": { + "encoding": "inplace", + "label": "contract IRandomBeaconConsumer", + "numberOfBytes": "20" + }, + "t_contract(IStaking)9039": { + "encoding": "inplace", + "label": "contract IStaking", + "numberOfBytes": "20" + }, + "t_contract(ReimbursementPool)14998": { + "encoding": "inplace", + "label": "contract ReimbursementPool", + "numberOfBytes": "20" + }, + "t_contract(SortitionPool)1980": { + "encoding": "inplace", + "label": "contract SortitionPool", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_address)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => address)", + "numberOfBytes": "32", + "value": "t_address" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_address,t_struct(AuthorizationDecrease)16576_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct BeaconAuthorization.AuthorizationDecrease)", + "numberOfBytes": "32", + "value": "t_struct(AuthorizationDecrease)16576_storage" + }, + "t_mapping(t_bytes32,t_struct(Group)19010_storage)": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => struct Groups.Group)", + "numberOfBytes": "32", + "value": "t_struct(Group)19010_storage" + }, + "t_mapping(t_uint64,t_uint256)": { + "encoding": "mapping", + "key": "t_uint64", + "label": "mapping(uint64 => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_struct(AuthorizationDecrease)16576_storage": { + "encoding": "inplace", + "label": "struct BeaconAuthorization.AuthorizationDecrease", + "members": [ + { + "astId": 16573, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "decreasingBy", + "offset": 0, + "slot": "0", + "type": "t_uint96" + }, + { + "astId": 16575, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "decreasingAt", + "offset": 12, + "slot": "0", + "type": "t_uint64" + } + ], + "numberOfBytes": "32" + }, + "t_struct(Data)16593_storage": { + "encoding": "inplace", + "label": "struct BeaconAuthorization.Data", + "members": [ + { + "astId": 16579, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "parameters", + "offset": 0, + "slot": "0", + "type": "t_struct(Parameters)16571_storage" + }, + { + "astId": 16583, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "stakingProviderToOperator", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_address,t_address)" + }, + { + "astId": 16587, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "operatorToStakingProvider", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_address,t_address)" + }, + { + "astId": 16592, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "pendingDecreases", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_address,t_struct(AuthorizationDecrease)16576_storage)" + } + ], + "numberOfBytes": "128" + }, + "t_struct(Data)17523_storage": { + "encoding": "inplace", + "label": "struct BeaconDkg.Data", + "members": [ + { + "astId": 17506, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "sortitionPool", + "offset": 0, + "slot": "0", + "type": "t_contract(SortitionPool)1980" + }, + { + "astId": 17509, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "dkgValidator", + "offset": 0, + "slot": "1", + "type": "t_contract(BeaconDkgValidator)9699" + }, + { + "astId": 17512, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "parameters", + "offset": 0, + "slot": "2", + "type": "t_struct(Parameters)17503_storage" + }, + { + "astId": 17514, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "startBlock", + "offset": 0, + "slot": "6", + "type": "t_uint256" + }, + { + "astId": 17516, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "seed", + "offset": 0, + "slot": "7", + "type": "t_uint256" + }, + { + "astId": 17518, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "resultSubmissionStartBlockOffset", + "offset": 0, + "slot": "8", + "type": "t_uint256" + }, + { + "astId": 17520, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "submittedResultHash", + "offset": 0, + "slot": "9", + "type": "t_bytes32" + }, + { + "astId": 17522, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "submittedResultBlock", + "offset": 0, + "slot": "10", + "type": "t_uint256" + } + ], + "numberOfBytes": "352" + }, + "t_struct(Data)18930_storage": { + "encoding": "inplace", + "label": "struct Callback.Data", + "members": [ + { + "astId": 18929, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "callbackContract", + "offset": 0, + "slot": "0", + "type": "t_contract(IRandomBeaconConsumer)15021" + } + ], + "numberOfBytes": "32" + }, + "t_struct(Data)19026_storage": { + "encoding": "inplace", + "label": "struct Groups.Data", + "members": [ + { + "astId": 19015, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "groupsData", + "offset": 0, + "slot": "0", + "type": "t_mapping(t_bytes32,t_struct(Group)19010_storage)" + }, + { + "astId": 19018, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "groupsRegistry", + "offset": 0, + "slot": "1", + "type": "t_array(t_bytes32)dyn_storage" + }, + { + "astId": 19021, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "activeTerminatedGroups", + "offset": 0, + "slot": "2", + "type": "t_array(t_uint64)dyn_storage" + }, + { + "astId": 19023, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "expiredGroupOffset", + "offset": 0, + "slot": "3", + "type": "t_uint64" + }, + { + "astId": 19025, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "groupLifetime", + "offset": 0, + "slot": "4", + "type": "t_uint256" + } + ], + "numberOfBytes": "160" + }, + "t_struct(Data)19920_storage": { + "encoding": "inplace", + "label": "struct Relay.Data", + "members": [ + { + "astId": 19904, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "requestCount", + "offset": 0, + "slot": "0", + "type": "t_uint64" + }, + { + "astId": 19906, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "currentRequestID", + "offset": 8, + "slot": "0", + "type": "t_uint64" + }, + { + "astId": 19908, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "currentRequestGroupID", + "offset": 16, + "slot": "0", + "type": "t_uint64" + }, + { + "astId": 19910, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "currentRequestStartBlock", + "offset": 24, + "slot": "0", + "type": "t_uint64" + }, + { + "astId": 19913, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "previousEntry", + "offset": 0, + "slot": "1", + "type": "t_struct(G1Point)15033_storage" + }, + { + "astId": 19915, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "relayEntrySoftTimeout", + "offset": 0, + "slot": "3", + "type": "t_uint32" + }, + { + "astId": 19917, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "relayEntryHardTimeout", + "offset": 4, + "slot": "3", + "type": "t_uint32" + }, + { + "astId": 19919, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "relayEntrySubmissionFailureSlashingAmount", + "offset": 8, + "slot": "3", + "type": "t_uint96" + } + ], + "numberOfBytes": "128" + }, + "t_struct(G1Point)15033_storage": { + "encoding": "inplace", + "label": "struct AltBn128.G1Point", + "members": [ + { + "astId": 15030, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "x", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 15032, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "y", + "offset": 0, + "slot": "1", + "type": "t_uint256" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Group)19010_storage": { + "encoding": "inplace", + "label": "struct Groups.Group", + "members": [ + { + "astId": 19003, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "groupPubKey", + "offset": 0, + "slot": "0", + "type": "t_bytes_storage" + }, + { + "astId": 19005, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "registrationBlockNumber", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 19007, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "membersHash", + "offset": 0, + "slot": "2", + "type": "t_bytes32" + }, + { + "astId": 19009, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "terminated", + "offset": 0, + "slot": "3", + "type": "t_bool" + } + ], + "numberOfBytes": "128" + }, + "t_struct(Parameters)16571_storage": { + "encoding": "inplace", + "label": "struct BeaconAuthorization.Parameters", + "members": [ + { + "astId": 16566, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "minimumAuthorization", + "offset": 0, + "slot": "0", + "type": "t_uint96" + }, + { + "astId": 16568, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "authorizationDecreaseDelay", + "offset": 12, + "slot": "0", + "type": "t_uint64" + }, + { + "astId": 16570, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "authorizationDecreaseChangePeriod", + "offset": 20, + "slot": "0", + "type": "t_uint64" + } + ], + "numberOfBytes": "32" + }, + "t_struct(Parameters)17503_storage": { + "encoding": "inplace", + "label": "struct BeaconDkg.Parameters", + "members": [ + { + "astId": 17496, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "resultChallengePeriodLength", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 17498, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "resultChallengeExtraGas", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 17500, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "resultSubmissionTimeout", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 17502, + "contract": "contracts/RandomBeacon.sol:RandomBeacon", + "label": "submitterPrecedencePeriodLength", + "offset": 0, + "slot": "3", + "type": "t_uint256" + } + ], + "numberOfBytes": "128" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint32": { + "encoding": "inplace", + "label": "uint32", + "numberOfBytes": "4" + }, + "t_uint64": { + "encoding": "inplace", + "label": "uint64", + "numberOfBytes": "8" + }, + "t_uint96": { + "encoding": "inplace", + "label": "uint96", + "numberOfBytes": "12" + } + } + }, + "userdoc": { + "kind": "user", + "methods": { + "approveAuthorizationDecrease(address)": { + "notice": "Approves the previously registered authorization decrease request. Reverts if authorization decrease delay has not passed yet or if the authorization decrease was not requested for the given staking provider." + }, + "approveDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))": { + "notice": "Approves DKG result. Can be called when the challenge period for the submitted result is finished. Considers the submitted result as valid, bans misbehaved group members from the sortition pool rewards, and completes the group creation by activating the candidate group. For the first `submitterPrecedencePeriodLength` blocks after the end of the challenge period can be called only by the DKG result submitter. After that time, can be called by anyone." + }, + "authorizationDecreaseRequested(address,uint96,uint96)": { + "notice": "Used by T staking contract to inform the beacon that the authorization decrease for the given staking provider has been requested. Reverts if the amount after deauthorization would be non-zero and lower than the minimum authorization. Reverts if another authorization decrease request is pending for the staking provider and not enough time passed since the original request (see `authorizationDecreaseChangePeriod`). If the operator is not known (`registerOperator` was not called) it lets to `approveAuthorizationDecrease` immediately. If the operator is known (`registerOperator` was called), the operator needs to update state of the sortition pool with a call to `joinSortitionPool` or `updateOperatorStatus`. After the sortition pool state is in sync, authorization decrease delay starts. After authorization decrease delay passes, authorization decrease request needs to be approved with a call to `approveAuthorizationDecrease` function. If there is a pending authorization decrease request, it is overwritten, but only if enough time passed since the original request. Otherwise, the function reverts." + }, + "authorizationIncreased(address,uint96,uint96)": { + "notice": "Used by T staking contract to inform the beacon that the authorized stake amount for the given staking provider increased. Reverts if the authorization amount is below the minimum. The function is not updating the sortition pool. Sortition pool state needs to be updated by the operator with a call to `joinSortitionPool` or `updateOperatorStatus`." + }, + "authorizationParameters()": { + "notice": "Returns authorization-related parameters of the beacon." + }, + "authorizedRequesters(address)": { + "notice": "Authorized addresses that can request a relay entry." + }, + "availableRewards(address)": { + "notice": "Returns the amount of rewards available for withdrawal for the given staking provider. Reverts if staking provider has not registered the operator address." + }, + "challengeDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))": { + "notice": "Challenges DKG result. If the submitted result is proved to be invalid it reverts the DKG back to the result submission phase. It removes a candidate group that was previously registered with the DKG result submission." + }, + "eligibleStake(address)": { + "notice": "Returns the current value of the staking provider's eligible stake. Eligible stake is defined as the currently authorized stake minus the pending authorization decrease. Eligible stake is what is used for operator's weight in the sortition pool. If the authorized stake minus the pending authorization decrease is below the minimum authorization, eligible stake is 0." + }, + "gasParameters()": { + "notice": "Returns gas-related parameters of the beacon." + }, + "genesis()": { + "notice": "Triggers group selection if there are no active groups." + }, + "getGroupCreationState()": { + "notice": "Check current group creation state." + }, + "groupCreationParameters()": { + "notice": "Returns group-creation-related parameters of the beacon." + }, + "hasDkgTimedOut()": { + "notice": "Checks if DKG timed out. The DKG timeout period includes time required for off-chain protocol execution and time for the result publication for all group members. After this time result cannot be submitted and DKG can be notified about the timeout." + }, + "inactivityClaimNonce(uint64)": { + "notice": "Stores current operator inactivity claim nonce for given group. Each claim is made with an unique nonce which protects against claim replay." + }, + "involuntaryAuthorizationDecrease(address,uint96,uint96)": { + "notice": "Used by T staking contract to inform the beacon the authorization has been decreased for the given staking provider involuntarily, as a result of slashing. If the operator is not known (`registerOperator` was not called) the function does nothing. The operator was never in a sortition pool so there is nothing to update. If the operator is known, sortition pool is unlocked, and the operator is in the sortition pool, the sortition pool state is updated. If the sortition pool is locked, update needs to be postponed. Every other staker is incentivized to call `updateOperatorStatus` for the problematic operator to increase their own rewards in the pool." + }, + "isOperatorInPool(address)": { + "notice": "Returns true if the given operator is in the sortition pool. Otherwise, returns false." + }, + "isOperatorUpToDate(address)": { + "notice": "Checks if the operator's authorized stake is in sync with operator's weight in the sortition pool. If the operator is not in the sortition pool and their authorized stake is non-zero, function returns false." + }, + "joinSortitionPool()": { + "notice": "Lets the operator join the sortition pool. The operator address must be known - before calling this function, it has to be appointed by the staking provider by calling `registerOperator`. Also, the operator must have the minimum authorization required by the beacon. Function reverts if there is no minimum stake authorized or if the operator is not known. If there was an authorization decrease requested, it is activated by starting the authorization decrease delay." + }, + "minimumAuthorization()": { + "notice": "The minimum authorization amount required so that operator can participate in the random beacon. This amount is required to execute slashing for providing a malicious DKG result or when a relay entry times out." + }, + "notifyDkgTimeout()": { + "notice": "Notifies about DKG timeout." + }, + "notifyOperatorInactivity((uint64,uint256[],bytes,uint256[]),uint256,uint32[])": { + "notice": "Notifies about operators who are inactive. Using this function, a majority of the group can decide about punishing specific group members who constantly fail doing their job. If the provided claim is proved to be valid and signed by sufficient number of group members, operators of members deemed as inactive are banned for sortition pool rewards for duration specified by `_sortitionPoolRewardsBanDuration` parameter. The sender of the claim must be one of the claim signers. This function can be called only for active and non-terminated groups." + }, + "operatorToStakingProvider(address)": { + "notice": "Returns staking provider of the given operator." + }, + "pendingAuthorizationDecrease(address)": { + "notice": "Returns the amount of stake that is pending authorization decrease for the given staking provider. If no authorization decrease has been requested, returns zero." + }, + "registerOperator(address)": { + "notice": "Used by staking provider to set operator address that will operate a node. The given staking provider can set operator address only one time. The operator address can not be changed and must be unique. Reverts if the operator is already set for the staking provider or if the operator address is already in use. Reverts if there is a pending authorization decrease for the staking provider." + }, + "relayEntryParameters()": { + "notice": "Returns relay-entry-related parameters of the beacon." + }, + "remainingAuthorizationDecreaseDelay(address)": { + "notice": "Returns the remaining time in seconds that needs to pass before the requested authorization decrease can be approved. If the sortition pool state was not updated yet by the operator after requesting the authorization decrease, returns `type(uint64).max`." + }, + "reportRelayEntryTimeout(uint32[])": { + "notice": "Reports a relay entry timeout." + }, + "reportUnauthorizedSigning(bytes,uint64,uint32[])": { + "notice": "Reports unauthorized groups signing. Must provide a valid signature of the sender's address as a message. Successful signature verification means the private key has been leaked and all group members should be punished by slashing their tokens. Group has to be active or expired. Unauthorized signing cannot be reported for a terminated group. In case of reporting unauthorized signing for a terminated group, or when the signature is invalid, function reverts." + }, + "requestRelayEntry(address)": { + "notice": "Creates a request to generate a new relay entry, which will include a random number (by signing the previous entry's random number). Requester must be previously authorized by the governance." + }, + "rewardParameters()": { + "notice": "Returns reward-related parameters of the beacon." + }, + "selectGroup()": { + "notice": "Selects a new group of operators. Can only be called when DKG is in progress and the pool is locked. At least one operator has to be registered in the pool, otherwise the function fails reverting the transaction." + }, + "setRequesterAuthorization(address,bool)": { + "notice": "Set authorization for requesters that can request a relay entry." + }, + "slashingParameters()": { + "notice": "Returns slashing-related parameters of the beacon." + }, + "stakingProviderToOperator(address)": { + "notice": "Returns operator registered for the given staking provider." + }, + "submitDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))": { + "notice": "`\\x19Ethereum signed message:\\n` before signing, so the message to sign is: `\\x19Ethereum signed message:\\n${keccak256(chainID,groupPubKey,misbehaved,startBlock)}`" + }, + "submitRelayEntry(bytes)": { + "notice": "Creates a new relay entry. Gas-optimized version that can be called only before the soft timeout. This should be the majority of cases." + }, + "submitRelayEntry(bytes,uint32[])": { + "notice": "Creates a new relay entry." + }, + "transferGovernance(address)": { + "notice": "Transfers governance of the contract to `newGovernance`." + }, + "updateAuthorizationParameters(uint96,uint64,uint64)": { + "notice": "Updates the values of authorization parameters." + }, + "updateGasParameters(uint256,uint256,uint256,uint256)": { + "notice": "Updates the values of gas parameters." + }, + "updateGroupCreationParameters(uint256,uint256,uint256,uint256,uint256,uint256)": { + "notice": "Updates the values of group creation parameters." + }, + "updateOperatorStatus(address)": { + "notice": "Updates status of the operator in the sortition pool. If there was an authorization decrease requested, it is activated by starting the authorization decrease delay. Function reverts if the operator is not known." + }, + "updateRelayEntryParameters(uint256,uint256,uint256)": { + "notice": "Updates the values of relay entry parameters." + }, + "updateRewardParameters(uint256,uint256,uint256,uint256)": { + "notice": "Updates the values of reward parameters." + }, + "updateSlashingParameters(uint96,uint96,uint96)": { + "notice": "Updates the values of slashing parameters." + }, + "withdrawIneligibleRewards(address)": { + "notice": "Withdraws rewards belonging to operators marked as ineligible for sortition pool rewards." + }, + "withdrawRewards(address)": { + "notice": "Withdraws application rewards for the given staking provider. Rewards are withdrawn to the staking provider's beneficiary address set in the staking contract. Reverts if staking provider has not registered the operator address." + } + }, + "notice": "Keep Random Beacon contract. It lets to request a new relay entry and validates the new relay entry provided by the network. This contract is in charge of all other Random Beacon activities such as group lifecycle or slashing.", + "version": 1 + } +} diff --git a/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/RandomBeaconChaosnet.sol/RandomBeaconChaosnet.json b/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/RandomBeaconChaosnet.sol/RandomBeaconChaosnet.json new file mode 100644 index 0000000000..06a483e953 --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/RandomBeaconChaosnet.sol/RandomBeaconChaosnet.json @@ -0,0 +1,222 @@ +{ + "contractName": "RandomBeaconChaosnet", + "sourceName": "contracts/RandomBeaconChaosnet.sol", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isAuthorized", + "type": "bool" + } + ], + "name": "RequesterAuthorizationUpdated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "authorizedRequesters", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IRandomBeaconConsumer", + "name": "callbackContract", + "type": "address" + } + ], + "name": "requestRelayEntry", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "bool", + "name": "isAuthorized", + "type": "bool" + } + ], + "name": "setRequesterAuthorization", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x60806040526e345a2a05aba6d6b069b7f5b1b12dc960025534801561002357600080fd5b5061002d33610032565b610082565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61043d806100916000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c80633ea478aa146100675780634368ec0c1461009f578063715018a6146100b45780638da5cb5b146100bc578063985e6487146100d7578063f2fde38b146100ea575b600080fd5b61008a6100753660046103a5565b60016020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6100b26100ad3660046103a5565b6100fd565b005b6100b26101f2565b6000546040516001600160a01b039091168152602001610096565b6100b26100e53660046103c9565b610206565b6100b26100f83660046103a5565b61026d565b3360009081526001602052604090205460ff166101615760405162461bcd60e51b815260206004820152601c60248201527f526571756573746572206d75737420626520617574686f72697a65640000000060448201526064015b60405180910390fd5b60025460405160200161017691815260200190565b60408051808303601f190181529082905280516020909101206002819055631bfaf51960e21b825260048201524360248201526001600160a01b03821690636febd46490604401600060405180830381600087803b1580156101d757600080fd5b505af11580156101eb573d6000803e3d6000fd5b5050505050565b6101fa6102e6565b6102046000610340565b565b61020e6102e6565b6001600160a01b038216600081815260016020908152604091829020805460ff191685151590811790915591519182527fb4d9db68405970190721d2b3726fc9f728c1413038755e60518dea67d5545556910160405180910390a25050565b6102756102e6565b6001600160a01b0381166102da5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610158565b6102e381610340565b50565b6000546001600160a01b031633146102045760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610158565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811681146102e357600080fd5b6000602082840312156103b757600080fd5b81356103c281610390565b9392505050565b600080604083850312156103dc57600080fd5b82356103e781610390565b9150602083013580151581146103fc57600080fd5b80915050925092905056fea2646970667358221220856a0ad265f63854383336ddb70989db38bfa9bf236963c74a4e7212b45ca4c564736f6c63430008110033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100625760003560e01c80633ea478aa146100675780634368ec0c1461009f578063715018a6146100b45780638da5cb5b146100bc578063985e6487146100d7578063f2fde38b146100ea575b600080fd5b61008a6100753660046103a5565b60016020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6100b26100ad3660046103a5565b6100fd565b005b6100b26101f2565b6000546040516001600160a01b039091168152602001610096565b6100b26100e53660046103c9565b610206565b6100b26100f83660046103a5565b61026d565b3360009081526001602052604090205460ff166101615760405162461bcd60e51b815260206004820152601c60248201527f526571756573746572206d75737420626520617574686f72697a65640000000060448201526064015b60405180910390fd5b60025460405160200161017691815260200190565b60408051808303601f190181529082905280516020909101206002819055631bfaf51960e21b825260048201524360248201526001600160a01b03821690636febd46490604401600060405180830381600087803b1580156101d757600080fd5b505af11580156101eb573d6000803e3d6000fd5b5050505050565b6101fa6102e6565b6102046000610340565b565b61020e6102e6565b6001600160a01b038216600081815260016020908152604091829020805460ff191685151590811790915591519182527fb4d9db68405970190721d2b3726fc9f728c1413038755e60518dea67d5545556910160405180910390a25050565b6102756102e6565b6001600160a01b0381166102da5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610158565b6102e381610340565b50565b6000546001600160a01b031633146102045760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610158565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811681146102e357600080fd5b6000602082840312156103b757600080fd5b81356103c281610390565b9392505050565b600080604083850312156103dc57600080fd5b82356103e781610390565b9150602083013580151581146103fc57600080fd5b80915050925092905056fea2646970667358221220856a0ad265f63854383336ddb70989db38bfa9bf236963c74a4e7212b45ca4c564736f6c63430008110033", + "linkReferences": {}, + "deployedLinkReferences": {}, + "devdoc": { + "kind": "dev", + "methods": { + "owner()": { + "details": "Returns the address of the current owner." + }, + "renounceOwnership()": { + "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner." + }, + "requestRelayEntry(address)": { + "details": "The caller must be an authorized requester.", + "params": { + "callbackContract": "Beacon consumer callback contract - Wallet Registry" + } + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." + } + }, + "title": "Keep Random Beacon Chaosnet", + "version": 1 + }, + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isAuthorized\",\"type\":\"bool\"}],\"name\":\"RequesterAuthorizationUpdated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"authorizedRequesters\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IRandomBeaconConsumer\",\"name\":\"callbackContract\",\"type\":\"address\"}],\"name\":\"requestRelayEntry\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"isAuthorized\",\"type\":\"bool\"}],\"name\":\"setRequesterAuthorization\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"requestRelayEntry(address)\":{\"details\":\"The caller must be an authorized requester.\",\"params\":{\"callbackContract\":\"Beacon consumer callback contract - Wallet Registry\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"title\":\"Keep Random Beacon Chaosnet\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"authorizedRequesters(address)\":{\"notice\":\"Authorized addresses that can request a relay entry.\"},\"requestRelayEntry(address)\":{\"notice\":\"Executes the callback with an arbitrary relay entry number.\"},\"setRequesterAuthorization(address,bool)\":{\"notice\":\"Authorizes a requester of the relay entry.\"}},\"notice\":\"A stub contract that will be used temporarily until the real-world random beacon client implementation is ready.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/RandomBeaconChaosnet.sol\":\"RandomBeaconChaosnet\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"contracts/RandomBeaconChaosnet.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./api/IRandomBeacon.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/// @title Keep Random Beacon Chaosnet\\n/// @notice A stub contract that will be used temporarily until the real-world\\n/// random beacon client implementation is ready.\\ncontract RandomBeaconChaosnet is IRandomBeacon, Ownable {\\n /// @notice Authorized addresses that can request a relay entry.\\n mapping(address => bool) public authorizedRequesters;\\n\\n /// @notice Arbitrary relay entry. Initially set to the Euler's number.\\n /// It's updated after each relay entry request.\\n uint256 internal entry = 271828182845904523536028747135266249;\\n\\n event RequesterAuthorizationUpdated(\\n address indexed requester,\\n bool isAuthorized\\n );\\n\\n /// @notice Executes the callback with an arbitrary relay entry number.\\n /// @param callbackContract Beacon consumer callback contract - Wallet Registry\\n /// @dev The caller must be an authorized requester.\\n function requestRelayEntry(IRandomBeaconConsumer callbackContract)\\n external\\n {\\n require(\\n authorizedRequesters[msg.sender],\\n \\\"Requester must be authorized\\\"\\n );\\n\\n // Update the entry so that a different group of wallet operators is\\n // selected in `WalletRegistry` on each request.\\n entry = uint256(keccak256(abi.encodePacked(entry)));\\n callbackContract.__beaconCallback(entry, block.number);\\n }\\n\\n /// @notice Authorizes a requester of the relay entry.\\n function setRequesterAuthorization(address requester, bool isAuthorized)\\n external\\n onlyOwner\\n {\\n authorizedRequesters[requester] = isAuthorized;\\n\\n emit RequesterAuthorizationUpdated(requester, isAuthorized);\\n }\\n}\\n\",\"keccak256\":\"0x9f633134dc47371f464d3bf8c2649ad60a362657382250df889ecb5820c122fb\",\"license\":\"GPL-3.0-only\"},\"contracts/api/IRandomBeacon.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IRandomBeaconConsumer.sol\\\";\\n\\n/// @title Random Beacon interface\\ninterface IRandomBeacon {\\n /// @notice Creates a request to generate a new relay entry. Requires a\\n /// request fee denominated in T token.\\n /// @param callbackContract Beacon consumer callback contract.\\n function requestRelayEntry(IRandomBeaconConsumer callbackContract) external;\\n}\\n\",\"keccak256\":\"0xc5f6ddbf69b2f2e2c03fe78b3857a1f038982e858679f520101f53c4ebe2f4bf\",\"license\":\"GPL-3.0-only\"},\"contracts/api/IRandomBeaconConsumer.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\ninterface IRandomBeaconConsumer {\\n /// @notice Receives relay entry produced by Keep Random Beacon. This function\\n /// should be called only by Keep Random Beacon.\\n ///\\n /// @param relayEntry Relay entry (random number) produced by Keep Random\\n /// Beacon.\\n /// @param blockNumber Block number at which the relay entry was submitted\\n /// to the chain.\\n function __beaconCallback(uint256 relayEntry, uint256 blockNumber) external;\\n}\\n\",\"keccak256\":\"0x84ce236b4eeb664ccb02782777a05c6ebb410be9b9e586a123a1205437a2ed9f\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "storageLayout": { + "storage": [ + { + "astId": 3888, + "contract": "contracts/RandomBeaconChaosnet.sol:RandomBeaconChaosnet", + "label": "_owner", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 12130, + "contract": "contracts/RandomBeaconChaosnet.sol:RandomBeaconChaosnet", + "label": "authorizedRequesters", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_address,t_bool)" + }, + { + "astId": 12134, + "contract": "contracts/RandomBeaconChaosnet.sol:RandomBeaconChaosnet", + "label": "entry", + "offset": 0, + "slot": "2", + "type": "t_uint256" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + }, + "userdoc": { + "kind": "user", + "methods": { + "authorizedRequesters(address)": { + "notice": "Authorized addresses that can request a relay entry." + }, + "requestRelayEntry(address)": { + "notice": "Executes the callback with an arbitrary relay entry number." + }, + "setRequesterAuthorization(address,bool)": { + "notice": "Authorizes a requester of the relay entry." + } + }, + "notice": "A stub contract that will be used temporarily until the real-world random beacon client implementation is ready.", + "version": 1 + } +} diff --git a/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/RandomBeaconGovernance.sol/RandomBeaconGovernance.json b/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/RandomBeaconGovernance.sol/RandomBeaconGovernance.json new file mode 100644 index 0000000000..7912b8d496 --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/RandomBeaconGovernance.sol/RandomBeaconGovernance.json @@ -0,0 +1,3466 @@ +{ + "contractName": "RandomBeaconGovernance", + "sourceName": "contracts/RandomBeaconGovernance.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "contract RandomBeacon", + "name": "_randomBeacon", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_governanceDelay", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "authorizationDecreaseChangePeriod", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "AuthorizationDecreaseChangePeriodUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "authorizationDecreaseChangePeriod", + "type": "uint64" + } + ], + "name": "AuthorizationDecreaseChangePeriodUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "authorizationDecreaseDelay", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "AuthorizationDecreaseDelayUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "authorizationDecreaseDelay", + "type": "uint64" + } + ], + "name": "AuthorizationDecreaseDelayUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "callbackGasLimit", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "CallbackGasLimitUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "callbackGasLimit", + "type": "uint256" + } + ], + "name": "CallbackGasLimitUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgMaliciousResultNotificationRewardMultiplier", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "DkgMaliciousResultNotificationRewardMultiplierUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgMaliciousResultNotificationRewardMultiplier", + "type": "uint256" + } + ], + "name": "DkgMaliciousResultNotificationRewardMultiplierUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultApprovalGasOffset", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "DkgResultApprovalGasOffsetUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultApprovalGasOffset", + "type": "uint256" + } + ], + "name": "DkgResultApprovalGasOffsetUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultChallengeExtraGas", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "DkgResultChallengeExtraGasUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultChallengeExtraGas", + "type": "uint256" + } + ], + "name": "DkgResultChallengeExtraGasUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultChallengePeriodLength", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "DkgResultChallengePeriodLengthUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultChallengePeriodLength", + "type": "uint256" + } + ], + "name": "DkgResultChallengePeriodLengthUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultSubmissionGas", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "DkgResultSubmissionGasUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultSubmissionGas", + "type": "uint256" + } + ], + "name": "DkgResultSubmissionGasUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultSubmissionTimeout", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "DkgResultSubmissionTimeoutUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultSubmissionTimeout", + "type": "uint256" + } + ], + "name": "DkgResultSubmissionTimeoutUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "submitterPrecedencePeriodLength", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "DkgSubmitterPrecedencePeriodLengthUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "submitterPrecedencePeriodLength", + "type": "uint256" + } + ], + "name": "DkgSubmitterPrecedencePeriodLengthUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "governanceDelay", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "GovernanceDelayUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "governanceDelay", + "type": "uint256" + } + ], + "name": "GovernanceDelayUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "groupCreationFrequency", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "GroupCreationFrequencyUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "groupCreationFrequency", + "type": "uint256" + } + ], + "name": "GroupCreationFrequencyUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "groupLifetime", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "GroupLifetimeUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "groupLifetime", + "type": "uint256" + } + ], + "name": "GroupLifetimeUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint96", + "name": "maliciousDkgResultSlashingAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "MaliciousDkgResultSlashingAmountUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint96", + "name": "maliciousDkgResultSlashingAmount", + "type": "uint96" + } + ], + "name": "MaliciousDkgResultSlashingAmountUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint96", + "name": "minimumAuthorization", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "MinimumAuthorizationUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint96", + "name": "minimumAuthorization", + "type": "uint96" + } + ], + "name": "MinimumAuthorizationUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "notifyOperatorInactivityGasOffset", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "NotifyOperatorInactivityGasOffsetUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "notifyOperatorInactivityGasOffset", + "type": "uint256" + } + ], + "name": "NotifyOperatorInactivityGasOffsetUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newRandomBeaconGovernance", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "RandomBeaconGovernanceTransferStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newRandomBeaconGovernance", + "type": "address" + } + ], + "name": "RandomBeaconGovernanceTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntryHardTimeout", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "RelayEntryHardTimeoutUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntryHardTimeout", + "type": "uint256" + } + ], + "name": "RelayEntryHardTimeoutUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntrySoftTimeout", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "RelayEntrySoftTimeoutUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntrySoftTimeout", + "type": "uint256" + } + ], + "name": "RelayEntrySoftTimeoutUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint96", + "name": "relayEntrySubmissionFailureSlashingAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "RelayEntrySubmissionFailureSlashingAmountUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint96", + "name": "relayEntrySubmissionFailureSlashingAmount", + "type": "uint96" + } + ], + "name": "RelayEntrySubmissionFailureSlashingAmountUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntrySubmissionGasOffset", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "RelayEntrySubmissionGasOffsetUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntrySubmissionGasOffset", + "type": "uint256" + } + ], + "name": "RelayEntrySubmissionGasOffsetUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntryTimeoutNotificationRewardMultiplier", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "RelayEntryTimeoutNotificationRewardMultiplierUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntryTimeoutNotificationRewardMultiplier", + "type": "uint256" + } + ], + "name": "RelayEntryTimeoutNotificationRewardMultiplierUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "sortitionPoolRewardsBanDuration", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "SortitionPoolRewardsBanDurationUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "sortitionPoolRewardsBanDuration", + "type": "uint256" + } + ], + "name": "SortitionPoolRewardsBanDurationUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "unauthorizedSigningTimeoutNotificationRewardMultiplier", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "UnauthorizedSigningNotificationRewardMultiplierUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "unauthorizedSigningTimeoutNotificationRewardMultiplier", + "type": "uint256" + } + ], + "name": "UnauthorizedSigningNotificationRewardMultiplierUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint96", + "name": "unauthorizedSigningSlashingAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "UnauthorizedSigningSlashingAmountUpdateStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint96", + "name": "unauthorizedSigningSlashingAmount", + "type": "uint96" + } + ], + "name": "UnauthorizedSigningSlashingAmountUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "authorizationDecreaseChangePeriodChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "authorizationDecreaseDelayChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "_newAuthorizationDecreaseChangePeriod", + "type": "uint64" + } + ], + "name": "beginAuthorizationDecreaseChangePeriodUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "_newAuthorizationDecreaseDelay", + "type": "uint64" + } + ], + "name": "beginAuthorizationDecreaseDelayUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newCallbackGasLimit", + "type": "uint256" + } + ], + "name": "beginCallbackGasLimitUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newDkgMaliciousResultNotificationRewardMultiplier", + "type": "uint256" + } + ], + "name": "beginDkgMaliciousResultNotificationRewardMultiplierUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newDkgResultApprovalGasOffset", + "type": "uint256" + } + ], + "name": "beginDkgResultApprovalGasOffsetUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newDkgResultChallengeExtraGas", + "type": "uint256" + } + ], + "name": "beginDkgResultChallengeExtraGasUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newDkgResultChallengePeriodLength", + "type": "uint256" + } + ], + "name": "beginDkgResultChallengePeriodLengthUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newDkgResultSubmissionGas", + "type": "uint256" + } + ], + "name": "beginDkgResultSubmissionGasUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newDkgResultSubmissionTimeout", + "type": "uint256" + } + ], + "name": "beginDkgResultSubmissionTimeoutUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newDkgSubmitterPrecedencePeriodLength", + "type": "uint256" + } + ], + "name": "beginDkgSubmitterPrecedencePeriodLengthUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newGovernanceDelay", + "type": "uint256" + } + ], + "name": "beginGovernanceDelayUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newGroupCreationFrequency", + "type": "uint256" + } + ], + "name": "beginGroupCreationFrequencyUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newGroupLifetime", + "type": "uint256" + } + ], + "name": "beginGroupLifetimeUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "_newMaliciousDkgResultSlashingAmount", + "type": "uint96" + } + ], + "name": "beginMaliciousDkgResultSlashingAmountUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "_newMinimumAuthorization", + "type": "uint96" + } + ], + "name": "beginMinimumAuthorizationUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newNotifyOperatorInactivityGasOffset", + "type": "uint256" + } + ], + "name": "beginNotifyOperatorInactivityGasOffsetUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newRandomBeaconGovernance", + "type": "address" + } + ], + "name": "beginRandomBeaconGovernanceTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newRelayEntryHardTimeout", + "type": "uint256" + } + ], + "name": "beginRelayEntryHardTimeoutUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newRelayEntrySoftTimeout", + "type": "uint256" + } + ], + "name": "beginRelayEntrySoftTimeoutUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "_newRelayEntrySubmissionFailureSlashingAmount", + "type": "uint96" + } + ], + "name": "beginRelayEntrySubmissionFailureSlashingAmountUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newRelayEntrySubmissionGasOffset", + "type": "uint256" + } + ], + "name": "beginRelayEntrySubmissionGasOffsetUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newRelayEntryTimeoutNotificationRewardMultiplier", + "type": "uint256" + } + ], + "name": "beginRelayEntryTimeoutNotificationRewardMultiplierUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newSortitionPoolRewardsBanDuration", + "type": "uint256" + } + ], + "name": "beginSortitionPoolRewardsBanDurationUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newUnauthorizedSigningNotificationRewardMultiplier", + "type": "uint256" + } + ], + "name": "beginUnauthorizedSigningNotificationRewardMultiplierUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "_newUnauthorizedSigningSlashingAmount", + "type": "uint96" + } + ], + "name": "beginUnauthorizedSigningSlashingAmountUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "callbackGasLimitChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "dkgMaliciousResultNotificationRewardMultiplierChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "dkgResultApprovalGasOffsetChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "dkgResultChallengeExtraGasChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "dkgResultChallengePeriodLengthChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "dkgResultSubmissionGasChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "dkgResultSubmissionTimeoutChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "dkgSubmitterPrecedencePeriodLengthChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeAuthorizationDecreaseChangePeriodUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeAuthorizationDecreaseDelayUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeCallbackGasLimitUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeDkgMaliciousResultNotificationRewardMultiplierUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeDkgResultApprovalGasOffsetUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeDkgResultChallengeExtraGasUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeDkgResultChallengePeriodLengthUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeDkgResultSubmissionGasUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeDkgResultSubmissionTimeoutUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeDkgSubmitterPrecedencePeriodLengthUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeGovernanceDelayUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeGroupCreationFrequencyUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeGroupLifetimeUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeMaliciousDkgResultSlashingAmountUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeMinimumAuthorizationUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeNotifyOperatorInactivityGasOffsetUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeRandomBeaconGovernanceTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeRelayEntryHardTimeoutUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeRelayEntrySoftTimeoutUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeRelayEntrySubmissionFailureSlashingAmountUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeRelayEntrySubmissionGasOffsetUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeRelayEntryTimeoutNotificationRewardMultiplierUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeSortitionPoolRewardsBanDurationUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeUnauthorizedSigningNotificationRewardMultiplierUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeUnauthorizedSigningSlashingAmountUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingAuthorizationDecreaseChangePeriodUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingAuthorizationDecreaseDelayUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingCallbackGasLimitUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingDkgMaliciousResultNotificationRewardMultiplierUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingDkgResultApprovalGasOffsetUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingDkgResultChallengeExtraGasUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingDkgResultChallengePeriodLengthUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingDkgResultSubmissionGasUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingDkgResultSubmissionTimeoutUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingDkgSubmitterPrecedencePeriodLengthUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingGovernanceDelayUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingGroupCreationFrequencyUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingGroupLifetimeUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingMaliciousDkgResultSlashingAmountUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingMimimumAuthorizationUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingNotifyOperatorInactivityGasOffsetUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingRandomBeaconGovernanceTransferDelayTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingRelayEntryHardTimeoutUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingRelayEntrySoftTimeoutUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingRelayEntrySubmissionFailureSlashingAmountUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingRelayEntrySubmissionGasOffsetUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingRelayEntryTimeoutNotificationRewardMultiplierUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingSortitionPoolRewardsBanDurationUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingUnauthorizedSigningNotificationRewardMultiplierUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRemainingUnauthorizedSigningSlashingAmountUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "governanceDelay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "governanceDelayChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "groupCreationFrequencyChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "groupLifetimeChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maliciousDkgResultSlashingAmountChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minimumAuthorizationChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newAuthorizationDecreaseChangePeriod", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newAuthorizationDecreaseDelay", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newCallbackGasLimit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newDkgMaliciousResultNotificationRewardMultiplier", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newDkgResultApprovalGasOffset", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newDkgResultChallengeExtraGas", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newDkgResultChallengePeriodLength", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newDkgResultSubmissionGas", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newDkgResultSubmissionTimeout", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newDkgSubmitterPrecedencePeriodLength", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newGovernanceDelay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newGroupCreationFrequency", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newGroupLifetime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newMaliciousDkgResultSlashingAmount", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newMinimumAuthorization", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newNotifyOperatorInactivityGasOffset", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newRandomBeaconGovernance", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newRelayEntryHardTimeout", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newRelayEntrySoftTimeout", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newRelayEntrySubmissionFailureSlashingAmount", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newRelayEntrySubmissionGasOffset", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newRelayEntryTimeoutNotificationRewardMultiplier", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newSortitionPoolRewardsBanDuration", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newUnauthorizedSigningNotificationRewardMultiplier", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newUnauthorizedSigningSlashingAmount", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "notifyOperatorInactivityGasOffsetChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "randomBeacon", + "outputs": [ + { + "internalType": "contract RandomBeacon", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "randomBeaconGovernanceTransferInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "relayEntryHardTimeoutChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "relayEntrySoftTimeoutChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "relayEntrySubmissionFailureSlashingAmountChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "relayEntrySubmissionGasOffsetChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "relayEntryTimeoutNotificationRewardMultiplierChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "bool", + "name": "isAuthorized", + "type": "bool" + } + ], + "name": "setRequesterAuthorization", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sortitionPoolRewardsBanDurationChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unauthorizedSigningNotificationRewardMultiplierChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "unauthorizedSigningSlashingAmountChangeInitiated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + } + ], + "name": "withdrawIneligibleRewards", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x60a06040523480156200001157600080fd5b5060405162004efa38038062004efa833981016040819052620000349162000154565b6200003f3362000104565b6001600160a01b0382166200009b5760405162461bcd60e51b815260206004820152601660248201527f5a65726f2d61646472657373207265666572656e63650000000000000000000060448201526064015b60405180910390fd5b80600003620000ed5760405162461bcd60e51b815260206004820152601360248201527f4e6f20676f7665726e616e63652064656c617900000000000000000000000000604482015260640162000092565b6001600160a01b0390911660805260335562000190565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080604083850312156200016857600080fd5b82516001600160a01b03811681146200018057600080fd5b6020939093015192949293505050565b608051614bf7620003036000396000818161080501528181610eba01528181610f7a015281816110a10152818161114f0152818161136c0152818161143f0152818161154801528181611607015281816118ac0152818161196101528181611acb01528181611b9f01528181611eb101528181611f6901528181612073015281816121cb015281816122a0015281816123c001528181612479015281816125880152818161264001528181612802015281816128c1015281816129d601528181612aa801528181612c6301528181612d2201528181612e2e01528181612f510152818161301101528181613126015281816131d4015281816132ef015281816133a6015281816135dc015281816136950152818161387f0152818161395201528181613a7801528181613c1a01528181613cda01528181613f5001528181614010015281816141770152818161422f0152818161434801528181614400015281816145bb015261468f0152614bf76000f3fe608060405234801561001057600080fd5b50600436106107bb5760003560e01c80638b63cc22116103f5578063af21b29011610215578063d24521aa11610130578063e731cc53116100c3578063ee8e6e5e11610092578063ee8e6e5e14610dd5578063f0bb6ce814610dde578063f2fde38b14610de6578063fb5ccedc14610df9578063fe3bb37014610e0257600080fd5b8063e731cc5314610da9578063e79b8c4614610db1578063e8507b0614610dba578063ec9d1d9614610dcd57600080fd5b8063dde37ab8116100ff578063dde37ab814610d88578063de0ce4c914610d90578063df5ee8f614610d98578063e259b55114610da157600080fd5b8063d24521aa14610d67578063d31121de14610d6f578063d57da0b814610d77578063dbc439c714610d7f57600080fd5b8063c17a1471116101a8578063cb1ec15311610177578063cb1ec15314610d3a578063ccc5488a14610d43578063cdfaeb9814610d4b578063ce123d2814610d5457600080fd5b8063c17a147114610d03578063c1b2ba9714610d16578063c268650e14610d1f578063c97e8feb14610d3257600080fd5b8063ba5c9e7e116101e4578063ba5c9e7e14610ccc578063bba3293914610cd4578063bcc5d20414610cdd578063c16d606f14610cf057600080fd5b8063af21b29014610c94578063b0ed20bb14610c9d578063b1fae48b14610cb0578063b392e3be14610cb957600080fd5b80639de6bc9d11610310578063a72aedae116102a3578063ac21f57c11610272578063ac21f57c14610c5f578063aceb164814610c72578063ae1a332514610c7b578063ae98cbf014610c83578063aea6933914610c8c57600080fd5b8063a72aedae14610c29578063a7b9a7a014610c3c578063a955b3f314610c44578063a9b32c3d14610c5757600080fd5b8063a01bc828116102df578063a01bc82814610bfd578063a0a94bbb14610c05578063a5b9ab4d14610c0d578063a6d025f114610c1657600080fd5b80639de6bc9d14610bd05780639ec67b3114610bd85780639f40edf014610bec5780639fc3da9614610bf557600080fd5b8063914f512f11610388578063985e648711610357578063985e648714610ba55780639949d70e14610bb85780639b849b9214610bc05780639cde7da914610bc857600080fd5b8063914f512f14610b6e57806395ba105d14610b7657806396fd955e14610b7f5780639810f32714610b9257600080fd5b80638d2e0c3c116103c45780638d2e0c3c14610b395780638da5cb5b14610b425780638e0442f814610b53578063914adf8f14610b6657600080fd5b80638b63cc2214610b0e5780638bc32f3314610b215780638c5f0d6714610b295780638cdb432914610b3157600080fd5b80634885b171116105e057806364e32d74116104fb578063785180e71161048e57806382e70cb81161045d57806382e70cb814610ae4578063863b45a414610aec5780638837037714610af5578063894ee96814610afe5780638a4f77ef14610b0657600080fd5b8063785180e714610ab8578063798f022314610acb5780637ab18adf14610ad35780637b81ef5214610adc57600080fd5b8063692be745116104ca578063692be74514610a95578063715018a614610a9e578063765a783214610aa657806377bf781414610aaf57600080fd5b806364e32d7414610a54578063660f903114610a5c578063663032cd14610a6f5780636795afe614610a8257600080fd5b8063542ced771161057357806361038b911161054257806361038b9114610a2857806361d4b5ef14610a3157806362c78d0914610a39578063648392ac14610a4157600080fd5b8063542ced77146109f15780635b6bd01714610a045780635c07405614610a0c5780635f735a1014610a1f57600080fd5b80634ca107cc116105af5780634ca107cc146109c45780634cf11abc146109cd5780634ed05ade146109d557806352f1bf14146109de57600080fd5b80634885b17114610996578063488a4b261461099f578063495cb121146109a85780634b928642146109bb57600080fd5b80632d318efc116106db578063363388331161066e5780633bf8a5381161063d5780633bf8a5381461093d5780633edf74e71461096a578063412bd7b41461097d578063429cdaa814610985578063481d021f1461098e57600080fd5b8063363388331461091057806337f547901461091957806337fa5d51146109215780633b7b1b081461093457600080fd5b80632ff8aa33116106aa5780632ff8aa33146108e357806333a17f98146108f6578063345cdef5146108fe5780633611f0021461090757600080fd5b80632d318efc146108c15780632d340433146108c95780632f006f4e146108d25780632f505f1f146108db57600080fd5b80631937c64711610753578063209e80ea11610722578063209e80ea14610895578063260b5a85146108a857806326825a9d146108b15780632b702150146108b957600080fd5b80631937c6471461087257806319f1103f1461087a5780631e44a72c146108835780631ff566c71461088c57600080fd5b8063152ba58f1161078f578063152ba58f146107f8578063153622b314610800578063154028f41461083f5780631722dd291461086a57600080fd5b80626b050c146107c0578063040215af146107dc57806306201e1c146107e557806314385adb146107ef575b600080fd5b6107c960315481565b6040519081526020015b60405180910390f35b6107c9600c5481565b6107ed610e15565b005b6107c960205481565b6107c9610ff9565b6108277f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016107d3565b601b54610852906001600160601b031681565b6040516001600160601b0390911681526020016107d3565b6107ed61100b565b6107c96111c2565b6107c9601e5481565b6107c960085481565b6107c960025481565b6107ed6108a33660046148db565b6111cf565b6107c960225481565b6107ed611220565b6107c96112c4565b6107ed6112d1565b6107c9600d5481565b6107c960105481565b6107ed6114ad565b6107ed6108f13660046148db565b611686565b6107c96116f0565b6107c9602f5481565b6107c960135481565b6107c960165481565b6107c96116fd565b6107ed61092f3660046148db565b61170a565b6107c960155481565b6025546109519067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016107d3565b6107ed6109783660046148db565b611754565b6107c9611809565b6107c9600f5481565b6107ed611816565b6107c960095481565b6107c960285481565b6107ed6109b6366004614909565b6119cd565b6107c960215481565b6107c960265481565b6107ed611a30565b6107c960185481565b6107ed6109ec3660046148db565b611c0d565b6107ed6109ff3660046148db565b611cb3565b6107c9611cfd565b6107ed610a1a3660046148db565b611d0a565b6107c9602d5481565b6107c960305481565b6107c9611db2565b6107c9611dbf565b6107ed610a4f3660046148db565b611dcc565b6107ed611e16565b6107ed610a6a36600461493c565b611fe7565b6107ed610a7d366004614975565b61204c565b6107ed610a903660046148db565b6120d2565b6107c9601d5481565b6107ed61211c565b6107c960075481565b6107c960295481565b601954610852906001600160601b031681565b6107ed612130565b6107c9601a5481565b6107c961230e565b6107c961231b565b6107c960065481565b6107c960245481565b6107ed612328565b6107ed6124ed565b6107ed610b1c3660046148db565b6126be565b6107ed61276a565b6107c961292e565b6107ed61293b565b6107c9600a5481565b6000546001600160a01b0316610827565b6107ed610b613660046148db565b612b17565b6107ed612bcb565b6107c9612d8f565b6107c960015481565b602354610852906001600160601b031681565b6107ed610ba0366004614909565b612d9c565b6107ed610bb3366004614990565b612dff565b6107c9612e8e565b6107c9612e9b565b6107c9612ea8565b6107ed612eb5565b6027546109519067ffffffffffffffff1681565b6107c9601c5481565b6107ed613090565b6107c9613247565b6107ed613254565b6107c960145481565b6107ed610c243660046148db565b613425565b6107ed610c37366004614975565b61346f565b6107ed613544565b6107ed610c523660046148db565b613709565b6107c9613774565b6107ed610c6d366004614909565b613781565b6107c960045481565b6107ed6137e4565b6107c960055481565b6107ed6139c0565b6107c9602a5481565b6107ed610cab3660046148db565b613aee565b6107c9602c5481565b6107ed610cc73660046148db565b613b38565b6107ed613b82565b6107c960335481565b601754610852906001600160601b031681565b6107ed610cfe3660046148db565b613d46565b600354610827906001600160a01b031681565b6107c9602e5481565b6107ed610d2d3660046148db565b613e05565b6107c9613eab565b6107c9601f5481565b6107ed613eb8565b6107c9602b5481565b6107ed610d62366004614909565b61407c565b6107ed6140df565b6107c96142a3565b6107ed6142b0565b6107c960115481565b6107c9614474565b6107c9614481565b6107c960125481565b6107c961448e565b6107c961449b565b6107c9600e5481565b6107ed610dc83660046148db565b6144a8565b6107c9614513565b6107c9600b5481565b6107ed614520565b6107ed610df4366004614975565b6146fd565b6107c960325481565b6107ed610e1036600461493c565b614776565b610e1d6147db565b60285460008111610e495760405162461bcd60e51b8152600401610e40906149cc565b60405180910390fd5b603354610e5682426149fa565b1015610e745760405162461bcd60e51b8152600401610e4090614a21565b60275460405167ffffffffffffffff90911681527f6a7551372930a2bc4aec844a266609ca90cf9b805f875e92680e901b43d5273f9060200160405180910390a16000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637b14729e6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610f16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3a9190614a56565b506027546040516301409c5360e71b81526001600160601b038416600482015267ffffffffffffffff8084166024830152909116604482015291935091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a04e298090606401600060405180830381600087803b158015610fc657600080fd5b505af1158015610fda573d6000803e3d6000fd5b5050600060285550506027805467ffffffffffffffff19169055505050565b6000611006601454614835565b905090565b6110136147db565b600854600081116110365760405162461bcd60e51b8152600401610e40906149cc565b60335461104382426149fa565b10156110615760405162461bcd60e51b8152600401610e4090614a21565b7f1aa56185678cf82df5663d3bf97731024fc6da8f9ab832de58fe6411bb7aacad60075460405161109491815260200190565b60405180910390a16000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166374024ab76040518163ffffffff1660e01b8152600401606060405180830381865afa1580156110fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111219190614aa3565b600754604051639a7d093560e01b8152600481018590526024810191909152604481018290529294509250507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639a7d093590606401600060405180830381600087803b15801561119b57600080fd5b505af11580156111af573d6000803e3d6000fd5b5050600060088190556007555050505050565b6000611006600654614835565b6111d76147db565b601d81905542601e8190556040805183815260208101929092527f523803e7f157ab532da5ae1e1d19b71f16b18376cf65a301ef8e3f07076d6bfd91015b60405180910390a150565b6112286147db565b6002546000811161124b5760405162461bcd60e51b8152600401610e40906149cc565b60335461125882426149fa565b10156112765760405162461bcd60e51b8152600401610e4090614a21565b7f657e578b1ed229f1e01ab5ce4700399f19ddd24b09b071ab9e72122f18aa72976001546040516112a991815260200190565b60405180910390a15060018054603355600060028190559055565b6000611006601054614835565b6112d96147db565b600e54600081116112fc5760405162461bcd60e51b8152600401610e40906149cc565b60335461130982426149fa565b10156113275760405162461bcd60e51b8152600401610e4090614a21565b7fc2b1fc49f84728c2be30441ba73a73fe63ff40017b462dca6045e8b5933dfd97600d5460405161135a91815260200190565b60405180910390a160008060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b142f85c6040518163ffffffff1660e01b815260040160c060405180830381865afa1580156113c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ec9190614ad1565b600d546040516377a5a7bd60e01b815260048101889052602481019190915260448101859052606481018490526084810183905260a48101829052959a5092985090965094509250506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906377a5a7bd9060c401600060405180830381600087803b15801561148357600080fd5b505af1158015611497573d6000803e3d6000fd5b50506000600e819055600d555050505050505050565b6114b56147db565b602454600081116114d85760405162461bcd60e51b8152600401610e40906149cc565b6033546114e582426149fa565b10156115035760405162461bcd60e51b8152600401610e4090614a21565b6023546040516001600160601b0390911681527fca5de5c00e5da52e22f64b23ecfa308e487441bcbd0f4b84657799102e3ee3719060200160405180910390a16000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637b14729e6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156115a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c89190614a56565b6023546040516301409c5360e71b81526001600160601b03909116600482015267ffffffffffffffff80841660248301528216604482015291945092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316915063a04e298090606401600060405180830381600087803b15801561165457600080fd5b505af1158015611668573d6000803e3d6000fd5b505060006024555050602380546001600160601b0319169055505050565b61168e6147db565b60648111156116af5760405162461bcd60e51b8152600401610e4090614b1b565b601f81905542602081815560408051848152918201929092527f236b3b5a701c1727d0ddd01db13475e0da9be45561decb6f0d3d958c18e09e8b9101611215565b6000611006603254614835565b6000611006602054614835565b6117126147db565b60018190554260028190556040805183815260208101929092527f1ed485551399b30c188ed4d426c6c62d7b703b9fec6b486c70a3fe616c2707c89101611215565b61175c6147db565b600081116117c75760405162461bcd60e51b815260206004820152603260248201527f444b47207375626d697474657220707265636564656e636520706572696f642060448201527106c656e677468206d757374206265203e20360741b6064820152608401610e40565b60158190554260168190556040805183815260208101929092527f69f992e32ba993676818a20dfe808b5d41e0db4bdd3a52917701443500a423ca9101611215565b6000611006602c54614835565b61181e6147db565b600654600081116118415760405162461bcd60e51b8152600401610e40906149cc565b60335461184e82426149fa565b101561186c5760405162461bcd60e51b8152600401610e4090614a21565b7f63db42a2e13b78bf39d9f3c14718c3c925ccdf3e30a0477d5a7626914164620260055460405161189f91815260200190565b60405180910390a16000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166374024ab76040518163ffffffff1660e01b8152600401606060405180830381865afa158015611908573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061192c9190614aa3565b600554604051639a7d093560e01b81526004810191909152602481018390526044810182905291945092506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169150639a7d093590606401600060405180830381600087803b1580156119a657600080fd5b505af11580156119ba573d6000803e3d6000fd5b5050600060068190556005555050505050565b6119d56147db565b601980546001600160601b0319166001600160601b03831690811790915542601a8190556040805192835260208301919091527f8087387fa6bcbf89a9e273adcf21735f21e89ae8024417df321d8ccc106123089101611215565b611a386147db565b60105460008111611a5b5760405162461bcd60e51b8152600401610e40906149cc565b603354611a6882426149fa565b1015611a865760405162461bcd60e51b8152600401610e4090614a21565b7f54eb240e49fe7d2dc26863f9a2682d5834812e39417dbac77797c3b01b97395c600f54604051611ab991815260200190565b60405180910390a160008060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b142f85c6040518163ffffffff1660e01b815260040160c060405180830381865afa158015611b27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b4b9190614ad1565b600f546040516377a5a7bd60e01b815260048101889052602481018790526044810191909152606481018490526084810183905260a48101829052959a509398509096509450909250506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906377a5a7bd9060c401600060405180830381600087803b158015611be357600080fd5b505af1158015611bf7573d6000803e3d6000fd5b505060006010819055600f555050505050505050565b611c156147db565b60008111611c715760405162461bcd60e51b8152602060048201526024808201527f47726f7570206372656174696f6e206672657175656e6379206d7573742062656044820152630203e20360e41b6064820152608401610e40565b600b81905542600c8190556040805183815260208101929092527f9356f2202b7c2dd20837653ce617753f36c435d28464b7f8c4c4c174acecec3d9101611215565b611cbb6147db565b602b81905542602c8190556040805183815260208101929092527fe7f67ed355ceb941da1b6600c508f5493967c944c9fee75936aaa986b9e0344c9101611215565b6000611006601e54614835565b611d126147db565b60008111611d705760405162461bcd60e51b815260206004820152602560248201527f47726f7570206c69666574696d65206d75737420626520677265617465722074604482015264068616e20360dc1b6064820152608401610e40565b600d81905542600e8190556040805183815260208101929092527f2061f522ba42a34f2907b875dca3bf5f0d999cacbbb635e894ee3c5792727e649101611215565b6000611006602854614835565b6000611006600854614835565b611dd46147db565b602f8190554260308190556040805183815260208101929092527f6ff3903999be3f8c1262f638998917b6d6c6f8097cb7cb9e60edaa1a5f2a66719101611215565b611e1e6147db565b601c5460008111611e415760405162461bcd60e51b8152600401610e40906149cc565b603354611e4e82426149fa565b1015611e6c5760405162461bcd60e51b8152600401610e4090614a21565b601b546040516001600160601b0390911681527f13f3e65295154bda4919d5f46898c2284edbf9283ee94654515cec984e767c809060200160405180910390a16000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631d35fa636040518163ffffffff1660e01b8152600401606060405180830381865afa158015611f0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f319190614b49565b50601b54604051630519e99160e01b81526001600160601b0380851660048301528084166024830152909116604482015291935091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690630519e99190606401600060405180830381600087803b158015611fb557600080fd5b505af1158015611fc9573d6000803e3d6000fd5b50506000601c555050601b80546001600160601b0319169055505050565b611fef6147db565b6027805467ffffffffffffffff191667ffffffffffffffff83169081179091554260288190556040805192835260208301919091527f979c18cc9822195c2af34f89e0713a14edbd9713b32932c60471951cc1fa02db9101611215565b6120546147db565b60405163663032cd60e01b81526001600160a01b0382811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063663032cd90602401600060405180830381600087803b1580156120b757600080fd5b505af11580156120cb573d6000803e3d6000fd5b5050505050565b6120da6147db565b60118190554260128190556040805183815260208101929092527fff34014c09b30234094b14f309369c4b204ab5f24daa98f6922ac40a04768bf09101611215565b6121246147db565b61212e600061488b565b565b6121386147db565b6012546000811161215b5760405162461bcd60e51b8152600401610e40906149cc565b60335461216882426149fa565b10156121865760405162461bcd60e51b8152600401610e4090614a21565b7ffc489bb20492c4590e5a1edb8e096301dd7e9c24843a5af9221ddafff010f0f06011546040516121b991815260200190565b60405180910390a160008060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b142f85c6040518163ffffffff1660e01b815260040160c060405180830381865afa158015612227573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061224b9190614ad1565b6011546040516377a5a7bd60e01b815260048101889052602481018790526044810186905260648101919091526084810183905260a48101829052959a50939850919650909450909250506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906377a5a7bd9060c401600060405180830381600087803b1580156122e457600080fd5b505af11580156122f8573d6000803e3d6000fd5b5050600060128190556011555050505050505050565b6000611006602454614835565b6000611006602654614835565b6123306147db565b603054600081116123535760405162461bcd60e51b8152600401610e40906149cc565b60335461236082426149fa565b101561237e5760405162461bcd60e51b8152600401610e4090614a21565b7fc02f8fddd9d337adf38d4f97d3ab8c91b69075b48db9bc25c461b0d02c3d4092602f546040516123b191815260200190565b60405180910390a160008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166388a595906040518163ffffffff1660e01b8152600401608060405180830381865afa15801561241c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124409190614b8b565b602f54604051635868086b60e11b81526004810186905260248101859052604481019190915260648101829052939650919450909250507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b0d010d690608401600060405180830381600087803b1580156124c557600080fd5b505af11580156124d9573d6000803e3d6000fd5b505060006030819055602f55505050505050565b6124f56147db565b601a54600081116125185760405162461bcd60e51b8152600401610e40906149cc565b60335461252582426149fa565b10156125435760405162461bcd60e51b8152600401610e4090614a21565b6019546040516001600160601b0390911681527fe1adae42a74e6bb380e06f34e96abe3134e824a1a152a8e6a7458be153404d179060200160405180910390a16000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631d35fa636040518163ffffffff1660e01b8152600401606060405180830381865afa1580156125e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126089190614b49565b601954604051630519e99160e01b81526001600160601b038086166004830152918216602482015290821660448201529294509250507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690630519e99190606401600060405180830381600087803b15801561268c57600080fd5b505af11580156126a0573d6000803e3d6000fd5b50506000601a555050601980546001600160601b0319169055505050565b6126c66147db565b600081116127285760405162461bcd60e51b815260206004820152602960248201527f444b4720726573756c74207375626d697373696f6e2074696d656f7574206d7560448201526807374206265203e20360bc1b6064820152608401610e40565b60138190554260148190556040805183815260208101929092527f77bd6dceb389516c704e337d2e53bab8397e3fd1de7e3b852090742804ba13b49101611215565b6127726147db565b602c54600081116127955760405162461bcd60e51b8152600401610e40906149cc565b6033546127a282426149fa565b10156127c05760405162461bcd60e51b8152600401610e4090614a21565b7ff71bf0b76dcaef665875c3a1d4959efda6ea75c7171f5fae1bd305f7c8509283602b546040516127f391815260200190565b60405180910390a160008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166388a595906040518163ffffffff1660e01b8152600401608060405180830381865afa15801561285e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128829190614b8b565b602b54604051635868086b60e11b8152600481019190915260248101849052604481018390526064810182905292965090945092506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016915063b0d010d690608401600060405180830381600087803b15801561290657600080fd5b505af115801561291a573d6000803e3d6000fd5b50506000602c819055602b55505050505050565b6000611006601854614835565b6129436147db565b600c54600081116129665760405162461bcd60e51b8152600401610e40906149cc565b60335461297382426149fa565b10156129915760405162461bcd60e51b8152600401610e4090614a21565b7fe3daa3940e1269d029800f83e889021793ccd69dd79a7152b9171a3071eb45a3600b546040516129c491815260200190565b60405180910390a160008060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b142f85c6040518163ffffffff1660e01b815260040160c060405180830381865afa158015612a32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a569190614ad1565b600b546040516377a5a7bd60e01b815260048101919091526024810186905260448101859052606481018490526084810183905260a48101829052949a50929850909650945092506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691506377a5a7bd9060c401600060405180830381600087803b158015612aed57600080fd5b505af1158015612b01573d6000803e3d6000fd5b50506000600c819055600b555050505050505050565b612b1f6147db565b600a811015612b895760405162461bcd60e51b815260206004820152603060248201527f444b4720726573756c74206368616c6c656e676520706572696f64206c656e6760448201526f07468206d757374206265203e3d2031360841b6064820152608401610e40565b600f8190554260108190556040805183815260208101929092527f4bc54f06db7242d34e1d1cdd7b4b33807a8210c54fc440ba45e6e5ffa04e083d9101611215565b612bd36147db565b601e5460008111612bf65760405162461bcd60e51b8152600401610e40906149cc565b603354612c0382426149fa565b1015612c215760405162461bcd60e51b8152600401610e4090614a21565b7f0945b46b311d9dd20cdadf139b3449fe2e50026e619f33cabedbd7461c429076601d54604051612c5491815260200190565b60405180910390a160008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663529023016040518163ffffffff1660e01b8152600401608060405180830381865afa158015612cbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ce39190614b8b565b601d54604051630ce591ab60e21b8152600481019190915260248101849052604481018390526064810182905292965090945092506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016915063339646ac90608401600060405180830381600087803b158015612d6757600080fd5b505af1158015612d7b573d6000803e3d6000fd5b50506000601e819055601d55505050505050565b6000611006602a54614835565b612da46147db565b601b80546001600160601b0319166001600160601b03831690811790915542601c8190556040805192835260208301919091527f060327865259e01939f90eed5ad911c6e0509663b7671bccd0f6382f56aba4d39101611215565b612e076147db565b60405163985e648760e01b81526001600160a01b03838116600483015282151560248301527f0000000000000000000000000000000000000000000000000000000000000000169063985e648790604401600060405180830381600087803b158015612e7257600080fd5b505af1158015612e86573d6000803e3d6000fd5b505050505050565b6000611006601a54614835565b6000611006600c54614835565b6000611006601254614835565b612ebd6147db565b60265460008111612ee05760405162461bcd60e51b8152600401610e40906149cc565b603354612eed82426149fa565b1015612f0b5760405162461bcd60e51b8152600401610e4090614a21565b60255460405167ffffffffffffffff90911681527fcc354ece588e8fa730a65a72ebb90039caf81a2a9efedf80e8124566d42a75e89060200160405180910390a16000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637b14729e6040518163ffffffff1660e01b8152600401606060405180830381865afa158015612fad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fd19190614a56565b506025546040516301409c5360e71b81526001600160601b038416600482015267ffffffffffffffff9182166024820152908216604482015291935091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a04e298090606401600060405180830381600087803b15801561305d57600080fd5b505af1158015613071573d6000803e3d6000fd5b5050600060265550506025805467ffffffffffffffff19169055505050565b6130986147db565b600a54600081116130bb5760405162461bcd60e51b8152600401610e40906149cc565b6033546130c882426149fa565b10156130e65760405162461bcd60e51b8152600401610e4090614a21565b7f01e43c4ca2dc8df5a6c64198b1ad31e61ff7584833e5a7933892dd79d8eb905260095460405161311991815260200190565b60405180910390a16000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166374024ab76040518163ffffffff1660e01b8152600401606060405180830381865afa158015613182573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a69190614aa3565b50600954604051639a7d093560e01b81526004810184905260248101839052604481019190915291935091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639a7d093590606401600060405180830381600087803b15801561322057600080fd5b505af1158015613234573d6000803e3d6000fd5b50506000600a8190556009555050505050565b6000611006600254614835565b61325c6147db565b6018546000811161327f5760405162461bcd60e51b8152600401610e40906149cc565b60335461328c82426149fa565b10156132aa5760405162461bcd60e51b8152600401610e4090614a21565b6017546040516001600160601b0390911681527f5e7ca6fb8d090a2753e006c53b0aab79da28ab5e198b62cc105bda8f96caa6a09060200160405180910390a16000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631d35fa636040518163ffffffff1660e01b8152600401606060405180830381865afa15801561334b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061336f9190614b49565b601754604051630519e99160e01b81526001600160601b0391821660048201528184166024820152908216604482015291945092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169150630519e99190606401600060405180830381600087803b1580156133f357600080fd5b505af1158015613407573d6000803e3d6000fd5b505060006018555050601780546001600160601b0319169055505050565b61342d6147db565b602d81905542602e8190556040805183815260208101929092527f8ff92b4fa51728d3b3bebd82f5bcfa8904b0278abbce025a1e33aaf9719fdb0d9101611215565b6134776147db565b6001600160a01b0381166134e95760405162461bcd60e51b815260206004820152603360248201527f4e65772072616e646f6d20626561636f6e20676f7665726e616e636520616464604482015272726573732063616e6e6f74206265207a65726f60681b6064820152608401610e40565b600380546001600160a01b0319166001600160a01b0383169081179091554260048190556040805192835260208301919091527fcda4dd0dbaee4278532e4689e026f08f707ec8602188caa303750b225cde00789101611215565b61354c6147db565b6022546000811161356f5760405162461bcd60e51b8152600401610e40906149cc565b60335461357c82426149fa565b101561359a5760405162461bcd60e51b8152600401610e4090614a21565b7f32aac559d8ae735853362fec3c6751b37b45f12097c074ee06d51b10180c68626021546040516135cd91815260200190565b60405180910390a160008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663529023016040518163ffffffff1660e01b8152600401608060405180830381865afa158015613638573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061365c9190614b8b565b602154604051630ce591ab60e21b81526004810186905260248101859052604481019190915260648101829052939650919450909250507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063339646ac90608401600060405180830381600087803b1580156136e157600080fd5b505af11580156136f5573d6000803e3d6000fd5b505060006022819055602155505050505050565b6137116147db565b60648111156137325760405162461bcd60e51b8152600401610e4090614b1b565b60218190554260228190556040805183815260208101929092527fb62064224fade801c12ce2e348d8fff15f8e451792137664811b44b6ffe37d919101611215565b6000611006600e54614835565b6137896147db565b601780546001600160601b0319166001600160601b0383169081179091554260188190556040805192835260208301919091527fb5da59c72c3f617da3620449ee7c88d5b8a81e1f98e9f61fc62207ecab6b099f9101611215565b6137ec6147db565b6016546000811161380f5760405162461bcd60e51b8152600401610e40906149cc565b60335461381c82426149fa565b101561383a5760405162461bcd60e51b8152600401610e4090614a21565b7ffc88a5167b8569e72b62f4b76b3caae7699e46c7f6f16a8d011b135ac613acc460155460405161386d91815260200190565b60405180910390a160008060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b142f85c6040518163ffffffff1660e01b815260040160c060405180830381865afa1580156138db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138ff9190614ad1565b506015546040516377a5a7bd60e01b8152600481018790526024810186905260448101859052606481018490526084810183905260a4810191909152949950929750909550935091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906377a5a7bd9060c401600060405180830381600087803b15801561399657600080fd5b505af11580156139aa573d6000803e3d6000fd5b5050600060168190556015555050505050505050565b6139c86147db565b600454600081116139eb5760405162461bcd60e51b8152600401610e40906149cc565b6033546139f882426149fa565b1015613a165760405162461bcd60e51b8152600401610e4090614a21565b6003546040516001600160a01b0390911681527f2682a33c437aa00b19b3e527d140e9800f735bc8fab66653e6ae22c8d07b4a909060200160405180910390a16003546040516334e2fffd60e21b81526001600160a01b0391821660048201527f00000000000000000000000000000000000000000000000000000000000000009091169063d38bfff490602401600060405180830381600087803b158015613abe57600080fd5b505af1158015613ad2573d6000803e3d6000fd5b505060006004555050600380546001600160a01b031916905550565b613af66147db565b60318190554260328190556040805183815260208101929092527f9eeb84ca445446640c66e65b8036794dd92ad3c3b9177714c8802c2644ab79e59101611215565b613b406147db565b60078190554260088190556040805183815260208101929092527f9cd90f9d45b916da6108ff464eaded2b92aa41867f12437a20b57247298086979101611215565b613b8a6147db565b60325460008111613bad5760405162461bcd60e51b8152600401610e40906149cc565b603354613bba82426149fa565b1015613bd85760405162461bcd60e51b8152600401610e4090614a21565b7f274cf9dfd48eeb8969817e347b3a2951ff7b3127772bd70827012266466ae229603154604051613c0b91815260200190565b60405180910390a160008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166388a595906040518163ffffffff1660e01b8152600401608060405180830381865afa158015613c76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c9a9190614b8b565b50603154604051635868086b60e11b8152600481018590526024810184905260448101839052606481019190915292955090935091506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063b0d010d690608401600060405180830381600087803b158015613d1e57600080fd5b505af1158015613d32573d6000803e3d6000fd5b505060006032819055603155505050505050565b613d4e6147db565b600081118015613d615750620f42408111155b613dc35760405162461bcd60e51b815260206004820152602d60248201527f43616c6c6261636b20676173206c696d6974206d757374206265203e2030206160448201526c06e64203c3d203130303030303609c1b6064820152608401610e40565b600981905542600a8190556040805183815260208101929092527f0aeac6506f5606a033c22dd1659065c5f75e5ea933fd3b49948ea79a59759b239101611215565b613e0d6147db565b60008111613e695760405162461bcd60e51b8152602060048201526024808201527f52656c617920656e74727920736f66742074696d656f7574206d7573742062656044820152630203e20360e41b6064820152608401610e40565b60058190554260068190556040805183815260208101929092527fb4c6d786da48691c308faaf332c8a4ccaa952d2145eb5798624c60548ce4b8a39101611215565b6000611006603054614835565b613ec06147db565b602a5460008111613ee35760405162461bcd60e51b8152600401610e40906149cc565b603354613ef082426149fa565b1015613f0e5760405162461bcd60e51b8152600401610e4090614a21565b7f8ad0f1f70b7c422ad8dee17b865a5118d91bc633151cdf66293f7827fea7164c602954604051613f4191815260200190565b60405180910390a160008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663529023016040518163ffffffff1660e01b8152600401608060405180830381865afa158015613fac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fd09190614b8b565b50602954604051630ce591ab60e21b8152600481018590526024810184905260448101839052606481019190915292955090935091506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063339646ac90608401600060405180830381600087803b15801561405457600080fd5b505af1158015614068573d6000803e3d6000fd5b50506000602a819055602955505050505050565b6140846147db565b602380546001600160601b0319166001600160601b0383169081179091554260248190556040805192835260208301919091527f456911403e756f0141f9a154095c7495b7002db4f6b26a7ff03c4f09335abc4b9101611215565b6140e76147db565b602e546000811161410a5760405162461bcd60e51b8152600401610e40906149cc565b60335461411782426149fa565b10156141355760405162461bcd60e51b8152600401610e4090614a21565b7f9eb4413d73f3cae81d9e8ab119d94a8d2cd6b2564117c30f2112b972dcf84f96602d5460405161416891815260200190565b60405180910390a160008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166388a595906040518163ffffffff1660e01b8152600401608060405180830381865afa1580156141d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141f79190614b8b565b602d54604051635868086b60e11b815260048101869052602481019190915260448101839052606481018290529396509094509250507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b0d010d690608401600060405180830381600087803b15801561427b57600080fd5b505af115801561428f573d6000803e3d6000fd5b50506000602e819055602d55505050505050565b6000611006600454614835565b6142b86147db565b602054600081116142db5760405162461bcd60e51b8152600401610e40906149cc565b6033546142e882426149fa565b10156143065760405162461bcd60e51b8152600401610e4090614a21565b7f3114ff9b112e2012da7dadf3d620cfd5af0546afe8cd887c052f0166fddb0004601f5460405161433991815260200190565b60405180910390a160008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663529023016040518163ffffffff1660e01b8152600401608060405180830381865afa1580156143a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143c89190614b8b565b601f54604051630ce591ab60e21b815260048101869052602481019190915260448101839052606481018290529396509094509250507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063339646ac90608401600060405180830381600087803b15801561444c57600080fd5b505af1158015614460573d6000803e3d6000fd5b505060006020819055601f55505050505050565b6000611006601c54614835565b6000611006601654614835565b6000611006602254614835565b6000611006600a54614835565b6144b06147db565b60648111156144d15760405162461bcd60e51b8152600401610e4090614b1b565b602981905542602a8190556040805183815260208101929092527f363de88db002648ead34367d7bc43c7eb86051555a3e29ff3d6ab2cd12f880569101611215565b6000611006602e54614835565b6145286147db565b6014546000811161454b5760405162461bcd60e51b8152600401610e40906149cc565b60335461455882426149fa565b10156145765760405162461bcd60e51b8152600401610e4090614a21565b7ff0db347eb933ec2636808975682b1fd63249be20775411ced58d2fd61e0fe7426013546040516145a991815260200190565b60405180910390a160008060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b142f85c6040518163ffffffff1660e01b815260040160c060405180830381865afa158015614617573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061463b9190614ad1565b6013546040516377a5a7bd60e01b815260048101889052602481018790526044810186905260648101859052608481019190915260a48101829052959a509398509196509450909250506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906377a5a7bd9060c401600060405180830381600087803b1580156146d357600080fd5b505af11580156146e7573d6000803e3d6000fd5b5050600060148190556013555050505050505050565b6147056147db565b6001600160a01b03811661476a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610e40565b6147738161488b565b50565b61477e6147db565b6025805467ffffffffffffffff191667ffffffffffffffff83169081179091554260268190556040805192835260208301919091527f98f756aaf5ba8f60be58f0b035a3a5f54bdfbc5d1ada450c235b9e500625df389101611215565b6000546001600160a01b0316331461212e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610e40565b60008082116148565760405162461bcd60e51b8152600401610e40906149cc565b600061486283426149fa565b905060335481106148765750600092915050565b8060335461488491906149fa565b9392505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000602082840312156148ed57600080fd5b5035919050565b6001600160601b038116811461477357600080fd5b60006020828403121561491b57600080fd5b8135614884816148f4565b67ffffffffffffffff8116811461477357600080fd5b60006020828403121561494e57600080fd5b813561488481614926565b80356001600160a01b038116811461497057600080fd5b919050565b60006020828403121561498757600080fd5b61488482614959565b600080604083850312156149a357600080fd5b6149ac83614959565b9150602083013580151581146149c157600080fd5b809150509250929050565b60208082526014908201527310da185b99d9481b9bdd081a5b9a5d1a585d195960621b604082015260600190565b81810381811115614a1b57634e487b7160e01b600052601160045260246000fd5b92915050565b6020808252818101527f476f7665726e616e63652064656c617920686173206e6f7420656c6170736564604082015260600190565b600080600060608486031215614a6b57600080fd5b8351614a76816148f4565b6020850151909350614a8781614926565b6040850151909250614a9881614926565b809150509250925092565b600080600060608486031215614ab857600080fd5b8351925060208401519150604084015190509250925092565b60008060008060008060c08789031215614aea57600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b60208082526014908201527304d6178696d756d2076616c7565206973203130360641b604082015260600190565b600080600060608486031215614b5e57600080fd5b8351614b69816148f4565b6020850151909350614b7a816148f4565b6040850151909250614a98816148f4565b60008060008060808587031215614ba157600080fd5b50508251602084015160408501516060909501519196909550909250905056fea2646970667358221220dbd8081e14f054632d2a93a00aa4d4b88c9783c165a4568fe3e1db029acc2e7764736f6c63430008110033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106107bb5760003560e01c80638b63cc22116103f5578063af21b29011610215578063d24521aa11610130578063e731cc53116100c3578063ee8e6e5e11610092578063ee8e6e5e14610dd5578063f0bb6ce814610dde578063f2fde38b14610de6578063fb5ccedc14610df9578063fe3bb37014610e0257600080fd5b8063e731cc5314610da9578063e79b8c4614610db1578063e8507b0614610dba578063ec9d1d9614610dcd57600080fd5b8063dde37ab8116100ff578063dde37ab814610d88578063de0ce4c914610d90578063df5ee8f614610d98578063e259b55114610da157600080fd5b8063d24521aa14610d67578063d31121de14610d6f578063d57da0b814610d77578063dbc439c714610d7f57600080fd5b8063c17a1471116101a8578063cb1ec15311610177578063cb1ec15314610d3a578063ccc5488a14610d43578063cdfaeb9814610d4b578063ce123d2814610d5457600080fd5b8063c17a147114610d03578063c1b2ba9714610d16578063c268650e14610d1f578063c97e8feb14610d3257600080fd5b8063ba5c9e7e116101e4578063ba5c9e7e14610ccc578063bba3293914610cd4578063bcc5d20414610cdd578063c16d606f14610cf057600080fd5b8063af21b29014610c94578063b0ed20bb14610c9d578063b1fae48b14610cb0578063b392e3be14610cb957600080fd5b80639de6bc9d11610310578063a72aedae116102a3578063ac21f57c11610272578063ac21f57c14610c5f578063aceb164814610c72578063ae1a332514610c7b578063ae98cbf014610c83578063aea6933914610c8c57600080fd5b8063a72aedae14610c29578063a7b9a7a014610c3c578063a955b3f314610c44578063a9b32c3d14610c5757600080fd5b8063a01bc828116102df578063a01bc82814610bfd578063a0a94bbb14610c05578063a5b9ab4d14610c0d578063a6d025f114610c1657600080fd5b80639de6bc9d14610bd05780639ec67b3114610bd85780639f40edf014610bec5780639fc3da9614610bf557600080fd5b8063914f512f11610388578063985e648711610357578063985e648714610ba55780639949d70e14610bb85780639b849b9214610bc05780639cde7da914610bc857600080fd5b8063914f512f14610b6e57806395ba105d14610b7657806396fd955e14610b7f5780639810f32714610b9257600080fd5b80638d2e0c3c116103c45780638d2e0c3c14610b395780638da5cb5b14610b425780638e0442f814610b53578063914adf8f14610b6657600080fd5b80638b63cc2214610b0e5780638bc32f3314610b215780638c5f0d6714610b295780638cdb432914610b3157600080fd5b80634885b171116105e057806364e32d74116104fb578063785180e71161048e57806382e70cb81161045d57806382e70cb814610ae4578063863b45a414610aec5780638837037714610af5578063894ee96814610afe5780638a4f77ef14610b0657600080fd5b8063785180e714610ab8578063798f022314610acb5780637ab18adf14610ad35780637b81ef5214610adc57600080fd5b8063692be745116104ca578063692be74514610a95578063715018a614610a9e578063765a783214610aa657806377bf781414610aaf57600080fd5b806364e32d7414610a54578063660f903114610a5c578063663032cd14610a6f5780636795afe614610a8257600080fd5b8063542ced771161057357806361038b911161054257806361038b9114610a2857806361d4b5ef14610a3157806362c78d0914610a39578063648392ac14610a4157600080fd5b8063542ced77146109f15780635b6bd01714610a045780635c07405614610a0c5780635f735a1014610a1f57600080fd5b80634ca107cc116105af5780634ca107cc146109c45780634cf11abc146109cd5780634ed05ade146109d557806352f1bf14146109de57600080fd5b80634885b17114610996578063488a4b261461099f578063495cb121146109a85780634b928642146109bb57600080fd5b80632d318efc116106db578063363388331161066e5780633bf8a5381161063d5780633bf8a5381461093d5780633edf74e71461096a578063412bd7b41461097d578063429cdaa814610985578063481d021f1461098e57600080fd5b8063363388331461091057806337f547901461091957806337fa5d51146109215780633b7b1b081461093457600080fd5b80632ff8aa33116106aa5780632ff8aa33146108e357806333a17f98146108f6578063345cdef5146108fe5780633611f0021461090757600080fd5b80632d318efc146108c15780632d340433146108c95780632f006f4e146108d25780632f505f1f146108db57600080fd5b80631937c64711610753578063209e80ea11610722578063209e80ea14610895578063260b5a85146108a857806326825a9d146108b15780632b702150146108b957600080fd5b80631937c6471461087257806319f1103f1461087a5780631e44a72c146108835780631ff566c71461088c57600080fd5b8063152ba58f1161078f578063152ba58f146107f8578063153622b314610800578063154028f41461083f5780631722dd291461086a57600080fd5b80626b050c146107c0578063040215af146107dc57806306201e1c146107e557806314385adb146107ef575b600080fd5b6107c960315481565b6040519081526020015b60405180910390f35b6107c9600c5481565b6107ed610e15565b005b6107c960205481565b6107c9610ff9565b6108277f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016107d3565b601b54610852906001600160601b031681565b6040516001600160601b0390911681526020016107d3565b6107ed61100b565b6107c96111c2565b6107c9601e5481565b6107c960085481565b6107c960025481565b6107ed6108a33660046148db565b6111cf565b6107c960225481565b6107ed611220565b6107c96112c4565b6107ed6112d1565b6107c9600d5481565b6107c960105481565b6107ed6114ad565b6107ed6108f13660046148db565b611686565b6107c96116f0565b6107c9602f5481565b6107c960135481565b6107c960165481565b6107c96116fd565b6107ed61092f3660046148db565b61170a565b6107c960155481565b6025546109519067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016107d3565b6107ed6109783660046148db565b611754565b6107c9611809565b6107c9600f5481565b6107ed611816565b6107c960095481565b6107c960285481565b6107ed6109b6366004614909565b6119cd565b6107c960215481565b6107c960265481565b6107ed611a30565b6107c960185481565b6107ed6109ec3660046148db565b611c0d565b6107ed6109ff3660046148db565b611cb3565b6107c9611cfd565b6107ed610a1a3660046148db565b611d0a565b6107c9602d5481565b6107c960305481565b6107c9611db2565b6107c9611dbf565b6107ed610a4f3660046148db565b611dcc565b6107ed611e16565b6107ed610a6a36600461493c565b611fe7565b6107ed610a7d366004614975565b61204c565b6107ed610a903660046148db565b6120d2565b6107c9601d5481565b6107ed61211c565b6107c960075481565b6107c960295481565b601954610852906001600160601b031681565b6107ed612130565b6107c9601a5481565b6107c961230e565b6107c961231b565b6107c960065481565b6107c960245481565b6107ed612328565b6107ed6124ed565b6107ed610b1c3660046148db565b6126be565b6107ed61276a565b6107c961292e565b6107ed61293b565b6107c9600a5481565b6000546001600160a01b0316610827565b6107ed610b613660046148db565b612b17565b6107ed612bcb565b6107c9612d8f565b6107c960015481565b602354610852906001600160601b031681565b6107ed610ba0366004614909565b612d9c565b6107ed610bb3366004614990565b612dff565b6107c9612e8e565b6107c9612e9b565b6107c9612ea8565b6107ed612eb5565b6027546109519067ffffffffffffffff1681565b6107c9601c5481565b6107ed613090565b6107c9613247565b6107ed613254565b6107c960145481565b6107ed610c243660046148db565b613425565b6107ed610c37366004614975565b61346f565b6107ed613544565b6107ed610c523660046148db565b613709565b6107c9613774565b6107ed610c6d366004614909565b613781565b6107c960045481565b6107ed6137e4565b6107c960055481565b6107ed6139c0565b6107c9602a5481565b6107ed610cab3660046148db565b613aee565b6107c9602c5481565b6107ed610cc73660046148db565b613b38565b6107ed613b82565b6107c960335481565b601754610852906001600160601b031681565b6107ed610cfe3660046148db565b613d46565b600354610827906001600160a01b031681565b6107c9602e5481565b6107ed610d2d3660046148db565b613e05565b6107c9613eab565b6107c9601f5481565b6107ed613eb8565b6107c9602b5481565b6107ed610d62366004614909565b61407c565b6107ed6140df565b6107c96142a3565b6107ed6142b0565b6107c960115481565b6107c9614474565b6107c9614481565b6107c960125481565b6107c961448e565b6107c961449b565b6107c9600e5481565b6107ed610dc83660046148db565b6144a8565b6107c9614513565b6107c9600b5481565b6107ed614520565b6107ed610df4366004614975565b6146fd565b6107c960325481565b6107ed610e1036600461493c565b614776565b610e1d6147db565b60285460008111610e495760405162461bcd60e51b8152600401610e40906149cc565b60405180910390fd5b603354610e5682426149fa565b1015610e745760405162461bcd60e51b8152600401610e4090614a21565b60275460405167ffffffffffffffff90911681527f6a7551372930a2bc4aec844a266609ca90cf9b805f875e92680e901b43d5273f9060200160405180910390a16000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637b14729e6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610f16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3a9190614a56565b506027546040516301409c5360e71b81526001600160601b038416600482015267ffffffffffffffff8084166024830152909116604482015291935091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a04e298090606401600060405180830381600087803b158015610fc657600080fd5b505af1158015610fda573d6000803e3d6000fd5b5050600060285550506027805467ffffffffffffffff19169055505050565b6000611006601454614835565b905090565b6110136147db565b600854600081116110365760405162461bcd60e51b8152600401610e40906149cc565b60335461104382426149fa565b10156110615760405162461bcd60e51b8152600401610e4090614a21565b7f1aa56185678cf82df5663d3bf97731024fc6da8f9ab832de58fe6411bb7aacad60075460405161109491815260200190565b60405180910390a16000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166374024ab76040518163ffffffff1660e01b8152600401606060405180830381865afa1580156110fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111219190614aa3565b600754604051639a7d093560e01b8152600481018590526024810191909152604481018290529294509250507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639a7d093590606401600060405180830381600087803b15801561119b57600080fd5b505af11580156111af573d6000803e3d6000fd5b5050600060088190556007555050505050565b6000611006600654614835565b6111d76147db565b601d81905542601e8190556040805183815260208101929092527f523803e7f157ab532da5ae1e1d19b71f16b18376cf65a301ef8e3f07076d6bfd91015b60405180910390a150565b6112286147db565b6002546000811161124b5760405162461bcd60e51b8152600401610e40906149cc565b60335461125882426149fa565b10156112765760405162461bcd60e51b8152600401610e4090614a21565b7f657e578b1ed229f1e01ab5ce4700399f19ddd24b09b071ab9e72122f18aa72976001546040516112a991815260200190565b60405180910390a15060018054603355600060028190559055565b6000611006601054614835565b6112d96147db565b600e54600081116112fc5760405162461bcd60e51b8152600401610e40906149cc565b60335461130982426149fa565b10156113275760405162461bcd60e51b8152600401610e4090614a21565b7fc2b1fc49f84728c2be30441ba73a73fe63ff40017b462dca6045e8b5933dfd97600d5460405161135a91815260200190565b60405180910390a160008060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b142f85c6040518163ffffffff1660e01b815260040160c060405180830381865afa1580156113c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ec9190614ad1565b600d546040516377a5a7bd60e01b815260048101889052602481019190915260448101859052606481018490526084810183905260a48101829052959a5092985090965094509250506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906377a5a7bd9060c401600060405180830381600087803b15801561148357600080fd5b505af1158015611497573d6000803e3d6000fd5b50506000600e819055600d555050505050505050565b6114b56147db565b602454600081116114d85760405162461bcd60e51b8152600401610e40906149cc565b6033546114e582426149fa565b10156115035760405162461bcd60e51b8152600401610e4090614a21565b6023546040516001600160601b0390911681527fca5de5c00e5da52e22f64b23ecfa308e487441bcbd0f4b84657799102e3ee3719060200160405180910390a16000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637b14729e6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156115a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c89190614a56565b6023546040516301409c5360e71b81526001600160601b03909116600482015267ffffffffffffffff80841660248301528216604482015291945092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316915063a04e298090606401600060405180830381600087803b15801561165457600080fd5b505af1158015611668573d6000803e3d6000fd5b505060006024555050602380546001600160601b0319169055505050565b61168e6147db565b60648111156116af5760405162461bcd60e51b8152600401610e4090614b1b565b601f81905542602081815560408051848152918201929092527f236b3b5a701c1727d0ddd01db13475e0da9be45561decb6f0d3d958c18e09e8b9101611215565b6000611006603254614835565b6000611006602054614835565b6117126147db565b60018190554260028190556040805183815260208101929092527f1ed485551399b30c188ed4d426c6c62d7b703b9fec6b486c70a3fe616c2707c89101611215565b61175c6147db565b600081116117c75760405162461bcd60e51b815260206004820152603260248201527f444b47207375626d697474657220707265636564656e636520706572696f642060448201527106c656e677468206d757374206265203e20360741b6064820152608401610e40565b60158190554260168190556040805183815260208101929092527f69f992e32ba993676818a20dfe808b5d41e0db4bdd3a52917701443500a423ca9101611215565b6000611006602c54614835565b61181e6147db565b600654600081116118415760405162461bcd60e51b8152600401610e40906149cc565b60335461184e82426149fa565b101561186c5760405162461bcd60e51b8152600401610e4090614a21565b7f63db42a2e13b78bf39d9f3c14718c3c925ccdf3e30a0477d5a7626914164620260055460405161189f91815260200190565b60405180910390a16000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166374024ab76040518163ffffffff1660e01b8152600401606060405180830381865afa158015611908573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061192c9190614aa3565b600554604051639a7d093560e01b81526004810191909152602481018390526044810182905291945092506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169150639a7d093590606401600060405180830381600087803b1580156119a657600080fd5b505af11580156119ba573d6000803e3d6000fd5b5050600060068190556005555050505050565b6119d56147db565b601980546001600160601b0319166001600160601b03831690811790915542601a8190556040805192835260208301919091527f8087387fa6bcbf89a9e273adcf21735f21e89ae8024417df321d8ccc106123089101611215565b611a386147db565b60105460008111611a5b5760405162461bcd60e51b8152600401610e40906149cc565b603354611a6882426149fa565b1015611a865760405162461bcd60e51b8152600401610e4090614a21565b7f54eb240e49fe7d2dc26863f9a2682d5834812e39417dbac77797c3b01b97395c600f54604051611ab991815260200190565b60405180910390a160008060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b142f85c6040518163ffffffff1660e01b815260040160c060405180830381865afa158015611b27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b4b9190614ad1565b600f546040516377a5a7bd60e01b815260048101889052602481018790526044810191909152606481018490526084810183905260a48101829052959a509398509096509450909250506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906377a5a7bd9060c401600060405180830381600087803b158015611be357600080fd5b505af1158015611bf7573d6000803e3d6000fd5b505060006010819055600f555050505050505050565b611c156147db565b60008111611c715760405162461bcd60e51b8152602060048201526024808201527f47726f7570206372656174696f6e206672657175656e6379206d7573742062656044820152630203e20360e41b6064820152608401610e40565b600b81905542600c8190556040805183815260208101929092527f9356f2202b7c2dd20837653ce617753f36c435d28464b7f8c4c4c174acecec3d9101611215565b611cbb6147db565b602b81905542602c8190556040805183815260208101929092527fe7f67ed355ceb941da1b6600c508f5493967c944c9fee75936aaa986b9e0344c9101611215565b6000611006601e54614835565b611d126147db565b60008111611d705760405162461bcd60e51b815260206004820152602560248201527f47726f7570206c69666574696d65206d75737420626520677265617465722074604482015264068616e20360dc1b6064820152608401610e40565b600d81905542600e8190556040805183815260208101929092527f2061f522ba42a34f2907b875dca3bf5f0d999cacbbb635e894ee3c5792727e649101611215565b6000611006602854614835565b6000611006600854614835565b611dd46147db565b602f8190554260308190556040805183815260208101929092527f6ff3903999be3f8c1262f638998917b6d6c6f8097cb7cb9e60edaa1a5f2a66719101611215565b611e1e6147db565b601c5460008111611e415760405162461bcd60e51b8152600401610e40906149cc565b603354611e4e82426149fa565b1015611e6c5760405162461bcd60e51b8152600401610e4090614a21565b601b546040516001600160601b0390911681527f13f3e65295154bda4919d5f46898c2284edbf9283ee94654515cec984e767c809060200160405180910390a16000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631d35fa636040518163ffffffff1660e01b8152600401606060405180830381865afa158015611f0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f319190614b49565b50601b54604051630519e99160e01b81526001600160601b0380851660048301528084166024830152909116604482015291935091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690630519e99190606401600060405180830381600087803b158015611fb557600080fd5b505af1158015611fc9573d6000803e3d6000fd5b50506000601c555050601b80546001600160601b0319169055505050565b611fef6147db565b6027805467ffffffffffffffff191667ffffffffffffffff83169081179091554260288190556040805192835260208301919091527f979c18cc9822195c2af34f89e0713a14edbd9713b32932c60471951cc1fa02db9101611215565b6120546147db565b60405163663032cd60e01b81526001600160a01b0382811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063663032cd90602401600060405180830381600087803b1580156120b757600080fd5b505af11580156120cb573d6000803e3d6000fd5b5050505050565b6120da6147db565b60118190554260128190556040805183815260208101929092527fff34014c09b30234094b14f309369c4b204ab5f24daa98f6922ac40a04768bf09101611215565b6121246147db565b61212e600061488b565b565b6121386147db565b6012546000811161215b5760405162461bcd60e51b8152600401610e40906149cc565b60335461216882426149fa565b10156121865760405162461bcd60e51b8152600401610e4090614a21565b7ffc489bb20492c4590e5a1edb8e096301dd7e9c24843a5af9221ddafff010f0f06011546040516121b991815260200190565b60405180910390a160008060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b142f85c6040518163ffffffff1660e01b815260040160c060405180830381865afa158015612227573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061224b9190614ad1565b6011546040516377a5a7bd60e01b815260048101889052602481018790526044810186905260648101919091526084810183905260a48101829052959a50939850919650909450909250506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906377a5a7bd9060c401600060405180830381600087803b1580156122e457600080fd5b505af11580156122f8573d6000803e3d6000fd5b5050600060128190556011555050505050505050565b6000611006602454614835565b6000611006602654614835565b6123306147db565b603054600081116123535760405162461bcd60e51b8152600401610e40906149cc565b60335461236082426149fa565b101561237e5760405162461bcd60e51b8152600401610e4090614a21565b7fc02f8fddd9d337adf38d4f97d3ab8c91b69075b48db9bc25c461b0d02c3d4092602f546040516123b191815260200190565b60405180910390a160008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166388a595906040518163ffffffff1660e01b8152600401608060405180830381865afa15801561241c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124409190614b8b565b602f54604051635868086b60e11b81526004810186905260248101859052604481019190915260648101829052939650919450909250507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b0d010d690608401600060405180830381600087803b1580156124c557600080fd5b505af11580156124d9573d6000803e3d6000fd5b505060006030819055602f55505050505050565b6124f56147db565b601a54600081116125185760405162461bcd60e51b8152600401610e40906149cc565b60335461252582426149fa565b10156125435760405162461bcd60e51b8152600401610e4090614a21565b6019546040516001600160601b0390911681527fe1adae42a74e6bb380e06f34e96abe3134e824a1a152a8e6a7458be153404d179060200160405180910390a16000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631d35fa636040518163ffffffff1660e01b8152600401606060405180830381865afa1580156125e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126089190614b49565b601954604051630519e99160e01b81526001600160601b038086166004830152918216602482015290821660448201529294509250507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690630519e99190606401600060405180830381600087803b15801561268c57600080fd5b505af11580156126a0573d6000803e3d6000fd5b50506000601a555050601980546001600160601b0319169055505050565b6126c66147db565b600081116127285760405162461bcd60e51b815260206004820152602960248201527f444b4720726573756c74207375626d697373696f6e2074696d656f7574206d7560448201526807374206265203e20360bc1b6064820152608401610e40565b60138190554260148190556040805183815260208101929092527f77bd6dceb389516c704e337d2e53bab8397e3fd1de7e3b852090742804ba13b49101611215565b6127726147db565b602c54600081116127955760405162461bcd60e51b8152600401610e40906149cc565b6033546127a282426149fa565b10156127c05760405162461bcd60e51b8152600401610e4090614a21565b7ff71bf0b76dcaef665875c3a1d4959efda6ea75c7171f5fae1bd305f7c8509283602b546040516127f391815260200190565b60405180910390a160008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166388a595906040518163ffffffff1660e01b8152600401608060405180830381865afa15801561285e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128829190614b8b565b602b54604051635868086b60e11b8152600481019190915260248101849052604481018390526064810182905292965090945092506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016915063b0d010d690608401600060405180830381600087803b15801561290657600080fd5b505af115801561291a573d6000803e3d6000fd5b50506000602c819055602b55505050505050565b6000611006601854614835565b6129436147db565b600c54600081116129665760405162461bcd60e51b8152600401610e40906149cc565b60335461297382426149fa565b10156129915760405162461bcd60e51b8152600401610e4090614a21565b7fe3daa3940e1269d029800f83e889021793ccd69dd79a7152b9171a3071eb45a3600b546040516129c491815260200190565b60405180910390a160008060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b142f85c6040518163ffffffff1660e01b815260040160c060405180830381865afa158015612a32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a569190614ad1565b600b546040516377a5a7bd60e01b815260048101919091526024810186905260448101859052606481018490526084810183905260a48101829052949a50929850909650945092506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691506377a5a7bd9060c401600060405180830381600087803b158015612aed57600080fd5b505af1158015612b01573d6000803e3d6000fd5b50506000600c819055600b555050505050505050565b612b1f6147db565b600a811015612b895760405162461bcd60e51b815260206004820152603060248201527f444b4720726573756c74206368616c6c656e676520706572696f64206c656e6760448201526f07468206d757374206265203e3d2031360841b6064820152608401610e40565b600f8190554260108190556040805183815260208101929092527f4bc54f06db7242d34e1d1cdd7b4b33807a8210c54fc440ba45e6e5ffa04e083d9101611215565b612bd36147db565b601e5460008111612bf65760405162461bcd60e51b8152600401610e40906149cc565b603354612c0382426149fa565b1015612c215760405162461bcd60e51b8152600401610e4090614a21565b7f0945b46b311d9dd20cdadf139b3449fe2e50026e619f33cabedbd7461c429076601d54604051612c5491815260200190565b60405180910390a160008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663529023016040518163ffffffff1660e01b8152600401608060405180830381865afa158015612cbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ce39190614b8b565b601d54604051630ce591ab60e21b8152600481019190915260248101849052604481018390526064810182905292965090945092506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016915063339646ac90608401600060405180830381600087803b158015612d6757600080fd5b505af1158015612d7b573d6000803e3d6000fd5b50506000601e819055601d55505050505050565b6000611006602a54614835565b612da46147db565b601b80546001600160601b0319166001600160601b03831690811790915542601c8190556040805192835260208301919091527f060327865259e01939f90eed5ad911c6e0509663b7671bccd0f6382f56aba4d39101611215565b612e076147db565b60405163985e648760e01b81526001600160a01b03838116600483015282151560248301527f0000000000000000000000000000000000000000000000000000000000000000169063985e648790604401600060405180830381600087803b158015612e7257600080fd5b505af1158015612e86573d6000803e3d6000fd5b505050505050565b6000611006601a54614835565b6000611006600c54614835565b6000611006601254614835565b612ebd6147db565b60265460008111612ee05760405162461bcd60e51b8152600401610e40906149cc565b603354612eed82426149fa565b1015612f0b5760405162461bcd60e51b8152600401610e4090614a21565b60255460405167ffffffffffffffff90911681527fcc354ece588e8fa730a65a72ebb90039caf81a2a9efedf80e8124566d42a75e89060200160405180910390a16000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637b14729e6040518163ffffffff1660e01b8152600401606060405180830381865afa158015612fad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fd19190614a56565b506025546040516301409c5360e71b81526001600160601b038416600482015267ffffffffffffffff9182166024820152908216604482015291935091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a04e298090606401600060405180830381600087803b15801561305d57600080fd5b505af1158015613071573d6000803e3d6000fd5b5050600060265550506025805467ffffffffffffffff19169055505050565b6130986147db565b600a54600081116130bb5760405162461bcd60e51b8152600401610e40906149cc565b6033546130c882426149fa565b10156130e65760405162461bcd60e51b8152600401610e4090614a21565b7f01e43c4ca2dc8df5a6c64198b1ad31e61ff7584833e5a7933892dd79d8eb905260095460405161311991815260200190565b60405180910390a16000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166374024ab76040518163ffffffff1660e01b8152600401606060405180830381865afa158015613182573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a69190614aa3565b50600954604051639a7d093560e01b81526004810184905260248101839052604481019190915291935091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639a7d093590606401600060405180830381600087803b15801561322057600080fd5b505af1158015613234573d6000803e3d6000fd5b50506000600a8190556009555050505050565b6000611006600254614835565b61325c6147db565b6018546000811161327f5760405162461bcd60e51b8152600401610e40906149cc565b60335461328c82426149fa565b10156132aa5760405162461bcd60e51b8152600401610e4090614a21565b6017546040516001600160601b0390911681527f5e7ca6fb8d090a2753e006c53b0aab79da28ab5e198b62cc105bda8f96caa6a09060200160405180910390a16000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631d35fa636040518163ffffffff1660e01b8152600401606060405180830381865afa15801561334b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061336f9190614b49565b601754604051630519e99160e01b81526001600160601b0391821660048201528184166024820152908216604482015291945092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169150630519e99190606401600060405180830381600087803b1580156133f357600080fd5b505af1158015613407573d6000803e3d6000fd5b505060006018555050601780546001600160601b0319169055505050565b61342d6147db565b602d81905542602e8190556040805183815260208101929092527f8ff92b4fa51728d3b3bebd82f5bcfa8904b0278abbce025a1e33aaf9719fdb0d9101611215565b6134776147db565b6001600160a01b0381166134e95760405162461bcd60e51b815260206004820152603360248201527f4e65772072616e646f6d20626561636f6e20676f7665726e616e636520616464604482015272726573732063616e6e6f74206265207a65726f60681b6064820152608401610e40565b600380546001600160a01b0319166001600160a01b0383169081179091554260048190556040805192835260208301919091527fcda4dd0dbaee4278532e4689e026f08f707ec8602188caa303750b225cde00789101611215565b61354c6147db565b6022546000811161356f5760405162461bcd60e51b8152600401610e40906149cc565b60335461357c82426149fa565b101561359a5760405162461bcd60e51b8152600401610e4090614a21565b7f32aac559d8ae735853362fec3c6751b37b45f12097c074ee06d51b10180c68626021546040516135cd91815260200190565b60405180910390a160008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663529023016040518163ffffffff1660e01b8152600401608060405180830381865afa158015613638573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061365c9190614b8b565b602154604051630ce591ab60e21b81526004810186905260248101859052604481019190915260648101829052939650919450909250507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063339646ac90608401600060405180830381600087803b1580156136e157600080fd5b505af11580156136f5573d6000803e3d6000fd5b505060006022819055602155505050505050565b6137116147db565b60648111156137325760405162461bcd60e51b8152600401610e4090614b1b565b60218190554260228190556040805183815260208101929092527fb62064224fade801c12ce2e348d8fff15f8e451792137664811b44b6ffe37d919101611215565b6000611006600e54614835565b6137896147db565b601780546001600160601b0319166001600160601b0383169081179091554260188190556040805192835260208301919091527fb5da59c72c3f617da3620449ee7c88d5b8a81e1f98e9f61fc62207ecab6b099f9101611215565b6137ec6147db565b6016546000811161380f5760405162461bcd60e51b8152600401610e40906149cc565b60335461381c82426149fa565b101561383a5760405162461bcd60e51b8152600401610e4090614a21565b7ffc88a5167b8569e72b62f4b76b3caae7699e46c7f6f16a8d011b135ac613acc460155460405161386d91815260200190565b60405180910390a160008060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b142f85c6040518163ffffffff1660e01b815260040160c060405180830381865afa1580156138db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138ff9190614ad1565b506015546040516377a5a7bd60e01b8152600481018790526024810186905260448101859052606481018490526084810183905260a4810191909152949950929750909550935091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906377a5a7bd9060c401600060405180830381600087803b15801561399657600080fd5b505af11580156139aa573d6000803e3d6000fd5b5050600060168190556015555050505050505050565b6139c86147db565b600454600081116139eb5760405162461bcd60e51b8152600401610e40906149cc565b6033546139f882426149fa565b1015613a165760405162461bcd60e51b8152600401610e4090614a21565b6003546040516001600160a01b0390911681527f2682a33c437aa00b19b3e527d140e9800f735bc8fab66653e6ae22c8d07b4a909060200160405180910390a16003546040516334e2fffd60e21b81526001600160a01b0391821660048201527f00000000000000000000000000000000000000000000000000000000000000009091169063d38bfff490602401600060405180830381600087803b158015613abe57600080fd5b505af1158015613ad2573d6000803e3d6000fd5b505060006004555050600380546001600160a01b031916905550565b613af66147db565b60318190554260328190556040805183815260208101929092527f9eeb84ca445446640c66e65b8036794dd92ad3c3b9177714c8802c2644ab79e59101611215565b613b406147db565b60078190554260088190556040805183815260208101929092527f9cd90f9d45b916da6108ff464eaded2b92aa41867f12437a20b57247298086979101611215565b613b8a6147db565b60325460008111613bad5760405162461bcd60e51b8152600401610e40906149cc565b603354613bba82426149fa565b1015613bd85760405162461bcd60e51b8152600401610e4090614a21565b7f274cf9dfd48eeb8969817e347b3a2951ff7b3127772bd70827012266466ae229603154604051613c0b91815260200190565b60405180910390a160008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166388a595906040518163ffffffff1660e01b8152600401608060405180830381865afa158015613c76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c9a9190614b8b565b50603154604051635868086b60e11b8152600481018590526024810184905260448101839052606481019190915292955090935091506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063b0d010d690608401600060405180830381600087803b158015613d1e57600080fd5b505af1158015613d32573d6000803e3d6000fd5b505060006032819055603155505050505050565b613d4e6147db565b600081118015613d615750620f42408111155b613dc35760405162461bcd60e51b815260206004820152602d60248201527f43616c6c6261636b20676173206c696d6974206d757374206265203e2030206160448201526c06e64203c3d203130303030303609c1b6064820152608401610e40565b600981905542600a8190556040805183815260208101929092527f0aeac6506f5606a033c22dd1659065c5f75e5ea933fd3b49948ea79a59759b239101611215565b613e0d6147db565b60008111613e695760405162461bcd60e51b8152602060048201526024808201527f52656c617920656e74727920736f66742074696d656f7574206d7573742062656044820152630203e20360e41b6064820152608401610e40565b60058190554260068190556040805183815260208101929092527fb4c6d786da48691c308faaf332c8a4ccaa952d2145eb5798624c60548ce4b8a39101611215565b6000611006603054614835565b613ec06147db565b602a5460008111613ee35760405162461bcd60e51b8152600401610e40906149cc565b603354613ef082426149fa565b1015613f0e5760405162461bcd60e51b8152600401610e4090614a21565b7f8ad0f1f70b7c422ad8dee17b865a5118d91bc633151cdf66293f7827fea7164c602954604051613f4191815260200190565b60405180910390a160008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663529023016040518163ffffffff1660e01b8152600401608060405180830381865afa158015613fac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fd09190614b8b565b50602954604051630ce591ab60e21b8152600481018590526024810184905260448101839052606481019190915292955090935091506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063339646ac90608401600060405180830381600087803b15801561405457600080fd5b505af1158015614068573d6000803e3d6000fd5b50506000602a819055602955505050505050565b6140846147db565b602380546001600160601b0319166001600160601b0383169081179091554260248190556040805192835260208301919091527f456911403e756f0141f9a154095c7495b7002db4f6b26a7ff03c4f09335abc4b9101611215565b6140e76147db565b602e546000811161410a5760405162461bcd60e51b8152600401610e40906149cc565b60335461411782426149fa565b10156141355760405162461bcd60e51b8152600401610e4090614a21565b7f9eb4413d73f3cae81d9e8ab119d94a8d2cd6b2564117c30f2112b972dcf84f96602d5460405161416891815260200190565b60405180910390a160008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166388a595906040518163ffffffff1660e01b8152600401608060405180830381865afa1580156141d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141f79190614b8b565b602d54604051635868086b60e11b815260048101869052602481019190915260448101839052606481018290529396509094509250507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b0d010d690608401600060405180830381600087803b15801561427b57600080fd5b505af115801561428f573d6000803e3d6000fd5b50506000602e819055602d55505050505050565b6000611006600454614835565b6142b86147db565b602054600081116142db5760405162461bcd60e51b8152600401610e40906149cc565b6033546142e882426149fa565b10156143065760405162461bcd60e51b8152600401610e4090614a21565b7f3114ff9b112e2012da7dadf3d620cfd5af0546afe8cd887c052f0166fddb0004601f5460405161433991815260200190565b60405180910390a160008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663529023016040518163ffffffff1660e01b8152600401608060405180830381865afa1580156143a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143c89190614b8b565b601f54604051630ce591ab60e21b815260048101869052602481019190915260448101839052606481018290529396509094509250507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063339646ac90608401600060405180830381600087803b15801561444c57600080fd5b505af1158015614460573d6000803e3d6000fd5b505060006020819055601f55505050505050565b6000611006601c54614835565b6000611006601654614835565b6000611006602254614835565b6000611006600a54614835565b6144b06147db565b60648111156144d15760405162461bcd60e51b8152600401610e4090614b1b565b602981905542602a8190556040805183815260208101929092527f363de88db002648ead34367d7bc43c7eb86051555a3e29ff3d6ab2cd12f880569101611215565b6000611006602e54614835565b6145286147db565b6014546000811161454b5760405162461bcd60e51b8152600401610e40906149cc565b60335461455882426149fa565b10156145765760405162461bcd60e51b8152600401610e4090614a21565b7ff0db347eb933ec2636808975682b1fd63249be20775411ced58d2fd61e0fe7426013546040516145a991815260200190565b60405180910390a160008060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b142f85c6040518163ffffffff1660e01b815260040160c060405180830381865afa158015614617573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061463b9190614ad1565b6013546040516377a5a7bd60e01b815260048101889052602481018790526044810186905260648101859052608481019190915260a48101829052959a509398509196509450909250506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906377a5a7bd9060c401600060405180830381600087803b1580156146d357600080fd5b505af11580156146e7573d6000803e3d6000fd5b5050600060148190556013555050505050505050565b6147056147db565b6001600160a01b03811661476a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610e40565b6147738161488b565b50565b61477e6147db565b6025805467ffffffffffffffff191667ffffffffffffffff83169081179091554260268190556040805192835260208301919091527f98f756aaf5ba8f60be58f0b035a3a5f54bdfbc5d1ada450c235b9e500625df389101611215565b6000546001600160a01b0316331461212e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610e40565b60008082116148565760405162461bcd60e51b8152600401610e40906149cc565b600061486283426149fa565b905060335481106148765750600092915050565b8060335461488491906149fa565b9392505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000602082840312156148ed57600080fd5b5035919050565b6001600160601b038116811461477357600080fd5b60006020828403121561491b57600080fd5b8135614884816148f4565b67ffffffffffffffff8116811461477357600080fd5b60006020828403121561494e57600080fd5b813561488481614926565b80356001600160a01b038116811461497057600080fd5b919050565b60006020828403121561498757600080fd5b61488482614959565b600080604083850312156149a357600080fd5b6149ac83614959565b9150602083013580151581146149c157600080fd5b809150509250929050565b60208082526014908201527310da185b99d9481b9bdd081a5b9a5d1a585d195960621b604082015260600190565b81810381811115614a1b57634e487b7160e01b600052601160045260246000fd5b92915050565b6020808252818101527f476f7665726e616e63652064656c617920686173206e6f7420656c6170736564604082015260600190565b600080600060608486031215614a6b57600080fd5b8351614a76816148f4565b6020850151909350614a8781614926565b6040850151909250614a9881614926565b809150509250925092565b600080600060608486031215614ab857600080fd5b8351925060208401519150604084015190509250925092565b60008060008060008060c08789031215614aea57600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b60208082526014908201527304d6178696d756d2076616c7565206973203130360641b604082015260600190565b600080600060608486031215614b5e57600080fd5b8351614b69816148f4565b6020850151909350614b7a816148f4565b6040850151909250614a98816148f4565b60008060008060808587031215614ba157600080fd5b50508251602084015160408501516060909501519196909550909250905056fea2646970667358221220dbd8081e14f054632d2a93a00aa4d4b88c9783c165a4568fe3e1db029acc2e7764736f6c63430008110033", + "linkReferences": {}, + "deployedLinkReferences": {}, + "devdoc": { + "kind": "dev", + "methods": { + "beginAuthorizationDecreaseChangePeriodUpdate(uint64)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newAuthorizationDecreaseChangePeriod": "New authorization decrease change period" + } + }, + "beginAuthorizationDecreaseDelayUpdate(uint64)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newAuthorizationDecreaseDelay": "New authorization decrease delay" + } + }, + "beginCallbackGasLimitUpdate(uint256)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newCallbackGasLimit": "New callback gas limit" + } + }, + "beginDkgMaliciousResultNotificationRewardMultiplierUpdate(uint256)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newDkgMaliciousResultNotificationRewardMultiplier": "New DKG malicious result notification reward multiplier." + } + }, + "beginDkgResultApprovalGasOffsetUpdate(uint256)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newDkgResultApprovalGasOffset": "New DKG approval gas offset" + } + }, + "beginDkgResultChallengeExtraGasUpdate(uint256)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newDkgResultChallengeExtraGas": "New DKG result challenge extra gas" + } + }, + "beginDkgResultChallengePeriodLengthUpdate(uint256)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newDkgResultChallengePeriodLength": "New DKG result challenge period length in blocks" + } + }, + "beginDkgResultSubmissionGasUpdate(uint256)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newDkgResultSubmissionGas": "New relay entry submission gas offset" + } + }, + "beginDkgResultSubmissionTimeoutUpdate(uint256)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newDkgResultSubmissionTimeout": "New DKG result submission timeout in blocks" + } + }, + "beginDkgSubmitterPrecedencePeriodLengthUpdate(uint256)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newDkgSubmitterPrecedencePeriodLength": "New DKG submitter precedence period length in blocks" + } + }, + "beginGovernanceDelayUpdate(uint256)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newGovernanceDelay": "New governance delay" + } + }, + "beginGroupCreationFrequencyUpdate(uint256)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newGroupCreationFrequency": "New group creation frequency" + } + }, + "beginGroupLifetimeUpdate(uint256)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newGroupLifetime": "New group lifetime in blocks" + } + }, + "beginMaliciousDkgResultSlashingAmountUpdate(uint96)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newMaliciousDkgResultSlashingAmount": "New malicious DKG result slashing amount" + } + }, + "beginMinimumAuthorizationUpdate(uint96)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newMinimumAuthorization": "New minimum authorization amount." + } + }, + "beginNotifyOperatorInactivityGasOffsetUpdate(uint256)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newNotifyOperatorInactivityGasOffset": "New operator inactivity notification gas offset" + } + }, + "beginRandomBeaconGovernanceTransfer(address)": { + "details": "Can be called only by the current contract governance." + }, + "beginRelayEntryHardTimeoutUpdate(uint256)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newRelayEntryHardTimeout": "New relay entry hard timeout in blocks" + } + }, + "beginRelayEntrySoftTimeoutUpdate(uint256)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newRelayEntrySoftTimeout": "New relay entry submission timeout in blocks" + } + }, + "beginRelayEntrySubmissionFailureSlashingAmountUpdate(uint96)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newRelayEntrySubmissionFailureSlashingAmount": "New relay entry submission failure slashing amount" + } + }, + "beginRelayEntrySubmissionGasOffsetUpdate(uint256)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newRelayEntrySubmissionGasOffset": "New relay entry submission gas offset" + } + }, + "beginRelayEntryTimeoutNotificationRewardMultiplierUpdate(uint256)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newRelayEntryTimeoutNotificationRewardMultiplier": "New relay entry timeout notification reward multiplier." + } + }, + "beginSortitionPoolRewardsBanDurationUpdate(uint256)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newSortitionPoolRewardsBanDuration": "New sortition pool rewards ban duration." + } + }, + "beginUnauthorizedSigningNotificationRewardMultiplierUpdate(uint256)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newUnauthorizedSigningNotificationRewardMultiplier": "New unauthorized signing notification reward multiplier." + } + }, + "beginUnauthorizedSigningSlashingAmountUpdate(uint96)": { + "details": "Can be called only by the contract owner.", + "params": { + "_newUnauthorizedSigningSlashingAmount": "New unauthorized signing slashing amount" + } + }, + "finalizeAuthorizationDecreaseChangePeriodUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeAuthorizationDecreaseDelayUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeCallbackGasLimitUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeDkgMaliciousResultNotificationRewardMultiplierUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeDkgResultApprovalGasOffsetUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeDkgResultChallengeExtraGasUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeDkgResultChallengePeriodLengthUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeDkgResultSubmissionGasUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeDkgResultSubmissionTimeoutUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeDkgSubmitterPrecedencePeriodLengthUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeGovernanceDelayUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeGroupCreationFrequencyUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeGroupLifetimeUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeMaliciousDkgResultSlashingAmountUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeMinimumAuthorizationUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeNotifyOperatorInactivityGasOffsetUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeRandomBeaconGovernanceTransfer()": { + "details": "Can be called only by the current contract governance, after the governance delay elapses." + }, + "finalizeRelayEntryHardTimeoutUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeRelayEntrySoftTimeoutUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeRelayEntrySubmissionFailureSlashingAmountUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeRelayEntrySubmissionGasOffsetUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeRelayEntryTimeoutNotificationRewardMultiplierUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeSortitionPoolRewardsBanDurationUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeUnauthorizedSigningNotificationRewardMultiplierUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "finalizeUnauthorizedSigningSlashingAmountUpdate()": { + "details": "Can be called only by the contract owner, after the governance delay elapses." + }, + "getRemainingAuthorizationDecreaseChangePeriodUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingAuthorizationDecreaseDelayUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingCallbackGasLimitUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingDkgMaliciousResultNotificationRewardMultiplierUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingDkgResultApprovalGasOffsetUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingDkgResultChallengeExtraGasUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingDkgResultChallengePeriodLengthUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingDkgResultSubmissionGasUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingDkgResultSubmissionTimeoutUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingDkgSubmitterPrecedencePeriodLengthUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingGovernanceDelayUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingGroupCreationFrequencyUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingGroupLifetimeUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingMaliciousDkgResultSlashingAmountUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingMimimumAuthorizationUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingNotifyOperatorInactivityGasOffsetUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingRandomBeaconGovernanceTransferDelayTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingRelayEntryHardTimeoutUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingRelayEntrySoftTimeoutUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingRelayEntrySubmissionFailureSlashingAmountUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingRelayEntrySubmissionGasOffsetUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingRelayEntryTimeoutNotificationRewardMultiplierUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingSortitionPoolRewardsBanDurationUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingUnauthorizedSigningNotificationRewardMultiplierUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "getRemainingUnauthorizedSigningSlashingAmountUpdateTime()": { + "returns": { + "_0": "Remaining time in seconds." + } + }, + "owner()": { + "details": "Returns the address of the current owner." + }, + "renounceOwnership()": { + "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner." + }, + "setRequesterAuthorization(address,bool)": { + "params": { + "isAuthorized": "True or false", + "requester": "Requester, can be a contract or EOA" + } + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." + }, + "withdrawIneligibleRewards(address)": { + "details": "Can be called only by the contract owner.", + "params": { + "recipient": "Recipient of withdrawn rewards." + } + } + }, + "title": "Keep Random Beacon Governance", + "version": 1 + }, + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract RandomBeacon\",\"name\":\"_randomBeacon\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_governanceDelay\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"authorizationDecreaseChangePeriod\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"AuthorizationDecreaseChangePeriodUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"authorizationDecreaseChangePeriod\",\"type\":\"uint64\"}],\"name\":\"AuthorizationDecreaseChangePeriodUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"authorizationDecreaseDelay\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"AuthorizationDecreaseDelayUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"authorizationDecreaseDelay\",\"type\":\"uint64\"}],\"name\":\"AuthorizationDecreaseDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"callbackGasLimit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"CallbackGasLimitUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"callbackGasLimit\",\"type\":\"uint256\"}],\"name\":\"CallbackGasLimitUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgMaliciousResultNotificationRewardMultiplier\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"DkgMaliciousResultNotificationRewardMultiplierUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgMaliciousResultNotificationRewardMultiplier\",\"type\":\"uint256\"}],\"name\":\"DkgMaliciousResultNotificationRewardMultiplierUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgResultApprovalGasOffset\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"DkgResultApprovalGasOffsetUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgResultApprovalGasOffset\",\"type\":\"uint256\"}],\"name\":\"DkgResultApprovalGasOffsetUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgResultChallengeExtraGas\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"DkgResultChallengeExtraGasUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgResultChallengeExtraGas\",\"type\":\"uint256\"}],\"name\":\"DkgResultChallengeExtraGasUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgResultChallengePeriodLength\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"DkgResultChallengePeriodLengthUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgResultChallengePeriodLength\",\"type\":\"uint256\"}],\"name\":\"DkgResultChallengePeriodLengthUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgResultSubmissionGas\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"DkgResultSubmissionGasUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgResultSubmissionGas\",\"type\":\"uint256\"}],\"name\":\"DkgResultSubmissionGasUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgResultSubmissionTimeout\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"DkgResultSubmissionTimeoutUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgResultSubmissionTimeout\",\"type\":\"uint256\"}],\"name\":\"DkgResultSubmissionTimeoutUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"submitterPrecedencePeriodLength\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"DkgSubmitterPrecedencePeriodLengthUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"submitterPrecedencePeriodLength\",\"type\":\"uint256\"}],\"name\":\"DkgSubmitterPrecedencePeriodLengthUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"governanceDelay\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"GovernanceDelayUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"governanceDelay\",\"type\":\"uint256\"}],\"name\":\"GovernanceDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"groupCreationFrequency\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"GroupCreationFrequencyUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"groupCreationFrequency\",\"type\":\"uint256\"}],\"name\":\"GroupCreationFrequencyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"groupLifetime\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"GroupLifetimeUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"groupLifetime\",\"type\":\"uint256\"}],\"name\":\"GroupLifetimeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"maliciousDkgResultSlashingAmount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"MaliciousDkgResultSlashingAmountUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"maliciousDkgResultSlashingAmount\",\"type\":\"uint96\"}],\"name\":\"MaliciousDkgResultSlashingAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"minimumAuthorization\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"MinimumAuthorizationUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"minimumAuthorization\",\"type\":\"uint96\"}],\"name\":\"MinimumAuthorizationUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"notifyOperatorInactivityGasOffset\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"NotifyOperatorInactivityGasOffsetUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"notifyOperatorInactivityGasOffset\",\"type\":\"uint256\"}],\"name\":\"NotifyOperatorInactivityGasOffsetUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newRandomBeaconGovernance\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"RandomBeaconGovernanceTransferStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newRandomBeaconGovernance\",\"type\":\"address\"}],\"name\":\"RandomBeaconGovernanceTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"relayEntryHardTimeout\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"RelayEntryHardTimeoutUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"relayEntryHardTimeout\",\"type\":\"uint256\"}],\"name\":\"RelayEntryHardTimeoutUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"relayEntrySoftTimeout\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"RelayEntrySoftTimeoutUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"relayEntrySoftTimeout\",\"type\":\"uint256\"}],\"name\":\"RelayEntrySoftTimeoutUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"relayEntrySubmissionFailureSlashingAmount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"RelayEntrySubmissionFailureSlashingAmountUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"relayEntrySubmissionFailureSlashingAmount\",\"type\":\"uint96\"}],\"name\":\"RelayEntrySubmissionFailureSlashingAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"relayEntrySubmissionGasOffset\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"RelayEntrySubmissionGasOffsetUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"relayEntrySubmissionGasOffset\",\"type\":\"uint256\"}],\"name\":\"RelayEntrySubmissionGasOffsetUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"relayEntryTimeoutNotificationRewardMultiplier\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"RelayEntryTimeoutNotificationRewardMultiplierUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"relayEntryTimeoutNotificationRewardMultiplier\",\"type\":\"uint256\"}],\"name\":\"RelayEntryTimeoutNotificationRewardMultiplierUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"sortitionPoolRewardsBanDuration\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"SortitionPoolRewardsBanDurationUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"sortitionPoolRewardsBanDuration\",\"type\":\"uint256\"}],\"name\":\"SortitionPoolRewardsBanDurationUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"unauthorizedSigningTimeoutNotificationRewardMultiplier\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"UnauthorizedSigningNotificationRewardMultiplierUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"unauthorizedSigningTimeoutNotificationRewardMultiplier\",\"type\":\"uint256\"}],\"name\":\"UnauthorizedSigningNotificationRewardMultiplierUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"unauthorizedSigningSlashingAmount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"UnauthorizedSigningSlashingAmountUpdateStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"unauthorizedSigningSlashingAmount\",\"type\":\"uint96\"}],\"name\":\"UnauthorizedSigningSlashingAmountUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"authorizationDecreaseChangePeriodChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"authorizationDecreaseDelayChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_newAuthorizationDecreaseChangePeriod\",\"type\":\"uint64\"}],\"name\":\"beginAuthorizationDecreaseChangePeriodUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_newAuthorizationDecreaseDelay\",\"type\":\"uint64\"}],\"name\":\"beginAuthorizationDecreaseDelayUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newCallbackGasLimit\",\"type\":\"uint256\"}],\"name\":\"beginCallbackGasLimitUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newDkgMaliciousResultNotificationRewardMultiplier\",\"type\":\"uint256\"}],\"name\":\"beginDkgMaliciousResultNotificationRewardMultiplierUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newDkgResultApprovalGasOffset\",\"type\":\"uint256\"}],\"name\":\"beginDkgResultApprovalGasOffsetUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newDkgResultChallengeExtraGas\",\"type\":\"uint256\"}],\"name\":\"beginDkgResultChallengeExtraGasUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newDkgResultChallengePeriodLength\",\"type\":\"uint256\"}],\"name\":\"beginDkgResultChallengePeriodLengthUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newDkgResultSubmissionGas\",\"type\":\"uint256\"}],\"name\":\"beginDkgResultSubmissionGasUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newDkgResultSubmissionTimeout\",\"type\":\"uint256\"}],\"name\":\"beginDkgResultSubmissionTimeoutUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newDkgSubmitterPrecedencePeriodLength\",\"type\":\"uint256\"}],\"name\":\"beginDkgSubmitterPrecedencePeriodLengthUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newGovernanceDelay\",\"type\":\"uint256\"}],\"name\":\"beginGovernanceDelayUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newGroupCreationFrequency\",\"type\":\"uint256\"}],\"name\":\"beginGroupCreationFrequencyUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newGroupLifetime\",\"type\":\"uint256\"}],\"name\":\"beginGroupLifetimeUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"_newMaliciousDkgResultSlashingAmount\",\"type\":\"uint96\"}],\"name\":\"beginMaliciousDkgResultSlashingAmountUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"_newMinimumAuthorization\",\"type\":\"uint96\"}],\"name\":\"beginMinimumAuthorizationUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newNotifyOperatorInactivityGasOffset\",\"type\":\"uint256\"}],\"name\":\"beginNotifyOperatorInactivityGasOffsetUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newRandomBeaconGovernance\",\"type\":\"address\"}],\"name\":\"beginRandomBeaconGovernanceTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newRelayEntryHardTimeout\",\"type\":\"uint256\"}],\"name\":\"beginRelayEntryHardTimeoutUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newRelayEntrySoftTimeout\",\"type\":\"uint256\"}],\"name\":\"beginRelayEntrySoftTimeoutUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"_newRelayEntrySubmissionFailureSlashingAmount\",\"type\":\"uint96\"}],\"name\":\"beginRelayEntrySubmissionFailureSlashingAmountUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newRelayEntrySubmissionGasOffset\",\"type\":\"uint256\"}],\"name\":\"beginRelayEntrySubmissionGasOffsetUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newRelayEntryTimeoutNotificationRewardMultiplier\",\"type\":\"uint256\"}],\"name\":\"beginRelayEntryTimeoutNotificationRewardMultiplierUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newSortitionPoolRewardsBanDuration\",\"type\":\"uint256\"}],\"name\":\"beginSortitionPoolRewardsBanDurationUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newUnauthorizedSigningNotificationRewardMultiplier\",\"type\":\"uint256\"}],\"name\":\"beginUnauthorizedSigningNotificationRewardMultiplierUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"_newUnauthorizedSigningSlashingAmount\",\"type\":\"uint96\"}],\"name\":\"beginUnauthorizedSigningSlashingAmountUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"callbackGasLimitChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dkgMaliciousResultNotificationRewardMultiplierChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dkgResultApprovalGasOffsetChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dkgResultChallengeExtraGasChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dkgResultChallengePeriodLengthChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dkgResultSubmissionGasChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dkgResultSubmissionTimeoutChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dkgSubmitterPrecedencePeriodLengthChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeAuthorizationDecreaseChangePeriodUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeAuthorizationDecreaseDelayUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeCallbackGasLimitUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeDkgMaliciousResultNotificationRewardMultiplierUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeDkgResultApprovalGasOffsetUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeDkgResultChallengeExtraGasUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeDkgResultChallengePeriodLengthUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeDkgResultSubmissionGasUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeDkgResultSubmissionTimeoutUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeDkgSubmitterPrecedencePeriodLengthUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeGovernanceDelayUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeGroupCreationFrequencyUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeGroupLifetimeUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeMaliciousDkgResultSlashingAmountUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeMinimumAuthorizationUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeNotifyOperatorInactivityGasOffsetUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeRandomBeaconGovernanceTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeRelayEntryHardTimeoutUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeRelayEntrySoftTimeoutUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeRelayEntrySubmissionFailureSlashingAmountUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeRelayEntrySubmissionGasOffsetUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeRelayEntryTimeoutNotificationRewardMultiplierUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeSortitionPoolRewardsBanDurationUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeUnauthorizedSigningNotificationRewardMultiplierUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizeUnauthorizedSigningSlashingAmountUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingAuthorizationDecreaseChangePeriodUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingAuthorizationDecreaseDelayUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingCallbackGasLimitUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingDkgMaliciousResultNotificationRewardMultiplierUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingDkgResultApprovalGasOffsetUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingDkgResultChallengeExtraGasUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingDkgResultChallengePeriodLengthUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingDkgResultSubmissionGasUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingDkgResultSubmissionTimeoutUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingDkgSubmitterPrecedencePeriodLengthUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingGovernanceDelayUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingGroupCreationFrequencyUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingGroupLifetimeUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingMaliciousDkgResultSlashingAmountUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingMimimumAuthorizationUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingNotifyOperatorInactivityGasOffsetUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingRandomBeaconGovernanceTransferDelayTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingRelayEntryHardTimeoutUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingRelayEntrySoftTimeoutUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingRelayEntrySubmissionFailureSlashingAmountUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingRelayEntrySubmissionGasOffsetUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingRelayEntryTimeoutNotificationRewardMultiplierUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingSortitionPoolRewardsBanDurationUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingUnauthorizedSigningNotificationRewardMultiplierUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRemainingUnauthorizedSigningSlashingAmountUpdateTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governanceDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governanceDelayChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"groupCreationFrequencyChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"groupLifetimeChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maliciousDkgResultSlashingAmountChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minimumAuthorizationChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newAuthorizationDecreaseChangePeriod\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newAuthorizationDecreaseDelay\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newCallbackGasLimit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newDkgMaliciousResultNotificationRewardMultiplier\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newDkgResultApprovalGasOffset\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newDkgResultChallengeExtraGas\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newDkgResultChallengePeriodLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newDkgResultSubmissionGas\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newDkgResultSubmissionTimeout\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newDkgSubmitterPrecedencePeriodLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newGovernanceDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newGroupCreationFrequency\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newGroupLifetime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newMaliciousDkgResultSlashingAmount\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newMinimumAuthorization\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newNotifyOperatorInactivityGasOffset\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newRandomBeaconGovernance\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newRelayEntryHardTimeout\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newRelayEntrySoftTimeout\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newRelayEntrySubmissionFailureSlashingAmount\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newRelayEntrySubmissionGasOffset\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newRelayEntryTimeoutNotificationRewardMultiplier\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newSortitionPoolRewardsBanDuration\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newUnauthorizedSigningNotificationRewardMultiplier\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newUnauthorizedSigningSlashingAmount\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"notifyOperatorInactivityGasOffsetChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"randomBeacon\",\"outputs\":[{\"internalType\":\"contract RandomBeacon\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"randomBeaconGovernanceTransferInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"relayEntryHardTimeoutChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"relayEntrySoftTimeoutChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"relayEntrySubmissionFailureSlashingAmountChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"relayEntrySubmissionGasOffsetChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"relayEntryTimeoutNotificationRewardMultiplierChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"isAuthorized\",\"type\":\"bool\"}],\"name\":\"setRequesterAuthorization\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sortitionPoolRewardsBanDurationChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unauthorizedSigningNotificationRewardMultiplierChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unauthorizedSigningSlashingAmountChangeInitiated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"withdrawIneligibleRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"beginAuthorizationDecreaseChangePeriodUpdate(uint64)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newAuthorizationDecreaseChangePeriod\":\"New authorization decrease change period\"}},\"beginAuthorizationDecreaseDelayUpdate(uint64)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newAuthorizationDecreaseDelay\":\"New authorization decrease delay\"}},\"beginCallbackGasLimitUpdate(uint256)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newCallbackGasLimit\":\"New callback gas limit\"}},\"beginDkgMaliciousResultNotificationRewardMultiplierUpdate(uint256)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newDkgMaliciousResultNotificationRewardMultiplier\":\"New DKG malicious result notification reward multiplier.\"}},\"beginDkgResultApprovalGasOffsetUpdate(uint256)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newDkgResultApprovalGasOffset\":\"New DKG approval gas offset\"}},\"beginDkgResultChallengeExtraGasUpdate(uint256)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newDkgResultChallengeExtraGas\":\"New DKG result challenge extra gas\"}},\"beginDkgResultChallengePeriodLengthUpdate(uint256)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newDkgResultChallengePeriodLength\":\"New DKG result challenge period length in blocks\"}},\"beginDkgResultSubmissionGasUpdate(uint256)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newDkgResultSubmissionGas\":\"New relay entry submission gas offset\"}},\"beginDkgResultSubmissionTimeoutUpdate(uint256)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newDkgResultSubmissionTimeout\":\"New DKG result submission timeout in blocks\"}},\"beginDkgSubmitterPrecedencePeriodLengthUpdate(uint256)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newDkgSubmitterPrecedencePeriodLength\":\"New DKG submitter precedence period length in blocks\"}},\"beginGovernanceDelayUpdate(uint256)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newGovernanceDelay\":\"New governance delay\"}},\"beginGroupCreationFrequencyUpdate(uint256)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newGroupCreationFrequency\":\"New group creation frequency\"}},\"beginGroupLifetimeUpdate(uint256)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newGroupLifetime\":\"New group lifetime in blocks\"}},\"beginMaliciousDkgResultSlashingAmountUpdate(uint96)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newMaliciousDkgResultSlashingAmount\":\"New malicious DKG result slashing amount\"}},\"beginMinimumAuthorizationUpdate(uint96)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newMinimumAuthorization\":\"New minimum authorization amount.\"}},\"beginNotifyOperatorInactivityGasOffsetUpdate(uint256)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newNotifyOperatorInactivityGasOffset\":\"New operator inactivity notification gas offset\"}},\"beginRandomBeaconGovernanceTransfer(address)\":{\"details\":\"Can be called only by the current contract governance.\"},\"beginRelayEntryHardTimeoutUpdate(uint256)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newRelayEntryHardTimeout\":\"New relay entry hard timeout in blocks\"}},\"beginRelayEntrySoftTimeoutUpdate(uint256)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newRelayEntrySoftTimeout\":\"New relay entry submission timeout in blocks\"}},\"beginRelayEntrySubmissionFailureSlashingAmountUpdate(uint96)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newRelayEntrySubmissionFailureSlashingAmount\":\"New relay entry submission failure slashing amount\"}},\"beginRelayEntrySubmissionGasOffsetUpdate(uint256)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newRelayEntrySubmissionGasOffset\":\"New relay entry submission gas offset\"}},\"beginRelayEntryTimeoutNotificationRewardMultiplierUpdate(uint256)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newRelayEntryTimeoutNotificationRewardMultiplier\":\"New relay entry timeout notification reward multiplier.\"}},\"beginSortitionPoolRewardsBanDurationUpdate(uint256)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newSortitionPoolRewardsBanDuration\":\"New sortition pool rewards ban duration.\"}},\"beginUnauthorizedSigningNotificationRewardMultiplierUpdate(uint256)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newUnauthorizedSigningNotificationRewardMultiplier\":\"New unauthorized signing notification reward multiplier.\"}},\"beginUnauthorizedSigningSlashingAmountUpdate(uint96)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"_newUnauthorizedSigningSlashingAmount\":\"New unauthorized signing slashing amount\"}},\"finalizeAuthorizationDecreaseChangePeriodUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeAuthorizationDecreaseDelayUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeCallbackGasLimitUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeDkgMaliciousResultNotificationRewardMultiplierUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeDkgResultApprovalGasOffsetUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeDkgResultChallengeExtraGasUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeDkgResultChallengePeriodLengthUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeDkgResultSubmissionGasUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeDkgResultSubmissionTimeoutUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeDkgSubmitterPrecedencePeriodLengthUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeGovernanceDelayUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeGroupCreationFrequencyUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeGroupLifetimeUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeMaliciousDkgResultSlashingAmountUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeMinimumAuthorizationUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeNotifyOperatorInactivityGasOffsetUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeRandomBeaconGovernanceTransfer()\":{\"details\":\"Can be called only by the current contract governance, after the governance delay elapses.\"},\"finalizeRelayEntryHardTimeoutUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeRelayEntrySoftTimeoutUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeRelayEntrySubmissionFailureSlashingAmountUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeRelayEntrySubmissionGasOffsetUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeRelayEntryTimeoutNotificationRewardMultiplierUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeSortitionPoolRewardsBanDurationUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeUnauthorizedSigningNotificationRewardMultiplierUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"finalizeUnauthorizedSigningSlashingAmountUpdate()\":{\"details\":\"Can be called only by the contract owner, after the governance delay elapses.\"},\"getRemainingAuthorizationDecreaseChangePeriodUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingAuthorizationDecreaseDelayUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingCallbackGasLimitUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingDkgMaliciousResultNotificationRewardMultiplierUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingDkgResultApprovalGasOffsetUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingDkgResultChallengeExtraGasUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingDkgResultChallengePeriodLengthUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingDkgResultSubmissionGasUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingDkgResultSubmissionTimeoutUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingDkgSubmitterPrecedencePeriodLengthUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingGovernanceDelayUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingGroupCreationFrequencyUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingGroupLifetimeUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingMaliciousDkgResultSlashingAmountUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingMimimumAuthorizationUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingNotifyOperatorInactivityGasOffsetUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingRandomBeaconGovernanceTransferDelayTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingRelayEntryHardTimeoutUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingRelayEntrySoftTimeoutUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingRelayEntrySubmissionFailureSlashingAmountUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingRelayEntrySubmissionGasOffsetUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingRelayEntryTimeoutNotificationRewardMultiplierUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingSortitionPoolRewardsBanDurationUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingUnauthorizedSigningNotificationRewardMultiplierUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"getRemainingUnauthorizedSigningSlashingAmountUpdateTime()\":{\"returns\":{\"_0\":\"Remaining time in seconds.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setRequesterAuthorization(address,bool)\":{\"params\":{\"isAuthorized\":\"True or false\",\"requester\":\"Requester, can be a contract or EOA\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"withdrawIneligibleRewards(address)\":{\"details\":\"Can be called only by the contract owner.\",\"params\":{\"recipient\":\"Recipient of withdrawn rewards.\"}}},\"title\":\"Keep Random Beacon Governance\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"beginAuthorizationDecreaseChangePeriodUpdate(uint64)\":{\"notice\":\"Begins the authorization decrease change period update process.\"},\"beginAuthorizationDecreaseDelayUpdate(uint64)\":{\"notice\":\"Begins the authorization decrease delay update process.\"},\"beginCallbackGasLimitUpdate(uint256)\":{\"notice\":\"Begins the callback gas limit update process.\"},\"beginDkgMaliciousResultNotificationRewardMultiplierUpdate(uint256)\":{\"notice\":\"Begins the DKG malicious result notification reward multiplier update process.\"},\"beginDkgResultApprovalGasOffsetUpdate(uint256)\":{\"notice\":\"Begins the DKG result approval gas offset update process.\"},\"beginDkgResultChallengeExtraGasUpdate(uint256)\":{\"notice\":\"Begins the DKG result challenge extra gas update process.\"},\"beginDkgResultChallengePeriodLengthUpdate(uint256)\":{\"notice\":\"Begins the DKG result challenge period length update process.\"},\"beginDkgResultSubmissionGasUpdate(uint256)\":{\"notice\":\"Begins the DKG result submission gas update process.\"},\"beginDkgResultSubmissionTimeoutUpdate(uint256)\":{\"notice\":\"Begins the DKG result submission timeout update process.\"},\"beginDkgSubmitterPrecedencePeriodLengthUpdate(uint256)\":{\"notice\":\"Begins the DKG submitter precedence period length.\"},\"beginGovernanceDelayUpdate(uint256)\":{\"notice\":\"Begins the governance delay update process.\"},\"beginGroupCreationFrequencyUpdate(uint256)\":{\"notice\":\"Begins the group creation frequency update process.\"},\"beginGroupLifetimeUpdate(uint256)\":{\"notice\":\"Begins the group lifetime update process. Group lifetime needs to be shorter than the authorization decrease delay to ensure every active group is backed by enough stake. A new group lifetime value is in blocks and has to be calculated based on the average block time and authorization decrease delay which value is in seconds.\"},\"beginMaliciousDkgResultSlashingAmountUpdate(uint96)\":{\"notice\":\"Begins the malicious DKG result slashing amount update process.\"},\"beginMinimumAuthorizationUpdate(uint96)\":{\"notice\":\"Begins the minimum authorization amount update process.\"},\"beginNotifyOperatorInactivityGasOffsetUpdate(uint256)\":{\"notice\":\"Begins the notify operator inactivity gas offset update process.\"},\"beginRandomBeaconGovernanceTransfer(address)\":{\"notice\":\"Begins the random beacon governance transfer process.\"},\"beginRelayEntryHardTimeoutUpdate(uint256)\":{\"notice\":\"Begins the relay entry hard timeout update process.\"},\"beginRelayEntrySoftTimeoutUpdate(uint256)\":{\"notice\":\"Begins the relay entry soft timeout update process.\"},\"beginRelayEntrySubmissionFailureSlashingAmountUpdate(uint96)\":{\"notice\":\"Begins the relay entry submission failure slashing amount update process.\"},\"beginRelayEntrySubmissionGasOffsetUpdate(uint256)\":{\"notice\":\"Begins the relay entry submission gas offset update process.\"},\"beginRelayEntryTimeoutNotificationRewardMultiplierUpdate(uint256)\":{\"notice\":\"Begins the relay entry timeout notification reward multiplier update process.\"},\"beginSortitionPoolRewardsBanDurationUpdate(uint256)\":{\"notice\":\"Begins the sortition pool rewards ban duration update process.\"},\"beginUnauthorizedSigningNotificationRewardMultiplierUpdate(uint256)\":{\"notice\":\"Begins the unauthorized signing notification reward multiplier update process.\"},\"beginUnauthorizedSigningSlashingAmountUpdate(uint96)\":{\"notice\":\"Begins the unauthorized signing slashing amount update process.\"},\"finalizeAuthorizationDecreaseChangePeriodUpdate()\":{\"notice\":\"Finalizes the authorization decrease change period update process.\"},\"finalizeAuthorizationDecreaseDelayUpdate()\":{\"notice\":\"Finalizes the authorization decrease delay update process.\"},\"finalizeCallbackGasLimitUpdate()\":{\"notice\":\"Finalizes the callback gas limit update process.\"},\"finalizeDkgMaliciousResultNotificationRewardMultiplierUpdate()\":{\"notice\":\"Finalizes the DKG malicious result notification reward multiplier update process.\"},\"finalizeDkgResultApprovalGasOffsetUpdate()\":{\"notice\":\"Finalizes the DKG result approval gas offset update process.\"},\"finalizeDkgResultChallengeExtraGasUpdate()\":{\"notice\":\"Finalizes the DKG result challenge extra gas update process.\"},\"finalizeDkgResultChallengePeriodLengthUpdate()\":{\"notice\":\"Finalizes the DKG result challenge period length update process.\"},\"finalizeDkgResultSubmissionGasUpdate()\":{\"notice\":\"Finalizes DKG result submission gas update process.\"},\"finalizeDkgResultSubmissionTimeoutUpdate()\":{\"notice\":\"Finalizes the DKG result submission timeout update process.\"},\"finalizeDkgSubmitterPrecedencePeriodLengthUpdate()\":{\"notice\":\"Finalizes the DKG submitter precedence period length.\"},\"finalizeGovernanceDelayUpdate()\":{\"notice\":\"Finalizes the governance delay update process.\"},\"finalizeGroupCreationFrequencyUpdate()\":{\"notice\":\"Finalizes the group creation frequency update process.\"},\"finalizeGroupLifetimeUpdate()\":{\"notice\":\"Finalizes the group creation frequency update process.\"},\"finalizeMaliciousDkgResultSlashingAmountUpdate()\":{\"notice\":\"Finalizes the malicious DKG result slashing amount update process.\"},\"finalizeMinimumAuthorizationUpdate()\":{\"notice\":\"Finalizes the minimum authorization amount update process.\"},\"finalizeNotifyOperatorInactivityGasOffsetUpdate()\":{\"notice\":\"Finalizes the notify operator inactivity gas offset update process.\"},\"finalizeRandomBeaconGovernanceTransfer()\":{\"notice\":\"Finalizes the random beacon governance transfer process.\"},\"finalizeRelayEntryHardTimeoutUpdate()\":{\"notice\":\"Finalizes the relay entry hard timeout update process.\"},\"finalizeRelayEntrySoftTimeoutUpdate()\":{\"notice\":\"Finalizes the relay entry soft timeout update process.\"},\"finalizeRelayEntrySubmissionFailureSlashingAmountUpdate()\":{\"notice\":\"Finalizes the relay entry submission failure slashing amount update process.\"},\"finalizeRelayEntrySubmissionGasOffsetUpdate()\":{\"notice\":\"Finalizes relay entry submission gas offset update process.\"},\"finalizeRelayEntryTimeoutNotificationRewardMultiplierUpdate()\":{\"notice\":\"Finalizes the relay entry timeout notification reward multiplier update process.\"},\"finalizeSortitionPoolRewardsBanDurationUpdate()\":{\"notice\":\"Finalizes the sortition pool rewards ban duration update process.\"},\"finalizeUnauthorizedSigningNotificationRewardMultiplierUpdate()\":{\"notice\":\"Finalizes the unauthorized signing notification reward multiplier update process.\"},\"finalizeUnauthorizedSigningSlashingAmountUpdate()\":{\"notice\":\"Finalizes the unauthorized signing slashing amount update process.\"},\"getRemainingAuthorizationDecreaseChangePeriodUpdateTime()\":{\"notice\":\"Get the time remaining until the authorization decrease change period can be updated.\"},\"getRemainingAuthorizationDecreaseDelayUpdateTime()\":{\"notice\":\"Get the time remaining until the authorization decrease delay can be updated.\"},\"getRemainingCallbackGasLimitUpdateTime()\":{\"notice\":\"Get the time remaining until the callback gas limit can be updated.\"},\"getRemainingDkgMaliciousResultNotificationRewardMultiplierUpdateTime()\":{\"notice\":\"Get the time remaining until the DKG malicious result notification reward multiplier duration can be updated.\"},\"getRemainingDkgResultApprovalGasOffsetUpdateTime()\":{\"notice\":\"Get the time remaining until the DKG approval gas offset duration can be updated.\"},\"getRemainingDkgResultChallengeExtraGasUpdateTime()\":{\"notice\":\"Get the time remaining until the DKG result challenge extra gas can be updated.\"},\"getRemainingDkgResultChallengePeriodLengthUpdateTime()\":{\"notice\":\"Get the time remaining until the DKG result challenge period length can be updated.\"},\"getRemainingDkgResultSubmissionGasUpdateTime()\":{\"notice\":\"Get the time remaining until the DKG result submission gas duration can be updated.\"},\"getRemainingDkgResultSubmissionTimeoutUpdateTime()\":{\"notice\":\"Get the time remaining until the DKG result submission timeout can be updated.\"},\"getRemainingDkgSubmitterPrecedencePeriodLengthUpdateTime()\":{\"notice\":\"Get the time remaining until the wallet owner can be updated.\"},\"getRemainingGovernanceDelayUpdateTime()\":{\"notice\":\"Get the time remaining until the governance delay can be updated.\"},\"getRemainingGroupCreationFrequencyUpdateTime()\":{\"notice\":\"Get the time remaining until the group creation frequency can be updated.\"},\"getRemainingGroupLifetimeUpdateTime()\":{\"notice\":\"Get the time remaining until the group lifetime can be updated.\"},\"getRemainingMaliciousDkgResultSlashingAmountUpdateTime()\":{\"notice\":\"Get the time remaining until the malicious DKG result slashing amount can be updated.\"},\"getRemainingMimimumAuthorizationUpdateTime()\":{\"notice\":\"Get the time remaining until the minimum authorization amount can be updated.\"},\"getRemainingNotifyOperatorInactivityGasOffsetUpdateTime()\":{\"notice\":\"Get the time remaining until the operator inactivity notification gas offset duration can be updated.\"},\"getRemainingRandomBeaconGovernanceTransferDelayTime()\":{\"notice\":\"Get the time remaining until the random beacon governance can be transferred.\"},\"getRemainingRelayEntryHardTimeoutUpdateTime()\":{\"notice\":\"Get the time remaining until the relay entry hard timeout can be updated.\"},\"getRemainingRelayEntrySoftTimeoutUpdateTime()\":{\"notice\":\"Get the time remaining until the relay entry submission soft timeout can be updated.\"},\"getRemainingRelayEntrySubmissionFailureSlashingAmountUpdateTime()\":{\"notice\":\"Get the time remaining until the relay entry submission failure slashing amount can be updated.\"},\"getRemainingRelayEntrySubmissionGasOffsetUpdateTime()\":{\"notice\":\"Get the time remaining until the relay entry submission gas offset duration can be updated.\"},\"getRemainingRelayEntryTimeoutNotificationRewardMultiplierUpdateTime()\":{\"notice\":\"Get the time remaining until the relay entry timeout notification reward multiplier duration can be updated.\"},\"getRemainingSortitionPoolRewardsBanDurationUpdateTime()\":{\"notice\":\"Get the time remaining until the sortition pool rewards ban duration can be updated.\"},\"getRemainingUnauthorizedSigningNotificationRewardMultiplierUpdateTime()\":{\"notice\":\"Get the time remaining until the unauthorized signing notification reward multiplier duration can be updated.\"},\"getRemainingUnauthorizedSigningSlashingAmountUpdateTime()\":{\"notice\":\"Get the time remaining until the unauthorized signing slashing amount can be updated.\"},\"setRequesterAuthorization(address,bool)\":{\"notice\":\"Set authorization for requesters that can request a relay entry. It can be done by the governance only.\"},\"withdrawIneligibleRewards(address)\":{\"notice\":\"Withdraws rewards belonging to operators marked as ineligible for sortition pool rewards.\"}},\"notice\":\"Owns the `RandomBeacon` contract and is responsible for updating its governable parameters in respect to governance delay individual for each parameter.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/RandomBeaconGovernance.sol\":\"RandomBeaconGovernance\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@keep-network/sortition-pools/contracts/Branch.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\n/// @notice The implicit 8-ary trees of the sortition pool\\n/// rely on packing 8 \\\"slots\\\" of 32-bit values into each uint256.\\n/// The Branch library permits efficient calculations on these slots.\\nlibrary Branch {\\n /// @notice Calculate the right shift required\\n /// to make the 32 least significant bits of an uint256\\n /// be the bits of the `position`th slot\\n /// when treating the uint256 as a uint32[8].\\n ///\\n /// @dev Not used for efficiency reasons,\\n /// but left to illustrate the meaning of a common pattern.\\n /// I wish solidity had macros, even C macros.\\n function slotShift(uint256 position) internal pure returns (uint256) {\\n unchecked {\\n return position * Constants.SLOT_WIDTH;\\n }\\n }\\n\\n /// @notice Return the `position`th slot of the `node`,\\n /// treating `node` as a uint32[32].\\n function getSlot(uint256 node, uint256 position)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Doing a bitwise AND with `SLOT_MAX`\\n // clears all but the 32 least significant bits.\\n // Because of the right shift by `slotShift(position)` bits,\\n // those 32 bits contain the 32 bits in the `position`th slot of `node`.\\n return (node >> shiftBits) & Constants.SLOT_MAX;\\n }\\n }\\n\\n /// @notice Return `node` with the `position`th slot set to zero.\\n function clearSlot(uint256 node, uint256 position)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Shifting `SLOT_MAX` left by `slotShift(position)` bits\\n // gives us a number where all bits of the `position`th slot are set,\\n // and all other bits are unset.\\n //\\n // Using a bitwise NOT on this number,\\n // we get a uint256 where all bits are set\\n // except for those of the `position`th slot.\\n //\\n // Bitwise ANDing the original `node` with this number\\n // sets the bits of `position`th slot to zero,\\n // leaving all other bits unchanged.\\n return node & ~(Constants.SLOT_MAX << shiftBits);\\n }\\n }\\n\\n /// @notice Return `node` with the `position`th slot set to `weight`.\\n ///\\n /// @param weight The weight of of the node.\\n /// Safely truncated to a 32-bit number,\\n /// but this should never be called with an overflowing weight regardless.\\n function setSlot(\\n uint256 node,\\n uint256 position,\\n uint256 weight\\n ) internal pure returns (uint256) {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Clear the `position`th slot like in `clearSlot()`.\\n uint256 clearedNode = node & ~(Constants.SLOT_MAX << shiftBits);\\n // Bitwise AND `weight` with `SLOT_MAX`\\n // to clear all but the 32 least significant bits.\\n //\\n // Shift this left by `slotShift(position)` bits\\n // to obtain a uint256 with all bits unset\\n // except in the `position`th slot\\n // which contains the 32-bit value of `weight`.\\n uint256 shiftedWeight = (weight & Constants.SLOT_MAX) << shiftBits;\\n // When we bitwise OR these together,\\n // all other slots except the `position`th one come from the left argument,\\n // and the `position`th gets filled with `weight` from the right argument.\\n return clearedNode | shiftedWeight;\\n }\\n }\\n\\n /// @notice Calculate the summed weight of all slots in the `node`.\\n function sumWeight(uint256 node) internal pure returns (uint256 sum) {\\n unchecked {\\n sum = node & Constants.SLOT_MAX;\\n // Iterate through each slot\\n // by shifting `node` right in increments of 32 bits,\\n // and adding the 32 least significant bits to the `sum`.\\n uint256 newNode = node >> Constants.SLOT_WIDTH;\\n while (newNode > 0) {\\n sum += (newNode & Constants.SLOT_MAX);\\n newNode = newNode >> Constants.SLOT_WIDTH;\\n }\\n return sum;\\n }\\n }\\n\\n /// @notice Pick a slot in `node` that corresponds to `index`.\\n /// Treats the node like an array of virtual stakers,\\n /// the number of virtual stakers in each slot corresponding to its weight,\\n /// and picks which slot contains the `index`th virtual staker.\\n ///\\n /// @dev Requires that `index` be lower than `sumWeight(node)`.\\n /// However, this is not enforced for performance reasons.\\n /// If `index` exceeds the permitted range,\\n /// `pickWeightedSlot()` returns the rightmost slot\\n /// and an excessively high `newIndex`.\\n ///\\n /// @return slot The slot of `node` containing the `index`th virtual staker.\\n ///\\n /// @return newIndex The index of the `index`th virtual staker of `node`\\n /// within the returned slot.\\n function pickWeightedSlot(uint256 node, uint256 index)\\n internal\\n pure\\n returns (uint256 slot, uint256 newIndex)\\n {\\n unchecked {\\n newIndex = index;\\n uint256 newNode = node;\\n uint256 currentSlotWeight = newNode & Constants.SLOT_MAX;\\n while (newIndex >= currentSlotWeight) {\\n newIndex -= currentSlotWeight;\\n slot++;\\n newNode = newNode >> Constants.SLOT_WIDTH;\\n currentSlotWeight = newNode & Constants.SLOT_MAX;\\n }\\n return (slot, newIndex);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa7fb1c9c9789f30493e9a40e24a24f46875dc5e7630b4f67478167759f6d1882\"},\"@keep-network/sortition-pools/contracts/Chaosnet.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\n/// @title Chaosnet\\n/// @notice This is a beta staker program for stakers willing to go the extra\\n/// mile with monitoring, share their logs with the dev team, and allow to more\\n/// carefully monitor the bootstrapping network. As the network matures, the\\n/// beta program will be ended.\\ncontract Chaosnet {\\n /// @notice Indicates if the chaosnet is active. The chaosnet is active\\n /// after the contract deployment and can be ended with a call to\\n /// `deactivateChaosnet()`. Once deactivated chaosnet can not be activated\\n /// again.\\n bool public isChaosnetActive;\\n\\n /// @notice Indicates if the given operator is a beta operator for chaosnet.\\n mapping(address => bool) public isBetaOperator;\\n\\n /// @notice Address controlling chaosnet status and beta operator addresses.\\n address public chaosnetOwner;\\n\\n event BetaOperatorsAdded(address[] operators);\\n\\n event ChaosnetOwnerRoleTransferred(\\n address oldChaosnetOwner,\\n address newChaosnetOwner\\n );\\n\\n event ChaosnetDeactivated();\\n\\n constructor() {\\n _transferChaosnetOwner(msg.sender);\\n isChaosnetActive = true;\\n }\\n\\n modifier onlyChaosnetOwner() {\\n require(msg.sender == chaosnetOwner, \\\"Not the chaosnet owner\\\");\\n _;\\n }\\n\\n modifier onlyOnChaosnet() {\\n require(isChaosnetActive, \\\"Chaosnet is not active\\\");\\n _;\\n }\\n\\n /// @notice Adds beta operator to chaosnet. Can be called only by the\\n /// chaosnet owner when the chaosnet is active. Once the operator is added\\n /// as a beta operator, it can not be removed.\\n function addBetaOperators(address[] calldata operators)\\n public\\n onlyOnChaosnet\\n onlyChaosnetOwner\\n {\\n for (uint256 i = 0; i < operators.length; i++) {\\n isBetaOperator[operators[i]] = true;\\n }\\n\\n emit BetaOperatorsAdded(operators);\\n }\\n\\n /// @notice Deactivates the chaosnet. Can be called only by the chaosnet\\n /// owner. Once deactivated chaosnet can not be activated again.\\n function deactivateChaosnet() public onlyOnChaosnet onlyChaosnetOwner {\\n isChaosnetActive = false;\\n emit ChaosnetDeactivated();\\n }\\n\\n /// @notice Transfers the chaosnet owner role to another non-zero address.\\n function transferChaosnetOwnerRole(address newChaosnetOwner)\\n public\\n onlyChaosnetOwner\\n {\\n require(\\n newChaosnetOwner != address(0),\\n \\\"New chaosnet owner must not be zero address\\\"\\n );\\n _transferChaosnetOwner(newChaosnetOwner);\\n }\\n\\n function _transferChaosnetOwner(address newChaosnetOwner) internal {\\n address oldChaosnetOwner = chaosnetOwner;\\n chaosnetOwner = newChaosnetOwner;\\n emit ChaosnetOwnerRoleTransferred(oldChaosnetOwner, newChaosnetOwner);\\n }\\n}\\n\",\"keccak256\":\"0xeaf7bdd5626f88c329793a012621039692ce1b6e1f13013997ddb13d7e3032df\"},\"@keep-network/sortition-pools/contracts/Constants.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nlibrary Constants {\\n ////////////////////////////////////////////////////////////////////////////\\n // Parameters for configuration\\n\\n // How many bits a position uses per level of the tree;\\n // each branch of the tree contains 2**SLOT_BITS slots.\\n uint256 constant SLOT_BITS = 3;\\n uint256 constant LEVELS = 7;\\n ////////////////////////////////////////////////////////////////////////////\\n\\n ////////////////////////////////////////////////////////////////////////////\\n // Derived constants, do not touch\\n uint256 constant SLOT_COUNT = 2**SLOT_BITS;\\n uint256 constant SLOT_WIDTH = 256 / SLOT_COUNT;\\n uint256 constant LAST_SLOT = SLOT_COUNT - 1;\\n uint256 constant SLOT_MAX = (2**SLOT_WIDTH) - 1;\\n uint256 constant POOL_CAPACITY = SLOT_COUNT**LEVELS;\\n\\n uint256 constant ID_WIDTH = SLOT_WIDTH;\\n uint256 constant ID_MAX = SLOT_MAX;\\n\\n uint256 constant BLOCKHEIGHT_WIDTH = 96 - ID_WIDTH;\\n uint256 constant BLOCKHEIGHT_MAX = (2**BLOCKHEIGHT_WIDTH) - 1;\\n\\n uint256 constant SLOT_POINTER_MAX = (2**SLOT_BITS) - 1;\\n uint256 constant LEAF_FLAG = 1 << 255;\\n\\n uint256 constant WEIGHT_WIDTH = 256 / SLOT_COUNT;\\n ////////////////////////////////////////////////////////////////////////////\\n}\\n\",\"keccak256\":\"0xaef690ced707935745ff1482b7bb9bd9eb77bf6a39c717465e64cf12db8a7d39\"},\"@keep-network/sortition-pools/contracts/Leaf.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary Leaf {\\n function make(\\n address _operator,\\n uint256 _creationBlock,\\n uint256 _id\\n ) internal pure returns (uint256) {\\n assert(_creationBlock <= type(uint64).max);\\n assert(_id <= type(uint32).max);\\n // Converting a bytesX type into a larger type\\n // adds zero bytes on the right.\\n uint256 op = uint256(bytes32(bytes20(_operator)));\\n // Bitwise AND the id to erase\\n // all but the 32 least significant bits\\n uint256 uid = _id & Constants.ID_MAX;\\n // Erase all but the 64 least significant bits,\\n // then shift left by 32 bits to make room for the id\\n uint256 cb = (_creationBlock & Constants.BLOCKHEIGHT_MAX) <<\\n Constants.ID_WIDTH;\\n // Bitwise OR them all together to get\\n // [address operator || uint64 creationBlock || uint32 id]\\n return (op | cb | uid);\\n }\\n\\n function operator(uint256 leaf) internal pure returns (address) {\\n // Converting a bytesX type into a smaller type\\n // truncates it on the right.\\n return address(bytes20(bytes32(leaf)));\\n }\\n\\n /// @notice Return the block number the leaf was created in.\\n function creationBlock(uint256 leaf) internal pure returns (uint256) {\\n return ((leaf >> Constants.ID_WIDTH) & Constants.BLOCKHEIGHT_MAX);\\n }\\n\\n function id(uint256 leaf) internal pure returns (uint32) {\\n // Id is stored in the 32 least significant bits.\\n // Bitwise AND ensures that we only get the contents of those bits.\\n return uint32(leaf & Constants.ID_MAX);\\n }\\n}\\n\",\"keccak256\":\"0xbd107a1a43e48884885e5e966ffcbcd8fa5e89863715d717bb4006e9f89cdc2b\"},\"@keep-network/sortition-pools/contracts/Position.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary Position {\\n // Return the last 3 bits of a position number,\\n // corresponding to its slot in its parent\\n function slot(uint256 a) internal pure returns (uint256) {\\n return a & Constants.SLOT_POINTER_MAX;\\n }\\n\\n // Return the parent of a position number\\n function parent(uint256 a) internal pure returns (uint256) {\\n return a >> Constants.SLOT_BITS;\\n }\\n\\n // Return the location of the child of a at the given slot\\n function child(uint256 a, uint256 s) internal pure returns (uint256) {\\n return (a << Constants.SLOT_BITS) | (s & Constants.SLOT_POINTER_MAX); // slot(s)\\n }\\n\\n // Return the uint p as a flagged position uint:\\n // the least significant 21 bits contain the position\\n // and the 22nd bit is set as a flag\\n // to distinguish the position 0x000000 from an empty field.\\n function setFlag(uint256 p) internal pure returns (uint256) {\\n return p | Constants.LEAF_FLAG;\\n }\\n\\n // Turn a flagged position into an unflagged position\\n // by removing the flag at the 22nd least significant bit.\\n //\\n // We shouldn't _actually_ need this\\n // as all position-manipulating code should ignore non-position bits anyway\\n // but it's cheap to call so might as well do it.\\n function unsetFlag(uint256 p) internal pure returns (uint256) {\\n return p & (~Constants.LEAF_FLAG);\\n }\\n}\\n\",\"keccak256\":\"0xd3a927908080ac21353a92a6bce3d69e94a5c30f6b51f16b271b6cc679f110e2\"},\"@keep-network/sortition-pools/contracts/RNG.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Leaf.sol\\\";\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary RNG {\\n /// @notice Get an index in the range `[0 .. range-1]`\\n /// and the new state of the RNG,\\n /// using the provided `state` of the RNG.\\n ///\\n /// @param range The upper bound of the index, exclusive.\\n ///\\n /// @param state The previous state of the RNG.\\n /// The initial state needs to be obtained\\n /// from a trusted randomness oracle (the random beacon),\\n /// or from a chain of earlier calls to `RNG.getIndex()`\\n /// on an originally trusted seed.\\n ///\\n /// @dev Calculates the number of bits required for the desired range,\\n /// takes the least significant bits of `state`\\n /// and checks if the obtained index is within the desired range.\\n /// The original state is hashed with `keccak256` to get a new state.\\n /// If the index is outside the range,\\n /// the function retries until it gets a suitable index.\\n ///\\n /// @return index A random integer between `0` and `range - 1`, inclusive.\\n ///\\n /// @return newState The new state of the RNG.\\n /// When `getIndex()` is called one or more times,\\n /// care must be taken to always use the output `state`\\n /// of the most recent call as the input `state` of a subsequent call.\\n /// At the end of a transaction calling `RNG.getIndex()`,\\n /// the previous stored state must be overwritten with the latest output.\\n function getIndex(\\n uint256 range,\\n bytes32 state,\\n uint256 bits\\n ) internal view returns (uint256, bytes32) {\\n bool found = false;\\n uint256 index = 0;\\n bytes32 newState = state;\\n while (!found) {\\n index = truncate(bits, uint256(newState));\\n newState = keccak256(abi.encodePacked(newState, address(this)));\\n if (index < range) {\\n found = true;\\n }\\n }\\n return (index, newState);\\n }\\n\\n /// @notice Calculate how many bits are required\\n /// for an index in the range `[0 .. range-1]`.\\n ///\\n /// @param range The upper bound of the desired range, exclusive.\\n ///\\n /// @return uint The smallest number of bits\\n /// that can contain the number `range-1`.\\n function bitsRequired(uint256 range) internal pure returns (uint256) {\\n unchecked {\\n if (range == 1) {\\n return 0;\\n }\\n\\n uint256 bits = Constants.WEIGHT_WIDTH - 1;\\n\\n // Left shift by `bits`,\\n // so we have a 1 in the (bits + 1)th least significant bit\\n // and 0 in other bits.\\n // If this number is equal or greater than `range`,\\n // the range [0, range-1] fits in `bits` bits.\\n //\\n // Because we loop from high bits to low bits,\\n // we find the highest number of bits that doesn't fit the range,\\n // and return that number + 1.\\n while (1 << bits >= range) {\\n bits--;\\n }\\n\\n return bits + 1;\\n }\\n }\\n\\n /// @notice Truncate `input` to the `bits` least significant bits.\\n function truncate(uint256 bits, uint256 input)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n return input & ((1 << bits) - 1);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x67f87f589cd5123ffa32f883ea2f09b0e56258508bae82b8c655b3c27c71eb5e\"},\"@keep-network/sortition-pools/contracts/Rewards.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\n/// @title Rewards\\n/// @notice Rewards are allocated proportionally to operators\\n/// present in the pool at payout based on their weight in the pool.\\n///\\n/// To facilitate this, we use a global accumulator value\\n/// to track the total rewards one unit of weight would've earned\\n/// since the creation of the pool.\\n///\\n/// Whenever a reward is paid, the accumulator is increased\\n/// by the size of the reward divided by the total weight\\n/// of all eligible operators in the pool.\\n///\\n/// Each operator has an individual accumulator value,\\n/// set to equal the global accumulator when the operator joins the pool.\\n/// This accumulator reflects the amount of rewards\\n/// that have already been accounted for with that operator.\\n///\\n/// Whenever an operator's weight in the pool changes,\\n/// we can update the amount of rewards the operator has earned\\n/// by subtracting the operator's accumulator from the global accumulator.\\n/// This gives us the amount of rewards one unit of weight has earned\\n/// since the last time the operator's rewards have been updated.\\n/// Then we multiply that by the operator's previous (pre-change) weight\\n/// to determine how much rewards in total the operator has earned,\\n/// and add this to the operator's earned rewards.\\n/// Finally, we set the operator's accumulator to the global accumulator value.\\ncontract Rewards {\\n struct OperatorRewards {\\n // The state of the global accumulator\\n // when the operator's rewards were last updated\\n uint96 accumulated;\\n // The amount of rewards collected by the operator after the latest update.\\n // The amount the operator could withdraw may equal `available`\\n // or it may be greater, if more rewards have been paid in since then.\\n // To evaulate the most recent amount including rewards potentially paid\\n // since the last update, use `availableRewards` function.\\n uint96 available;\\n // If nonzero, the operator is ineligible for rewards\\n // and may only re-enable rewards after the specified timestamp.\\n // XXX: unsigned 32-bit integer unix seconds, will break around 2106\\n uint32 ineligibleUntil;\\n // Locally cached weight of the operator,\\n // used to reduce the cost of setting operators ineligible.\\n uint32 weight;\\n }\\n\\n // The global accumulator of how much rewards\\n // a hypothetical operator of weight 1 would have earned\\n // since the creation of the pool.\\n uint96 internal globalRewardAccumulator;\\n // If the amount of reward tokens paid in\\n // does not divide cleanly by pool weight,\\n // the difference is recorded as rounding dust\\n // and added to the next reward.\\n uint96 internal rewardRoundingDust;\\n\\n // The amount of rewards that would've been earned by ineligible operators\\n // had they not been ineligible.\\n uint96 public ineligibleEarnedRewards;\\n\\n // Ineligibility times are calculated from this offset,\\n // set at contract creation.\\n uint256 internal immutable ineligibleOffsetStart;\\n\\n mapping(uint32 => OperatorRewards) internal operatorRewards;\\n\\n constructor() {\\n // solhint-disable-next-line not-rely-on-time\\n ineligibleOffsetStart = block.timestamp;\\n }\\n\\n /// @notice Return whether the operator is eligible for rewards or not.\\n function isEligibleForRewards(uint32 operator) internal view returns (bool) {\\n return operatorRewards[operator].ineligibleUntil == 0;\\n }\\n\\n /// @notice Return the time the operator's reward eligibility can be restored.\\n function rewardsEligibilityRestorableAt(uint32 operator)\\n internal\\n view\\n returns (uint256)\\n {\\n uint32 until = operatorRewards[operator].ineligibleUntil;\\n require(until != 0, \\\"Operator already eligible\\\");\\n return (uint256(until) + ineligibleOffsetStart);\\n }\\n\\n /// @notice Return whether the operator is able to restore their eligibility\\n /// for rewards right away.\\n function canRestoreRewardEligibility(uint32 operator)\\n internal\\n view\\n returns (bool)\\n {\\n // solhint-disable-next-line not-rely-on-time\\n return rewardsEligibilityRestorableAt(operator) <= block.timestamp;\\n }\\n\\n /// @notice Internal function for updating the global state of rewards.\\n function addRewards(uint96 rewardAmount, uint32 currentPoolWeight) internal {\\n require(currentPoolWeight > 0, \\\"No recipients in pool\\\");\\n\\n uint96 totalAmount = rewardAmount + rewardRoundingDust;\\n uint96 perWeightReward = totalAmount / currentPoolWeight;\\n uint96 newRoundingDust = totalAmount % currentPoolWeight;\\n\\n globalRewardAccumulator += perWeightReward;\\n rewardRoundingDust = newRoundingDust;\\n }\\n\\n /// @notice Internal function for updating the operator's reward state.\\n function updateOperatorRewards(uint32 operator, uint32 newWeight) internal {\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n if (o.ineligibleUntil == 0) {\\n // If operator is not ineligible, update their earned rewards\\n o.available += accruedRewards;\\n } else {\\n // If ineligible, put the rewards into the ineligible pot\\n ineligibleEarnedRewards += accruedRewards;\\n }\\n // In any case, update their accumulator and weight\\n o.accumulated = acc;\\n o.weight = newWeight;\\n operatorRewards[operator] = o;\\n }\\n\\n /// @notice Set the amount of withdrawable tokens to zero\\n /// and return the previous withdrawable amount.\\n /// @dev Does not update the withdrawable amount,\\n /// but should usually be accompanied by an update.\\n function withdrawOperatorRewards(uint32 operator)\\n internal\\n returns (uint96 withdrawable)\\n {\\n OperatorRewards storage o = operatorRewards[operator];\\n withdrawable = o.available;\\n o.available = 0;\\n }\\n\\n /// @notice Set the amount of ineligible-earned tokens to zero\\n /// and return the previous amount.\\n function withdrawIneligibleRewards() internal returns (uint96 withdrawable) {\\n withdrawable = ineligibleEarnedRewards;\\n ineligibleEarnedRewards = 0;\\n }\\n\\n /// @notice Set the given operators as ineligible for rewards.\\n /// The operators can restore their eligibility at the given time.\\n function setIneligible(uint32[] memory operators, uint256 until) internal {\\n OperatorRewards memory o = OperatorRewards(0, 0, 0, 0);\\n uint96 globalAcc = globalRewardAccumulator;\\n uint96 accrued = 0;\\n // Record ineligibility as seconds after contract creation\\n uint32 _until = uint32(until - ineligibleOffsetStart);\\n\\n for (uint256 i = 0; i < operators.length; i++) {\\n uint32 operator = operators[i];\\n OperatorRewards storage r = operatorRewards[operator];\\n o.available = r.available;\\n o.accumulated = r.accumulated;\\n o.ineligibleUntil = r.ineligibleUntil;\\n o.weight = r.weight;\\n\\n if (o.ineligibleUntil != 0) {\\n // If operator is already ineligible,\\n // don't earn rewards or shorten its ineligibility\\n if (o.ineligibleUntil < _until) {\\n o.ineligibleUntil = _until;\\n }\\n } else {\\n // The operator becomes ineligible -> earn rewards\\n o.ineligibleUntil = _until;\\n accrued = (globalAcc - o.accumulated) * uint96(o.weight);\\n o.available += accrued;\\n }\\n o.accumulated = globalAcc;\\n\\n r.available = o.available;\\n r.accumulated = o.accumulated;\\n r.ineligibleUntil = o.ineligibleUntil;\\n r.weight = o.weight;\\n }\\n }\\n\\n /// @notice Restore the given operator's eligibility for rewards.\\n function restoreEligibility(uint32 operator) internal {\\n // solhint-disable-next-line not-rely-on-time\\n require(canRestoreRewardEligibility(operator), \\\"Operator still ineligible\\\");\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n ineligibleEarnedRewards += accruedRewards;\\n o.accumulated = acc;\\n o.ineligibleUntil = 0;\\n operatorRewards[operator] = o;\\n }\\n\\n /// @notice Returns the amount of rewards currently available for withdrawal\\n /// for the given operator.\\n function availableRewards(uint32 operator) internal view returns (uint96) {\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n if (o.ineligibleUntil == 0) {\\n // If operator is not ineligible, calculate newly accrued rewards and add\\n // them to the available ones, calculated during the last update.\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n return o.available + accruedRewards;\\n } else {\\n // If ineligible, return only the rewards calculated during the last\\n // update.\\n return o.available;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3a10abb408b44335a092387b2c7ee01db3b27997f1f2c888d9b7a2d92934c4e2\"},\"@keep-network/sortition-pools/contracts/SortitionPool.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"@thesis/solidity-contracts/contracts/token/IERC20WithPermit.sol\\\";\\nimport \\\"@thesis/solidity-contracts/contracts/token/IReceiveApproval.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\nimport \\\"./RNG.sol\\\";\\nimport \\\"./SortitionTree.sol\\\";\\nimport \\\"./Rewards.sol\\\";\\nimport \\\"./Chaosnet.sol\\\";\\n\\n/// @title Sortition Pool\\n/// @notice A logarithmic data structure used to store the pool of eligible\\n/// operators weighted by their stakes. It allows to select a group of operators\\n/// based on the provided pseudo-random seed.\\ncontract SortitionPool is\\n SortitionTree,\\n Rewards,\\n Ownable,\\n Chaosnet,\\n IReceiveApproval\\n{\\n using Branch for uint256;\\n using Leaf for uint256;\\n using Position for uint256;\\n\\n IERC20WithPermit public immutable rewardToken;\\n\\n uint256 public immutable poolWeightDivisor;\\n\\n bool public isLocked;\\n\\n event IneligibleForRewards(uint32[] ids, uint256 until);\\n\\n event RewardEligibilityRestored(address indexed operator, uint32 indexed id);\\n\\n /// @notice Reverts if called while pool is locked.\\n modifier onlyUnlocked() {\\n require(!isLocked, \\\"Sortition pool locked\\\");\\n _;\\n }\\n\\n /// @notice Reverts if called while pool is unlocked.\\n modifier onlyLocked() {\\n require(isLocked, \\\"Sortition pool unlocked\\\");\\n _;\\n }\\n\\n constructor(IERC20WithPermit _rewardToken, uint256 _poolWeightDivisor) {\\n rewardToken = _rewardToken;\\n poolWeightDivisor = _poolWeightDivisor;\\n }\\n\\n function receiveApproval(\\n address sender,\\n uint256 amount,\\n address token,\\n bytes calldata\\n ) external override {\\n require(token == address(rewardToken), \\\"Unsupported token\\\");\\n rewardToken.transferFrom(sender, address(this), amount);\\n Rewards.addRewards(uint96(amount), uint32(root.sumWeight()));\\n }\\n\\n /// @notice Withdraws all available rewards for the given operator to the\\n /// given beneficiary.\\n /// @dev Can be called only be the owner. Does not validate if the provided\\n /// beneficiary is associated with the provided operator - this needs to\\n /// be done by the owner calling this function.\\n /// @return The amount of rewards withdrawn in this call.\\n function withdrawRewards(address operator, address beneficiary)\\n public\\n onlyOwner\\n returns (uint96)\\n {\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(getPoolWeight(operator)));\\n uint96 earned = Rewards.withdrawOperatorRewards(id);\\n rewardToken.transfer(beneficiary, uint256(earned));\\n return earned;\\n }\\n\\n /// @notice Withdraws rewards not allocated to operators marked as ineligible\\n /// to the given recipient address.\\n /// @dev Can be called only by the owner.\\n function withdrawIneligible(address recipient) public onlyOwner {\\n uint96 earned = Rewards.withdrawIneligibleRewards();\\n rewardToken.transfer(recipient, uint256(earned));\\n }\\n\\n /// @notice Locks the sortition pool. In locked state, members cannot be\\n /// inserted and removed from the pool. Members statuses cannot\\n /// be updated as well.\\n /// @dev Can be called only by the contract owner.\\n function lock() public onlyOwner {\\n isLocked = true;\\n }\\n\\n /// @notice Unlocks the sortition pool. Removes all restrictions set by\\n /// the `lock` method.\\n /// @dev Can be called only by the contract owner.\\n function unlock() public onlyOwner {\\n isLocked = false;\\n }\\n\\n /// @notice Inserts an operator to the pool. Reverts if the operator is\\n /// already present. Reverts if the operator is not eligible because of their\\n /// authorized stake. Reverts if the chaosnet is active and the operator is\\n /// not a beta operator.\\n /// @dev Can be called only by the contract owner.\\n /// @param operator Address of the inserted operator.\\n /// @param authorizedStake Inserted operator's authorized stake for the application.\\n function insertOperator(address operator, uint256 authorizedStake)\\n public\\n onlyOwner\\n onlyUnlocked\\n {\\n uint256 weight = getWeight(authorizedStake);\\n require(weight > 0, \\\"Operator not eligible\\\");\\n\\n if (isChaosnetActive) {\\n require(isBetaOperator[operator], \\\"Not beta operator for chaosnet\\\");\\n }\\n\\n _insertOperator(operator, weight);\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(weight));\\n }\\n\\n /// @notice Update the operator's weight if present and eligible,\\n /// or remove from the pool if present and ineligible.\\n /// @dev Can be called only by the contract owner.\\n /// @param operator Address of the updated operator.\\n /// @param authorizedStake Operator's authorized stake for the application.\\n function updateOperatorStatus(address operator, uint256 authorizedStake)\\n public\\n onlyOwner\\n onlyUnlocked\\n {\\n uint256 weight = getWeight(authorizedStake);\\n\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(weight));\\n\\n if (weight == 0) {\\n _removeOperator(operator);\\n } else {\\n updateOperator(operator, weight);\\n }\\n }\\n\\n /// @notice Set the given operators as ineligible for rewards.\\n /// The operators can restore their eligibility at the given time.\\n function setRewardIneligibility(uint32[] calldata operators, uint256 until)\\n public\\n onlyOwner\\n {\\n Rewards.setIneligible(operators, until);\\n emit IneligibleForRewards(operators, until);\\n }\\n\\n /// @notice Restores reward eligibility for the operator.\\n function restoreRewardEligibility(address operator) public {\\n uint32 id = getOperatorID(operator);\\n Rewards.restoreEligibility(id);\\n emit RewardEligibilityRestored(operator, id);\\n }\\n\\n /// @notice Returns whether the operator is eligible for rewards or not.\\n function isEligibleForRewards(address operator) public view returns (bool) {\\n uint32 id = getOperatorID(operator);\\n return Rewards.isEligibleForRewards(id);\\n }\\n\\n /// @notice Returns the time the operator's reward eligibility can be restored.\\n function rewardsEligibilityRestorableAt(address operator)\\n public\\n view\\n returns (uint256)\\n {\\n uint32 id = getOperatorID(operator);\\n return Rewards.rewardsEligibilityRestorableAt(id);\\n }\\n\\n /// @notice Returns whether the operator is able to restore their eligibility\\n /// for rewards right away.\\n function canRestoreRewardEligibility(address operator)\\n public\\n view\\n returns (bool)\\n {\\n uint32 id = getOperatorID(operator);\\n return Rewards.canRestoreRewardEligibility(id);\\n }\\n\\n /// @notice Returns the amount of rewards withdrawable for the given operator.\\n function getAvailableRewards(address operator) public view returns (uint96) {\\n uint32 id = getOperatorID(operator);\\n return availableRewards(id);\\n }\\n\\n /// @notice Return whether the operator is present in the pool.\\n function isOperatorInPool(address operator) public view returns (bool) {\\n return getFlaggedLeafPosition(operator) != 0;\\n }\\n\\n /// @notice Return whether the operator's weight in the pool\\n /// matches their eligible weight.\\n function isOperatorUpToDate(address operator, uint256 authorizedStake)\\n public\\n view\\n returns (bool)\\n {\\n return getWeight(authorizedStake) == getPoolWeight(operator);\\n }\\n\\n /// @notice Return the weight of the operator in the pool,\\n /// which may or may not be out of date.\\n function getPoolWeight(address operator) public view returns (uint256) {\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n if (flaggedPosition == 0) {\\n return 0;\\n } else {\\n uint256 leafPosition = flaggedPosition.unsetFlag();\\n uint256 leafWeight = getLeafWeight(leafPosition);\\n return leafWeight;\\n }\\n }\\n\\n /// @notice Selects a new group of operators of the provided size based on\\n /// the provided pseudo-random seed. At least one operator has to be\\n /// registered in the pool, otherwise the function fails reverting the\\n /// transaction.\\n /// @param groupSize Size of the requested group\\n /// @param seed Pseudo-random number used to select operators to group\\n /// @return selected Members of the selected group\\n function selectGroup(uint256 groupSize, bytes32 seed)\\n public\\n view\\n onlyLocked\\n returns (uint32[] memory)\\n {\\n uint256 _root = root;\\n\\n bytes32 rngState = seed;\\n uint256 rngRange = _root.sumWeight();\\n require(rngRange > 0, \\\"Not enough operators in pool\\\");\\n uint256 currentIndex;\\n\\n uint256 bits = RNG.bitsRequired(rngRange);\\n\\n uint32[] memory selected = new uint32[](groupSize);\\n\\n for (uint256 i = 0; i < groupSize; i++) {\\n (currentIndex, rngState) = RNG.getIndex(rngRange, rngState, bits);\\n\\n uint256 leafPosition = pickWeightedLeaf(currentIndex, _root);\\n\\n uint256 leaf = leaves[leafPosition];\\n selected[i] = leaf.id();\\n }\\n return selected;\\n }\\n\\n function getWeight(uint256 authorization) internal view returns (uint256) {\\n return authorization / poolWeightDivisor;\\n }\\n}\\n\",\"keccak256\":\"0xab42e7c5b1828f42a73f699eb2dc96d4f793572a6323b8b1fbd7c5e0c065bda7\"},\"@keep-network/sortition-pools/contracts/SortitionTree.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Branch.sol\\\";\\nimport \\\"./Position.sol\\\";\\nimport \\\"./Leaf.sol\\\";\\nimport \\\"./Constants.sol\\\";\\n\\ncontract SortitionTree {\\n using Branch for uint256;\\n using Position for uint256;\\n using Leaf for uint256;\\n\\n // implicit tree\\n // root 8\\n // level2 64\\n // level3 512\\n // level4 4k\\n // level5 32k\\n // level6 256k\\n // level7 2M\\n uint256 internal root;\\n\\n // A 2-index mapping from layer => (index (0-index) => branch). For example,\\n // to access the 6th branch in the 2nd layer (right below the root node; the\\n // first branch layer), call branches[2][5]. Mappings are used in place of\\n // arrays for efficiency. The root is the first layer, the branches occupy\\n // layers 2 through 7, and layer 8 is for the leaves. Following this\\n // convention, the first index in `branches` is `2`, and the last index is\\n // `7`.\\n mapping(uint256 => mapping(uint256 => uint256)) internal branches;\\n\\n // A 0-index mapping from index => leaf, acting as an array. For example, to\\n // access the 42nd leaf, call leaves[41].\\n mapping(uint256 => uint256) internal leaves;\\n\\n // the flagged (see setFlag() and unsetFlag() in Position.sol) positions\\n // of all operators present in the pool\\n mapping(address => uint256) internal flaggedLeafPosition;\\n\\n // the leaf after the rightmost occupied leaf of each stack\\n uint256 internal rightmostLeaf;\\n\\n // the empty leaves in each stack\\n // between 0 and the rightmost occupied leaf\\n uint256[] internal emptyLeaves;\\n\\n // Each operator has an uint32 ID number\\n // which is allocated when they first join the pool\\n // and remains unchanged even if they leave and rejoin the pool.\\n mapping(address => uint32) internal operatorID;\\n\\n // The idAddress array records the address corresponding to each ID number.\\n // The ID number 0 is initialized with a zero address and is not used.\\n address[] internal idAddress;\\n\\n constructor() {\\n root = 0;\\n rightmostLeaf = 0;\\n idAddress.push();\\n }\\n\\n /// @notice Return the ID number of the given operator address. An ID number\\n /// of 0 means the operator has not been allocated an ID number yet.\\n /// @param operator Address of the operator.\\n /// @return the ID number of the given operator address\\n function getOperatorID(address operator) public view returns (uint32) {\\n return operatorID[operator];\\n }\\n\\n /// @notice Get the operator address corresponding to the given ID number. A\\n /// zero address means the ID number has not been allocated yet.\\n /// @param id ID of the operator\\n /// @return the address of the operator\\n function getIDOperator(uint32 id) public view returns (address) {\\n return idAddress.length > id ? idAddress[id] : address(0);\\n }\\n\\n /// @notice Gets the operator addresses corresponding to the given ID\\n /// numbers. A zero address means the ID number has not been allocated yet.\\n /// This function works just like getIDOperator except that it allows to fetch\\n /// operator addresses for multiple IDs in one call.\\n /// @param ids the array of the operator ids\\n /// @return an array of the associated operator addresses\\n function getIDOperators(uint32[] calldata ids)\\n public\\n view\\n returns (address[] memory)\\n {\\n uint256 idCount = idAddress.length;\\n\\n address[] memory operators = new address[](ids.length);\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint32 id = ids[i];\\n operators[i] = idCount > id ? idAddress[id] : address(0);\\n }\\n return operators;\\n }\\n\\n /// @notice Checks if operator is already registered in the pool.\\n /// @param operator the address of the operator\\n /// @return whether or not the operator is already registered in the pool\\n function isOperatorRegistered(address operator) public view returns (bool) {\\n return getFlaggedLeafPosition(operator) != 0;\\n }\\n\\n /// @notice Sum the number of operators in each trunk.\\n /// @return the number of operators in the pool\\n function operatorsInPool() public view returns (uint256) {\\n // Get the number of leaves that might be occupied;\\n // if `rightmostLeaf` equals `firstLeaf()` the tree must be empty,\\n // otherwise the difference between these numbers\\n // gives the number of leaves that may be occupied.\\n uint256 nPossiblyUsedLeaves = rightmostLeaf;\\n // Get the number of empty leaves\\n // not accounted for by the `rightmostLeaf`\\n uint256 nEmptyLeaves = emptyLeaves.length;\\n\\n return (nPossiblyUsedLeaves - nEmptyLeaves);\\n }\\n\\n /// @notice Convenience method to return the total weight of the pool\\n /// @return the total weight of the pool\\n function totalWeight() public view returns (uint256) {\\n return root.sumWeight();\\n }\\n\\n /// @notice Give the operator a new ID number.\\n /// Does not check if the operator already has an ID number.\\n /// @param operator the address of the operator\\n /// @return a new ID for that operator\\n function allocateOperatorID(address operator) internal returns (uint256) {\\n uint256 id = idAddress.length;\\n\\n require(id <= type(uint32).max, \\\"Pool capacity exceeded\\\");\\n\\n operatorID[operator] = uint32(id);\\n idAddress.push(operator);\\n return id;\\n }\\n\\n /// @notice Inserts an operator into the sortition pool\\n /// @param operator the address of an operator to insert\\n /// @param weight how much weight that operator has in the pool\\n function _insertOperator(address operator, uint256 weight) internal {\\n require(\\n !isOperatorRegistered(operator),\\n \\\"Operator is already registered in the pool\\\"\\n );\\n\\n // Fetch the operator's ID, and if they don't have one, allocate them one.\\n uint256 id = getOperatorID(operator);\\n if (id == 0) {\\n id = allocateOperatorID(operator);\\n }\\n\\n // Determine which leaf to insert them into\\n uint256 position = getEmptyLeafPosition();\\n // Record the block the operator was inserted in\\n uint256 theLeaf = Leaf.make(operator, block.number, id);\\n\\n // Update the leaf, and propagate the weight changes all the way up to the\\n // root.\\n root = setLeaf(position, theLeaf, weight, root);\\n\\n // Without position flags,\\n // the position 0x000000 would be treated as empty\\n flaggedLeafPosition[operator] = position.setFlag();\\n }\\n\\n /// @notice Remove an operator (and their weight) from the pool.\\n /// @param operator the address of the operator to remove\\n function _removeOperator(address operator) internal {\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n require(flaggedPosition != 0, \\\"Operator is not registered in the pool\\\");\\n uint256 unflaggedPosition = flaggedPosition.unsetFlag();\\n\\n // Update the leaf, and propagate the weight changes all the way up to the\\n // root.\\n root = removeLeaf(unflaggedPosition, root);\\n removeLeafPositionRecord(operator);\\n }\\n\\n /// @notice Update an operator's weight in the pool.\\n /// @param operator the address of the operator to update\\n /// @param weight the new weight\\n function updateOperator(address operator, uint256 weight) internal {\\n require(\\n isOperatorRegistered(operator),\\n \\\"Operator is not registered in the pool\\\"\\n );\\n\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n uint256 unflaggedPosition = flaggedPosition.unsetFlag();\\n root = updateLeaf(unflaggedPosition, weight, root);\\n }\\n\\n /// @notice Helper method to remove a leaf position record for an operator.\\n /// @param operator the address of the operator to remove the record for\\n function removeLeafPositionRecord(address operator) internal {\\n flaggedLeafPosition[operator] = 0;\\n }\\n\\n /// @notice Removes the data and weight from a particular leaf.\\n /// @param position the leaf index to remove\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function removeLeaf(uint256 position, uint256 _root)\\n internal\\n returns (uint256)\\n {\\n uint256 rightmostSubOne = rightmostLeaf - 1;\\n bool isRightmost = position == rightmostSubOne;\\n\\n // Clears out the data in the leaf node, and then propagates the weight\\n // changes all the way up to the root.\\n uint256 newRoot = setLeaf(position, 0, 0, _root);\\n\\n // Infer if need to fall back on emptyLeaves yet\\n if (isRightmost) {\\n rightmostLeaf = rightmostSubOne;\\n } else {\\n emptyLeaves.push(position);\\n }\\n return newRoot;\\n }\\n\\n /// @notice Updates the tree to give a particular leaf a new weight.\\n /// @param position the index of the leaf to update\\n /// @param weight the new weight\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function updateLeaf(\\n uint256 position,\\n uint256 weight,\\n uint256 _root\\n ) internal returns (uint256) {\\n if (getLeafWeight(position) != weight) {\\n return updateTree(position, weight, _root);\\n } else {\\n return _root;\\n }\\n }\\n\\n /// @notice Places a leaf into a particular position, with a given weight and\\n /// propagates that change.\\n /// @param position the index to place the leaf in\\n /// @param theLeaf the new leaf to place in the position\\n /// @param leafWeight the weight of the leaf\\n /// @param _root the root containing the new leaf\\n /// @return the updated root node\\n function setLeaf(\\n uint256 position,\\n uint256 theLeaf,\\n uint256 leafWeight,\\n uint256 _root\\n ) internal returns (uint256) {\\n // set leaf\\n leaves[position] = theLeaf;\\n\\n return (updateTree(position, leafWeight, _root));\\n }\\n\\n /// @notice Propagates a weight change at a position through the tree,\\n /// eventually returning the updated root.\\n /// @param position the index of leaf to update\\n /// @param weight the new weight of the leaf\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function updateTree(\\n uint256 position,\\n uint256 weight,\\n uint256 _root\\n ) internal returns (uint256) {\\n uint256 childSlot;\\n uint256 treeNode;\\n uint256 newNode;\\n uint256 nodeWeight = weight;\\n\\n uint256 parent = position;\\n // set levels 7 to 2\\n for (uint256 level = Constants.LEVELS; level >= 2; level--) {\\n childSlot = parent.slot();\\n parent = parent.parent();\\n treeNode = branches[level][parent];\\n newNode = treeNode.setSlot(childSlot, nodeWeight);\\n branches[level][parent] = newNode;\\n nodeWeight = newNode.sumWeight();\\n }\\n\\n // set level Root\\n childSlot = parent.slot();\\n return _root.setSlot(childSlot, nodeWeight);\\n }\\n\\n /// @notice Retrieves the next available empty leaf position. Tries to fill\\n /// left to right first, ignoring leaf removals, and then fills\\n /// most-recent-removals first.\\n /// @return the position of the empty leaf\\n function getEmptyLeafPosition() internal returns (uint256) {\\n uint256 rLeaf = rightmostLeaf;\\n bool spaceOnRight = (rLeaf + 1) < Constants.POOL_CAPACITY;\\n if (spaceOnRight) {\\n rightmostLeaf = rLeaf + 1;\\n return rLeaf;\\n } else {\\n uint256 emptyLeafCount = emptyLeaves.length;\\n require(emptyLeafCount > 0, \\\"Pool is full\\\");\\n uint256 emptyLeaf = emptyLeaves[emptyLeafCount - 1];\\n emptyLeaves.pop();\\n return emptyLeaf;\\n }\\n }\\n\\n /// @notice Gets the flagged leaf position for an operator.\\n /// @param operator the address of the operator\\n /// @return the leaf position of that operator\\n function getFlaggedLeafPosition(address operator)\\n internal\\n view\\n returns (uint256)\\n {\\n return flaggedLeafPosition[operator];\\n }\\n\\n /// @notice Gets the weight of a leaf at a particular position.\\n /// @param position the index of the leaf\\n /// @return the weight of the leaf at that position\\n function getLeafWeight(uint256 position) internal view returns (uint256) {\\n uint256 slot = position.slot();\\n uint256 parent = position.parent();\\n\\n // A leaf's weight information is stored a 32-bit slot in the branch layer\\n // directly above the leaf layer. To access it, we calculate that slot and\\n // parent position, and always know the hard-coded layer index.\\n uint256 node = branches[Constants.LEVELS][parent];\\n return node.getSlot(slot);\\n }\\n\\n /// @notice Picks a leaf given a random index.\\n /// @param index a number in `[0, _root.totalWeight())` used to decide\\n /// between leaves\\n /// @param _root the root of the tree\\n function pickWeightedLeaf(uint256 index, uint256 _root)\\n internal\\n view\\n returns (uint256 leafPosition)\\n {\\n uint256 currentIndex = index;\\n uint256 currentNode = _root;\\n uint256 currentPosition = 0;\\n uint256 currentSlot;\\n\\n require(index < currentNode.sumWeight(), \\\"Index exceeds weight\\\");\\n\\n // get root slot\\n (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex);\\n\\n // get slots from levels 2 to 7\\n for (uint256 level = 2; level <= Constants.LEVELS; level++) {\\n currentPosition = currentPosition.child(currentSlot);\\n currentNode = branches[level][currentPosition];\\n (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex);\\n }\\n\\n // get leaf position\\n leafPosition = currentPosition.child(currentSlot);\\n }\\n}\\n\",\"keccak256\":\"0x51daeca62ef52be78a1a9de4d2a1c5900c873165f59eda14d5965d7d7da90a03\"},\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/security/ReentrancyGuard.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Contract module that helps prevent reentrant calls to a function.\\n *\\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\\n * available, which can be applied to functions to make sure there are no nested\\n * (reentrant) calls to them.\\n *\\n * Note that because there is a single `nonReentrant` guard, functions marked as\\n * `nonReentrant` may not call one another. This can be worked around by making\\n * those functions `private`, and then adding `external` `nonReentrant` entry\\n * points to them.\\n *\\n * TIP: If you would like to learn more about reentrancy and alternative ways\\n * to protect against it, check out our blog post\\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\\n */\\nabstract contract ReentrancyGuard {\\n // Booleans are more expensive than uint256 or any type that takes up a full\\n // word because each write operation emits an extra SLOAD to first read the\\n // slot's contents, replace the bits taken up by the boolean, and then write\\n // back. This is the compiler's defense against contract upgrades and\\n // pointer aliasing, and it cannot be disabled.\\n\\n // The values being non-zero value makes deployment a bit more expensive,\\n // but in exchange the refund on every call to nonReentrant will be lower in\\n // amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to\\n // increase the likelihood of the full refund coming into effect.\\n uint256 private constant _NOT_ENTERED = 1;\\n uint256 private constant _ENTERED = 2;\\n\\n uint256 private _status;\\n\\n constructor() {\\n _status = _NOT_ENTERED;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and making it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_status != _ENTERED, \\\"ReentrancyGuard: reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n _status = _ENTERED;\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _status = _NOT_ENTERED;\\n }\\n}\\n\",\"keccak256\":\"0x0e9621f60b2faabe65549f7ed0f24e8853a45c1b7990d47e8160e523683f3935\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n uint8 private constant _ADDRESS_LENGTH = 20;\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\\n */\\n function toHexString(address addr) internal pure returns (string memory) {\\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\\n }\\n}\\n\",\"keccak256\":\"0xaf159a8b1923ad2a26d516089bceca9bdeaeacd04be50983ea00ba63070f08a3\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.3) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n /// @solidity memory-safe-assembly\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0xdb7f5c28fc61cda0bd8ab60ce288e206b791643bcd3ba464a70cbec18895a2f5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\n /**\\n * @dev Returns the largest of two numbers.\\n */\\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a >= b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the smallest of two numbers.\\n */\\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a < b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the average of two numbers. The result is rounded towards\\n * zero.\\n */\\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b) / 2 can overflow.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1);\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. It the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`.\\n // We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`.\\n // This gives `2**k < a <= 2**(k+1)` \\u2192 `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`.\\n // Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a\\n // good first aproximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1;\\n uint256 x = a;\\n if (x >> 128 > 0) {\\n x >>= 128;\\n result <<= 64;\\n }\\n if (x >> 64 > 0) {\\n x >>= 64;\\n result <<= 32;\\n }\\n if (x >> 32 > 0) {\\n x >>= 32;\\n result <<= 16;\\n }\\n if (x >> 16 > 0) {\\n x >>= 16;\\n result <<= 8;\\n }\\n if (x >> 8 > 0) {\\n x >>= 8;\\n result <<= 4;\\n }\\n if (x >> 4 > 0) {\\n x >>= 4;\\n result <<= 2;\\n }\\n if (x >> 2 > 0) {\\n result <<= 1;\\n }\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n uint256 result = sqrt(a);\\n if (rounding == Rounding.Up && result * result < a) {\\n result += 1;\\n }\\n return result;\\n }\\n}\\n\",\"keccak256\":\"0xd15c3e400531f00203839159b2b8e7209c5158b35618f570c695b7e47f12e9f0\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IApproveAndCall.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\n/// @notice An interface that should be implemented by tokens supporting\\n/// `approveAndCall`/`receiveApproval` pattern.\\ninterface IApproveAndCall {\\n /// @notice Executes `receiveApproval` function on spender as specified in\\n /// `IReceiveApproval` interface. Approves spender to withdraw from\\n /// the caller multiple times, up to the `amount`. If this\\n /// function is called again, it overwrites the current allowance\\n /// with `amount`. Reverts if the approval reverted or if\\n /// `receiveApproval` call on the spender reverted.\\n function approveAndCall(\\n address spender,\\n uint256 amount,\\n bytes memory extraData\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x393d18ef81a57dcc96fff4c340cc2945deaebb37b9796c322cf2bc96872c3df8\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IERC20WithPermit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\\\";\\n\\nimport \\\"./IApproveAndCall.sol\\\";\\n\\n/// @title IERC20WithPermit\\n/// @notice Burnable ERC20 token with EIP2612 permit functionality. User can\\n/// authorize a transfer of their token with a signature conforming\\n/// EIP712 standard instead of an on-chain transaction from their\\n/// address. Anyone can submit this signature on the user's behalf by\\n/// calling the permit function, as specified in EIP2612 standard,\\n/// paying gas fees, and possibly performing other actions in the same\\n/// transaction.\\ninterface IERC20WithPermit is IERC20, IERC20Metadata, IApproveAndCall {\\n /// @notice EIP2612 approval made with secp256k1 signature.\\n /// Users can authorize a transfer of their tokens with a signature\\n /// conforming EIP712 standard, rather than an on-chain transaction\\n /// from their address. Anyone can submit this signature on the\\n /// user's behalf by calling the permit function, paying gas fees,\\n /// and possibly performing other actions in the same transaction.\\n /// @dev The deadline argument can be set to `type(uint256).max to create\\n /// permits that effectively never expire.\\n function permit(\\n address owner,\\n address spender,\\n uint256 amount,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /// @notice Destroys `amount` tokens from the caller.\\n function burn(uint256 amount) external;\\n\\n /// @notice Destroys `amount` of tokens from `account`, deducting the amount\\n /// from caller's allowance.\\n function burnFrom(address account, uint256 amount) external;\\n\\n /// @notice Returns hash of EIP712 Domain struct with the token name as\\n /// a signing domain and token contract as a verifying contract.\\n /// Used to construct EIP2612 signature provided to `permit`\\n /// function.\\n /* solhint-disable-next-line func-name-mixedcase */\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n\\n /// @notice Returns the current nonce for EIP2612 permission for the\\n /// provided token owner for a replay protection. Used to construct\\n /// EIP2612 signature provided to `permit` function.\\n function nonce(address owner) external view returns (uint256);\\n\\n /// @notice Returns EIP2612 Permit message hash. Used to construct EIP2612\\n /// signature provided to `permit` function.\\n /* solhint-disable-next-line func-name-mixedcase */\\n function PERMIT_TYPEHASH() external pure returns (bytes32);\\n}\\n\",\"keccak256\":\"0xdac9a5086c19a7128b505a7be1ab0ac1aa314f6989cb88d2417e9d7383f89fa9\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IReceiveApproval.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\n/// @notice An interface that should be implemented by contracts supporting\\n/// `approveAndCall`/`receiveApproval` pattern.\\ninterface IReceiveApproval {\\n /// @notice Receives approval to spend tokens. Called as a result of\\n /// `approveAndCall` call on the token.\\n function receiveApproval(\\n address from,\\n uint256 amount,\\n address token,\\n bytes calldata extraData\\n ) external;\\n}\\n\",\"keccak256\":\"0x6a30d83ad230548b1e7839737affc8489a035314209de14b89dbef7fb0f66395\",\"license\":\"MIT\"},\"@threshold-network/solidity-contracts/contracts/staking/IApplication.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-or-later\\n\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n\\npragma solidity ^0.8.9;\\n\\n/// @title Application interface for Threshold Network applications\\n/// @notice Generic interface for an application. Application is an external\\n/// smart contract or a set of smart contracts utilizing functionalities\\n/// offered by Threshold Network. Applications authorized for the given\\n/// staking provider are eligible to slash the stake delegated to that\\n/// staking provider.\\ninterface IApplication {\\n /// @dev Event emitted by `withdrawRewards` function.\\n event RewardsWithdrawn(address indexed stakingProvider, uint96 amount);\\n\\n /// @notice Withdraws application rewards for the given staking provider.\\n /// Rewards are withdrawn to the staking provider's beneficiary\\n /// address set in the staking contract.\\n /// @dev Emits `RewardsWithdrawn` event.\\n function withdrawRewards(address stakingProvider) external;\\n\\n /// @notice Used by T staking contract to inform the application that the\\n /// authorized amount for the given staking provider increased.\\n /// The application may do any necessary housekeeping. The\\n /// application must revert the transaction in case the\\n /// authorization is below the minimum required.\\n function authorizationIncreased(\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external;\\n\\n /// @notice Used by T staking contract to inform the application that the\\n /// authorization decrease for the given staking provider has been\\n /// requested. The application should mark the authorization as\\n /// pending decrease and respond to the staking contract with\\n /// `approveAuthorizationDecrease` at its discretion. It may\\n /// happen right away but it also may happen several months later.\\n /// If there is already a pending authorization decrease request\\n /// for the application, and the application does not agree for\\n /// overwriting it, the function should revert.\\n function authorizationDecreaseRequested(\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external;\\n\\n /// @notice Used by T staking contract to inform the application the\\n /// authorization has been decreased for the given staking provider\\n /// involuntarily, as a result of slashing. Lets the application to\\n /// do any housekeeping neccessary. Called with 250k gas limit and\\n /// does not revert the transaction if\\n /// `involuntaryAuthorizationDecrease` call failed.\\n function involuntaryAuthorizationDecrease(\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external;\\n\\n /// @notice Returns the amount of application rewards available for\\n /// withdrawal for the given staking provider.\\n function availableRewards(address stakingProvider)\\n external\\n view\\n returns (uint96);\\n\\n /// @notice The minimum authorization amount required for the staking\\n /// provider so that they can participate in the application.\\n function minimumAuthorization() external view returns (uint96);\\n}\\n\",\"keccak256\":\"0x43d707dccc548bf48ad316d9652450cb297203234d251132cdc6b97508eb44c5\",\"license\":\"GPL-3.0-or-later\"},\"@threshold-network/solidity-contracts/contracts/staking/IStaking.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-or-later\\n\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n\\npragma solidity ^0.8.9;\\n\\n/// @title Interface of Threshold Network staking contract\\n/// @notice The staking contract enables T owners to have their wallets offline\\n/// and their stake managed by staking providers on their behalf.\\n/// The staking contract does not define operator role. The operator\\n/// responsible for running off-chain client software is appointed by\\n/// the staking provider in the particular application utilizing the\\n/// staking contract. All off-chain client software should be able\\n/// to run without exposing operator's or staking provider\\u2019s private\\n/// key and should not require any owner\\u2019s keys at all. The stake\\n/// delegation optimizes the network throughput without compromising the\\n/// security of the owners\\u2019 stake.\\ninterface IStaking {\\n enum StakeType {\\n NU,\\n KEEP,\\n T\\n }\\n\\n //\\n //\\n // Delegating a stake\\n //\\n //\\n\\n /// @notice Creates a delegation with `msg.sender` owner with the given\\n /// staking provider, beneficiary, and authorizer. Transfers the\\n /// given amount of T to the staking contract.\\n /// @dev The owner of the delegation needs to have the amount approved to\\n /// transfer to the staking contract.\\n function stake(\\n address stakingProvider,\\n address payable beneficiary,\\n address authorizer,\\n uint96 amount\\n ) external;\\n\\n /// @notice Allows the Governance to set the minimum required stake amount.\\n /// This amount is required to protect against griefing the staking\\n /// contract and individual applications are allowed to require\\n /// higher minimum stakes if necessary.\\n function setMinimumStakeAmount(uint96 amount) external;\\n\\n //\\n //\\n // Authorizing an application\\n //\\n //\\n\\n /// @notice Allows the Governance to approve the particular application\\n /// before individual stake authorizers are able to authorize it.\\n function approveApplication(address application) external;\\n\\n /// @notice Increases the authorization of the given staking provider for\\n /// the given application by the given amount. Can only be called by\\n /// the authorizer for that staking provider.\\n /// @dev Calls `authorizationIncreased(address stakingProvider, uint256 amount)`\\n /// on the given application to notify the application about\\n /// authorization change. See `IApplication`.\\n function increaseAuthorization(\\n address stakingProvider,\\n address application,\\n uint96 amount\\n ) external;\\n\\n /// @notice Requests decrease of the authorization for the given staking\\n /// provider on the given application by the provided amount.\\n /// It may not change the authorized amount immediatelly. When\\n /// it happens depends on the application. Can only be called by the\\n /// given staking provider\\u2019s authorizer. Overwrites pending\\n /// authorization decrease for the given staking provider and\\n /// application if the application agrees for that. If the\\n /// application does not agree for overwriting, the function\\n /// reverts.\\n /// @dev Calls `authorizationDecreaseRequested(address stakingProvider, uint256 amount)`\\n /// on the given application. See `IApplication`.\\n function requestAuthorizationDecrease(\\n address stakingProvider,\\n address application,\\n uint96 amount\\n ) external;\\n\\n /// @notice Requests decrease of all authorizations for the given staking\\n /// provider on all applications by all authorized amount.\\n /// It may not change the authorized amount immediatelly. When\\n /// it happens depends on the application. Can only be called by the\\n /// given staking provider\\u2019s authorizer. Overwrites pending\\n /// authorization decrease for the given staking provider and\\n /// application.\\n /// @dev Calls `authorizationDecreaseRequested(address stakingProvider, uint256 amount)`\\n /// for each authorized application. See `IApplication`.\\n function requestAuthorizationDecrease(address stakingProvider) external;\\n\\n /// @notice Called by the application at its discretion to approve the\\n /// previously requested authorization decrease request. Can only be\\n /// called by the application that was previously requested to\\n /// decrease the authorization for that staking provider.\\n /// Returns resulting authorized amount for the application.\\n function approveAuthorizationDecrease(address stakingProvider)\\n external\\n returns (uint96);\\n\\n /// @notice Decreases the authorization for the given `stakingProvider` on\\n /// the given disabled `application`, for all authorized amount.\\n /// Can be called by anyone.\\n function forceDecreaseAuthorization(\\n address stakingProvider,\\n address application\\n ) external;\\n\\n /// @notice Pauses the given application\\u2019s eligibility to slash stakes.\\n /// Besides that stakers can't change authorization to the application.\\n /// Can be called only by the Panic Button of the particular\\n /// application. The paused application can not slash stakes until\\n /// it is approved again by the Governance using `approveApplication`\\n /// function. Should be used only in case of an emergency.\\n function pauseApplication(address application) external;\\n\\n /// @notice Disables the given application. The disabled application can't\\n /// slash stakers. Also stakers can't increase authorization to that\\n /// application but can decrease without waiting by calling\\n /// `requestAuthorizationDecrease` at any moment. Can be called only\\n /// by the governance. The disabled application can't be approved\\n /// again. Should be used only in case of an emergency.\\n function disableApplication(address application) external;\\n\\n /// @notice Sets the Panic Button role for the given application to the\\n /// provided address. Can only be called by the Governance. If the\\n /// Panic Button for the given application should be disabled, the\\n /// role address should be set to 0x0 address.\\n function setPanicButton(address application, address panicButton) external;\\n\\n /// @notice Sets the maximum number of applications one staking provider can\\n /// have authorized. Used to protect against DoSing slashing queue.\\n /// Can only be called by the Governance.\\n function setAuthorizationCeiling(uint256 ceiling) external;\\n\\n //\\n //\\n // Stake top-up\\n //\\n //\\n\\n /// @notice Increases the amount of the stake for the given staking provider.\\n /// If `autoIncrease` flag is true then the amount will be added for\\n /// all authorized applications.\\n /// @dev The sender of this transaction needs to have the amount approved to\\n /// transfer to the staking contract.\\n function topUp(address stakingProvider, uint96 amount) external;\\n\\n /// @notice Toggle `autoIncrease` flag. If true then the complete amount\\n /// in top-up will be added to already authorized applications.\\n function toggleAutoAuthorizationIncrease(address stakingProvider) external;\\n\\n //\\n //\\n // Undelegating a stake (unstaking)\\n //\\n //\\n\\n /// @notice Reduces the liquid T stake amount by the provided amount and\\n /// withdraws T to the owner. Reverts if there is at least one\\n /// authorization higher than the sum of the legacy stake and\\n /// remaining liquid T stake or if the unstake amount is higher than\\n /// the liquid T stake amount. Can be called only by the delegation\\n /// owner or the staking provider.\\n function unstakeT(address stakingProvider, uint96 amount) external;\\n\\n /// @notice Sets the legacy KEEP staking contract active stake amount cached\\n /// in T staking contract to 0. Reverts if the amount of liquid T\\n /// staked in T staking contract is lower than the highest\\n /// application authorization. This function allows to unstake from\\n /// KEEP staking contract and still being able to operate in T\\n /// network and earning rewards based on the liquid T staked. Can be\\n /// called only by the delegation owner or the staking provider.\\n function unstakeKeep(address stakingProvider) external;\\n\\n /// @notice Sets to 0 the amount of T that is cached from the legacy\\n /// NU staking contract. Reverts if there is at least one\\n /// authorization higher than the sum of remaining legacy NU stake\\n /// and native T stake for that staking provider or if the unstaked\\n /// amount is higher than the cached legacy stake amount. If succeeded,\\n /// the legacy NU stake can be partially or fully undelegated on\\n /// the legacy NU staking contract. This function allows to unstake\\n /// from NU staking contract while still being able to operate in\\n /// T network and earning rewards based on the native T staked.\\n /// Can be called only by the stake owner or the staking provider.\\n function unstakeNu(address stakingProvider) external;\\n\\n /// @notice Sets cached legacy stake amount to 0, sets the liquid T stake\\n /// amount to 0 and withdraws all liquid T from the stake to the\\n /// owner. Reverts if there is at least one non-zero authorization.\\n /// Can be called only by the delegation owner or the staking\\n /// provider.\\n function unstakeAll(address stakingProvider) external;\\n\\n //\\n //\\n // Keeping information in sync\\n //\\n //\\n\\n /// @notice Sets reward in T tokens for notification of misbehaviour\\n /// of one staking provider. Can only be called by the governance.\\n function setNotificationReward(uint96 reward) external;\\n\\n /// @notice Transfer some amount of T tokens as reward for notifications\\n /// of misbehaviour\\n function pushNotificationReward(uint96 reward) external;\\n\\n /// @notice Withdraw some amount of T tokens from notifiers treasury.\\n /// Can only be called by the governance.\\n function withdrawNotificationReward(address recipient, uint96 amount)\\n external;\\n\\n /// @notice Adds staking providers to the slashing queue along with the\\n /// amount that should be slashed from each one of them. Can only be\\n /// called by application authorized for all staking providers in\\n /// the array.\\n function slash(uint96 amount, address[] memory stakingProviders) external;\\n\\n /// @notice Adds staking providers to the slashing queue along with the\\n /// amount. The notifier will receive reward per each staking\\n /// provider from notifiers treasury. Can only be called by\\n /// application authorized for all staking providers in the array.\\n function seize(\\n uint96 amount,\\n uint256 rewardMultipier,\\n address notifier,\\n address[] memory stakingProviders\\n ) external;\\n\\n /// @notice Takes the given number of queued slashing operations and\\n /// processes them. Receives 5% of the slashed amount.\\n /// Executes `involuntaryAllocationDecrease` function on each\\n /// affected application.\\n function processSlashing(uint256 count) external;\\n\\n //\\n //\\n // Auxiliary functions\\n //\\n //\\n\\n /// @notice Returns the authorized stake amount of the staking provider for\\n /// the application.\\n function authorizedStake(address stakingProvider, address application)\\n external\\n view\\n returns (uint96);\\n\\n /// @notice Returns staked amount of T, Keep and Nu for the specified\\n /// staking provider.\\n /// @dev All values are in T denomination\\n function stakes(address stakingProvider)\\n external\\n view\\n returns (\\n uint96 tStake,\\n uint96 keepInTStake,\\n uint96 nuInTStake\\n );\\n\\n /// @notice Returns start staking timestamp.\\n /// @dev This value is set at most once.\\n function getStartStakingTimestamp(address stakingProvider)\\n external\\n view\\n returns (uint256);\\n\\n /// @notice Returns auto-increase flag.\\n function getAutoIncreaseFlag(address stakingProvider)\\n external\\n view\\n returns (bool);\\n\\n /// @notice Returns staked amount of NU for the specified staking provider.\\n function stakedNu(address stakingProvider) external view returns (uint256);\\n\\n /// @notice Gets the stake owner, the beneficiary and the authorizer\\n /// for the specified staking provider address.\\n /// @return owner Stake owner address.\\n /// @return beneficiary Beneficiary address.\\n /// @return authorizer Authorizer address.\\n function rolesOf(address stakingProvider)\\n external\\n view\\n returns (\\n address owner,\\n address payable beneficiary,\\n address authorizer\\n );\\n\\n /// @notice Returns length of application array\\n function getApplicationsLength() external view returns (uint256);\\n\\n /// @notice Returns length of slashing queue\\n function getSlashingQueueLength() external view returns (uint256);\\n\\n /// @notice Returns minimum possible stake for T, KEEP or NU in T\\n /// denomination.\\n /// @dev For example, suppose the given staking provider has 10 T, 20 T worth\\n /// of KEEP, and 30 T worth of NU all staked, and the maximum\\n /// application authorization is 40 T, then `getMinStaked` for\\n /// that staking provider returns:\\n /// * 0 T if KEEP stake type specified i.e.\\n /// min = 40 T max - (10 T) = 30 T\\n /// * 10 T if NU stake type specified i.e.\\n /// min = 40 T max - (10 T) = 30 T\\n /// * 0 T if T stake type specified i.e.\\n /// min = 40 T max = 40 T\\n /// In other words, the minimum stake amount for the specified\\n /// stake type is the minimum amount of stake of the given type\\n /// needed to satisfy the maximum application authorization given\\n /// the staked amounts of the T stake types for that staking provider.\\n function getMinStaked(address stakingProvider, StakeType stakeTypes)\\n external\\n view\\n returns (uint96);\\n\\n /// @notice Returns available amount to authorize for the specified application\\n function getAvailableToAuthorize(\\n address stakingProvider,\\n address application\\n ) external view returns (uint96);\\n}\\n\",\"keccak256\":\"0xc8fbea45ba10de0383d6e7b2dd0f3931971e1b702e4a308ff8325bb23fdff81c\",\"license\":\"GPL-3.0-or-later\"},\"contracts/BeaconDkgValidator.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\nimport \\\"./libraries/BytesLib.sol\\\";\\nimport {BeaconDkg as DKG} from \\\"./libraries/BeaconDkg.sol\\\";\\n\\n/// @title DKG result validator\\n/// @notice DKGValidator allows performing a full validation of DKG result,\\n/// including checking the format of fields in the result, declared\\n/// selected group members, and signatures of operators supporting the\\n/// result. The operator submitting the result should perform the\\n/// validation using a free contract call before submitting the result\\n/// to ensure their result is valid and can not be challenged. All other\\n/// network operators should perform validation of the submitted result\\n/// using a free contract call and challenge the result if the\\n/// validation fails.\\ncontract BeaconDkgValidator {\\n using BytesLib for bytes;\\n using ECDSA for bytes32;\\n\\n /// @dev Size of a group in the threshold relay.\\n uint256 public constant groupSize = 64;\\n\\n /// @dev The minimum number of group members needed to interact according to\\n /// the protocol to produce a relay entry. The adversary can not learn\\n /// anything about the key as long as it does not break into\\n /// groupThreshold+1 of members.\\n uint256 public constant groupThreshold = 33;\\n\\n /// @dev The minimum number of active and properly behaving group members\\n /// during the DKG needed to accept the result. This number is higher\\n /// than `groupThreshold` to keep a safety margin for members becoming\\n /// inactive after DKG so that the group can still produce a relay\\n /// entry.\\n uint256 public constant activeThreshold = 58; // 90% of groupSize\\n\\n /// @dev Size in bytes of a single signature produced by operator supporting\\n /// DKG result.\\n uint256 public constant signatureByteSize = 65;\\n\\n SortitionPool public immutable sortitionPool;\\n\\n constructor(SortitionPool _sortitionPool) {\\n require(\\n address(_sortitionPool) != address(0),\\n \\\"Zero-address reference\\\"\\n );\\n\\n sortitionPool = _sortitionPool;\\n }\\n\\n /// @notice Performs a full validation of DKG result, including checking the\\n /// format of fields in the result, declared selected group members,\\n /// and signatures of operators supporting the result.\\n /// @param seed seed used to start the DKG and select group members\\n /// @param startBlock DKG start block\\n /// @return isValid true if the result is valid, false otherwise\\n /// @return errorMsg validation error message; empty for a valid result\\n function validate(\\n DKG.Result calldata result,\\n uint256 seed,\\n uint256 startBlock\\n ) external view returns (bool isValid, string memory errorMsg) {\\n (bool hasValidFields, string memory error) = validateFields(result);\\n if (!hasValidFields) {\\n return (false, error);\\n }\\n\\n if (!validateSignatures(result, startBlock)) {\\n return (false, \\\"Invalid signatures\\\");\\n }\\n\\n if (!validateGroupMembers(result, seed)) {\\n return (false, \\\"Invalid group members\\\");\\n }\\n\\n // At this point all group members and mishbehaved members were verified\\n if (!validateMembersHash(result)) {\\n return (false, \\\"Invalid members hash\\\");\\n }\\n\\n return (true, \\\"\\\");\\n }\\n\\n /// @notice Performs a static validation of DKG result fields: lengths,\\n /// ranges, and order of arrays.\\n /// @return isValid true if the result is valid, false otherwise\\n /// @return errorMsg validation error message; empty for a valid result\\n function validateFields(DKG.Result calldata result)\\n public\\n pure\\n returns (bool isValid, string memory errorMsg)\\n {\\n // Group public key needs to be 128 bytes long.\\n if (result.groupPubKey.length != 128) {\\n return (false, \\\"Malformed group public key\\\");\\n }\\n\\n // The number of misbehaved members can not exceed the threshold.\\n // Misbehaved member indices needs to be unique, between [1, groupSize],\\n // and sorted in ascending order.\\n uint8[] calldata misbehavedMembersIndices = result\\n .misbehavedMembersIndices;\\n if (groupSize - misbehavedMembersIndices.length < activeThreshold) {\\n return (false, \\\"Too many members misbehaving during DKG\\\");\\n }\\n if (misbehavedMembersIndices.length > 1) {\\n if (\\n misbehavedMembersIndices[0] < 1 ||\\n misbehavedMembersIndices[misbehavedMembersIndices.length - 1] >\\n groupSize\\n ) {\\n return (false, \\\"Corrupted misbehaved members indices\\\");\\n }\\n for (uint256 i = 1; i < misbehavedMembersIndices.length; i++) {\\n if (\\n misbehavedMembersIndices[i - 1] >=\\n misbehavedMembersIndices[i]\\n ) {\\n return (false, \\\"Corrupted misbehaved members indices\\\");\\n }\\n }\\n }\\n\\n // Each signature needs to have a correct length and signatures need to\\n // be provided.\\n uint256 signaturesCount = result.signatures.length / signatureByteSize;\\n if (result.signatures.length == 0) {\\n return (false, \\\"No signatures provided\\\");\\n }\\n if (result.signatures.length % signatureByteSize != 0) {\\n return (false, \\\"Malformed signatures array\\\");\\n }\\n\\n // We expect the same amount of signatures as the number of declared\\n // group member indices that signed the result.\\n uint256[] calldata signingMembersIndices = result.signingMembersIndices;\\n if (signaturesCount != signingMembersIndices.length) {\\n return (false, \\\"Unexpected signatures count\\\");\\n }\\n if (signaturesCount < groupThreshold) {\\n return (false, \\\"Too few signatures\\\");\\n }\\n if (signaturesCount > groupSize) {\\n return (false, \\\"Too many signatures\\\");\\n }\\n\\n // Signing member indices needs to be unique, between [1,groupSize],\\n // and sorted in ascending order.\\n if (\\n signingMembersIndices[0] < 1 ||\\n signingMembersIndices[signingMembersIndices.length - 1] > groupSize\\n ) {\\n return (false, \\\"Corrupted signing member indices\\\");\\n }\\n for (uint256 i = 1; i < signingMembersIndices.length; i++) {\\n if (signingMembersIndices[i - 1] >= signingMembersIndices[i]) {\\n return (false, \\\"Corrupted signing member indices\\\");\\n }\\n }\\n\\n return (true, \\\"\\\");\\n }\\n\\n /// @notice Performs validation of group members as declared in DKG\\n /// result against group members selected by the sortition pool.\\n /// @param seed seed used to start the DKG and select group members\\n /// @return true if group members matches; false otherwise\\n function validateGroupMembers(DKG.Result calldata result, uint256 seed)\\n public\\n view\\n returns (bool)\\n {\\n uint32[] calldata resultMembers = result.members;\\n uint32[] memory actualGroupMembers = sortitionPool.selectGroup(\\n groupSize,\\n bytes32(seed)\\n );\\n if (resultMembers.length != actualGroupMembers.length) {\\n return false;\\n }\\n for (uint256 i = 0; i < resultMembers.length; i++) {\\n if (resultMembers[i] != actualGroupMembers[i]) {\\n return false;\\n }\\n }\\n return true;\\n }\\n\\n /// @notice Performs validation of signatures supplied in DKG result.\\n /// Note that this function does not check if addresses which\\n /// supplied signatures supporting the result are the ones selected\\n /// to the group by sortition pool. This function should be used\\n /// together with `validateGroupMembers`.\\n /// @param startBlock DKG start block\\n /// @return true if group members matches; false otherwise\\n function validateSignatures(DKG.Result calldata result, uint256 startBlock)\\n public\\n view\\n returns (bool)\\n {\\n bytes32 hash = keccak256(\\n abi.encode(\\n block.chainid,\\n result.groupPubKey,\\n result.misbehavedMembersIndices,\\n startBlock\\n )\\n ).toEthSignedMessageHash();\\n\\n uint256[] calldata signingMembersIndices = result.signingMembersIndices;\\n uint32[] memory signingMemberIds = new uint32[](\\n signingMembersIndices.length\\n );\\n for (uint256 i = 0; i < signingMembersIndices.length; i++) {\\n signingMemberIds[i] = result.members[signingMembersIndices[i] - 1];\\n }\\n\\n address[] memory signingMemberAddresses = sortitionPool.getIDOperators(\\n signingMemberIds\\n );\\n\\n bytes memory current; // Current signature to be checked.\\n\\n uint256 signaturesCount = result.signatures.length / signatureByteSize;\\n for (uint256 i = 0; i < signaturesCount; i++) {\\n current = result.signatures.slice(\\n signatureByteSize * i,\\n signatureByteSize\\n );\\n address recoveredAddress = hash.recover(current);\\n\\n if (signingMemberAddresses[i] != recoveredAddress) {\\n return false;\\n }\\n }\\n\\n return true;\\n }\\n\\n /// @notice Performs validation of hashed group members that actively took\\n /// part in DKG.\\n /// @param result DKG result\\n /// @return true if result's group members hash matches with the one that is\\n /// challenged.\\n function validateMembersHash(DKG.Result calldata result)\\n public\\n pure\\n returns (bool)\\n {\\n if (result.misbehavedMembersIndices.length > 0) {\\n // members that generated a group signing key\\n uint32[] memory groupMembers = new uint32[](\\n result.members.length - result.misbehavedMembersIndices.length\\n );\\n uint256 k = 0; // misbehaved members counter\\n uint256 j = 0; // group members counter\\n for (uint256 i = 0; i < result.members.length; i++) {\\n // misbehaved member indices start from 1, so we need to -1 on misbehaved\\n if (i != result.misbehavedMembersIndices[k] - 1) {\\n groupMembers[j] = result.members[i];\\n j++;\\n } else if (k < result.misbehavedMembersIndices.length - 1) {\\n k++;\\n }\\n }\\n\\n return keccak256(abi.encode(groupMembers)) == result.membersHash;\\n }\\n\\n return keccak256(abi.encode(result.members)) == result.membersHash;\\n }\\n}\\n\",\"keccak256\":\"0xaacb5961dc3181238036f1e747b3d1935f356ca5ff27bd9c9c1c0c22dee6630c\",\"license\":\"GPL-3.0-only\"},\"contracts/Governable.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\n/// @notice Governable contract.\\n/// @dev A constructor is not defined, which makes the contract compatible with\\n/// upgradable proxies. This requires calling explicitly `_transferGovernance`\\n/// function in a child contract.\\nabstract contract Governable {\\n // Governance of the contract\\n // The variable should be initialized by the implementing contract.\\n // slither-disable-next-line uninitialized-state\\n address public governance;\\n\\n // Reserved storage space in case we need to add more variables,\\n // since there are upgradeable contracts that inherit from this one.\\n // See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\\n // slither-disable-next-line unused-state\\n uint256[49] private __gap;\\n\\n event GovernanceTransferred(address oldGovernance, address newGovernance);\\n\\n modifier onlyGovernance() virtual {\\n require(governance == msg.sender, \\\"Caller is not the governance\\\");\\n _;\\n }\\n\\n /// @notice Transfers governance of the contract to `newGovernance`.\\n function transferGovernance(address newGovernance)\\n external\\n virtual\\n onlyGovernance\\n {\\n require(\\n newGovernance != address(0),\\n \\\"New governance is the zero address\\\"\\n );\\n _transferGovernance(newGovernance);\\n }\\n\\n function _transferGovernance(address newGovernance) internal virtual {\\n address oldGovernance = governance;\\n governance = newGovernance;\\n emit GovernanceTransferred(oldGovernance, newGovernance);\\n }\\n}\\n\",\"keccak256\":\"0xcc6a0fe8fdf05a805d2874dc7dd76dede1eb16e3ab77f2d0069dbb92272ab0a3\",\"license\":\"GPL-3.0-only\"},\"contracts/RandomBeacon.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./api/IRandomBeacon.sol\\\";\\nimport \\\"./libraries/Groups.sol\\\";\\nimport \\\"./libraries/Relay.sol\\\";\\nimport \\\"./libraries/Groups.sol\\\";\\nimport \\\"./libraries/Callback.sol\\\";\\nimport \\\"./Reimbursable.sol\\\";\\nimport \\\"./Governable.sol\\\";\\nimport {BeaconInactivity as Inactivity} from \\\"./libraries/BeaconInactivity.sol\\\";\\nimport {BeaconAuthorization as Authorization} from \\\"./libraries/BeaconAuthorization.sol\\\";\\nimport {BeaconDkg as DKG} from \\\"./libraries/BeaconDkg.sol\\\";\\nimport {BeaconDkgValidator as DKGValidator} from \\\"./BeaconDkgValidator.sol\\\";\\n\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\nimport \\\"@threshold-network/solidity-contracts/contracts/staking/IApplication.sol\\\";\\nimport \\\"@threshold-network/solidity-contracts/contracts/staking/IStaking.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/Math.sol\\\";\\n\\n/// @title Keep Random Beacon\\n/// @notice Keep Random Beacon contract. It lets to request a new\\n/// relay entry and validates the new relay entry provided by the\\n/// network. This contract is in charge of all other Random Beacon\\n/// activities such as group lifecycle or slashing.\\n/// @dev Should be owned by the governance contract controlling Random Beacon\\n/// parameters.\\ncontract RandomBeacon is IRandomBeacon, IApplication, Governable, Reimbursable {\\n using SafeERC20 for IERC20;\\n using Authorization for Authorization.Data;\\n using DKG for DKG.Data;\\n using Groups for Groups.Data;\\n using Relay for Relay.Data;\\n using Callback for Callback.Data;\\n\\n // Constant parameters\\n\\n /// @notice Seed value used for the genesis group selection.\\n /// https://www.wolframalpha.com/input/?i=pi+to+78+digits\\n uint256 internal constant genesisSeed =\\n 31415926535897932384626433832795028841971693993751058209749445923078164062862;\\n\\n // Governable parameters\\n\\n /// @notice Relay entry callback gas limit. This is the gas limit with which\\n /// callback function provided in the relay request transaction is\\n /// executed. The callback is executed with a new relay entry value\\n /// in the same transaction the relay entry is submitted.\\n uint256 internal _callbackGasLimit;\\n\\n /// @notice The frequency of new group creation. Groups are created with\\n /// a fixed frequency of relay requests.\\n uint256 internal _groupCreationFrequency;\\n\\n /// @notice Slashing amount for submitting a malicious DKG result. Every\\n /// DKG result submitted can be challenged for the time of\\n /// `dkg.ResultChallengePeriodLength`. If the DKG result submitted\\n /// is challenged and proven to be malicious, the operator who\\n /// submitted the malicious result is slashed for\\n /// `_maliciousDkgResultSlashingAmount`.\\n uint96 internal _maliciousDkgResultSlashingAmount;\\n\\n /// @notice Slashing amount when an unauthorized signing has been proved,\\n /// which means the private key leaked and all the group members\\n /// should be punished.\\n uint96 internal _unauthorizedSigningSlashingAmount;\\n\\n /// @notice Duration of the sortition pool rewards ban imposed on operators\\n /// who misbehaved during DKG by being inactive or disqualified and\\n /// for operators that were identified by the rest of group members\\n /// as inactive via `notifyOperatorInactivity`.\\n uint256 internal _sortitionPoolRewardsBanDuration;\\n\\n /// @notice Percentage of the staking contract malicious behavior\\n /// notification reward which will be transferred to the notifier\\n /// reporting about relay entry timeout. Notifiers are rewarded\\n /// from a notifiers treasury pool. For example, if\\n /// notification reward is 1000 and the value of the multiplier is\\n /// 5, the notifier will receive: 5% of 1000 = 50 per each\\n /// operator affected.\\n uint256 internal _relayEntryTimeoutNotificationRewardMultiplier;\\n\\n /// @notice Percentage of the staking contract malicious behavior\\n /// notification reward which will be transferred to the notifier\\n /// reporting about unauthorized signing. Notifiers are rewarded\\n /// from a notifiers treasury pool. For example, if a\\n /// notification reward is 1000 and the value of the multiplier is\\n /// 5, the notifier will receive: 5% of 1000 = 50 per each\\n /// operator affected.\\n uint256 internal _unauthorizedSigningNotificationRewardMultiplier;\\n\\n /// @notice Percentage of the staking contract malicious behavior\\n /// notification reward which will be transferred to the notifier\\n /// reporting about a malicious DKG result. Notifiers are rewarded\\n /// from a notifiers treasury pool. For example, if\\n /// notification reward is 1000 and the value of the multiplier is\\n /// 5, the notifier will receive: 5% of 1000 = 50 per each\\n /// operator affected.\\n uint256 internal _dkgMaliciousResultNotificationRewardMultiplier;\\n\\n /// @notice Calculated gas cost for submitting a DKG result. This will\\n /// be refunded as part of the DKG approval process. It is in the\\n /// submitter's interest to not skip his priority turn on the approval,\\n /// otherwise the refund of the DKG submission will be refunded to\\n /// another group member that will call the DKG approve function.\\n uint256 internal _dkgResultSubmissionGas;\\n\\n /// @notice Gas that is meant to balance the DKG result approval's overall\\n /// cost. Can be updated by the governance based on the current\\n /// market conditions.\\n uint256 internal _dkgResultApprovalGasOffset;\\n\\n /// @notice Gas that is meant to balance the operator inactivity notification\\n /// cost. Can be updated by the governance based on the current\\n /// market conditions.\\n uint256 internal _notifyOperatorInactivityGasOffset;\\n\\n /// @notice Gas that is meant to balance the relay entry submission cost.\\n /// Can be updated by the governance based on the current market\\n /// conditions.\\n uint256 internal _relayEntrySubmissionGasOffset;\\n\\n // Other parameters\\n\\n /// @notice Stores current operator inactivity claim nonce for given group.\\n /// Each claim is made with an unique nonce which protects\\n /// against claim replay.\\n mapping(uint64 => uint256) public inactivityClaimNonce; // groupId -> nonce\\n\\n /// @notice Authorized addresses that can request a relay entry.\\n mapping(address => bool) public authorizedRequesters;\\n\\n // External dependencies\\n\\n SortitionPool public sortitionPool;\\n IERC20 public tToken;\\n IStaking public staking;\\n\\n // Libraries data storages\\n\\n Authorization.Data internal authorization;\\n DKG.Data internal dkg;\\n Groups.Data internal groups;\\n Relay.Data internal relay;\\n Callback.Data internal callback;\\n\\n // Events\\n\\n event AuthorizationParametersUpdated(\\n uint96 minimumAuthorization,\\n uint64 authorizationDecreaseDelay,\\n uint64 authorizationDecreaseChangePeriod\\n );\\n\\n event RelayEntryParametersUpdated(\\n uint256 relayEntrySoftTimeout,\\n uint256 relayEntryHardTimeout,\\n uint256 callbackGasLimit\\n );\\n\\n event GroupCreationParametersUpdated(\\n uint256 groupCreationFrequency,\\n uint256 groupLifetime,\\n uint256 dkgResultChallengePeriodLength,\\n uint256 dkgResultChallengeExtraGas,\\n uint256 dkgResultSubmissionTimeout,\\n uint256 dkgResultSubmitterPrecedencePeriodLength\\n );\\n\\n event RewardParametersUpdated(\\n uint256 sortitionPoolRewardsBanDuration,\\n uint256 relayEntryTimeoutNotificationRewardMultiplier,\\n uint256 unauthorizedSigningNotificationRewardMultiplier,\\n uint256 dkgMaliciousResultNotificationRewardMultiplier\\n );\\n\\n event SlashingParametersUpdated(\\n uint256 relayEntrySubmissionFailureSlashingAmount,\\n uint256 maliciousDkgResultSlashingAmount,\\n uint256 unauthorizedSigningSlashingAmount\\n );\\n\\n event GasParametersUpdated(\\n uint256 dkgResultSubmissionGas,\\n uint256 dkgResultApprovalGasOffset,\\n uint256 notifyOperatorInactivityGasOffset,\\n uint256 relayEntrySubmissionGasOffset\\n );\\n\\n event RequesterAuthorizationUpdated(\\n address indexed requester,\\n bool isAuthorized\\n );\\n\\n event DkgStarted(uint256 indexed seed);\\n\\n event DkgResultSubmitted(\\n bytes32 indexed resultHash,\\n uint256 indexed seed,\\n DKG.Result result\\n );\\n\\n event DkgTimedOut();\\n\\n event DkgResultApproved(\\n bytes32 indexed resultHash,\\n address indexed approver\\n );\\n\\n event DkgResultChallenged(\\n bytes32 indexed resultHash,\\n address indexed challenger,\\n string reason\\n );\\n\\n event DkgMaliciousResultSlashed(\\n bytes32 indexed resultHash,\\n uint256 slashingAmount,\\n address maliciousSubmitter\\n );\\n\\n event DkgMaliciousResultSlashingFailed(\\n bytes32 indexed resultHash,\\n uint256 slashingAmount,\\n address maliciousSubmitter\\n );\\n\\n event DkgStateLocked();\\n\\n event DkgSeedTimedOut();\\n\\n event GroupRegistered(uint64 indexed groupId, bytes indexed groupPubKey);\\n\\n event RelayEntryRequested(\\n uint256 indexed requestId,\\n uint64 groupId,\\n bytes previousEntry\\n );\\n\\n event RelayEntrySubmitted(\\n uint256 indexed requestId,\\n address submitter,\\n bytes entry\\n );\\n\\n event RelayEntryTimedOut(\\n uint256 indexed requestId,\\n uint64 terminatedGroupId\\n );\\n\\n event RelayEntryDelaySlashed(\\n uint256 indexed requestId,\\n uint256 slashingAmount,\\n address[] groupMembers\\n );\\n\\n event RelayEntryDelaySlashingFailed(\\n uint256 indexed requestId,\\n uint256 slashingAmount,\\n address[] groupMembers\\n );\\n\\n event RelayEntryTimeoutSlashed(\\n uint256 indexed requestId,\\n uint256 slashingAmount,\\n address[] groupMembers\\n );\\n\\n event RelayEntryTimeoutSlashingFailed(\\n uint256 indexed requestId,\\n uint256 slashingAmount,\\n address[] groupMembers\\n );\\n\\n event UnauthorizedSigningSlashed(\\n uint64 indexed groupId,\\n uint256 unauthorizedSigningSlashingAmount,\\n address[] groupMembers\\n );\\n\\n event UnauthorizedSigningSlashingFailed(\\n uint64 indexed groupId,\\n uint256 unauthorizedSigningSlashingAmount,\\n address[] groupMembers\\n );\\n\\n event CallbackFailed(uint256 entry, uint256 entrySubmittedBlock);\\n\\n event InactivityClaimed(\\n uint64 indexed groupId,\\n uint256 nonce,\\n address notifier\\n );\\n\\n event OperatorRegistered(\\n address indexed stakingProvider,\\n address indexed operator\\n );\\n\\n event AuthorizationIncreased(\\n address indexed stakingProvider,\\n address indexed operator,\\n uint96 fromAmount,\\n uint96 toAmount\\n );\\n\\n event AuthorizationDecreaseRequested(\\n address indexed stakingProvider,\\n address indexed operator,\\n uint96 fromAmount,\\n uint96 toAmount,\\n uint64 decreasingAt\\n );\\n\\n event AuthorizationDecreaseApproved(address indexed stakingProvider);\\n\\n event InvoluntaryAuthorizationDecreaseFailed(\\n address indexed stakingProvider,\\n address indexed operator,\\n uint96 fromAmount,\\n uint96 toAmount\\n );\\n\\n event OperatorJoinedSortitionPool(\\n address indexed stakingProvider,\\n address indexed operator\\n );\\n\\n event OperatorStatusUpdated(\\n address indexed stakingProvider,\\n address indexed operator\\n );\\n\\n /// @dev Assigns initial values to parameters to make the beacon work\\n /// safely. These parameters are just proposed defaults and they might\\n /// be updated with `update*` functions after the contract deployment\\n /// and before transferring the ownership to the governance contract.\\n constructor(\\n SortitionPool _sortitionPool,\\n IERC20 _tToken,\\n IStaking _staking,\\n DKGValidator _dkgValidator,\\n ReimbursementPool _reimbursementPool\\n ) {\\n sortitionPool = _sortitionPool;\\n tToken = _tToken;\\n staking = _staking;\\n reimbursementPool = _reimbursementPool;\\n\\n require(\\n address(_sortitionPool) != address(0),\\n \\\"Zero-address reference\\\"\\n );\\n require(address(_tToken) != address(0), \\\"Zero-address reference\\\");\\n require(address(_staking) != address(0), \\\"Zero-address reference\\\");\\n require(address(_dkgValidator) != address(0), \\\"Zero-address reference\\\");\\n require(\\n address(_reimbursementPool) != address(0),\\n \\\"Zero-address reference\\\"\\n );\\n\\n dkg.init(_sortitionPool, _dkgValidator);\\n relay.initSeedEntry();\\n\\n _transferGovernance(msg.sender);\\n\\n //\\n // All parameters set in the constructor are initial ones, used at the\\n // moment contracts were deployed for the first time. Parameters are\\n // governable and values assigned in the constructor do not need to\\n // reflect the current ones.\\n //\\n\\n // Minimum authorization is 40k T.\\n //\\n // Authorization decrease delay is 45 days.\\n //\\n // Authorization decrease change period is 45 days. It means pending\\n // authorization decrease can be overwritten all the time.\\n authorization.setParameters(40_000e18, 3_888_000, 3_888_000);\\n\\n // Malicious DKG result slashing amount is set initially to 1% of the\\n // minimum authorization (400 T). This values needs to be increased\\n // significantly once the system is fully launched.\\n //\\n // Unauthorized signing slashing amount is set initially to 1% of the\\n // minimum authorization (400 T). This values needs to be increased\\n // significantly once the system is fully launched.\\n //\\n // Slashing amount for not providing relay entry on time is set\\n // initially to 1% of the minimum authorization (400 T). This values\\n // needs to be increased significantly once the system is fully launched.\\n //\\n // Inactive operators are set as ineligible for rewards for 2 weeks.\\n _maliciousDkgResultSlashingAmount = 400e18;\\n _unauthorizedSigningSlashingAmount = 400e18;\\n relay.setRelayEntrySubmissionFailureSlashingAmount(400e18);\\n\\n // Notifier of a malicious DKG result receives 100% of the notifier\\n // reward from the staking contract.\\n //\\n // Notifier of unauthorized signing receives 100% of the notifier\\n // reward from the staking contract.\\n //\\n // Notifier of relay entry timeout receives 100% of the notifier\\n // reward from the staking contract.\\n _dkgMaliciousResultNotificationRewardMultiplier = 100;\\n _unauthorizedSigningNotificationRewardMultiplier = 100;\\n _relayEntryTimeoutNotificationRewardMultiplier = 100;\\n\\n // Inactive operators are set as ineligible for rewards for 2 weeks.\\n _sortitionPoolRewardsBanDuration = 2 weeks;\\n\\n // DKG result challenge period length is set to 48h, assuming\\n // 15s block time.\\n //\\n // The extra gas required for DKG result challenge is 50k units.\\n //\\n // DKG result submission timeout, gives each member 20 blocks to submit\\n // the result. Assuming 15s block time, it is ~8h to submit the result\\n // in the pessimistic case.\\n //\\n // The original DKG result submitter has 20 blocks to approve it before\\n // anyone else can do that.\\n //\\n // With these parameters, the happy path takes no more than 56 hours.\\n // In practice, it should take about 48 hours (just the challenge time).\\n dkg.setParameters(11_520, 50_000, 1_280, 20);\\n\\n // Relay entry soft timeout gives each of 64 members 20 blocks to submit\\n // the result.\\n //\\n // Relay entry hard timeout is set to ~48h assuming 15s block time.\\n relay.setTimeouts(1_280, 5_760);\\n\\n // Callback gas limit is set to 56k units of gas. As of April 2022, it\\n // is enough to store new entry and block number on-chain.\\n // If the cost of EVM opcodes change over time, these parameters will\\n // have to be updated.\\n _callbackGasLimit = 64_000;\\n\\n // Group lifetime is set to 45 days assuming 15s block time.\\n //\\n // New group is created every 2 relay requests.\\n //\\n // This way, even if ECDSA WalletRegistry is the only consumer of the\\n // beacon initially, and relay request is executed every week, we should\\n // have 2 active groups in the system all the time.\\n groups.setGroupLifetime(259_200);\\n _groupCreationFrequency = 2;\\n\\n // Gas parameters were adjusted based on Ethereum state in April 2022.\\n // If the cost of EVM opcodes change over time, these parameters will\\n // have to be updated.\\n _dkgResultSubmissionGas = 237_650;\\n _dkgResultApprovalGasOffset = 41_500;\\n _notifyOperatorInactivityGasOffset = 54_500;\\n _relayEntrySubmissionGasOffset = 11_250;\\n }\\n\\n modifier onlyStakingContract() {\\n require(\\n msg.sender == address(staking),\\n \\\"Caller is not the staking contract\\\"\\n );\\n _;\\n }\\n\\n modifier onlyReimbursableAdmin() override {\\n require(governance == msg.sender, \\\"Caller is not the governance\\\");\\n _;\\n }\\n\\n /// @notice Updates the values of authorization parameters.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract. The caller is responsible for\\n /// validating parameters.\\n /// @param _minimumAuthorization New minimum authorization amount\\n /// @param _authorizationDecreaseDelay New authorization decrease delay in\\n /// seconds\\n /// @param _authorizationDecreaseChangePeriod New authorization decrease\\n /// change period in seconds\\n function updateAuthorizationParameters(\\n uint96 _minimumAuthorization,\\n uint64 _authorizationDecreaseDelay,\\n uint64 _authorizationDecreaseChangePeriod\\n ) external onlyGovernance {\\n authorization.setParameters(\\n _minimumAuthorization,\\n _authorizationDecreaseDelay,\\n _authorizationDecreaseChangePeriod\\n );\\n\\n emit AuthorizationParametersUpdated(\\n _minimumAuthorization,\\n _authorizationDecreaseDelay,\\n _authorizationDecreaseChangePeriod\\n );\\n }\\n\\n /// @notice Updates the values of relay entry parameters.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract. The caller is responsible for\\n /// validating parameters.\\n /// @param relayEntrySoftTimeout New relay entry submission soft timeout\\n /// @param relayEntryHardTimeout New relay entry hard timeout\\n /// @param callbackGasLimit New callback gas limit\\n function updateRelayEntryParameters(\\n uint256 relayEntrySoftTimeout,\\n uint256 relayEntryHardTimeout,\\n uint256 callbackGasLimit\\n ) external onlyGovernance {\\n _callbackGasLimit = callbackGasLimit;\\n relay.setTimeouts(relayEntrySoftTimeout, relayEntryHardTimeout);\\n\\n emit RelayEntryParametersUpdated(\\n relayEntrySoftTimeout,\\n relayEntryHardTimeout,\\n callbackGasLimit\\n );\\n }\\n\\n /// @notice Updates the values of group creation parameters.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract. The caller is responsible for\\n /// validating parameters.\\n /// @param groupCreationFrequency New group creation frequency\\n /// @param groupLifetime New group lifetime in blocks\\n /// @param dkgResultChallengePeriodLength New DKG result challenge period\\n /// length\\n /// @param dkgResultChallengeExtraGas New DKG result challenge extra gas\\n /// @param dkgResultSubmissionTimeout New DKG result submission timeout\\n /// @param dkgSubmitterPrecedencePeriodLength New DKG result submitter\\n /// precedence period length\\n function updateGroupCreationParameters(\\n uint256 groupCreationFrequency,\\n uint256 groupLifetime,\\n uint256 dkgResultChallengePeriodLength,\\n uint256 dkgResultChallengeExtraGas,\\n uint256 dkgResultSubmissionTimeout,\\n uint256 dkgSubmitterPrecedencePeriodLength\\n ) external onlyGovernance {\\n _groupCreationFrequency = groupCreationFrequency;\\n groups.setGroupLifetime(groupLifetime);\\n dkg.setParameters(\\n dkgResultChallengePeriodLength,\\n dkgResultChallengeExtraGas,\\n dkgResultSubmissionTimeout,\\n dkgSubmitterPrecedencePeriodLength\\n );\\n\\n emit GroupCreationParametersUpdated(\\n groupCreationFrequency,\\n groupLifetime,\\n dkgResultChallengePeriodLength,\\n dkgResultChallengeExtraGas,\\n dkgResultSubmissionTimeout,\\n dkgSubmitterPrecedencePeriodLength\\n );\\n }\\n\\n /// @notice Updates the values of reward parameters.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract. The caller is responsible for\\n /// validating parameters.\\n /// @param sortitionPoolRewardsBanDuration New sortition pool rewards\\n /// ban duration in seconds.\\n /// @param relayEntryTimeoutNotificationRewardMultiplier New value of the\\n /// relay entry timeout notification reward multiplier\\n /// @param unauthorizedSigningNotificationRewardMultiplier New value of the\\n /// unauthorized signing notification reward multiplier\\n /// @param dkgMaliciousResultNotificationRewardMultiplier New value of the\\n /// DKG malicious result notification reward multiplier\\n function updateRewardParameters(\\n uint256 sortitionPoolRewardsBanDuration,\\n uint256 relayEntryTimeoutNotificationRewardMultiplier,\\n uint256 unauthorizedSigningNotificationRewardMultiplier,\\n uint256 dkgMaliciousResultNotificationRewardMultiplier\\n ) external onlyGovernance {\\n _sortitionPoolRewardsBanDuration = sortitionPoolRewardsBanDuration;\\n _relayEntryTimeoutNotificationRewardMultiplier = relayEntryTimeoutNotificationRewardMultiplier;\\n _unauthorizedSigningNotificationRewardMultiplier = unauthorizedSigningNotificationRewardMultiplier;\\n _dkgMaliciousResultNotificationRewardMultiplier = dkgMaliciousResultNotificationRewardMultiplier;\\n emit RewardParametersUpdated(\\n sortitionPoolRewardsBanDuration,\\n relayEntryTimeoutNotificationRewardMultiplier,\\n unauthorizedSigningNotificationRewardMultiplier,\\n dkgMaliciousResultNotificationRewardMultiplier\\n );\\n }\\n\\n /// @notice Updates the values of slashing parameters.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract. The caller is responsible for\\n /// validating parameters.\\n /// @param relayEntrySubmissionFailureSlashingAmount New relay entry\\n /// submission failure amount\\n /// @param maliciousDkgResultSlashingAmount New malicious DKG result\\n /// slashing amount\\n /// @param unauthorizedSigningSlashingAmount New unauthorized signing\\n /// slashing amount\\n function updateSlashingParameters(\\n uint96 relayEntrySubmissionFailureSlashingAmount,\\n uint96 maliciousDkgResultSlashingAmount,\\n uint96 unauthorizedSigningSlashingAmount\\n ) external onlyGovernance {\\n relay.setRelayEntrySubmissionFailureSlashingAmount(\\n relayEntrySubmissionFailureSlashingAmount\\n );\\n _maliciousDkgResultSlashingAmount = maliciousDkgResultSlashingAmount;\\n _unauthorizedSigningSlashingAmount = unauthorizedSigningSlashingAmount;\\n emit SlashingParametersUpdated(\\n relayEntrySubmissionFailureSlashingAmount,\\n maliciousDkgResultSlashingAmount,\\n unauthorizedSigningSlashingAmount\\n );\\n }\\n\\n /// @notice Updates the values of gas parameters.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract. The caller is responsible for\\n /// validating parameters.\\n /// @param dkgResultSubmissionGas New DKG result submission gas\\n /// @param dkgResultApprovalGasOffset New DKG result approval gas offset\\n /// @param notifyOperatorInactivityGasOffset New operator inactivity\\n /// notification gas offset\\n /// @param relayEntrySubmissionGasOffset New relay entry submission gas\\n /// offset\\n function updateGasParameters(\\n uint256 dkgResultSubmissionGas,\\n uint256 dkgResultApprovalGasOffset,\\n uint256 notifyOperatorInactivityGasOffset,\\n uint256 relayEntrySubmissionGasOffset\\n ) external onlyGovernance {\\n _dkgResultSubmissionGas = dkgResultSubmissionGas;\\n _dkgResultApprovalGasOffset = dkgResultApprovalGasOffset;\\n _notifyOperatorInactivityGasOffset = notifyOperatorInactivityGasOffset;\\n _relayEntrySubmissionGasOffset = relayEntrySubmissionGasOffset;\\n\\n emit GasParametersUpdated(\\n dkgResultSubmissionGas,\\n dkgResultApprovalGasOffset,\\n notifyOperatorInactivityGasOffset,\\n relayEntrySubmissionGasOffset\\n );\\n }\\n\\n /// @notice Set authorization for requesters that can request a relay\\n /// entry.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract.\\n /// @param requester Requester, can be a contract or EOA\\n /// @param isAuthorized True or false\\n function setRequesterAuthorization(address requester, bool isAuthorized)\\n external\\n onlyGovernance\\n {\\n authorizedRequesters[requester] = isAuthorized;\\n\\n emit RequesterAuthorizationUpdated(requester, isAuthorized);\\n }\\n\\n /// @notice Withdraws application rewards for the given staking provider.\\n /// Rewards are withdrawn to the staking provider's beneficiary\\n /// address set in the staking contract. Reverts if staking provider\\n /// has not registered the operator address.\\n /// @dev Emits `RewardsWithdrawn` event.\\n function withdrawRewards(address stakingProvider) external {\\n address operator = stakingProviderToOperator(stakingProvider);\\n require(operator != address(0), \\\"Unknown operator\\\");\\n (, address beneficiary, ) = staking.rolesOf(stakingProvider);\\n uint96 amount = sortitionPool.withdrawRewards(operator, beneficiary);\\n // slither-disable-next-line reentrancy-events\\n emit RewardsWithdrawn(stakingProvider, amount);\\n }\\n\\n /// @notice Withdraws rewards belonging to operators marked as ineligible\\n /// for sortition pool rewards.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract.\\n /// @param recipient Recipient of withdrawn rewards.\\n function withdrawIneligibleRewards(address recipient)\\n external\\n onlyGovernance\\n {\\n sortitionPool.withdrawIneligible(recipient);\\n }\\n\\n /// @notice Used by staking provider to set operator address that will\\n /// operate a node. The given staking provider can set operator\\n /// address only one time. The operator address can not be changed\\n /// and must be unique. Reverts if the operator is already set for\\n /// the staking provider or if the operator address is already in\\n /// use. Reverts if there is a pending authorization decrease for\\n /// the staking provider.\\n function registerOperator(address operator) external {\\n authorization.registerOperator(operator);\\n }\\n\\n /// @notice Lets the operator join the sortition pool. The operator address\\n /// must be known - before calling this function, it has to be\\n /// appointed by the staking provider by calling `registerOperator`.\\n /// Also, the operator must have the minimum authorization required\\n /// by the beacon. Function reverts if there is no minimum stake\\n /// authorized or if the operator is not known. If there was an\\n /// authorization decrease requested, it is activated by starting\\n /// the authorization decrease delay.\\n function joinSortitionPool() external {\\n authorization.joinSortitionPool(staking, sortitionPool);\\n }\\n\\n /// @notice Updates status of the operator in the sortition pool. If there\\n /// was an authorization decrease requested, it is activated by\\n /// starting the authorization decrease delay.\\n /// Function reverts if the operator is not known.\\n function updateOperatorStatus(address operator) external {\\n authorization.updateOperatorStatus(staking, sortitionPool, operator);\\n }\\n\\n /// @notice Used by T staking contract to inform the beacon that the\\n /// authorized stake amount for the given staking provider increased.\\n ///\\n /// Reverts if the authorization amount is below the minimum.\\n ///\\n /// The function is not updating the sortition pool. Sortition pool\\n /// state needs to be updated by the operator with a call to\\n /// `joinSortitionPool` or `updateOperatorStatus`.\\n ///\\n /// @dev Can only be called by T staking contract.\\n function authorizationIncreased(\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external onlyStakingContract {\\n authorization.authorizationIncreased(\\n stakingProvider,\\n fromAmount,\\n toAmount\\n );\\n }\\n\\n /// @notice Used by T staking contract to inform the beacon that the\\n /// authorization decrease for the given staking provider has been\\n /// requested.\\n ///\\n /// Reverts if the amount after deauthorization would be non-zero\\n /// and lower than the minimum authorization.\\n ///\\n /// Reverts if another authorization decrease request is pending for\\n /// the staking provider and not enough time passed since the\\n /// original request (see `authorizationDecreaseChangePeriod`).\\n ///\\n /// If the operator is not known (`registerOperator` was not called)\\n /// it lets to `approveAuthorizationDecrease` immediately. If the\\n /// operator is known (`registerOperator` was called), the operator\\n /// needs to update state of the sortition pool with a call to\\n /// `joinSortitionPool` or `updateOperatorStatus`. After the\\n /// sortition pool state is in sync, authorization decrease delay\\n /// starts.\\n ///\\n /// After authorization decrease delay passes, authorization\\n /// decrease request needs to be approved with a call to\\n /// `approveAuthorizationDecrease` function.\\n ///\\n /// If there is a pending authorization decrease request, it is\\n /// overwritten, but only if enough time passed since the original\\n /// request. Otherwise, the function reverts.\\n ///\\n /// @dev Can only be called by T staking contract.\\n function authorizationDecreaseRequested(\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external onlyStakingContract {\\n authorization.authorizationDecreaseRequested(\\n stakingProvider,\\n fromAmount,\\n toAmount\\n );\\n }\\n\\n /// @notice Approves the previously registered authorization decrease\\n /// request. Reverts if authorization decrease delay has not passed\\n /// yet or if the authorization decrease was not requested for the\\n /// given staking provider.\\n function approveAuthorizationDecrease(address stakingProvider) external {\\n authorization.approveAuthorizationDecrease(staking, stakingProvider);\\n }\\n\\n /// @notice Used by T staking contract to inform the beacon the\\n /// authorization has been decreased for the given staking provider\\n /// involuntarily, as a result of slashing.\\n ///\\n /// If the operator is not known (`registerOperator` was not called)\\n /// the function does nothing. The operator was never in a sortition\\n /// pool so there is nothing to update.\\n ///\\n /// If the operator is known, sortition pool is unlocked, and the\\n /// operator is in the sortition pool, the sortition pool state is\\n /// updated. If the sortition pool is locked, update needs to be\\n /// postponed. Every other staker is incentivized to call\\n /// `updateOperatorStatus` for the problematic operator to increase\\n /// their own rewards in the pool.\\n function involuntaryAuthorizationDecrease(\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external onlyStakingContract {\\n authorization.involuntaryAuthorizationDecrease(\\n staking,\\n sortitionPool,\\n stakingProvider,\\n fromAmount,\\n toAmount\\n );\\n }\\n\\n /// @notice Triggers group selection if there are no active groups.\\n function genesis() external {\\n require(groups.numberOfActiveGroups() == 0, \\\"Not awaiting genesis\\\");\\n\\n dkg.lockState();\\n dkg.start(\\n uint256(keccak256(abi.encodePacked(genesisSeed, block.number)))\\n );\\n }\\n\\n /// @notice Submits result of DKG protocol. It is on-chain part of phase 14 of\\n /// the protocol. The DKG result consists of result submitting member\\n /// index, calculated group public key, bytes array of misbehaved\\n /// members, concatenation of signatures from group members,\\n /// indices of members corresponding to each signature and\\n /// the list of group members.\\n /// When the result is verified successfully it gets registered and\\n /// waits for an approval. A result can be challenged to verify the\\n /// members list corresponds to the expected set of members determined\\n /// by the sortition pool.\\n /// A candidate group is registered based on the submitted DKG result\\n /// details.\\n /// @dev The message to be signed by each member is keccak256 hash of the\\n /// chain ID, calculated group public key, misbehaved members as bytes\\n /// and DKG start block. The calculated hash should be prefixed with\\n // prefixed with\\n /// `\\\\x19Ethereum signed message:\\\\n` before signing, so the message to\\n /// sign is:\\n /// `\\\\x19Ethereum signed message:\\\\n${keccak256(chainID,groupPubKey,misbehaved,startBlock)}`\\n /// @param dkgResult DKG result.\\n function submitDkgResult(DKG.Result calldata dkgResult) external {\\n groups.validatePublicKey(dkgResult.groupPubKey);\\n dkg.submitResult(dkgResult);\\n }\\n\\n /// @notice Notifies about DKG timeout.\\n function notifyDkgTimeout() external refundable(msg.sender) {\\n dkg.notifyTimeout();\\n }\\n\\n /// @notice Approves DKG result. Can be called when the challenge period for\\n /// the submitted result is finished. Considers the submitted result\\n /// as valid, bans misbehaved group members from the sortition pool\\n /// rewards, and completes the group creation by activating the\\n /// candidate group. For the first `submitterPrecedencePeriodLength`\\n /// blocks after the end of the challenge period can be called only\\n /// by the DKG result submitter. After that time, can be called by\\n /// anyone.\\n /// @param dkgResult Result to approve. Must match the submitted result\\n /// stored during `submitDkgResult`.\\n function approveDkgResult(DKG.Result calldata dkgResult) external {\\n uint256 gasStart = gasleft();\\n\\n uint32[] memory misbehavedMembers = dkg.approveResult(dkgResult);\\n\\n if (misbehavedMembers.length > 0) {\\n sortitionPool.setRewardIneligibility(\\n misbehavedMembers,\\n // solhint-disable-next-line not-rely-on-time\\n block.timestamp + _sortitionPoolRewardsBanDuration\\n );\\n }\\n\\n groups.addGroup(dkgResult.groupPubKey, dkgResult.membersHash);\\n dkg.complete();\\n\\n // Refund msg.sender's ETH for DKG result submission and result approval\\n reimbursementPool.refund(\\n _dkgResultSubmissionGas +\\n (gasStart - gasleft()) +\\n _dkgResultApprovalGasOffset,\\n msg.sender\\n );\\n }\\n\\n /// @notice Challenges DKG result. If the submitted result is proved to be\\n /// invalid it reverts the DKG back to the result submission phase.\\n /// It removes a candidate group that was previously registered with\\n /// the DKG result submission.\\n /// @param dkgResult Result to challenge. Must match the submitted result\\n /// stored during `submitDkgResult`.\\n /// @dev Due to EIP-150 1/64 of the gas is not forwarded to the call, and\\n /// will be kept to execute the remaining operations in the function\\n /// after the call inside the try-catch. To eliminate a class of\\n /// attacks related to the gas limit manipulation, this function\\n /// requires an extra amount of gas to be left at the end of the\\n /// execution.\\n function challengeDkgResult(DKG.Result calldata dkgResult) external {\\n (bytes32 maliciousResultHash, uint32 maliciousSubmitter) = dkg\\n .challengeResult(dkgResult);\\n\\n uint96 slashingAmount = _maliciousDkgResultSlashingAmount;\\n address maliciousSubmitterAddresses = sortitionPool.getIDOperator(\\n maliciousSubmitter\\n );\\n\\n address[] memory stakingProviderWrapper = new address[](1);\\n stakingProviderWrapper[0] = operatorToStakingProvider(\\n maliciousSubmitterAddresses\\n );\\n try\\n staking.seize(\\n slashingAmount,\\n _dkgMaliciousResultNotificationRewardMultiplier,\\n msg.sender,\\n stakingProviderWrapper\\n )\\n {\\n // slither-disable-next-line reentrancy-events\\n emit DkgMaliciousResultSlashed(\\n maliciousResultHash,\\n slashingAmount,\\n maliciousSubmitterAddresses\\n );\\n } catch {\\n // Should never happen but we want to ensure a non-critical path\\n // failure from an external contract does not stop the challenge\\n // to complete.\\n emit DkgMaliciousResultSlashingFailed(\\n maliciousResultHash,\\n slashingAmount,\\n maliciousSubmitterAddresses\\n );\\n }\\n\\n // Due to EIP-150, 1/64 of the gas is not forwarded to the call, and\\n // will be kept to execute the remaining operations in the function\\n // after the call inside the try-catch.\\n //\\n // To ensure there is no way for the caller to manipulate gas limit in\\n // such a way that the call inside try-catch fails with out-of-gas and\\n // the rest of the function is executed with the remaining 1/64 of gas,\\n // we require an extra gas amount to be left at the end of the call to\\n // `challengeDkgResult`.\\n dkg.requireChallengeExtraGas();\\n }\\n\\n /// @notice Check current group creation state.\\n function getGroupCreationState() external view returns (DKG.State) {\\n return dkg.currentState();\\n }\\n\\n /// @notice Checks if DKG timed out. The DKG timeout period includes time required\\n /// for off-chain protocol execution and time for the result publication\\n /// for all group members. After this time result cannot be submitted\\n /// and DKG can be notified about the timeout.\\n /// @return True if DKG timed out, false otherwise.\\n function hasDkgTimedOut() external view returns (bool) {\\n return dkg.hasDkgTimedOut();\\n }\\n\\n function getGroupsRegistry() external view returns (bytes32[] memory) {\\n return groups.groupsRegistry;\\n }\\n\\n function getGroup(uint64 groupId)\\n external\\n view\\n returns (Groups.Group memory)\\n {\\n return groups.getGroup(groupId);\\n }\\n\\n function getGroup(bytes memory groupPubKey)\\n external\\n view\\n returns (Groups.Group memory)\\n {\\n return groups.getGroup(groupPubKey);\\n }\\n\\n /// @notice Creates a request to generate a new relay entry, which will\\n /// include a random number (by signing the previous entry's\\n /// random number). Requester must be previously authorized by the\\n /// governance.\\n /// @param callbackContract Beacon consumer callback contract.\\n function requestRelayEntry(IRandomBeaconConsumer callbackContract)\\n external\\n {\\n require(\\n authorizedRequesters[msg.sender],\\n \\\"Requester must be authorized\\\"\\n );\\n\\n uint64 groupId = groups.selectGroup(\\n uint256(keccak256(AltBn128.g1Marshal(relay.previousEntry)))\\n );\\n\\n relay.requestEntry(groupId);\\n\\n callback.setCallbackContract(callbackContract);\\n\\n // If the current request should trigger group creation we need to lock\\n // DKG state (lock sortition pool) to prevent operators from changing\\n // its state before relay entry is known. That entry will be used as a\\n // group selection seed.\\n if (\\n relay.requestCount % _groupCreationFrequency == 0 &&\\n dkg.currentState() == DKG.State.IDLE\\n ) {\\n dkg.lockState();\\n }\\n }\\n\\n /// @notice Creates a new relay entry. Gas-optimized version that can be\\n /// called only before the soft timeout. This should be the majority\\n /// of cases.\\n /// @param entry Group BLS signature over the previous entry.\\n function submitRelayEntry(bytes calldata entry) external {\\n uint256 gasStart = gasleft();\\n\\n Groups.Group storage group = groups.getGroup(\\n relay.currentRequestGroupID\\n );\\n\\n relay.submitEntryBeforeSoftTimeout(entry, group.groupPubKey);\\n\\n // If DKG is awaiting a seed, that means the we should start the actual\\n // group creation process.\\n if (dkg.currentState() == DKG.State.AWAITING_SEED) {\\n dkg.start(uint256(keccak256(entry)));\\n }\\n\\n callback.executeCallback(uint256(keccak256(entry)), _callbackGasLimit);\\n\\n reimbursementPool.refund(\\n (gasStart - gasleft()) + _relayEntrySubmissionGasOffset,\\n msg.sender\\n );\\n }\\n\\n /// @notice Creates a new relay entry.\\n /// @param entry Group BLS signature over the previous entry.\\n /// @param groupMembers Identifiers of group members.\\n function submitRelayEntry(\\n bytes calldata entry,\\n uint32[] calldata groupMembers\\n ) external {\\n uint256 gasStart = gasleft();\\n uint256 currentRequestId = relay.currentRequestID;\\n\\n Groups.Group storage group = groups.getGroup(\\n relay.currentRequestGroupID\\n );\\n\\n require(\\n group.membersHash == keccak256(abi.encode(groupMembers)),\\n \\\"Invalid group members\\\"\\n );\\n\\n uint96 slashingAmount = relay.submitEntry(entry, group.groupPubKey);\\n\\n if (slashingAmount > 0) {\\n address[] memory groupMembersAddresses = sortitionPool\\n .getIDOperators(groupMembers);\\n\\n address[] memory stakingProvidersAddresses = new address[](\\n groupMembersAddresses.length\\n );\\n for (uint256 i = 0; i < groupMembersAddresses.length; i++) {\\n stakingProvidersAddresses[i] = operatorToStakingProvider(\\n groupMembersAddresses[i]\\n );\\n }\\n\\n try staking.slash(slashingAmount, stakingProvidersAddresses) {\\n // slither-disable-next-line reentrancy-events\\n emit RelayEntryDelaySlashed(\\n currentRequestId,\\n slashingAmount,\\n groupMembersAddresses\\n );\\n } catch {\\n // Should never happen but we want to ensure a non-critical path\\n // failure from an external contract does not stop group members\\n // from submitting a valid relay entry.\\n emit RelayEntryDelaySlashingFailed(\\n currentRequestId,\\n slashingAmount,\\n groupMembersAddresses\\n );\\n }\\n }\\n\\n // If DKG is awaiting a seed, that means the we should start the actual\\n // group creation process.\\n if (dkg.currentState() == DKG.State.AWAITING_SEED) {\\n dkg.start(uint256(keccak256(entry)));\\n }\\n\\n callback.executeCallback(uint256(keccak256(entry)), _callbackGasLimit);\\n reimbursementPool.refund(\\n (gasStart - gasleft()) + _relayEntrySubmissionGasOffset,\\n msg.sender\\n );\\n }\\n\\n /// @notice Reports a relay entry timeout.\\n /// @param groupMembers Identifiers of group members.\\n function reportRelayEntryTimeout(uint32[] calldata groupMembers) external {\\n uint64 groupId = relay.currentRequestGroupID;\\n Groups.Group storage group = groups.getGroup(groupId);\\n\\n require(\\n group.membersHash == keccak256(abi.encode(groupMembers)),\\n \\\"Invalid group members\\\"\\n );\\n\\n uint96 slashingAmount = relay.relayEntrySubmissionFailureSlashingAmount;\\n address[] memory groupMembersAddresses = sortitionPool.getIDOperators(\\n groupMembers\\n );\\n\\n address[] memory stakingProvidersAddresses = new address[](\\n groupMembersAddresses.length\\n );\\n for (uint256 i = 0; i < groupMembersAddresses.length; i++) {\\n stakingProvidersAddresses[i] = operatorToStakingProvider(\\n groupMembersAddresses[i]\\n );\\n }\\n\\n try\\n staking.seize(\\n slashingAmount,\\n _relayEntryTimeoutNotificationRewardMultiplier,\\n msg.sender,\\n stakingProvidersAddresses\\n )\\n {\\n // slither-disable-next-line reentrancy-events\\n emit RelayEntryTimeoutSlashed(\\n relay.currentRequestID,\\n slashingAmount,\\n groupMembersAddresses\\n );\\n } catch {\\n // Should never happen but we want to ensure a non-critical path\\n // failure from an external contract does not stop the challenge\\n // to complete.\\n emit RelayEntryTimeoutSlashingFailed(\\n relay.currentRequestID,\\n slashingAmount,\\n groupMembersAddresses\\n );\\n }\\n\\n groups.terminateGroup(groupId);\\n groups.expireOldGroups();\\n\\n if (groups.numberOfActiveGroups() > 0) {\\n groupId = groups.selectGroup(\\n uint256(keccak256(AltBn128.g1Marshal(relay.previousEntry)))\\n );\\n relay.retryOnEntryTimeout(groupId);\\n } else {\\n relay.cleanupOnEntryTimeout();\\n\\n // If DKG is awaiting a seed, we should notify about its timeout to\\n // avoid blocking the future group creation.\\n if (dkg.currentState() == DKG.State.AWAITING_SEED) {\\n dkg.notifySeedTimedOut();\\n }\\n }\\n }\\n\\n /// @notice Reports unauthorized groups signing. Must provide a valid signature\\n /// of the sender's address as a message. Successful signature\\n /// verification means the private key has been leaked and all group\\n /// members should be punished by slashing their tokens. Group has\\n /// to be active or expired. Unauthorized signing cannot be reported\\n /// for a terminated group. In case of reporting unauthorized\\n /// signing for a terminated group, or when the signature is invalid,\\n /// function reverts.\\n /// @param signedMsgSender Signature of the sender's address as a message.\\n /// @param groupId Group that is being reported for leaking a private key.\\n /// @param groupMembers Identifiers of group members.\\n function reportUnauthorizedSigning(\\n bytes memory signedMsgSender,\\n uint64 groupId,\\n uint32[] calldata groupMembers\\n ) external {\\n Groups.Group memory group = groups.getGroup(groupId);\\n\\n require(\\n group.membersHash == keccak256(abi.encode(groupMembers)),\\n \\\"Invalid group members\\\"\\n );\\n\\n require(!group.terminated, \\\"Group cannot be terminated\\\");\\n\\n require(\\n BLS.verifyBytes(\\n group.groupPubKey,\\n abi.encodePacked(msg.sender),\\n signedMsgSender\\n ),\\n \\\"Invalid signature\\\"\\n );\\n\\n groups.terminateGroup(groupId);\\n\\n address[] memory groupMembersAddresses = sortitionPool.getIDOperators(\\n groupMembers\\n );\\n\\n address[] memory stakingProvidersAddresses = new address[](\\n groupMembersAddresses.length\\n );\\n for (uint256 i = 0; i < groupMembersAddresses.length; i++) {\\n stakingProvidersAddresses[i] = operatorToStakingProvider(\\n groupMembersAddresses[i]\\n );\\n }\\n\\n try\\n staking.seize(\\n _unauthorizedSigningSlashingAmount,\\n _unauthorizedSigningNotificationRewardMultiplier,\\n msg.sender,\\n stakingProvidersAddresses\\n )\\n {\\n // slither-disable-next-line reentrancy-events\\n emit UnauthorizedSigningSlashed(\\n groupId,\\n _unauthorizedSigningSlashingAmount,\\n groupMembersAddresses\\n );\\n } catch {\\n // Should never happen but we want to ensure a non-critical path\\n // failure from an external contract does not stop the challenge\\n // to complete.\\n emit UnauthorizedSigningSlashingFailed(\\n groupId,\\n _unauthorizedSigningSlashingAmount,\\n groupMembersAddresses\\n );\\n }\\n }\\n\\n /// @notice Notifies about operators who are inactive. Using this function,\\n /// a majority of the group can decide about punishing specific\\n /// group members who constantly fail doing their job. If the provided\\n /// claim is proved to be valid and signed by sufficient number\\n /// of group members, operators of members deemed as inactive are\\n /// banned for sortition pool rewards for duration specified by\\n /// `_sortitionPoolRewardsBanDuration` parameter. The sender of\\n /// the claim must be one of the claim signers. This function can be\\n /// called only for active and non-terminated groups.\\n /// @param claim Operator inactivity claim.\\n /// @param nonce Current inactivity claim nonce for the given group. Must\\n /// be the same as the stored one.\\n /// @param groupMembers Identifiers of group members.\\n function notifyOperatorInactivity(\\n Inactivity.Claim calldata claim,\\n uint256 nonce,\\n uint32[] calldata groupMembers\\n ) external {\\n uint256 gasStart = gasleft();\\n uint64 groupId = claim.groupId;\\n\\n require(nonce == inactivityClaimNonce[groupId], \\\"Invalid nonce\\\");\\n\\n require(groups.isGroupActive(groupId), \\\"Group is not active\\\");\\n\\n Groups.Group storage group = groups.getGroup(groupId);\\n\\n require(\\n group.membersHash == keccak256(abi.encode(groupMembers)),\\n \\\"Invalid group members\\\"\\n );\\n\\n uint32[] memory ineligibleOperators = Inactivity.verifyClaim(\\n sortitionPool,\\n claim,\\n group.groupPubKey,\\n nonce,\\n groupMembers\\n );\\n\\n inactivityClaimNonce[groupId]++;\\n\\n emit InactivityClaimed(groupId, nonce, msg.sender);\\n\\n sortitionPool.setRewardIneligibility(\\n ineligibleOperators,\\n // solhint-disable-next-line not-rely-on-time\\n block.timestamp + _sortitionPoolRewardsBanDuration\\n );\\n\\n reimbursementPool.refund(\\n (gasStart - gasleft()) + _notifyOperatorInactivityGasOffset,\\n msg.sender\\n );\\n }\\n\\n /// @notice The minimum authorization amount required so that operator can\\n /// participate in the random beacon. This amount is required to\\n /// execute slashing for providing a malicious DKG result or when\\n /// a relay entry times out.\\n function minimumAuthorization() external view returns (uint96) {\\n return authorization.parameters.minimumAuthorization;\\n }\\n\\n /// @return Flag indicating whether a relay entry request is currently\\n /// in progress.\\n function isRelayRequestInProgress() external view returns (bool) {\\n return relay.isRequestInProgress();\\n }\\n\\n /// @notice Returns the current value of the staking provider's eligible\\n /// stake. Eligible stake is defined as the currently authorized\\n /// stake minus the pending authorization decrease. Eligible stake\\n /// is what is used for operator's weight in the sortition pool.\\n /// If the authorized stake minus the pending authorization decrease\\n /// is below the minimum authorization, eligible stake is 0.\\n function eligibleStake(address stakingProvider)\\n external\\n view\\n returns (uint96)\\n {\\n return authorization.eligibleStake(staking, stakingProvider);\\n }\\n\\n /// @notice Returns the amount of rewards available for withdrawal for the\\n /// given staking provider. Reverts if staking provider has not\\n /// registered the operator address.\\n function availableRewards(address stakingProvider)\\n external\\n view\\n returns (uint96)\\n {\\n address operator = stakingProviderToOperator(stakingProvider);\\n require(operator != address(0), \\\"Unknown operator\\\");\\n return sortitionPool.getAvailableRewards(operator);\\n }\\n\\n /// @notice Returns the amount of stake that is pending authorization\\n /// decrease for the given staking provider. If no authorization\\n /// decrease has been requested, returns zero.\\n function pendingAuthorizationDecrease(address stakingProvider)\\n external\\n view\\n returns (uint96)\\n {\\n return authorization.pendingAuthorizationDecrease(stakingProvider);\\n }\\n\\n /// @notice Returns the remaining time in seconds that needs to pass before\\n /// the requested authorization decrease can be approved.\\n /// If the sortition pool state was not updated yet by the operator\\n /// after requesting the authorization decrease, returns\\n /// `type(uint64).max`.\\n function remainingAuthorizationDecreaseDelay(address stakingProvider)\\n external\\n view\\n returns (uint64)\\n {\\n return\\n authorization.remainingAuthorizationDecreaseDelay(stakingProvider);\\n }\\n\\n /// @notice Returns operator registered for the given staking provider.\\n function stakingProviderToOperator(address stakingProvider)\\n public\\n view\\n returns (address)\\n {\\n return authorization.stakingProviderToOperator[stakingProvider];\\n }\\n\\n /// @notice Returns staking provider of the given operator.\\n function operatorToStakingProvider(address operator)\\n public\\n view\\n returns (address)\\n {\\n return authorization.operatorToStakingProvider[operator];\\n }\\n\\n /// @notice Checks if the operator's authorized stake is in sync with\\n /// operator's weight in the sortition pool.\\n /// If the operator is not in the sortition pool and their\\n /// authorized stake is non-zero, function returns false.\\n function isOperatorUpToDate(address operator) external view returns (bool) {\\n return\\n authorization.isOperatorUpToDate(staking, sortitionPool, operator);\\n }\\n\\n /// @notice Returns true if the given operator is in the sortition pool.\\n /// Otherwise, returns false.\\n function isOperatorInPool(address operator) external view returns (bool) {\\n return sortitionPool.isOperatorInPool(operator);\\n }\\n\\n /// @notice Selects a new group of operators. Can only be called when DKG\\n /// is in progress and the pool is locked.\\n /// At least one operator has to be registered in the pool,\\n /// otherwise the function fails reverting the transaction.\\n /// @return IDs of selected group members.\\n function selectGroup() external view returns (uint32[] memory) {\\n return sortitionPool.selectGroup(DKG.groupSize, bytes32(dkg.seed));\\n }\\n\\n /// @notice Returns authorization-related parameters of the beacon.\\n /// @dev The minimum authorization is also returned by `minimumAuthorization()`\\n /// function, as a requirement of `IApplication` interface.\\n /// @return minimumAuthorization The minimum authorization amount required\\n /// so that operator can participate in the random beacon. This\\n /// amount is required to execute slashing for providing a malicious\\n /// DKG result or when a relay entry times out.\\n /// @return authorizationDecreaseDelay Delay in seconds that needs to pass\\n /// between the time authorization decrease is requested and the\\n /// time that request gets approved. Protects against free-riders\\n /// earning rewards and not being active in the network.\\n /// @return authorizationDecreaseChangePeriod Authorization decrease change\\n /// period in seconds. It is the time, before authorization decrease\\n /// delay end, during which the pending authorization decrease\\n /// request can be overwritten.\\n /// If set to 0, pending authorization decrease request can not be\\n /// overwritten until the entire `authorizationDecreaseDelay` ends.\\n /// If set to value equal `authorizationDecreaseDelay`, request can\\n /// always be overwritten.\\n function authorizationParameters()\\n external\\n view\\n returns (\\n uint96 minimumAuthorization,\\n uint64 authorizationDecreaseDelay,\\n uint64 authorizationDecreaseChangePeriod\\n )\\n {\\n return (\\n authorization.parameters.minimumAuthorization,\\n authorization.parameters.authorizationDecreaseDelay,\\n authorization.parameters.authorizationDecreaseChangePeriod\\n );\\n }\\n\\n /// @notice Returns relay-entry-related parameters of the beacon.\\n /// @return relayEntrySoftTimeout Soft timeout in blocks for a group to\\n /// submit the relay entry. If the soft timeout is reached for\\n /// submitting the relay entry, the slashing starts.\\n /// @return relayEntryHardTimeout Hard timeout in blocks for a group to\\n /// submit the relay entry. After the soft timeout passes without\\n /// relay entry submitted, all group members start getting slashed.\\n /// The slashing amount increases linearly until the group submits\\n /// the relay entry or until `relayEntryHardTimeout` is reached.\\n /// When the hard timeout is reached, each group member will get\\n /// slashed for `_relayEntrySubmissionFailureSlashingAmount`.\\n /// @return callbackGasLimit Relay entry callback gas limit. This is the gas\\n /// limit with which callback function provided in the relay request\\n /// transaction is executed. The callback is executed with a new\\n /// relay entry value in the same transaction the relay entry is\\n /// submitted.\\n function relayEntryParameters()\\n external\\n view\\n returns (\\n uint256 relayEntrySoftTimeout,\\n uint256 relayEntryHardTimeout,\\n uint256 callbackGasLimit\\n )\\n {\\n return (\\n relay.relayEntrySoftTimeout,\\n relay.relayEntryHardTimeout,\\n _callbackGasLimit\\n );\\n }\\n\\n /// @notice Returns group-creation-related parameters of the beacon.\\n /// @return groupCreationFrequency The frequency of a new group creation.\\n /// Groups are created with a fixed frequency of relay requests.\\n /// @return groupLifetime Group lifetime in blocks. When a group reached its\\n /// lifetime, it is no longer selected for new relay requests but\\n /// may still be responsible for submitting relay entry if relay\\n /// request assigned to that group is still pending.\\n /// @return dkgResultChallengePeriodLength The number of blocks for which\\n /// a DKG result can be challenged. Anyone can challenge DKG result\\n /// for a certain number of blocks before the result is fully\\n /// accepted and the group registered in the pool of active groups.\\n /// If the challenge gets accepted, all operators who signed the\\n /// malicious result get slashed for and the notifier gets rewarded.\\n /// @return dkgResultChallengeExtraGas The extra gas required to be left at\\n /// the end of the challenge DKG result transaction.\\n /// @return dkgResultSubmissionTimeout Timeout in blocks for a group to\\n /// submit the DKG result. All members are eligible to submit the\\n /// DKG result. If `dkgResultSubmissionTimeout` passes without the\\n /// DKG result submitted, DKG is considered as timed out and no DKG\\n /// result for this group creation can be submitted anymore.\\n /// @return dkgSubmitterPrecedencePeriodLength Time during the DKG result\\n /// approval stage when the submitter of the DKG result takes the\\n /// precedence to approve the DKG result. After this time passes\\n /// anyone can approve the DKG result.\\n function groupCreationParameters()\\n external\\n view\\n returns (\\n uint256 groupCreationFrequency,\\n uint256 groupLifetime,\\n uint256 dkgResultChallengePeriodLength,\\n uint256 dkgResultChallengeExtraGas,\\n uint256 dkgResultSubmissionTimeout,\\n uint256 dkgSubmitterPrecedencePeriodLength\\n )\\n {\\n return (\\n _groupCreationFrequency,\\n groups.groupLifetime,\\n dkg.parameters.resultChallengePeriodLength,\\n dkg.parameters.resultChallengeExtraGas,\\n dkg.parameters.resultSubmissionTimeout,\\n dkg.parameters.submitterPrecedencePeriodLength\\n );\\n }\\n\\n /// @notice Returns reward-related parameters of the beacon.\\n /// @return sortitionPoolRewardsBanDuration Duration of the sortition pool\\n /// rewards ban imposed on operators who misbehaved during DKG by\\n /// being inactive or disqualified and for operators that were\\n /// identified by the rest of group members as inactive via\\n /// `notifyOperatorInactivity`.\\n /// @return relayEntryTimeoutNotificationRewardMultiplier Percentage of the\\n /// staking contract malicious behavior notification reward which\\n /// will be transferred to the notifier reporting about relay entry\\n /// timeout. Notifiers are rewarded from a notifiers treasury pool.\\n /// For example, if notification reward is 1000 and the value of the\\n /// multiplier is 5, the notifier will receive: 5% of 1000 = 50 per\\n /// each operator affected.\\n /// @return unauthorizedSigningNotificationRewardMultiplier Percentage of the\\n /// staking contract malicious behavior notification reward which\\n /// will be transferred to the notifier reporting about unauthorized\\n /// signing. Notifiers are rewarded from a notifiers treasury pool.\\n /// For example, if a notification reward is 1000 and the value of\\n /// the multiplier is 5, the notifier will receive: 5% of 1000 = 50\\n /// per each operator affected.\\n /// @return dkgMaliciousResultNotificationRewardMultiplier Percentage of the\\n /// staking contract malicious behavior notification reward which\\n /// will be transferred to the notifier reporting about a malicious\\n /// DKG result. Notifiers are rewarded from a notifiers treasury\\n /// pool. For example, if notification reward is 1000 and the value\\n /// of the multiplier is 5, the notifier will receive:\\n /// 5% of 1000 = 50 per each operator affected.\\n function rewardParameters()\\n external\\n view\\n returns (\\n uint256 sortitionPoolRewardsBanDuration,\\n uint256 relayEntryTimeoutNotificationRewardMultiplier,\\n uint256 unauthorizedSigningNotificationRewardMultiplier,\\n uint256 dkgMaliciousResultNotificationRewardMultiplier\\n )\\n {\\n return (\\n _sortitionPoolRewardsBanDuration,\\n _relayEntryTimeoutNotificationRewardMultiplier,\\n _unauthorizedSigningNotificationRewardMultiplier,\\n _dkgMaliciousResultNotificationRewardMultiplier\\n );\\n }\\n\\n /// @notice Returns slashing-related parameters of the beacon.\\n /// @return relayEntrySubmissionFailureSlashingAmount Slashing amount for\\n /// not submitting relay entry. When relay entry hard timeout is\\n /// reached without the relay entry submitted, each group member\\n /// gets slashed for `relayEntrySubmissionFailureSlashingAmount`.\\n /// If the relay entry gets submitted after the soft timeout, but\\n /// before the hard timeout, each group member gets slashed\\n /// proportionally to `relayEntrySubmissionFailureSlashingAmount`\\n /// and the time passed since the soft deadline.\\n /// @return maliciousDkgResultSlashingAmount Slashing amount for submitting\\n /// a malicious DKG result. Every DKG result submitted can be\\n /// challenged for the time of `dkg.ResultChallengePeriodLength`.\\n /// If the DKG result submitted is challenged and proven to be\\n /// malicious, the operator who submitted the malicious result is\\n /// slashed for `maliciousDkgResultSlashingAmount`.\\n /// @return unauthorizedSigningSlashingAmount Slashing amount when an\\n /// unauthorized signing has been proved, which means the private\\n /// key leaked and all the group members should be punished.\\n function slashingParameters()\\n external\\n view\\n returns (\\n uint96 relayEntrySubmissionFailureSlashingAmount,\\n uint96 maliciousDkgResultSlashingAmount,\\n uint96 unauthorizedSigningSlashingAmount\\n )\\n {\\n return (\\n relay.relayEntrySubmissionFailureSlashingAmount,\\n _maliciousDkgResultSlashingAmount,\\n _unauthorizedSigningSlashingAmount\\n );\\n }\\n\\n /// @notice Returns gas-related parameters of the beacon.\\n /// @return dkgResultSubmissionGas Calculated gas cost for submitting a DKG\\n /// result. This will be refunded as part of the DKG approval\\n /// process.\\n /// @return dkgResultApprovalGasOffset Gas that is meant to balance the DKG\\n /// result approval's overall cost.\\n /// @return notifyOperatorInactivityGasOffset Gas that is meant to balance\\n /// the operator inactivity notification cost.\\n /// @return relayEntrySubmissionGasOffset Gas that is meant to balance the\\n /// relay entry submission cost.\\n function gasParameters()\\n external\\n view\\n returns (\\n uint256 dkgResultSubmissionGas,\\n uint256 dkgResultApprovalGasOffset,\\n uint256 notifyOperatorInactivityGasOffset,\\n uint256 relayEntrySubmissionGasOffset\\n )\\n {\\n return (\\n _dkgResultSubmissionGas,\\n _dkgResultApprovalGasOffset,\\n _notifyOperatorInactivityGasOffset,\\n _relayEntrySubmissionGasOffset\\n );\\n }\\n}\\n\",\"keccak256\":\"0x50e6572ce7e51404a9918bf80d13004c4f4fd2a41fbc898f8aac84fa71423917\",\"license\":\"GPL-3.0-only\"},\"contracts/RandomBeaconGovernance.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./RandomBeacon.sol\\\";\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\n/// @title Keep Random Beacon Governance\\n/// @notice Owns the `RandomBeacon` contract and is responsible for updating its\\n/// governable parameters in respect to governance delay individual\\n/// for each parameter.\\ncontract RandomBeaconGovernance is Ownable {\\n uint256 public newGovernanceDelay;\\n uint256 public governanceDelayChangeInitiated;\\n\\n address public newRandomBeaconGovernance;\\n uint256 public randomBeaconGovernanceTransferInitiated;\\n\\n uint256 public newRelayEntrySoftTimeout;\\n uint256 public relayEntrySoftTimeoutChangeInitiated;\\n\\n uint256 public newRelayEntryHardTimeout;\\n uint256 public relayEntryHardTimeoutChangeInitiated;\\n\\n uint256 public newCallbackGasLimit;\\n uint256 public callbackGasLimitChangeInitiated;\\n\\n uint256 public newGroupCreationFrequency;\\n uint256 public groupCreationFrequencyChangeInitiated;\\n\\n uint256 public newGroupLifetime;\\n uint256 public groupLifetimeChangeInitiated;\\n\\n uint256 public newDkgResultChallengePeriodLength;\\n uint256 public dkgResultChallengePeriodLengthChangeInitiated;\\n\\n uint256 public newDkgResultChallengeExtraGas;\\n uint256 public dkgResultChallengeExtraGasChangeInitiated;\\n\\n uint256 public newDkgResultSubmissionTimeout;\\n uint256 public dkgResultSubmissionTimeoutChangeInitiated;\\n\\n uint256 public newDkgSubmitterPrecedencePeriodLength;\\n uint256 public dkgSubmitterPrecedencePeriodLengthChangeInitiated;\\n\\n uint96 public newRelayEntrySubmissionFailureSlashingAmount;\\n uint256 public relayEntrySubmissionFailureSlashingAmountChangeInitiated;\\n\\n uint96 public newMaliciousDkgResultSlashingAmount;\\n uint256 public maliciousDkgResultSlashingAmountChangeInitiated;\\n\\n uint96 public newUnauthorizedSigningSlashingAmount;\\n uint256 public unauthorizedSigningSlashingAmountChangeInitiated;\\n\\n uint256 public newSortitionPoolRewardsBanDuration;\\n uint256 public sortitionPoolRewardsBanDurationChangeInitiated;\\n\\n uint256 public newRelayEntryTimeoutNotificationRewardMultiplier;\\n uint256 public relayEntryTimeoutNotificationRewardMultiplierChangeInitiated;\\n\\n uint256 public newUnauthorizedSigningNotificationRewardMultiplier;\\n uint256\\n public unauthorizedSigningNotificationRewardMultiplierChangeInitiated;\\n\\n uint96 public newMinimumAuthorization;\\n uint256 public minimumAuthorizationChangeInitiated;\\n\\n uint64 public newAuthorizationDecreaseDelay;\\n uint256 public authorizationDecreaseDelayChangeInitiated;\\n\\n uint64 public newAuthorizationDecreaseChangePeriod;\\n uint256 public authorizationDecreaseChangePeriodChangeInitiated;\\n\\n uint256 public newDkgMaliciousResultNotificationRewardMultiplier;\\n uint256\\n public dkgMaliciousResultNotificationRewardMultiplierChangeInitiated;\\n\\n uint256 public newDkgResultSubmissionGas;\\n uint256 public dkgResultSubmissionGasChangeInitiated;\\n\\n uint256 public newDkgResultApprovalGasOffset;\\n uint256 public dkgResultApprovalGasOffsetChangeInitiated;\\n\\n uint256 public newNotifyOperatorInactivityGasOffset;\\n uint256 public notifyOperatorInactivityGasOffsetChangeInitiated;\\n\\n uint256 public newRelayEntrySubmissionGasOffset;\\n uint256 public relayEntrySubmissionGasOffsetChangeInitiated;\\n\\n RandomBeacon public immutable randomBeacon;\\n\\n uint256 public governanceDelay;\\n\\n event GovernanceDelayUpdateStarted(\\n uint256 governanceDelay,\\n uint256 timestamp\\n );\\n event GovernanceDelayUpdated(uint256 governanceDelay);\\n\\n event RandomBeaconGovernanceTransferStarted(\\n address newRandomBeaconGovernance,\\n uint256 timestamp\\n );\\n event RandomBeaconGovernanceTransferred(address newRandomBeaconGovernance);\\n\\n event RelayEntrySoftTimeoutUpdateStarted(\\n uint256 relayEntrySoftTimeout,\\n uint256 timestamp\\n );\\n event RelayEntrySoftTimeoutUpdated(uint256 relayEntrySoftTimeout);\\n\\n event RelayEntryHardTimeoutUpdateStarted(\\n uint256 relayEntryHardTimeout,\\n uint256 timestamp\\n );\\n event RelayEntryHardTimeoutUpdated(uint256 relayEntryHardTimeout);\\n\\n event CallbackGasLimitUpdateStarted(\\n uint256 callbackGasLimit,\\n uint256 timestamp\\n );\\n event CallbackGasLimitUpdated(uint256 callbackGasLimit);\\n\\n event GroupCreationFrequencyUpdateStarted(\\n uint256 groupCreationFrequency,\\n uint256 timestamp\\n );\\n event GroupCreationFrequencyUpdated(uint256 groupCreationFrequency);\\n\\n event GroupLifetimeUpdateStarted(uint256 groupLifetime, uint256 timestamp);\\n event GroupLifetimeUpdated(uint256 groupLifetime);\\n\\n event DkgResultChallengePeriodLengthUpdateStarted(\\n uint256 dkgResultChallengePeriodLength,\\n uint256 timestamp\\n );\\n event DkgResultChallengePeriodLengthUpdated(\\n uint256 dkgResultChallengePeriodLength\\n );\\n\\n event DkgResultChallengeExtraGasUpdateStarted(\\n uint256 dkgResultChallengeExtraGas,\\n uint256 timestamp\\n );\\n event DkgResultChallengeExtraGasUpdated(uint256 dkgResultChallengeExtraGas);\\n\\n event DkgResultSubmissionTimeoutUpdateStarted(\\n uint256 dkgResultSubmissionTimeout,\\n uint256 timestamp\\n );\\n event DkgResultSubmissionTimeoutUpdated(uint256 dkgResultSubmissionTimeout);\\n\\n event DkgSubmitterPrecedencePeriodLengthUpdateStarted(\\n uint256 submitterPrecedencePeriodLength,\\n uint256 timestamp\\n );\\n event DkgSubmitterPrecedencePeriodLengthUpdated(\\n uint256 submitterPrecedencePeriodLength\\n );\\n\\n event RelayEntrySubmissionFailureSlashingAmountUpdateStarted(\\n uint96 relayEntrySubmissionFailureSlashingAmount,\\n uint256 timestamp\\n );\\n event RelayEntrySubmissionFailureSlashingAmountUpdated(\\n uint96 relayEntrySubmissionFailureSlashingAmount\\n );\\n\\n event MaliciousDkgResultSlashingAmountUpdateStarted(\\n uint96 maliciousDkgResultSlashingAmount,\\n uint256 timestamp\\n );\\n event MaliciousDkgResultSlashingAmountUpdated(\\n uint96 maliciousDkgResultSlashingAmount\\n );\\n\\n event UnauthorizedSigningSlashingAmountUpdateStarted(\\n uint96 unauthorizedSigningSlashingAmount,\\n uint256 timestamp\\n );\\n event UnauthorizedSigningSlashingAmountUpdated(\\n uint96 unauthorizedSigningSlashingAmount\\n );\\n\\n event SortitionPoolRewardsBanDurationUpdateStarted(\\n uint256 sortitionPoolRewardsBanDuration,\\n uint256 timestamp\\n );\\n event SortitionPoolRewardsBanDurationUpdated(\\n uint256 sortitionPoolRewardsBanDuration\\n );\\n\\n event RelayEntryTimeoutNotificationRewardMultiplierUpdateStarted(\\n uint256 relayEntryTimeoutNotificationRewardMultiplier,\\n uint256 timestamp\\n );\\n event RelayEntryTimeoutNotificationRewardMultiplierUpdated(\\n uint256 relayEntryTimeoutNotificationRewardMultiplier\\n );\\n\\n event UnauthorizedSigningNotificationRewardMultiplierUpdateStarted(\\n uint256 unauthorizedSigningTimeoutNotificationRewardMultiplier,\\n uint256 timestamp\\n );\\n event UnauthorizedSigningNotificationRewardMultiplierUpdated(\\n uint256 unauthorizedSigningTimeoutNotificationRewardMultiplier\\n );\\n\\n event MinimumAuthorizationUpdateStarted(\\n uint96 minimumAuthorization,\\n uint256 timestamp\\n );\\n event MinimumAuthorizationUpdated(uint96 minimumAuthorization);\\n\\n event AuthorizationDecreaseDelayUpdateStarted(\\n uint64 authorizationDecreaseDelay,\\n uint256 timestamp\\n );\\n event AuthorizationDecreaseDelayUpdated(uint64 authorizationDecreaseDelay);\\n\\n event AuthorizationDecreaseChangePeriodUpdateStarted(\\n uint64 authorizationDecreaseChangePeriod,\\n uint256 timestamp\\n );\\n\\n event AuthorizationDecreaseChangePeriodUpdated(\\n uint64 authorizationDecreaseChangePeriod\\n );\\n\\n event DkgMaliciousResultNotificationRewardMultiplierUpdateStarted(\\n uint256 dkgMaliciousResultNotificationRewardMultiplier,\\n uint256 timestamp\\n );\\n event DkgMaliciousResultNotificationRewardMultiplierUpdated(\\n uint256 dkgMaliciousResultNotificationRewardMultiplier\\n );\\n\\n event DkgResultSubmissionGasUpdateStarted(\\n uint256 dkgResultSubmissionGas,\\n uint256 timestamp\\n );\\n event DkgResultSubmissionGasUpdated(uint256 dkgResultSubmissionGas);\\n\\n event DkgResultApprovalGasOffsetUpdateStarted(\\n uint256 dkgResultApprovalGasOffset,\\n uint256 timestamp\\n );\\n event DkgResultApprovalGasOffsetUpdated(uint256 dkgResultApprovalGasOffset);\\n\\n event NotifyOperatorInactivityGasOffsetUpdateStarted(\\n uint256 notifyOperatorInactivityGasOffset,\\n uint256 timestamp\\n );\\n event NotifyOperatorInactivityGasOffsetUpdated(\\n uint256 notifyOperatorInactivityGasOffset\\n );\\n\\n event RelayEntrySubmissionGasOffsetUpdateStarted(\\n uint256 relayEntrySubmissionGasOffset,\\n uint256 timestamp\\n );\\n event RelayEntrySubmissionGasOffsetUpdated(\\n uint256 relayEntrySubmissionGasOffset\\n );\\n\\n /// @notice Reverts if called before the governance delay elapses.\\n /// @param changeInitiatedTimestamp Timestamp indicating the beginning\\n /// of the change.\\n modifier onlyAfterGovernanceDelay(uint256 changeInitiatedTimestamp) {\\n /* solhint-disable not-rely-on-time */\\n require(changeInitiatedTimestamp > 0, \\\"Change not initiated\\\");\\n require(\\n block.timestamp - changeInitiatedTimestamp >= governanceDelay,\\n \\\"Governance delay has not elapsed\\\"\\n );\\n _;\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n constructor(RandomBeacon _randomBeacon, uint256 _governanceDelay) {\\n require(address(_randomBeacon) != address(0), \\\"Zero-address reference\\\");\\n require(_governanceDelay != 0, \\\"No governance delay\\\");\\n\\n randomBeacon = _randomBeacon;\\n governanceDelay = _governanceDelay;\\n }\\n\\n /// @notice Begins the governance delay update process.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newGovernanceDelay New governance delay\\n function beginGovernanceDelayUpdate(uint256 _newGovernanceDelay)\\n external\\n onlyOwner\\n {\\n newGovernanceDelay = _newGovernanceDelay;\\n /* solhint-disable not-rely-on-time */\\n governanceDelayChangeInitiated = block.timestamp;\\n emit GovernanceDelayUpdateStarted(_newGovernanceDelay, block.timestamp);\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes the governance delay update process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeGovernanceDelayUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(governanceDelayChangeInitiated)\\n {\\n emit GovernanceDelayUpdated(newGovernanceDelay);\\n governanceDelay = newGovernanceDelay;\\n governanceDelayChangeInitiated = 0;\\n newGovernanceDelay = 0;\\n }\\n\\n /// @notice Begins the random beacon governance transfer process.\\n /// @dev Can be called only by the current contract governance.\\n function beginRandomBeaconGovernanceTransfer(\\n address _newRandomBeaconGovernance\\n ) external onlyOwner {\\n require(\\n address(_newRandomBeaconGovernance) != address(0),\\n \\\"New random beacon governance address cannot be zero\\\"\\n );\\n newRandomBeaconGovernance = _newRandomBeaconGovernance;\\n /* solhint-disable not-rely-on-time */\\n randomBeaconGovernanceTransferInitiated = block.timestamp;\\n emit RandomBeaconGovernanceTransferStarted(\\n _newRandomBeaconGovernance,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes the random beacon governance transfer process.\\n /// @dev Can be called only by the current contract governance, after the\\n /// governance delay elapses.\\n function finalizeRandomBeaconGovernanceTransfer()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(randomBeaconGovernanceTransferInitiated)\\n {\\n emit RandomBeaconGovernanceTransferred(newRandomBeaconGovernance);\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.transferGovernance(newRandomBeaconGovernance);\\n randomBeaconGovernanceTransferInitiated = 0;\\n newRandomBeaconGovernance = address(0);\\n }\\n\\n /// @notice Begins the relay entry soft timeout update process.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newRelayEntrySoftTimeout New relay entry submission timeout in blocks\\n function beginRelayEntrySoftTimeoutUpdate(uint256 _newRelayEntrySoftTimeout)\\n external\\n onlyOwner\\n {\\n /* solhint-disable not-rely-on-time */\\n require(\\n _newRelayEntrySoftTimeout > 0,\\n \\\"Relay entry soft timeout must be > 0\\\"\\n );\\n newRelayEntrySoftTimeout = _newRelayEntrySoftTimeout;\\n relayEntrySoftTimeoutChangeInitiated = block.timestamp;\\n emit RelayEntrySoftTimeoutUpdateStarted(\\n _newRelayEntrySoftTimeout,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes the relay entry soft timeout update process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeRelayEntrySoftTimeoutUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(relayEntrySoftTimeoutChangeInitiated)\\n {\\n emit RelayEntrySoftTimeoutUpdated(newRelayEntrySoftTimeout);\\n (\\n ,\\n uint256 relayEntryHardTimeout,\\n uint256 callbackGasLimit\\n ) = randomBeacon.relayEntryParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateRelayEntryParameters(\\n newRelayEntrySoftTimeout,\\n relayEntryHardTimeout,\\n callbackGasLimit\\n );\\n relayEntrySoftTimeoutChangeInitiated = 0;\\n newRelayEntrySoftTimeout = 0;\\n }\\n\\n /// @notice Begins the relay entry hard timeout update process.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newRelayEntryHardTimeout New relay entry hard timeout in blocks\\n function beginRelayEntryHardTimeoutUpdate(uint256 _newRelayEntryHardTimeout)\\n external\\n onlyOwner\\n {\\n /* solhint-disable not-rely-on-time */\\n newRelayEntryHardTimeout = _newRelayEntryHardTimeout;\\n relayEntryHardTimeoutChangeInitiated = block.timestamp;\\n emit RelayEntryHardTimeoutUpdateStarted(\\n _newRelayEntryHardTimeout,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes the relay entry hard timeout update process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeRelayEntryHardTimeoutUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(relayEntryHardTimeoutChangeInitiated)\\n {\\n emit RelayEntryHardTimeoutUpdated(newRelayEntryHardTimeout);\\n (\\n uint256 relayEntrySoftTimeout,\\n ,\\n uint256 callbackGasLimit\\n ) = randomBeacon.relayEntryParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateRelayEntryParameters(\\n relayEntrySoftTimeout,\\n newRelayEntryHardTimeout,\\n callbackGasLimit\\n );\\n relayEntryHardTimeoutChangeInitiated = 0;\\n newRelayEntryHardTimeout = 0;\\n }\\n\\n /// @notice Begins the callback gas limit update process.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newCallbackGasLimit New callback gas limit\\n function beginCallbackGasLimitUpdate(uint256 _newCallbackGasLimit)\\n external\\n onlyOwner\\n {\\n /* solhint-disable not-rely-on-time */\\n // slither-disable-next-line too-many-digits\\n require(\\n _newCallbackGasLimit > 0 && _newCallbackGasLimit <= 1e6,\\n \\\"Callback gas limit must be > 0 and <= 1000000\\\"\\n );\\n newCallbackGasLimit = _newCallbackGasLimit;\\n callbackGasLimitChangeInitiated = block.timestamp;\\n emit CallbackGasLimitUpdateStarted(\\n _newCallbackGasLimit,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes the callback gas limit update process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeCallbackGasLimitUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(callbackGasLimitChangeInitiated)\\n {\\n emit CallbackGasLimitUpdated(newCallbackGasLimit);\\n (\\n uint256 relayEntrySoftTimeout,\\n uint256 relayEntryHardTimeout,\\n\\n ) = randomBeacon.relayEntryParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateRelayEntryParameters(\\n relayEntrySoftTimeout,\\n relayEntryHardTimeout,\\n newCallbackGasLimit\\n );\\n callbackGasLimitChangeInitiated = 0;\\n newCallbackGasLimit = 0;\\n }\\n\\n /// @notice Begins the group creation frequency update process.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newGroupCreationFrequency New group creation frequency\\n function beginGroupCreationFrequencyUpdate(\\n uint256 _newGroupCreationFrequency\\n ) external onlyOwner {\\n /* solhint-disable not-rely-on-time */\\n require(\\n _newGroupCreationFrequency > 0,\\n \\\"Group creation frequency must be > 0\\\"\\n );\\n newGroupCreationFrequency = _newGroupCreationFrequency;\\n groupCreationFrequencyChangeInitiated = block.timestamp;\\n emit GroupCreationFrequencyUpdateStarted(\\n _newGroupCreationFrequency,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes the group creation frequency update process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeGroupCreationFrequencyUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(groupCreationFrequencyChangeInitiated)\\n {\\n emit GroupCreationFrequencyUpdated(newGroupCreationFrequency);\\n (\\n ,\\n uint256 groupLifetime,\\n uint256 dkgResultChallengePeriodLength,\\n uint256 dkgResultChallengeExtraGas,\\n uint256 dkgResultSubmissionTimeout,\\n uint256 dkgSubmitterPrecedencePeriodLength\\n ) = randomBeacon.groupCreationParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateGroupCreationParameters(\\n newGroupCreationFrequency,\\n groupLifetime,\\n dkgResultChallengePeriodLength,\\n dkgResultChallengeExtraGas,\\n dkgResultSubmissionTimeout,\\n dkgSubmitterPrecedencePeriodLength\\n );\\n groupCreationFrequencyChangeInitiated = 0;\\n newGroupCreationFrequency = 0;\\n }\\n\\n /// @notice Begins the group lifetime update process. Group lifetime needs to\\n /// be shorter than the authorization decrease delay to ensure every\\n /// active group is backed by enough stake. A new group lifetime value\\n /// is in blocks and has to be calculated based on the average block\\n /// time and authorization decrease delay which value is in seconds.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newGroupLifetime New group lifetime in blocks\\n function beginGroupLifetimeUpdate(uint256 _newGroupLifetime)\\n external\\n onlyOwner\\n {\\n require(_newGroupLifetime > 0, \\\"Group lifetime must be greater than 0\\\");\\n /* solhint-disable not-rely-on-time */\\n newGroupLifetime = _newGroupLifetime;\\n groupLifetimeChangeInitiated = block.timestamp;\\n emit GroupLifetimeUpdateStarted(_newGroupLifetime, block.timestamp);\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes the group creation frequency update process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeGroupLifetimeUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(groupLifetimeChangeInitiated)\\n {\\n emit GroupLifetimeUpdated(newGroupLifetime);\\n (\\n uint256 groupCreationFrequency,\\n ,\\n uint256 dkgResultChallengePeriodLength,\\n uint256 dkgResultChallengeExtraGas,\\n uint256 dkgResultSubmissionTimeout,\\n uint256 dkgSubmitterPrecedencePeriodLength\\n ) = randomBeacon.groupCreationParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateGroupCreationParameters(\\n groupCreationFrequency,\\n newGroupLifetime,\\n dkgResultChallengePeriodLength,\\n dkgResultChallengeExtraGas,\\n dkgResultSubmissionTimeout,\\n dkgSubmitterPrecedencePeriodLength\\n );\\n groupLifetimeChangeInitiated = 0;\\n newGroupLifetime = 0;\\n }\\n\\n /// @notice Begins the DKG result challenge period length update process.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newDkgResultChallengePeriodLength New DKG result challenge\\n /// period length in blocks\\n function beginDkgResultChallengePeriodLengthUpdate(\\n uint256 _newDkgResultChallengePeriodLength\\n ) external onlyOwner {\\n /* solhint-disable not-rely-on-time */\\n require(\\n _newDkgResultChallengePeriodLength >= 10,\\n \\\"DKG result challenge period length must be >= 10\\\"\\n );\\n newDkgResultChallengePeriodLength = _newDkgResultChallengePeriodLength;\\n dkgResultChallengePeriodLengthChangeInitiated = block.timestamp;\\n emit DkgResultChallengePeriodLengthUpdateStarted(\\n _newDkgResultChallengePeriodLength,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes the DKG result challenge period length update process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeDkgResultChallengePeriodLengthUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(dkgResultChallengePeriodLengthChangeInitiated)\\n {\\n emit DkgResultChallengePeriodLengthUpdated(\\n newDkgResultChallengePeriodLength\\n );\\n (\\n uint256 groupCreationFrequency,\\n uint256 groupLifetime,\\n ,\\n uint256 dkgResultChallengeExtraGas,\\n uint256 dkgResultSubmissionTimeout,\\n uint256 dkgSubmitterPrecedencePeriodLength\\n ) = randomBeacon.groupCreationParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateGroupCreationParameters(\\n groupCreationFrequency,\\n groupLifetime,\\n newDkgResultChallengePeriodLength,\\n dkgResultChallengeExtraGas,\\n dkgResultSubmissionTimeout,\\n dkgSubmitterPrecedencePeriodLength\\n );\\n dkgResultChallengePeriodLengthChangeInitiated = 0;\\n newDkgResultChallengePeriodLength = 0;\\n }\\n\\n /// @notice Begins the DKG result challenge extra gas update process.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newDkgResultChallengeExtraGas New DKG result challenge extra gas\\n function beginDkgResultChallengeExtraGasUpdate(\\n uint256 _newDkgResultChallengeExtraGas\\n ) external onlyOwner {\\n /* solhint-disable not-rely-on-time */\\n newDkgResultChallengeExtraGas = _newDkgResultChallengeExtraGas;\\n dkgResultChallengeExtraGasChangeInitiated = block.timestamp;\\n emit DkgResultChallengeExtraGasUpdateStarted(\\n _newDkgResultChallengeExtraGas,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes the DKG result challenge extra gas update process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeDkgResultChallengeExtraGasUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(dkgResultChallengeExtraGasChangeInitiated)\\n {\\n emit DkgResultChallengeExtraGasUpdated(newDkgResultChallengeExtraGas);\\n (\\n uint256 groupCreationFrequency,\\n uint256 groupLifetime,\\n uint256 dkgResultChallengePeriodLength,\\n ,\\n uint256 dkgResultSubmissionTimeout,\\n uint256 dkgSubmitterPrecedencePeriodLength\\n ) = randomBeacon.groupCreationParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateGroupCreationParameters(\\n groupCreationFrequency,\\n groupLifetime,\\n dkgResultChallengePeriodLength,\\n newDkgResultChallengeExtraGas,\\n dkgResultSubmissionTimeout,\\n dkgSubmitterPrecedencePeriodLength\\n );\\n dkgResultChallengeExtraGasChangeInitiated = 0;\\n newDkgResultChallengeExtraGas = 0;\\n }\\n\\n /// @notice Begins the DKG result submission timeout update\\n /// process.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newDkgResultSubmissionTimeout New DKG result submission\\n /// timeout in blocks\\n function beginDkgResultSubmissionTimeoutUpdate(\\n uint256 _newDkgResultSubmissionTimeout\\n ) external onlyOwner {\\n /* solhint-disable not-rely-on-time */\\n require(\\n _newDkgResultSubmissionTimeout > 0,\\n \\\"DKG result submission timeout must be > 0\\\"\\n );\\n newDkgResultSubmissionTimeout = _newDkgResultSubmissionTimeout;\\n dkgResultSubmissionTimeoutChangeInitiated = block.timestamp;\\n emit DkgResultSubmissionTimeoutUpdateStarted(\\n _newDkgResultSubmissionTimeout,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes the DKG result submission timeout update\\n /// process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeDkgResultSubmissionTimeoutUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(dkgResultSubmissionTimeoutChangeInitiated)\\n {\\n emit DkgResultSubmissionTimeoutUpdated(newDkgResultSubmissionTimeout);\\n (\\n uint256 groupCreationFrequency,\\n uint256 groupLifetime,\\n uint256 dkgResultChallengePeriodLength,\\n uint256 dkgResultChallengeExtraGas,\\n ,\\n uint256 dkgSubmitterPrecedencePeriodLength\\n ) = randomBeacon.groupCreationParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateGroupCreationParameters(\\n groupCreationFrequency,\\n groupLifetime,\\n dkgResultChallengePeriodLength,\\n dkgResultChallengeExtraGas,\\n newDkgResultSubmissionTimeout,\\n dkgSubmitterPrecedencePeriodLength\\n );\\n dkgResultSubmissionTimeoutChangeInitiated = 0;\\n newDkgResultSubmissionTimeout = 0;\\n }\\n\\n /// @notice Begins the DKG submitter precedence period length.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newDkgSubmitterPrecedencePeriodLength New DKG submitter precedence\\n /// period length in blocks\\n function beginDkgSubmitterPrecedencePeriodLengthUpdate(\\n uint256 _newDkgSubmitterPrecedencePeriodLength\\n ) external onlyOwner {\\n /* solhint-disable not-rely-on-time */\\n require(\\n _newDkgSubmitterPrecedencePeriodLength > 0,\\n \\\"DKG submitter precedence period length must be > 0\\\"\\n );\\n newDkgSubmitterPrecedencePeriodLength = _newDkgSubmitterPrecedencePeriodLength;\\n dkgSubmitterPrecedencePeriodLengthChangeInitiated = block.timestamp;\\n emit DkgSubmitterPrecedencePeriodLengthUpdateStarted(\\n _newDkgSubmitterPrecedencePeriodLength,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes the DKG submitter precedence period length.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeDkgSubmitterPrecedencePeriodLengthUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(\\n dkgSubmitterPrecedencePeriodLengthChangeInitiated\\n )\\n {\\n emit DkgSubmitterPrecedencePeriodLengthUpdated(\\n newDkgSubmitterPrecedencePeriodLength\\n );\\n (\\n uint256 groupCreationFrequency,\\n uint256 groupLifetime,\\n uint256 dkgResultChallengePeriodLength,\\n uint256 dkgResultChallengeExtraGas,\\n uint256 dkgResultSubmissionTimeout,\\n\\n ) = randomBeacon.groupCreationParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateGroupCreationParameters(\\n groupCreationFrequency,\\n groupLifetime,\\n dkgResultChallengePeriodLength,\\n dkgResultChallengeExtraGas,\\n dkgResultSubmissionTimeout,\\n newDkgSubmitterPrecedencePeriodLength\\n );\\n dkgSubmitterPrecedencePeriodLengthChangeInitiated = 0;\\n newDkgSubmitterPrecedencePeriodLength = 0;\\n }\\n\\n /// @notice Begins the sortition pool rewards ban duration update process.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newSortitionPoolRewardsBanDuration New sortition pool rewards\\n /// ban duration.\\n function beginSortitionPoolRewardsBanDurationUpdate(\\n uint256 _newSortitionPoolRewardsBanDuration\\n ) external onlyOwner {\\n /* solhint-disable not-rely-on-time */\\n newSortitionPoolRewardsBanDuration = _newSortitionPoolRewardsBanDuration;\\n sortitionPoolRewardsBanDurationChangeInitiated = block.timestamp;\\n emit SortitionPoolRewardsBanDurationUpdateStarted(\\n _newSortitionPoolRewardsBanDuration,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes the sortition pool rewards ban duration update process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeSortitionPoolRewardsBanDurationUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(sortitionPoolRewardsBanDurationChangeInitiated)\\n {\\n emit SortitionPoolRewardsBanDurationUpdated(\\n newSortitionPoolRewardsBanDuration\\n );\\n (\\n ,\\n uint256 relayEntryTimeoutNotificationRewardMultiplier,\\n uint256 unauthorizedSigningNotificationRewardMultiplier,\\n uint256 dkgMaliciousResultNotificationRewardMultiplier\\n ) = randomBeacon.rewardParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateRewardParameters(\\n newSortitionPoolRewardsBanDuration,\\n relayEntryTimeoutNotificationRewardMultiplier,\\n unauthorizedSigningNotificationRewardMultiplier,\\n dkgMaliciousResultNotificationRewardMultiplier\\n );\\n sortitionPoolRewardsBanDurationChangeInitiated = 0;\\n newSortitionPoolRewardsBanDuration = 0;\\n }\\n\\n /// @notice Begins the relay entry timeout notification reward multiplier\\n /// update process.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newRelayEntryTimeoutNotificationRewardMultiplier New relay\\n /// entry timeout notification reward multiplier.\\n function beginRelayEntryTimeoutNotificationRewardMultiplierUpdate(\\n uint256 _newRelayEntryTimeoutNotificationRewardMultiplier\\n ) external onlyOwner {\\n /* solhint-disable not-rely-on-time */\\n require(\\n _newRelayEntryTimeoutNotificationRewardMultiplier <= 100,\\n \\\"Maximum value is 100\\\"\\n );\\n\\n newRelayEntryTimeoutNotificationRewardMultiplier = _newRelayEntryTimeoutNotificationRewardMultiplier;\\n relayEntryTimeoutNotificationRewardMultiplierChangeInitiated = block\\n .timestamp;\\n emit RelayEntryTimeoutNotificationRewardMultiplierUpdateStarted(\\n _newRelayEntryTimeoutNotificationRewardMultiplier,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Begins the unauthorized signing notification reward multiplier\\n /// update process.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newUnauthorizedSigningNotificationRewardMultiplier New unauthorized\\n /// signing notification reward multiplier.\\n function beginUnauthorizedSigningNotificationRewardMultiplierUpdate(\\n uint256 _newUnauthorizedSigningNotificationRewardMultiplier\\n ) external onlyOwner {\\n /* solhint-disable not-rely-on-time */\\n require(\\n _newUnauthorizedSigningNotificationRewardMultiplier <= 100,\\n \\\"Maximum value is 100\\\"\\n );\\n\\n newUnauthorizedSigningNotificationRewardMultiplier = _newUnauthorizedSigningNotificationRewardMultiplier;\\n unauthorizedSigningNotificationRewardMultiplierChangeInitiated = block\\n .timestamp;\\n emit UnauthorizedSigningNotificationRewardMultiplierUpdateStarted(\\n _newUnauthorizedSigningNotificationRewardMultiplier,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes the unauthorized signing notification reward\\n /// multiplier update process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeUnauthorizedSigningNotificationRewardMultiplierUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(\\n unauthorizedSigningNotificationRewardMultiplierChangeInitiated\\n )\\n {\\n emit UnauthorizedSigningNotificationRewardMultiplierUpdated(\\n newUnauthorizedSigningNotificationRewardMultiplier\\n );\\n (\\n uint256 sortitionPoolRewardsBanDuration,\\n uint256 relayEntryTimeoutNotificationRewardMultiplier,\\n ,\\n uint256 dkgMaliciousResultNotificationRewardMultiplier\\n ) = randomBeacon.rewardParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateRewardParameters(\\n sortitionPoolRewardsBanDuration,\\n relayEntryTimeoutNotificationRewardMultiplier,\\n newUnauthorizedSigningNotificationRewardMultiplier,\\n dkgMaliciousResultNotificationRewardMultiplier\\n );\\n unauthorizedSigningNotificationRewardMultiplierChangeInitiated = 0;\\n newUnauthorizedSigningNotificationRewardMultiplier = 0;\\n }\\n\\n /// @notice Finalizes the relay entry timeout notification reward\\n /// multiplier update process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeRelayEntryTimeoutNotificationRewardMultiplierUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(\\n relayEntryTimeoutNotificationRewardMultiplierChangeInitiated\\n )\\n {\\n emit RelayEntryTimeoutNotificationRewardMultiplierUpdated(\\n newRelayEntryTimeoutNotificationRewardMultiplier\\n );\\n (\\n uint256 sortitionPoolRewardsBanDuration,\\n ,\\n uint256 unauthorizedSigningNotificationRewardMultiplier,\\n uint256 dkgMaliciousResultNotificationRewardMultiplier\\n ) = randomBeacon.rewardParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateRewardParameters(\\n sortitionPoolRewardsBanDuration,\\n newRelayEntryTimeoutNotificationRewardMultiplier,\\n unauthorizedSigningNotificationRewardMultiplier,\\n dkgMaliciousResultNotificationRewardMultiplier\\n );\\n relayEntryTimeoutNotificationRewardMultiplierChangeInitiated = 0;\\n newRelayEntryTimeoutNotificationRewardMultiplier = 0;\\n }\\n\\n /// @notice Begins the DKG malicious result notification reward multiplier\\n /// update process.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newDkgMaliciousResultNotificationRewardMultiplier New DKG\\n /// malicious result notification reward multiplier.\\n function beginDkgMaliciousResultNotificationRewardMultiplierUpdate(\\n uint256 _newDkgMaliciousResultNotificationRewardMultiplier\\n ) external onlyOwner {\\n /* solhint-disable not-rely-on-time */\\n require(\\n _newDkgMaliciousResultNotificationRewardMultiplier <= 100,\\n \\\"Maximum value is 100\\\"\\n );\\n\\n newDkgMaliciousResultNotificationRewardMultiplier = _newDkgMaliciousResultNotificationRewardMultiplier;\\n dkgMaliciousResultNotificationRewardMultiplierChangeInitiated = block\\n .timestamp;\\n emit DkgMaliciousResultNotificationRewardMultiplierUpdateStarted(\\n _newDkgMaliciousResultNotificationRewardMultiplier,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes the DKG malicious result notification reward\\n /// multiplier update process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeDkgMaliciousResultNotificationRewardMultiplierUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(\\n dkgMaliciousResultNotificationRewardMultiplierChangeInitiated\\n )\\n {\\n emit DkgMaliciousResultNotificationRewardMultiplierUpdated(\\n newDkgMaliciousResultNotificationRewardMultiplier\\n );\\n (\\n uint256 sortitionPoolRewardsBanDuration,\\n uint256 relayEntryTimeoutNotificationRewardMultiplier,\\n uint256 unauthorizedSigningNotificationRewardMultiplier,\\n\\n ) = randomBeacon.rewardParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateRewardParameters(\\n sortitionPoolRewardsBanDuration,\\n relayEntryTimeoutNotificationRewardMultiplier,\\n unauthorizedSigningNotificationRewardMultiplier,\\n newDkgMaliciousResultNotificationRewardMultiplier\\n );\\n dkgMaliciousResultNotificationRewardMultiplierChangeInitiated = 0;\\n newDkgMaliciousResultNotificationRewardMultiplier = 0;\\n }\\n\\n /// @notice Begins the relay entry submission failure slashing amount update\\n /// process.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newRelayEntrySubmissionFailureSlashingAmount New relay entry\\n /// submission failure slashing amount\\n function beginRelayEntrySubmissionFailureSlashingAmountUpdate(\\n uint96 _newRelayEntrySubmissionFailureSlashingAmount\\n ) external onlyOwner {\\n /* solhint-disable not-rely-on-time */\\n newRelayEntrySubmissionFailureSlashingAmount = _newRelayEntrySubmissionFailureSlashingAmount;\\n relayEntrySubmissionFailureSlashingAmountChangeInitiated = block\\n .timestamp;\\n emit RelayEntrySubmissionFailureSlashingAmountUpdateStarted(\\n _newRelayEntrySubmissionFailureSlashingAmount,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes the relay entry submission failure slashing amount\\n /// update process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeRelayEntrySubmissionFailureSlashingAmountUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(\\n relayEntrySubmissionFailureSlashingAmountChangeInitiated\\n )\\n {\\n emit RelayEntrySubmissionFailureSlashingAmountUpdated(\\n newRelayEntrySubmissionFailureSlashingAmount\\n );\\n (\\n ,\\n uint96 maliciousDkgResultSlashingAmount,\\n uint96 unauthorizedSigningSlashingAmount\\n ) = randomBeacon.slashingParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateSlashingParameters(\\n newRelayEntrySubmissionFailureSlashingAmount,\\n maliciousDkgResultSlashingAmount,\\n unauthorizedSigningSlashingAmount\\n );\\n relayEntrySubmissionFailureSlashingAmountChangeInitiated = 0;\\n newRelayEntrySubmissionFailureSlashingAmount = 0;\\n }\\n\\n /// @notice Begins the DKG result submission gas update process.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newDkgResultSubmissionGas New relay entry submission gas offset\\n function beginDkgResultSubmissionGasUpdate(\\n uint256 _newDkgResultSubmissionGas\\n ) external onlyOwner {\\n /* solhint-disable not-rely-on-time */\\n newDkgResultSubmissionGas = _newDkgResultSubmissionGas;\\n dkgResultSubmissionGasChangeInitiated = block.timestamp;\\n emit DkgResultSubmissionGasUpdateStarted(\\n _newDkgResultSubmissionGas,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes DKG result submission gas update process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeDkgResultSubmissionGasUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(dkgResultSubmissionGasChangeInitiated)\\n {\\n emit DkgResultSubmissionGasUpdated(newDkgResultSubmissionGas);\\n (\\n ,\\n uint256 dkgResultApprovalGasOffset,\\n uint256 notifyOperatorInactivityGasOffset,\\n uint256 relayEntrySubmissionGasOffset\\n ) = randomBeacon.gasParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateGasParameters(\\n newDkgResultSubmissionGas,\\n dkgResultApprovalGasOffset,\\n notifyOperatorInactivityGasOffset,\\n relayEntrySubmissionGasOffset\\n );\\n dkgResultSubmissionGasChangeInitiated = 0;\\n newDkgResultSubmissionGas = 0;\\n }\\n\\n /// @notice Begins the DKG result approval gas offset update process.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newDkgResultApprovalGasOffset New DKG approval gas offset\\n function beginDkgResultApprovalGasOffsetUpdate(\\n uint256 _newDkgResultApprovalGasOffset\\n ) external onlyOwner {\\n /* solhint-disable not-rely-on-time */\\n newDkgResultApprovalGasOffset = _newDkgResultApprovalGasOffset;\\n dkgResultApprovalGasOffsetChangeInitiated = block.timestamp;\\n emit DkgResultApprovalGasOffsetUpdateStarted(\\n _newDkgResultApprovalGasOffset,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes the DKG result approval gas offset update process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeDkgResultApprovalGasOffsetUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(dkgResultApprovalGasOffsetChangeInitiated)\\n {\\n emit DkgResultApprovalGasOffsetUpdated(newDkgResultApprovalGasOffset);\\n (\\n uint256 dkgResultSubmissionGas,\\n ,\\n uint256 notifyOperatorInactivityGasOffset,\\n uint256 relayEntrySubmissionGasOffset\\n ) = randomBeacon.gasParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateGasParameters(\\n dkgResultSubmissionGas,\\n newDkgResultApprovalGasOffset,\\n notifyOperatorInactivityGasOffset,\\n relayEntrySubmissionGasOffset\\n );\\n dkgResultApprovalGasOffsetChangeInitiated = 0;\\n newDkgResultApprovalGasOffset = 0;\\n }\\n\\n /// @notice Begins the notify operator inactivity gas offset update process.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newNotifyOperatorInactivityGasOffset New operator inactivity\\n /// notification gas offset\\n function beginNotifyOperatorInactivityGasOffsetUpdate(\\n uint256 _newNotifyOperatorInactivityGasOffset\\n ) external onlyOwner {\\n /* solhint-disable not-rely-on-time */\\n newNotifyOperatorInactivityGasOffset = _newNotifyOperatorInactivityGasOffset;\\n notifyOperatorInactivityGasOffsetChangeInitiated = block.timestamp;\\n emit NotifyOperatorInactivityGasOffsetUpdateStarted(\\n _newNotifyOperatorInactivityGasOffset,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes the notify operator inactivity gas offset update process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeNotifyOperatorInactivityGasOffsetUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(\\n notifyOperatorInactivityGasOffsetChangeInitiated\\n )\\n {\\n emit NotifyOperatorInactivityGasOffsetUpdated(\\n newNotifyOperatorInactivityGasOffset\\n );\\n (\\n uint256 dkgResultSubmissionGas,\\n uint256 dkgResultApprovalGasOffset,\\n ,\\n uint256 relayEntrySubmissionGasOffset\\n ) = randomBeacon.gasParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateGasParameters(\\n dkgResultSubmissionGas,\\n dkgResultApprovalGasOffset,\\n newNotifyOperatorInactivityGasOffset,\\n relayEntrySubmissionGasOffset\\n );\\n notifyOperatorInactivityGasOffsetChangeInitiated = 0;\\n newNotifyOperatorInactivityGasOffset = 0;\\n }\\n\\n /// @notice Begins the relay entry submission gas offset update process.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newRelayEntrySubmissionGasOffset New relay entry submission gas offset\\n function beginRelayEntrySubmissionGasOffsetUpdate(\\n uint256 _newRelayEntrySubmissionGasOffset\\n ) external onlyOwner {\\n /* solhint-disable not-rely-on-time */\\n newRelayEntrySubmissionGasOffset = _newRelayEntrySubmissionGasOffset;\\n relayEntrySubmissionGasOffsetChangeInitiated = block.timestamp;\\n emit RelayEntrySubmissionGasOffsetUpdateStarted(\\n _newRelayEntrySubmissionGasOffset,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes relay entry submission gas offset update process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeRelayEntrySubmissionGasOffsetUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(relayEntrySubmissionGasOffsetChangeInitiated)\\n {\\n emit RelayEntrySubmissionGasOffsetUpdated(\\n newRelayEntrySubmissionGasOffset\\n );\\n (\\n uint256 dkgResultSubmissionGas,\\n uint256 dkgResultApprovalGasOffset,\\n uint256 notifyOperatorInactivityGasOffset,\\n\\n ) = randomBeacon.gasParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateGasParameters(\\n dkgResultSubmissionGas,\\n dkgResultApprovalGasOffset,\\n notifyOperatorInactivityGasOffset,\\n newRelayEntrySubmissionGasOffset\\n );\\n relayEntrySubmissionGasOffsetChangeInitiated = 0;\\n newRelayEntrySubmissionGasOffset = 0;\\n }\\n\\n /// @notice Begins the malicious DKG result slashing amount update process.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newMaliciousDkgResultSlashingAmount New malicious DKG result\\n /// slashing amount\\n function beginMaliciousDkgResultSlashingAmountUpdate(\\n uint96 _newMaliciousDkgResultSlashingAmount\\n ) external onlyOwner {\\n /* solhint-disable not-rely-on-time */\\n newMaliciousDkgResultSlashingAmount = _newMaliciousDkgResultSlashingAmount;\\n maliciousDkgResultSlashingAmountChangeInitiated = block.timestamp;\\n emit MaliciousDkgResultSlashingAmountUpdateStarted(\\n _newMaliciousDkgResultSlashingAmount,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes the malicious DKG result slashing amount update\\n /// process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeMaliciousDkgResultSlashingAmountUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(\\n maliciousDkgResultSlashingAmountChangeInitiated\\n )\\n {\\n emit MaliciousDkgResultSlashingAmountUpdated(\\n newMaliciousDkgResultSlashingAmount\\n );\\n (\\n uint96 relayEntrySubmissionFailureSlashingAmount,\\n ,\\n uint96 unauthorizedSigningSlashingAmount\\n ) = randomBeacon.slashingParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateSlashingParameters(\\n relayEntrySubmissionFailureSlashingAmount,\\n newMaliciousDkgResultSlashingAmount,\\n unauthorizedSigningSlashingAmount\\n );\\n maliciousDkgResultSlashingAmountChangeInitiated = 0;\\n newMaliciousDkgResultSlashingAmount = 0;\\n }\\n\\n /// @notice Begins the unauthorized signing slashing amount update process.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newUnauthorizedSigningSlashingAmount New unauthorized signing\\n /// slashing amount\\n function beginUnauthorizedSigningSlashingAmountUpdate(\\n uint96 _newUnauthorizedSigningSlashingAmount\\n ) external onlyOwner {\\n /* solhint-disable not-rely-on-time */\\n newUnauthorizedSigningSlashingAmount = _newUnauthorizedSigningSlashingAmount;\\n unauthorizedSigningSlashingAmountChangeInitiated = block.timestamp;\\n emit UnauthorizedSigningSlashingAmountUpdateStarted(\\n _newUnauthorizedSigningSlashingAmount,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes the unauthorized signing slashing amount update\\n /// process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeUnauthorizedSigningSlashingAmountUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(\\n unauthorizedSigningSlashingAmountChangeInitiated\\n )\\n {\\n emit UnauthorizedSigningSlashingAmountUpdated(\\n newUnauthorizedSigningSlashingAmount\\n );\\n (\\n uint96 relayEntrySubmissionFailureSlashingAmount,\\n uint96 maliciousDkgResultSlashingAmount,\\n\\n ) = randomBeacon.slashingParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateSlashingParameters(\\n relayEntrySubmissionFailureSlashingAmount,\\n maliciousDkgResultSlashingAmount,\\n newUnauthorizedSigningSlashingAmount\\n );\\n unauthorizedSigningSlashingAmountChangeInitiated = 0;\\n newUnauthorizedSigningSlashingAmount = 0;\\n }\\n\\n /// @notice Begins the minimum authorization amount update process.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newMinimumAuthorization New minimum authorization amount.\\n function beginMinimumAuthorizationUpdate(uint96 _newMinimumAuthorization)\\n external\\n onlyOwner\\n {\\n /* solhint-disable not-rely-on-time */\\n newMinimumAuthorization = _newMinimumAuthorization;\\n minimumAuthorizationChangeInitiated = block.timestamp;\\n emit MinimumAuthorizationUpdateStarted(\\n _newMinimumAuthorization,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes the minimum authorization amount update process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeMinimumAuthorizationUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(minimumAuthorizationChangeInitiated)\\n {\\n emit MinimumAuthorizationUpdated(newMinimumAuthorization);\\n (\\n ,\\n uint64 authorizationDecreaseDelay,\\n uint64 authorizationDecreaseChangePeriod\\n ) = randomBeacon.authorizationParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateAuthorizationParameters(\\n newMinimumAuthorization,\\n authorizationDecreaseDelay,\\n authorizationDecreaseChangePeriod\\n );\\n minimumAuthorizationChangeInitiated = 0;\\n newMinimumAuthorization = 0;\\n }\\n\\n /// @notice Begins the authorization decrease delay update process.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newAuthorizationDecreaseDelay New authorization decrease delay\\n function beginAuthorizationDecreaseDelayUpdate(\\n uint64 _newAuthorizationDecreaseDelay\\n ) external onlyOwner {\\n /* solhint-disable not-rely-on-time */\\n newAuthorizationDecreaseDelay = _newAuthorizationDecreaseDelay;\\n authorizationDecreaseDelayChangeInitiated = block.timestamp;\\n emit AuthorizationDecreaseDelayUpdateStarted(\\n _newAuthorizationDecreaseDelay,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes the authorization decrease delay update process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeAuthorizationDecreaseDelayUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(authorizationDecreaseDelayChangeInitiated)\\n {\\n emit AuthorizationDecreaseDelayUpdated(newAuthorizationDecreaseDelay);\\n (\\n uint96 minimumAuthorization,\\n uint64 authorizationDecreaseChangePeriod,\\n\\n ) = randomBeacon.authorizationParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateAuthorizationParameters(\\n minimumAuthorization,\\n newAuthorizationDecreaseDelay,\\n authorizationDecreaseChangePeriod\\n );\\n authorizationDecreaseDelayChangeInitiated = 0;\\n newAuthorizationDecreaseDelay = 0;\\n }\\n\\n /// @notice Begins the authorization decrease change period update process.\\n /// @dev Can be called only by the contract owner.\\n /// @param _newAuthorizationDecreaseChangePeriod New authorization decrease change period\\n function beginAuthorizationDecreaseChangePeriodUpdate(\\n uint64 _newAuthorizationDecreaseChangePeriod\\n ) external onlyOwner {\\n /* solhint-disable not-rely-on-time */\\n newAuthorizationDecreaseChangePeriod = _newAuthorizationDecreaseChangePeriod;\\n authorizationDecreaseChangePeriodChangeInitiated = block.timestamp;\\n emit AuthorizationDecreaseChangePeriodUpdateStarted(\\n _newAuthorizationDecreaseChangePeriod,\\n block.timestamp\\n );\\n /* solhint-enable not-rely-on-time */\\n }\\n\\n /// @notice Finalizes the authorization decrease change period update process.\\n /// @dev Can be called only by the contract owner, after the governance\\n /// delay elapses.\\n function finalizeAuthorizationDecreaseChangePeriodUpdate()\\n external\\n onlyOwner\\n onlyAfterGovernanceDelay(\\n authorizationDecreaseChangePeriodChangeInitiated\\n )\\n {\\n emit AuthorizationDecreaseChangePeriodUpdated(\\n newAuthorizationDecreaseChangePeriod\\n );\\n (\\n uint96 minimumAuthorization,\\n uint64 authorizationDecreaseDelay,\\n\\n ) = randomBeacon.authorizationParameters();\\n // slither-disable-next-line reentrancy-no-eth\\n randomBeacon.updateAuthorizationParameters(\\n minimumAuthorization,\\n authorizationDecreaseDelay,\\n newAuthorizationDecreaseChangePeriod\\n );\\n authorizationDecreaseChangePeriodChangeInitiated = 0;\\n newAuthorizationDecreaseChangePeriod = 0;\\n }\\n\\n /// @notice Set authorization for requesters that can request a relay\\n /// entry. It can be done by the governance only.\\n /// @param requester Requester, can be a contract or EOA\\n /// @param isAuthorized True or false\\n function setRequesterAuthorization(address requester, bool isAuthorized)\\n external\\n onlyOwner\\n {\\n randomBeacon.setRequesterAuthorization(requester, isAuthorized);\\n }\\n\\n /// @notice Withdraws rewards belonging to operators marked as ineligible\\n /// for sortition pool rewards.\\n /// @dev Can be called only by the contract owner.\\n /// @param recipient Recipient of withdrawn rewards.\\n function withdrawIneligibleRewards(address recipient) external onlyOwner {\\n randomBeacon.withdrawIneligibleRewards(recipient);\\n }\\n\\n /// @notice Get the time remaining until the governance delay can be updated.\\n /// @return Remaining time in seconds.\\n function getRemainingGovernanceDelayUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return getRemainingChangeTime(governanceDelayChangeInitiated);\\n }\\n\\n /// @notice Get the time remaining until the random beacon governance can\\n /// be transferred.\\n /// @return Remaining time in seconds.\\n function getRemainingRandomBeaconGovernanceTransferDelayTime()\\n external\\n view\\n returns (uint256)\\n {\\n return getRemainingChangeTime(randomBeaconGovernanceTransferInitiated);\\n }\\n\\n /// @notice Get the time remaining until the relay entry submission soft\\n /// timeout can be updated.\\n /// @return Remaining time in seconds.\\n function getRemainingRelayEntrySoftTimeoutUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return getRemainingChangeTime(relayEntrySoftTimeoutChangeInitiated);\\n }\\n\\n /// @notice Get the time remaining until the relay entry hard timeout can be\\n /// updated.\\n /// @return Remaining time in seconds.\\n function getRemainingRelayEntryHardTimeoutUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return getRemainingChangeTime(relayEntryHardTimeoutChangeInitiated);\\n }\\n\\n /// @notice Get the time remaining until the callback gas limit can be\\n /// updated.\\n /// @return Remaining time in seconds.\\n function getRemainingCallbackGasLimitUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return getRemainingChangeTime(callbackGasLimitChangeInitiated);\\n }\\n\\n /// @notice Get the time remaining until the group creation frequency can be\\n /// updated.\\n /// @return Remaining time in seconds.\\n function getRemainingGroupCreationFrequencyUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return getRemainingChangeTime(groupCreationFrequencyChangeInitiated);\\n }\\n\\n /// @notice Get the time remaining until the group lifetime can be updated.\\n /// @return Remaining time in seconds.\\n function getRemainingGroupLifetimeUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return getRemainingChangeTime(groupLifetimeChangeInitiated);\\n }\\n\\n /// @notice Get the time remaining until the DKG result challenge period\\n /// length can be updated.\\n /// @return Remaining time in seconds.\\n function getRemainingDkgResultChallengePeriodLengthUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return\\n getRemainingChangeTime(\\n dkgResultChallengePeriodLengthChangeInitiated\\n );\\n }\\n\\n /// @notice Get the time remaining until the DKG result challenge extra\\n /// gas can be updated.\\n /// @return Remaining time in seconds.\\n function getRemainingDkgResultChallengeExtraGasUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return\\n getRemainingChangeTime(dkgResultChallengeExtraGasChangeInitiated);\\n }\\n\\n /// @notice Get the time remaining until the DKG result submission timeout\\n /// can be updated.\\n /// @return Remaining time in seconds.\\n function getRemainingDkgResultSubmissionTimeoutUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return\\n getRemainingChangeTime(dkgResultSubmissionTimeoutChangeInitiated);\\n }\\n\\n /// @notice Get the time remaining until the wallet owner can be updated.\\n /// @return Remaining time in seconds.\\n function getRemainingDkgSubmitterPrecedencePeriodLengthUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return\\n getRemainingChangeTime(\\n dkgSubmitterPrecedencePeriodLengthChangeInitiated\\n );\\n }\\n\\n /// @notice Get the time remaining until the relay entry submission failure\\n /// slashing amount can be updated.\\n /// @return Remaining time in seconds.\\n function getRemainingRelayEntrySubmissionFailureSlashingAmountUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return\\n getRemainingChangeTime(\\n relayEntrySubmissionFailureSlashingAmountChangeInitiated\\n );\\n }\\n\\n /// @notice Get the time remaining until the malicious DKG result\\n /// slashing amount can be updated.\\n /// @return Remaining time in seconds.\\n function getRemainingMaliciousDkgResultSlashingAmountUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return\\n getRemainingChangeTime(\\n maliciousDkgResultSlashingAmountChangeInitiated\\n );\\n }\\n\\n /// @notice Get the time remaining until the unauthorized signing\\n /// slashing amount can be updated.\\n /// @return Remaining time in seconds.\\n function getRemainingUnauthorizedSigningSlashingAmountUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return\\n getRemainingChangeTime(\\n unauthorizedSigningSlashingAmountChangeInitiated\\n );\\n }\\n\\n /// @notice Get the time remaining until the minimum authorization amount\\n /// can be updated.\\n /// @return Remaining time in seconds.\\n function getRemainingMimimumAuthorizationUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return getRemainingChangeTime(minimumAuthorizationChangeInitiated);\\n }\\n\\n /// @notice Get the time remaining until the authorization decrease delay\\n /// can be updated.\\n /// @return Remaining time in seconds.\\n function getRemainingAuthorizationDecreaseDelayUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return\\n getRemainingChangeTime(authorizationDecreaseDelayChangeInitiated);\\n }\\n\\n /// @notice Get the time remaining until the authorization decrease change\\n /// period can be updated.\\n /// @return Remaining time in seconds.\\n function getRemainingAuthorizationDecreaseChangePeriodUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return\\n getRemainingChangeTime(\\n authorizationDecreaseChangePeriodChangeInitiated\\n );\\n }\\n\\n /// @notice Get the time remaining until the sortition pool rewards ban\\n /// duration can be updated.\\n /// @return Remaining time in seconds.\\n function getRemainingSortitionPoolRewardsBanDurationUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return\\n getRemainingChangeTime(\\n sortitionPoolRewardsBanDurationChangeInitiated\\n );\\n }\\n\\n /// @notice Get the time remaining until the relay entry timeout\\n /// notification reward multiplier duration can be updated.\\n /// @return Remaining time in seconds.\\n function getRemainingRelayEntryTimeoutNotificationRewardMultiplierUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return\\n getRemainingChangeTime(\\n relayEntryTimeoutNotificationRewardMultiplierChangeInitiated\\n );\\n }\\n\\n /// @notice Get the time remaining until the unauthorized signing\\n /// notification reward multiplier duration can be updated.\\n /// @return Remaining time in seconds.\\n function getRemainingUnauthorizedSigningNotificationRewardMultiplierUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return\\n getRemainingChangeTime(\\n unauthorizedSigningNotificationRewardMultiplierChangeInitiated\\n );\\n }\\n\\n /// @notice Get the time remaining until the DKG malicious result\\n /// notification reward multiplier duration can be updated.\\n /// @return Remaining time in seconds.\\n function getRemainingDkgMaliciousResultNotificationRewardMultiplierUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return\\n getRemainingChangeTime(\\n dkgMaliciousResultNotificationRewardMultiplierChangeInitiated\\n );\\n }\\n\\n /// @notice Get the time remaining until the DKG result submission gas\\n /// duration can be updated.\\n /// @return Remaining time in seconds.\\n function getRemainingDkgResultSubmissionGasUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return getRemainingChangeTime(dkgResultSubmissionGasChangeInitiated);\\n }\\n\\n /// @notice Get the time remaining until the DKG approval gas offset duration\\n /// can be updated.\\n /// @return Remaining time in seconds.\\n function getRemainingDkgResultApprovalGasOffsetUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return\\n getRemainingChangeTime(dkgResultApprovalGasOffsetChangeInitiated);\\n }\\n\\n /// @notice Get the time remaining until the operator inactivity notification\\n /// gas offset duration can be updated.\\n /// @return Remaining time in seconds.\\n function getRemainingNotifyOperatorInactivityGasOffsetUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return\\n getRemainingChangeTime(\\n notifyOperatorInactivityGasOffsetChangeInitiated\\n );\\n }\\n\\n /// @notice Get the time remaining until the relay entry submission gas offset\\n /// duration can be updated.\\n /// @return Remaining time in seconds.\\n function getRemainingRelayEntrySubmissionGasOffsetUpdateTime()\\n external\\n view\\n returns (uint256)\\n {\\n return\\n getRemainingChangeTime(\\n relayEntrySubmissionGasOffsetChangeInitiated\\n );\\n }\\n\\n /// @notice Gets the time remaining until the governable parameter update\\n /// can be committed.\\n /// @param changeTimestamp Timestamp indicating the beginning of the change.\\n /// @return Remaining time in seconds.\\n function getRemainingChangeTime(uint256 changeTimestamp)\\n internal\\n view\\n returns (uint256)\\n {\\n require(changeTimestamp > 0, \\\"Change not initiated\\\");\\n /* solhint-disable-next-line not-rely-on-time */\\n uint256 elapsed = block.timestamp - changeTimestamp;\\n if (elapsed >= governanceDelay) {\\n return 0;\\n } else {\\n return governanceDelay - elapsed;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x4da22ccc2350264caa1093a03cc44f43d080385bafb7b77b244faf8462549b36\",\"license\":\"GPL-3.0-only\"},\"contracts/Reimbursable.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./ReimbursementPool.sol\\\";\\n\\nabstract contract Reimbursable {\\n // The variable should be initialized by the implementing contract.\\n // slither-disable-next-line uninitialized-state\\n ReimbursementPool public reimbursementPool;\\n\\n // Reserved storage space in case we need to add more variables,\\n // since there are upgradeable contracts that inherit from this one.\\n // See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\\n // slither-disable-next-line unused-state\\n uint256[49] private __gap;\\n\\n event ReimbursementPoolUpdated(address newReimbursementPool);\\n\\n modifier refundable(address receiver) {\\n uint256 gasStart = gasleft();\\n _;\\n reimbursementPool.refund(gasStart - gasleft(), receiver);\\n }\\n\\n modifier onlyReimbursableAdmin() virtual {\\n _;\\n }\\n\\n function updateReimbursementPool(ReimbursementPool _reimbursementPool)\\n external\\n onlyReimbursableAdmin\\n {\\n emit ReimbursementPoolUpdated(address(_reimbursementPool));\\n\\n reimbursementPool = _reimbursementPool;\\n }\\n}\\n\",\"keccak256\":\"0x6b01344c1ec13aaab1dc432d3afabe08d6dd0d1a9248be8b36a0747ac22e5d9f\",\"license\":\"GPL-3.0-only\"},\"contracts/ReimbursementPool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/security/ReentrancyGuard.sol\\\";\\n\\ncontract ReimbursementPool is Ownable, ReentrancyGuard {\\n /// @notice Authorized contracts that can interact with the reimbursment pool.\\n /// Authorization can be granted and removed by the owner.\\n mapping(address => bool) public isAuthorized;\\n\\n /// @notice Static gas includes:\\n /// - cost of the refund function\\n /// - base transaction cost\\n uint256 public staticGas;\\n\\n /// @notice Max gas price used to reimburse a transaction submitter. Protects\\n /// against malicious operator-miners.\\n uint256 public maxGasPrice;\\n\\n event StaticGasUpdated(uint256 newStaticGas);\\n\\n event MaxGasPriceUpdated(uint256 newMaxGasPrice);\\n\\n event SendingEtherFailed(uint256 refundAmount, address receiver);\\n\\n event AuthorizedContract(address thirdPartyContract);\\n\\n event UnauthorizedContract(address thirdPartyContract);\\n\\n event FundsWithdrawn(uint256 withdrawnAmount, address receiver);\\n\\n constructor(uint256 _staticGas, uint256 _maxGasPrice) {\\n staticGas = _staticGas;\\n maxGasPrice = _maxGasPrice;\\n }\\n\\n /// @notice Receive ETH\\n receive() external payable {}\\n\\n /// @notice Refunds ETH to a spender for executing specific transactions.\\n /// @dev Ignoring the result of sending ETH to a receiver is made on purpose.\\n /// For EOA receiving ETH should always work. If a receiver is a smart\\n /// contract, then we do not want to fail a transaction, because in some\\n /// cases the refund is done at the very end of multiple calls where all\\n /// the previous calls were already paid off. It is a receiver's smart\\n /// contract resposibility to make sure it can receive ETH.\\n /// @dev Only authorized contracts are allowed calling this function.\\n /// @param gasSpent Gas spent on a transaction that needs to be reimbursed.\\n /// @param receiver Address where the reimbursment is sent.\\n function refund(uint256 gasSpent, address receiver) external nonReentrant {\\n require(\\n isAuthorized[msg.sender],\\n \\\"Contract is not authorized for a refund\\\"\\n );\\n require(receiver != address(0), \\\"Receiver's address cannot be zero\\\");\\n\\n uint256 gasPrice = tx.gasprice < maxGasPrice\\n ? tx.gasprice\\n : maxGasPrice;\\n\\n uint256 refundAmount = (gasSpent + staticGas) * gasPrice;\\n\\n /* solhint-disable avoid-low-level-calls */\\n // slither-disable-next-line low-level-calls,unchecked-lowlevel\\n (bool sent, ) = receiver.call{value: refundAmount}(\\\"\\\");\\n /* solhint-enable avoid-low-level-calls */\\n if (!sent) {\\n // slither-disable-next-line reentrancy-events\\n emit SendingEtherFailed(refundAmount, receiver);\\n }\\n }\\n\\n /// @notice Authorize a contract that can interact with this reimbursment pool.\\n /// Can be authorized by the owner only.\\n /// @param _contract Authorized contract.\\n function authorize(address _contract) external onlyOwner {\\n isAuthorized[_contract] = true;\\n\\n emit AuthorizedContract(_contract);\\n }\\n\\n /// @notice Unauthorize a contract that was previously authorized to interact\\n /// with this reimbursment pool. Can be unauthorized by the\\n /// owner only.\\n /// @param _contract Authorized contract.\\n function unauthorize(address _contract) external onlyOwner {\\n delete isAuthorized[_contract];\\n\\n emit UnauthorizedContract(_contract);\\n }\\n\\n /// @notice Setting a static gas cost for executing a transaction. Can be set\\n /// by the owner only.\\n /// @param _staticGas Static gas cost.\\n function setStaticGas(uint256 _staticGas) external onlyOwner {\\n staticGas = _staticGas;\\n\\n emit StaticGasUpdated(_staticGas);\\n }\\n\\n /// @notice Setting a max gas price for transactions. Can be set by the\\n /// owner only.\\n /// @param _maxGasPrice Max gas price used to reimburse tx submitters.\\n function setMaxGasPrice(uint256 _maxGasPrice) external onlyOwner {\\n maxGasPrice = _maxGasPrice;\\n\\n emit MaxGasPriceUpdated(_maxGasPrice);\\n }\\n\\n /// @notice Withdraws all ETH from this pool which are sent to a given\\n /// address. Can be set by the owner only.\\n /// @param receiver An address where ETH is sent.\\n function withdrawAll(address receiver) external onlyOwner {\\n withdraw(address(this).balance, receiver);\\n }\\n\\n /// @notice Withdraws ETH amount from this pool which are sent to a given\\n /// address. Can be set by the owner only.\\n /// @param amount Amount to withdraw from the pool.\\n /// @param receiver An address where ETH is sent.\\n function withdraw(uint256 amount, address receiver) public onlyOwner {\\n require(\\n address(this).balance >= amount,\\n \\\"Insufficient contract balance\\\"\\n );\\n require(receiver != address(0), \\\"Receiver's address cannot be zero\\\");\\n\\n emit FundsWithdrawn(amount, receiver);\\n\\n /* solhint-disable avoid-low-level-calls */\\n // slither-disable-next-line low-level-calls,arbitrary-send\\n (bool sent, ) = receiver.call{value: amount}(\\\"\\\");\\n /* solhint-enable avoid-low-level-calls */\\n require(sent, \\\"Failed to send Ether\\\");\\n }\\n}\\n\",\"keccak256\":\"0xd6c24368cc4c6349b8b614e878ca961cad8254b8e8db1cc0abe452a70022ce50\",\"license\":\"GPL-3.0-only\"},\"contracts/api/IRandomBeacon.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IRandomBeaconConsumer.sol\\\";\\n\\n/// @title Random Beacon interface\\ninterface IRandomBeacon {\\n /// @notice Creates a request to generate a new relay entry. Requires a\\n /// request fee denominated in T token.\\n /// @param callbackContract Beacon consumer callback contract.\\n function requestRelayEntry(IRandomBeaconConsumer callbackContract) external;\\n}\\n\",\"keccak256\":\"0xc5f6ddbf69b2f2e2c03fe78b3857a1f038982e858679f520101f53c4ebe2f4bf\",\"license\":\"GPL-3.0-only\"},\"contracts/api/IRandomBeaconConsumer.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\ninterface IRandomBeaconConsumer {\\n /// @notice Receives relay entry produced by Keep Random Beacon. This function\\n /// should be called only by Keep Random Beacon.\\n ///\\n /// @param relayEntry Relay entry (random number) produced by Keep Random\\n /// Beacon.\\n /// @param blockNumber Block number at which the relay entry was submitted\\n /// to the chain.\\n function __beaconCallback(uint256 relayEntry, uint256 blockNumber) external;\\n}\\n\",\"keccak256\":\"0x84ce236b4eeb664ccb02782777a05c6ebb410be9b9e586a123a1205437a2ed9f\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/AltBn128.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./ModUtils.sol\\\";\\n\\n/// @title Operations on alt_bn128\\n/// @dev Implementations of common elliptic curve operations on Ethereum's\\n/// (poorly named) alt_bn128 curve. Whenever possible, use post-Byzantium\\n/// pre-compiled contracts to offset gas costs. Note that these\\n/// pre-compiles might not be available on all (eg private) chains.\\nlibrary AltBn128 {\\n using ModUtils for uint256;\\n\\n // G1Point implements a point in G1 group.\\n struct G1Point {\\n uint256 x;\\n uint256 y;\\n }\\n\\n // gfP2 implements a field of size p\\u00b2 as a quadratic extension of the base\\n // field.\\n struct gfP2 {\\n uint256 x;\\n uint256 y;\\n }\\n\\n // G2Point implements a point in G2 group.\\n struct G2Point {\\n gfP2 x;\\n gfP2 y;\\n }\\n\\n // p is a prime over which we form a basic field\\n // Taken from go-ethereum/crypto/bn256/cloudflare/constants.go\\n uint256 internal constant p =\\n 21888242871839275222246405745257275088696311157297823662689037894645226208583;\\n\\n /// @dev Gets generator of G1 group.\\n /// Taken from go-ethereum/crypto/bn256/cloudflare/curve.go\\n uint256 internal constant g1x = 1;\\n uint256 internal constant g1y = 2;\\n\\n /// @dev Gets generator of G2 group.\\n /// Taken from go-ethereum/crypto/bn256/cloudflare/twist.go\\n uint256 internal constant g2xx =\\n 11559732032986387107991004021392285783925812861821192530917403151452391805634;\\n uint256 internal constant g2xy =\\n 10857046999023057135944570762232829481370756359578518086990519993285655852781;\\n uint256 internal constant g2yx =\\n 4082367875863433681332203403145435568316851327593401208105741076214120093531;\\n uint256 internal constant g2yy =\\n 8495653923123431417604973247489272438418190587263600148770280649306958101930;\\n\\n /// @dev Gets twist curve B constant.\\n /// Taken from go-ethereum/crypto/bn256/cloudflare/twist.go\\n uint256 internal constant twistBx =\\n 266929791119991161246907387137283842545076965332900288569378510910307636690;\\n uint256 internal constant twistBy =\\n 19485874751759354771024239261021720505790618469301721065564631296452457478373;\\n\\n /// @dev Gets root of the point where x and y are equal.\\n uint256 internal constant hexRootX =\\n 21573744529824266246521972077326577680729363968861965890554801909984373949499;\\n uint256 internal constant hexRootY =\\n 16854739155576650954933913186877292401521110422362946064090026408937773542853;\\n\\n /// @dev g1YFromX computes a Y value for a G1 point based on an X value.\\n /// This computation is simply evaluating the curve equation for Y on a\\n /// given X, and allows a point on the curve to be represented by just\\n /// an X value + a sign bit.\\n function g1YFromX(uint256 x) internal view returns (uint256) {\\n return ((x.modExp(3, p) + 3) % p).modSqrt(p);\\n }\\n\\n /// @dev Hash a byte array message, m, and map it deterministically to a\\n /// point on G1. Note that this approach was chosen for its simplicity\\n /// and lower gas cost on the EVM, rather than good distribution of\\n /// points on G1.\\n function g1HashToPoint(bytes memory m)\\n internal\\n view\\n returns (G1Point memory)\\n {\\n unchecked {\\n bytes32 h = sha256(m);\\n uint256 x = uint256(h) % p;\\n uint256 y;\\n\\n while (true) {\\n y = g1YFromX(x);\\n if (y > 0) {\\n return G1Point(x, y);\\n }\\n x += 1;\\n }\\n }\\n }\\n\\n /// @dev Decompress a point on G1 from a single uint256.\\n function g1Decompress(bytes32 m) internal view returns (G1Point memory) {\\n unchecked {\\n bytes32 mX = bytes32(0);\\n bytes1 leadX = m[0] & 0x7f;\\n // slither-disable-next-line incorrect-shift\\n uint256 mask = 0xff << (31 * 8);\\n mX = (m & ~bytes32(mask)) | (leadX >> 0);\\n\\n uint256 x = uint256(mX);\\n uint256 y = g1YFromX(x);\\n\\n if (parity(y) != (m[0] & 0x80) >> 7) {\\n y = p - y;\\n }\\n\\n require(\\n isG1PointOnCurve(G1Point(x, y)),\\n \\\"Malformed bn256.G1 point.\\\"\\n );\\n\\n return G1Point(x, y);\\n }\\n }\\n\\n /// @dev Wraps the point addition pre-compile introduced in Byzantium.\\n /// Returns the sum of two points on G1. Revert if the provided points\\n /// are not on the curve.\\n function g1Add(G1Point memory a, G1Point memory b)\\n internal\\n view\\n returns (G1Point memory c)\\n {\\n assembly {\\n let arg := mload(0x40)\\n mstore(arg, mload(a))\\n mstore(add(arg, 0x20), mload(add(a, 0x20)))\\n mstore(add(arg, 0x40), mload(b))\\n mstore(add(arg, 0x60), mload(add(b, 0x20)))\\n // 0x60 is the ECADD precompile address\\n if iszero(staticcall(not(0), 0x06, arg, 0x80, c, 0x40)) {\\n revert(0, 0)\\n }\\n }\\n }\\n\\n /// @dev Returns true if G1 point is on the curve.\\n function isG1PointOnCurve(G1Point memory point)\\n internal\\n view\\n returns (bool)\\n {\\n return point.y.modExp(2, p) == (point.x.modExp(3, p) + 3) % p;\\n }\\n\\n /// @dev Wraps the scalar point multiplication pre-compile introduced in\\n /// Byzantium. The result of a point from G1 multiplied by a scalar\\n /// should match the point added to itself the same number of times.\\n /// Revert if the provided point isn't on the curve.\\n function scalarMultiply(G1Point memory p_1, uint256 scalar)\\n internal\\n view\\n returns (G1Point memory p_2)\\n {\\n assembly {\\n let arg := mload(0x40)\\n mstore(arg, mload(p_1))\\n mstore(add(arg, 0x20), mload(add(p_1, 0x20)))\\n mstore(add(arg, 0x40), scalar)\\n // 0x07 is the ECMUL precompile address\\n if iszero(staticcall(not(0), 0x07, arg, 0x60, p_2, 0x40)) {\\n revert(0, 0)\\n }\\n }\\n }\\n\\n /// @dev Wraps the pairing check pre-compile introduced in Byzantium.\\n /// Returns the result of a pairing check of 2 pairs\\n /// (G1 p1, G2 p2) (G1 p3, G2 p4)\\n function pairing(\\n G1Point memory p1,\\n G2Point memory p2,\\n G1Point memory p3,\\n G2Point memory p4\\n ) internal view returns (bool result) {\\n uint256 _c;\\n assembly {\\n let c := mload(0x40)\\n let arg := add(c, 0x20)\\n\\n mstore(arg, mload(p1))\\n mstore(add(arg, 0x20), mload(add(p1, 0x20)))\\n\\n let p2x := mload(p2)\\n mstore(add(arg, 0x40), mload(p2x))\\n mstore(add(arg, 0x60), mload(add(p2x, 0x20)))\\n\\n let p2y := mload(add(p2, 0x20))\\n mstore(add(arg, 0x80), mload(p2y))\\n mstore(add(arg, 0xa0), mload(add(p2y, 0x20)))\\n\\n mstore(add(arg, 0xc0), mload(p3))\\n mstore(add(arg, 0xe0), mload(add(p3, 0x20)))\\n\\n let p4x := mload(p4)\\n mstore(add(arg, 0x100), mload(p4x))\\n mstore(add(arg, 0x120), mload(add(p4x, 0x20)))\\n\\n let p4y := mload(add(p4, 0x20))\\n mstore(add(arg, 0x140), mload(p4y))\\n mstore(add(arg, 0x160), mload(add(p4y, 0x20)))\\n\\n // call(gasLimit, to, value, inputOffset, inputSize, outputOffset, outputSize)\\n if iszero(staticcall(not(0), 0x08, arg, 0x180, c, 0x20)) {\\n revert(0, 0)\\n }\\n _c := mload(c)\\n }\\n return _c != 0;\\n }\\n\\n function getP() internal pure returns (uint256) {\\n return p;\\n }\\n\\n function g1() internal pure returns (G1Point memory) {\\n return G1Point(g1x, g1y);\\n }\\n\\n function g2() internal pure returns (G2Point memory) {\\n return G2Point(gfP2(g2xx, g2xy), gfP2(g2yx, g2yy));\\n }\\n\\n /// @dev g2YFromX computes a Y value for a G2 point based on an X value.\\n /// This computation is simply evaluating the curve equation for Y on a\\n /// given X, and allows a point on the curve to be represented by just\\n /// an X value + a sign bit.\\n function g2YFromX(gfP2 memory _x) internal pure returns (gfP2 memory y) {\\n (uint256 xx, uint256 xy) = _gfP2CubeAddTwistB(_x.x, _x.y);\\n\\n // Using formula y = x ^ (p^2 + 15) / 32 from\\n // https://github.com/ethereum/beacon_chain/blob/master/beacon_chain/utils/bls.py\\n // (p^2 + 15) / 32 results into a big 512bit value, so breaking it to two uint256 as (a * a + b)\\n uint256 a = 3869331240733915743250440106392954448556483137451914450067252501901456824595;\\n uint256 b = 146360017852723390495514512480590656176144969185739259173561346299185050597;\\n\\n (uint256 xbx, uint256 xby) = _gfP2Pow(xx, xy, b);\\n (uint256 yax, uint256 yay) = _gfP2Pow(xx, xy, a);\\n (uint256 ya2x, uint256 ya2y) = _gfP2Pow(yax, yay, a);\\n (y.x, y.y) = _gfP2Multiply(ya2x, ya2y, xbx, xby);\\n\\n // Multiply y by hexRoot constant to find correct y.\\n while (!_g2X2y(xx, xy, y.x, y.y)) {\\n (y.x, y.y) = _gfP2Multiply(y.x, y.y, hexRootX, hexRootY);\\n }\\n }\\n\\n /// @dev Compress a point on G1 to a single uint256 for serialization.\\n function g1Compress(G1Point memory point) internal pure returns (bytes32) {\\n bytes32 m = bytes32(point.x);\\n\\n bytes1 leadM = m[0] | (parity(point.y) << 7);\\n // slither-disable-next-line incorrect-shift\\n uint256 mask = 0xff << (31 * 8);\\n m = (m & ~bytes32(mask)) | (leadM >> 0);\\n\\n return m;\\n }\\n\\n /// @dev Compress a point on G2 to a pair of uint256 for serialization.\\n function g2Compress(G2Point memory point)\\n internal\\n pure\\n returns (bytes memory)\\n {\\n bytes32 m = bytes32(point.x.x);\\n\\n bytes1 leadM = m[0] | (parity(point.y.x) << 7);\\n // slither-disable-next-line incorrect-shift\\n uint256 mask = 0xff << (31 * 8);\\n m = (m & ~bytes32(mask)) | (leadM >> 0);\\n\\n return abi.encodePacked(m, bytes32(point.x.y));\\n }\\n\\n /// @dev Unmarshals a point on G1 from bytes in an uncompressed form.\\n function g1Unmarshal(bytes memory m)\\n internal\\n pure\\n returns (G1Point memory)\\n {\\n require(m.length == 64, \\\"Invalid G1 bytes length\\\");\\n\\n bytes32 x;\\n bytes32 y;\\n\\n assembly {\\n x := mload(add(m, 0x20))\\n y := mload(add(m, 0x40))\\n }\\n\\n return G1Point(uint256(x), uint256(y));\\n }\\n\\n /// @dev Marshals a point on G1 to bytes form.\\n function g1Marshal(G1Point memory point)\\n internal\\n pure\\n returns (bytes memory)\\n {\\n bytes memory m = new bytes(64);\\n bytes32 x = bytes32(point.x);\\n bytes32 y = bytes32(point.y);\\n\\n assembly {\\n mstore(add(m, 32), x)\\n mstore(add(m, 64), y)\\n }\\n\\n return m;\\n }\\n\\n /// @dev Unmarshals a point on G2 from bytes in an uncompressed form.\\n function g2Unmarshal(bytes memory m)\\n internal\\n pure\\n returns (G2Point memory)\\n {\\n require(m.length == 128, \\\"Invalid G2 bytes length\\\");\\n\\n uint256 xx;\\n uint256 xy;\\n uint256 yx;\\n uint256 yy;\\n\\n assembly {\\n xx := mload(add(m, 0x20))\\n xy := mload(add(m, 0x40))\\n yx := mload(add(m, 0x60))\\n yy := mload(add(m, 0x80))\\n }\\n\\n return G2Point(gfP2(xx, xy), gfP2(yx, yy));\\n }\\n\\n /// @dev Decompress a point on G2 from a pair of uint256.\\n function g2Decompress(bytes memory m)\\n internal\\n pure\\n returns (G2Point memory)\\n {\\n require(m.length == 64, \\\"Invalid G2 compressed bytes length\\\");\\n\\n bytes32 x1;\\n bytes32 x2;\\n uint256 temp;\\n\\n // Extract two bytes32 from bytes array\\n assembly {\\n temp := add(m, 32)\\n x1 := mload(temp)\\n temp := add(m, 64)\\n x2 := mload(temp)\\n }\\n\\n bytes32 mX = bytes32(0);\\n bytes1 leadX = x1[0] & 0x7f;\\n // slither-disable-next-line incorrect-shift\\n uint256 mask = 0xff << (31 * 8);\\n mX = (x1 & ~bytes32(mask)) | (leadX >> 0);\\n\\n gfP2 memory x = gfP2(uint256(mX), uint256(x2));\\n gfP2 memory y = g2YFromX(x);\\n\\n if (parity(y.x) != (m[0] & 0x80) >> 7) {\\n y.x = p - y.x;\\n y.y = p - y.y;\\n }\\n\\n return G2Point(x, y);\\n }\\n\\n /// @dev Returns the sum of two gfP2 field elements.\\n function gfP2Add(gfP2 memory a, gfP2 memory b)\\n internal\\n pure\\n returns (gfP2 memory)\\n {\\n return gfP2(addmod(a.x, b.x, p), addmod(a.y, b.y, p));\\n }\\n\\n /// @dev Returns multiplication of two gfP2 field elements.\\n function gfP2Multiply(gfP2 memory a, gfP2 memory b)\\n internal\\n pure\\n returns (gfP2 memory)\\n {\\n return\\n gfP2(\\n addmod(mulmod(a.x, b.y, p), mulmod(b.x, a.y, p), p),\\n addmod(mulmod(a.y, b.y, p), p - mulmod(a.x, b.x, p), p)\\n );\\n }\\n\\n /// @dev Returns gfP2 element to the power of the provided exponent.\\n function gfP2Pow(gfP2 memory _a, uint256 _exp)\\n internal\\n pure\\n returns (gfP2 memory result)\\n {\\n (uint256 x, uint256 y) = _gfP2Pow(_a.x, _a.y, _exp);\\n return gfP2(x, y);\\n }\\n\\n function gfP2Square(gfP2 memory a) internal pure returns (gfP2 memory) {\\n return gfP2Multiply(a, a);\\n }\\n\\n function gfP2Cube(gfP2 memory a) internal pure returns (gfP2 memory) {\\n return gfP2Multiply(a, gfP2Square(a));\\n }\\n\\n function gfP2CubeAddTwistB(gfP2 memory a)\\n internal\\n pure\\n returns (gfP2 memory)\\n {\\n (uint256 x, uint256 y) = _gfP2CubeAddTwistB(a.x, a.y);\\n return gfP2(x, y);\\n }\\n\\n /// @dev Returns true if G2 point's y^2 equals x.\\n function g2X2y(gfP2 memory x, gfP2 memory y) internal pure returns (bool) {\\n gfP2 memory y2;\\n y2 = gfP2Square(y);\\n\\n return (y2.x == x.x && y2.y == x.y);\\n }\\n\\n /// @dev Returns true if G2 point is on the curve.\\n function isG2PointOnCurve(G2Point memory point)\\n internal\\n pure\\n returns (bool)\\n {\\n (uint256 y2x, uint256 y2y) = _gfP2Square(point.y.x, point.y.y);\\n (uint256 x3x, uint256 x3y) = _gfP2CubeAddTwistB(point.x.x, point.x.y);\\n\\n return (y2x == x3x && y2y == x3y);\\n }\\n\\n function twistB() private pure returns (gfP2 memory) {\\n return gfP2(twistBx, twistBy);\\n }\\n\\n function hexRoot() private pure returns (gfP2 memory) {\\n return gfP2(hexRootX, hexRootY);\\n }\\n\\n /// @dev Calculates whether the provided number is even or odd.\\n /// @return 0x01 if y is an even number and 0x00 if it's odd.\\n function parity(uint256 value) private pure returns (bytes1) {\\n return bytes32(value)[31] & 0x01;\\n }\\n\\n function _gfP2Add(\\n uint256 ax,\\n uint256 ay,\\n uint256 bx,\\n uint256 by\\n ) private pure returns (uint256 x, uint256 y) {\\n x = addmod(ax, bx, p);\\n y = addmod(ay, by, p);\\n }\\n\\n function _gfP2Multiply(\\n uint256 ax,\\n uint256 ay,\\n uint256 bx,\\n uint256 by\\n ) private pure returns (uint256 x, uint256 y) {\\n x = addmod(mulmod(ax, by, p), mulmod(bx, ay, p), p);\\n y = addmod(mulmod(ay, by, p), p - mulmod(ax, bx, p), p);\\n }\\n\\n function _gfP2CubeAddTwistB(uint256 ax, uint256 ay)\\n private\\n pure\\n returns (uint256 x, uint256 y)\\n {\\n (uint256 a3x, uint256 a3y) = _gfP2Cube(ax, ay);\\n return _gfP2Add(a3x, a3y, twistBx, twistBy);\\n }\\n\\n function _gfP2Pow(\\n uint256 _ax,\\n uint256 _ay,\\n uint256 _exp\\n ) private pure returns (uint256 x, uint256 y) {\\n uint256 exp = _exp;\\n x = 0;\\n y = 1;\\n uint256 ax = _ax;\\n uint256 ay = _ay;\\n\\n // Reduce exp dividing by 2 gradually to 0 while computing final\\n // result only when exp is an odd number.\\n while (exp > 0) {\\n if (parity(exp) == 0x01) {\\n (x, y) = _gfP2Multiply(x, y, ax, ay);\\n }\\n\\n unchecked {\\n exp = exp / 2;\\n }\\n (ax, ay) = _gfP2Multiply(ax, ay, ax, ay);\\n }\\n }\\n\\n function _gfP2Square(uint256 _ax, uint256 _ay)\\n private\\n pure\\n returns (uint256 x, uint256 y)\\n {\\n return _gfP2Multiply(_ax, _ay, _ax, _ay);\\n }\\n\\n function _gfP2Cube(uint256 _ax, uint256 _ay)\\n private\\n pure\\n returns (uint256 x, uint256 y)\\n {\\n (uint256 _bx, uint256 _by) = _gfP2Square(_ax, _ay);\\n return _gfP2Multiply(_ax, _ay, _bx, _by);\\n }\\n\\n function _g2X2y(\\n uint256 xx,\\n uint256 xy,\\n uint256 yx,\\n uint256 yy\\n ) private pure returns (bool) {\\n (uint256 y2x, uint256 y2y) = _gfP2Square(yx, yy);\\n\\n return (y2x == xx && y2y == xy);\\n }\\n}\\n\",\"keccak256\":\"0x8a100028820ff5c424f4bb780fbedec1da2576fbc6d5aa4e7309d986b730a319\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BLS.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./AltBn128.sol\\\";\\n\\n/// @title BLS signatures verification\\n/// @dev Library for verification of 2-pairing-check BLS signatures, including\\n/// basic, aggregated, or reconstructed threshold BLS signatures, generated\\n/// using the AltBn128 curve.\\nlibrary BLS {\\n /// @dev Creates a signature over message using the provided secret key.\\n function sign(bytes memory message, uint256 secretKey)\\n external\\n view\\n returns (bytes memory)\\n {\\n AltBn128.G1Point memory p_1 = AltBn128.g1HashToPoint(message);\\n AltBn128.G1Point memory p_2 = AltBn128.scalarMultiply(p_1, secretKey);\\n\\n return AltBn128.g1Marshal(p_2);\\n }\\n\\n /// @dev Wraps the functionality of BLS.verify, but hashes a message to\\n /// a point on G1 and marshal to bytes first to allow raw bytes\\n /// verification.\\n function verifyBytes(\\n bytes memory publicKey,\\n bytes memory message,\\n bytes memory signature\\n ) external view returns (bool) {\\n AltBn128.G1Point memory point = AltBn128.g1HashToPoint(message);\\n bytes memory messageAsPoint = AltBn128.g1Marshal(point);\\n\\n return verify(publicKey, messageAsPoint, signature);\\n }\\n\\n /// @dev Verify performs the pairing operation to check if the signature\\n /// is correct for the provided message and the corresponding public\\n /// key. Public key must be a valid point on G2 curve in an\\n /// uncompressed format. Message must be a valid point on G1 curve in\\n /// an uncompressed format. Signature must be a valid point on G1\\n /// curve in an uncompressed format.\\n function verify(\\n bytes memory publicKey,\\n bytes memory message,\\n bytes memory signature\\n ) public view returns (bool) {\\n AltBn128.G1Point memory _signature = AltBn128.g1Unmarshal(signature);\\n\\n return\\n _verify(\\n AltBn128.g2Unmarshal(publicKey),\\n AltBn128.g1Unmarshal(message),\\n _signature\\n );\\n }\\n\\n function _verify(\\n AltBn128.G2Point memory publicKey,\\n AltBn128.G1Point memory message,\\n AltBn128.G1Point memory signature\\n ) public view returns (bool) {\\n return\\n AltBn128.pairing(\\n AltBn128.G1Point(signature.x, AltBn128.getP() - signature.y),\\n AltBn128.g2(),\\n message,\\n publicKey\\n );\\n }\\n}\\n\",\"keccak256\":\"0x08c7e739c63c31f5f45fb390695eca9e98a9525589ace41526f25060f46e43d4\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BeaconAuthorization.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\n// Initial version copied from Keep Network ECDSA Wallets:\\n// https://github.com/keep-network/keep-core/blob/5286ebc8ff99b2aa6569f9dd97fd6995f25b4630/solidity/ecdsa/contracts/libraries/EcdsaAuthorization.sol\\n//\\n// With the following differences:\\n// - functions' visibility was changed to public/external to deploy it as a linked\\n// library.\\n// - documentation was updated to be more generic.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\nimport \\\"@threshold-network/solidity-contracts/contracts/staking/IStaking.sol\\\";\\n\\n/// @notice Library managing the state of stake authorizations for the operator\\n/// contract and the presence of operators in the sortition\\n/// pool based on the stake authorized for them.\\nlibrary BeaconAuthorization {\\n struct Parameters {\\n // The minimum authorization required by the beacon so that\\n // operator can join the sortition pool and do the work.\\n uint96 minimumAuthorization;\\n // Authorization decrease delay in seconds between the time\\n // authorization decrease is requested and the time the authorization\\n // decrease can be approved. It is always the same value, no matter if\\n // authorization decrease amount is small, significant, or if it is\\n // a decrease to zero.\\n uint64 authorizationDecreaseDelay;\\n // The time period before the authorization decrease delay end,\\n // during which the authorization decrease request can be overwritten.\\n //\\n // When the request is overwritten, the authorization decrease delay is\\n // reset.\\n //\\n // For example, if `authorizationDecraseChangePeriod` is set to 4\\n // days, `authorizationDecreaseDelay` is set to 14 days, and someone\\n // requested authorization decrease, it means they can not\\n // request another decrease for the first 10 days. After 10 days pass,\\n // they can request again and overwrite the previous authorization\\n // decrease request. The delay time will reset for them and they\\n // will have to wait another 10 days to alter it and 14 days to\\n // approve it.\\n //\\n // This value protects against malicious operators who manipulate\\n // their weight by overwriting authorization decrease request, and\\n // lowering or increasing their eligible stake this way.\\n //\\n // If set to a value equal to `authorizationDecreaseDelay, it means\\n // that authorization decrease request can be always overwritten.\\n // If set to zero, it means authorization decrease request can not be\\n // overwritten until the delay end, and one needs to wait for the entire\\n // authorization decrease delay to approve their decrease and request\\n // for another one or to overwrite the pending one.\\n //\\n // (1) authorization decrease requested timestamp\\n // (2) from this moment authorization decrease request can be\\n // overwritten\\n // (3) from this moment authorization decrease request can be\\n // approved, assuming it was NOT overwritten in (2)\\n //\\n // (1) (2) (3)\\n // --x------------------------------x--------------------------x---->\\n // | \\\\________________________/\\n // | authorizationDecreaseChangePeriod\\n // \\\\______________________________________________________/\\n // authorizationDecreaseDelay\\n //\\n uint64 authorizationDecreaseChangePeriod;\\n }\\n\\n struct AuthorizationDecrease {\\n uint96 decreasingBy; // amount\\n uint64 decreasingAt; // timestamp\\n }\\n\\n struct Data {\\n Parameters parameters;\\n mapping(address => address) stakingProviderToOperator;\\n mapping(address => address) operatorToStakingProvider;\\n mapping(address => AuthorizationDecrease) pendingDecreases;\\n }\\n\\n event OperatorRegistered(\\n address indexed stakingProvider,\\n address indexed operator\\n );\\n\\n event AuthorizationIncreased(\\n address indexed stakingProvider,\\n address indexed operator,\\n uint96 fromAmount,\\n uint96 toAmount\\n );\\n\\n event AuthorizationDecreaseRequested(\\n address indexed stakingProvider,\\n address indexed operator,\\n uint96 fromAmount,\\n uint96 toAmount,\\n uint64 decreasingAt\\n );\\n\\n event AuthorizationDecreaseApproved(address indexed stakingProvider);\\n\\n event InvoluntaryAuthorizationDecreaseFailed(\\n address indexed stakingProvider,\\n address indexed operator,\\n uint96 fromAmount,\\n uint96 toAmount\\n );\\n\\n event OperatorJoinedSortitionPool(\\n address indexed stakingProvider,\\n address indexed operator\\n );\\n\\n event OperatorStatusUpdated(\\n address indexed stakingProvider,\\n address indexed operator\\n );\\n\\n /// @notice Updates authorization-related parameters.\\n /// @param _minimumAuthorization New value of the minimum authorization for\\n /// the beacon. Without at least the minimum authorization, staking\\n /// provider is not eligible to join and operate in the network.\\n /// @param _authorizationDecreaseDelay New value of the authorization\\n /// decrease delay. It is the time in seconds that needs to pass\\n /// between the time authorization decrease is requested and the time\\n /// the authorization decrease can be approved, no matter the\\n /// authorization decrease amount.\\n /// @param _authorizationDecreaseChangePeriod New value of the authorization\\n /// decrease change period. It is the time in seconds, before\\n /// authorization decrease delay end, during which the pending\\n /// authorization decrease request can be overwritten.\\n /// If set to 0, pending authorization decrease request can not be\\n /// overwritten until the entire `authorizationDecreaseDelay` ends.\\n /// If set to value equal `authorizationDecreaseDelay`, request can\\n /// always be overwritten.\\n function setParameters(\\n Data storage self,\\n uint96 _minimumAuthorization,\\n uint64 _authorizationDecreaseDelay,\\n uint64 _authorizationDecreaseChangePeriod\\n ) external {\\n self.parameters.minimumAuthorization = _minimumAuthorization;\\n self\\n .parameters\\n .authorizationDecreaseDelay = _authorizationDecreaseDelay;\\n self\\n .parameters\\n .authorizationDecreaseChangePeriod = _authorizationDecreaseChangePeriod;\\n }\\n\\n /// @notice Used by staking provider to set operator address that will\\n /// operate a node. The given staking provider can set operator\\n /// address only one time. The operator address can not be changed\\n /// and must be unique. Reverts if the operator is already set for\\n /// the staking provider or if the operator address is already in\\n /// use. Reverts if there is a pending authorization decrease for\\n /// the staking provider.\\n function registerOperator(Data storage self, address operator) public {\\n address stakingProvider = msg.sender;\\n\\n require(operator != address(0), \\\"Operator can not be zero address\\\");\\n require(\\n self.stakingProviderToOperator[stakingProvider] == address(0),\\n \\\"Operator already set for the staking provider\\\"\\n );\\n require(\\n self.operatorToStakingProvider[operator] == address(0),\\n \\\"Operator address already in use\\\"\\n );\\n\\n // Authorization request for a staking provider who has not yet\\n // registered their operator can be approved immediately.\\n // We need to make sure that the approval happens before operator\\n // is registered to do not let the operator join the sortition pool\\n // with an unresolved authorization decrease request that can be\\n // approved at any point.\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n require(\\n decrease.decreasingAt == 0,\\n \\\"There is a pending authorization decrease request\\\"\\n );\\n\\n emit OperatorRegistered(stakingProvider, operator);\\n\\n self.stakingProviderToOperator[stakingProvider] = operator;\\n self.operatorToStakingProvider[operator] = stakingProvider;\\n }\\n\\n /// @notice Used by T staking contract to inform the beacon that the\\n /// authorized stake amount for the given staking provider increased.\\n ///\\n /// Reverts if the authorization amount is below the minimum.\\n ///\\n /// The function is not updating the sortition pool. Sortition pool\\n /// state needs to be updated by the operator with a call to\\n /// `joinSortitionPool` or `updateOperatorStatus`.\\n ///\\n /// @dev Should only be callable by T staking contract.\\n function authorizationIncreased(\\n Data storage self,\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external {\\n require(\\n toAmount >= self.parameters.minimumAuthorization,\\n \\\"Authorization below the minimum\\\"\\n );\\n\\n // Note that this function does not require the operator address to be\\n // set for the given staking provider. This allows the stake owner\\n // who is also an authorizer to increase the authorization before the\\n // staking provider sets the operator. This allows delegating stake\\n // and increasing authorization immediately one after another without\\n // having to wait for the staking provider to do their part.\\n\\n address operator = self.stakingProviderToOperator[stakingProvider];\\n emit AuthorizationIncreased(\\n stakingProvider,\\n operator,\\n fromAmount,\\n toAmount\\n );\\n }\\n\\n /// @notice Used by T staking contract to inform the beacon that the\\n /// authorization decrease for the given staking provider has been\\n /// requested.\\n ///\\n /// Reverts if the amount after deauthorization would be non-zero\\n /// and lower than the minimum authorization.\\n ///\\n /// Reverts if another authorization decrease request is pending for\\n /// the staking provider and not enough time passed since the\\n /// original request (see `authorizationDecreaseChangePeriod`).\\n ///\\n /// If the operator is not known (`registerOperator` was not called)\\n /// it lets to `approveAuthorizationDecrease` immediately. If the\\n /// operator is known (`registerOperator` was called), the operator\\n /// needs to update state of the sortition pool with a call to\\n /// `joinSortitionPool` or `updateOperatorStatus`. After the\\n /// sortition pool state is in sync, authorization decrease delay\\n /// starts.\\n ///\\n /// After authorization decrease delay passes, authorization\\n /// decrease request needs to be approved with a call to\\n /// `approveAuthorizationDecrease` function.\\n ///\\n /// If there is a pending authorization decrease request, it is\\n /// overwritten, but only if enough time passed since the original\\n /// request. Otherwise, the function reverts.\\n ///\\n /// @dev Should only be callable by T staking contract.\\n function authorizationDecreaseRequested(\\n Data storage self,\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) public {\\n require(\\n toAmount == 0 || toAmount >= self.parameters.minimumAuthorization,\\n \\\"Authorization amount should be 0 or above the minimum\\\"\\n );\\n\\n address operator = self.stakingProviderToOperator[stakingProvider];\\n\\n uint64 decreasingAt;\\n\\n if (operator == address(0)) {\\n // Operator is not known. It means `registerOperator` was not\\n // called yet, and there is no chance the operator could\\n // call `joinSortitionPool`. We can let to approve authorization\\n // decrease immediately because that operator was never in the\\n // sortition pool.\\n\\n // solhint-disable-next-line not-rely-on-time\\n decreasingAt = uint64(block.timestamp);\\n } else {\\n // Operator is known. It means that this operator is or was in\\n // the sortition pool. Before authorization decrease delay starts,\\n // the operator needs to update the state of the sortition pool\\n // with a call to `joinSortitionPool` or `updateOperatorStatus`.\\n // For now, we set `decreasingAt` as \\\"never decreasing\\\" and let\\n // it be updated by `joinSortitionPool` or `updateOperatorStatus`\\n // once we know the sortition pool is in sync.\\n decreasingAt = type(uint64).max;\\n }\\n\\n uint96 decreasingBy = fromAmount - toAmount;\\n\\n AuthorizationDecrease storage decreaseRequest = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n uint64 pendingDecreaseAt = decreaseRequest.decreasingAt;\\n if (pendingDecreaseAt != 0 && pendingDecreaseAt != type(uint64).max) {\\n // If there is already a pending authorization decrease request for\\n // this staking provider and that request has been activated\\n // (sortition pool was updated), require enough time to pass before\\n // it can be overwritten.\\n require(\\n // solhint-disable-next-line not-rely-on-time\\n block.timestamp >=\\n pendingDecreaseAt -\\n self.parameters.authorizationDecreaseChangePeriod,\\n \\\"Not enough time passed since the original request\\\"\\n );\\n }\\n\\n decreaseRequest.decreasingBy = decreasingBy;\\n decreaseRequest.decreasingAt = decreasingAt;\\n\\n emit AuthorizationDecreaseRequested(\\n stakingProvider,\\n operator,\\n fromAmount,\\n toAmount,\\n decreasingAt\\n );\\n }\\n\\n /// @notice Approves the previously registered authorization decrease\\n /// request. Reverts if authorization decrease delay have not passed\\n /// yet or if the authorization decrease was not requested for the\\n /// given staking provider.\\n function approveAuthorizationDecrease(\\n Data storage self,\\n IStaking tokenStaking,\\n address stakingProvider\\n ) public {\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n require(\\n decrease.decreasingAt > 0,\\n \\\"Authorization decrease not requested\\\"\\n );\\n require(\\n decrease.decreasingAt != type(uint64).max,\\n \\\"Authorization decrease request not activated\\\"\\n );\\n require(\\n // solhint-disable-next-line not-rely-on-time\\n block.timestamp >= decrease.decreasingAt,\\n \\\"Authorization decrease delay not passed\\\"\\n );\\n\\n emit AuthorizationDecreaseApproved(stakingProvider);\\n\\n // slither-disable-next-line unused-return\\n tokenStaking.approveAuthorizationDecrease(stakingProvider);\\n delete self.pendingDecreases[stakingProvider];\\n }\\n\\n /// @notice Used by T staking contract to inform the beacon the\\n /// authorization has been decreased for the given staking provider\\n /// involuntarily, as a result of slashing.\\n ///\\n /// If the operator is not known (`registerOperator` was not called)\\n /// the function does nothing. The operator was never in a sortition\\n /// pool so there is nothing to update.\\n ///\\n /// If the operator is known, sortition pool is unlocked, and the\\n /// operator is in the sortition pool, the sortition pool state is\\n /// updated. If the sortition pool is locked, update needs to be\\n /// postponed. Every other staker is incentivized to call\\n /// `updateOperatorStatus` for the problematic operator to increase\\n /// their own rewards in the pool.\\n ///\\n /// @dev Should only be callable by T staking contract.\\n function involuntaryAuthorizationDecrease(\\n Data storage self,\\n IStaking tokenStaking,\\n SortitionPool sortitionPool,\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external {\\n address operator = self.stakingProviderToOperator[stakingProvider];\\n\\n if (operator == address(0)) {\\n // Operator is not known. It means `registerOperator` was not\\n // called yet, and there is no chance the operator could\\n // call `joinSortitionPool`. We can just ignore this update because\\n // operator was never in the sortition pool.\\n return;\\n } else {\\n // Operator is known. It means that this operator is or was in the\\n // sortition pool and the sortition pool may need to be updated.\\n //\\n // If the sortition pool is not locked and the operator is in the\\n // sortition pool, we are updating it.\\n //\\n // To keep stakes synchronized between applications when staking\\n // providers are slashed, without the risk of running out of gas,\\n // the staking contract queues up slashings and let users process\\n // the transactions. When an application slashes one or more staking\\n // providers, it adds them to the slashing queue on the staking\\n // contract. A queue entry contains the staking provider\\u2019s address\\n // and the amount they are due to be slashed.\\n //\\n // When there is at least one staking provider in the slashing\\n // queue, any account can submit a transaction processing one or\\n // more staking providers' slashings, and collecting a reward for\\n // doing so. A queued slashing is processed by updating the staking\\n // provider\\u2019s stake to the post-slashing amount, updating authorized\\n // amount for each affected application, and notifying all affected\\n // applications that the staking provider\\u2019s authorized stake has\\n // been reduced due to slashing.\\n //\\n // The entire idea is that the process transaction is expensive\\n // because each application needs to be updated, so the reward for\\n // the processor is hefty and comes from the slashed tokens.\\n // Practically, it means that if the sortition pool is unlocked, and\\n // can be updated, it should be updated because we already paid\\n // someone for updating it.\\n //\\n // If the sortition pool is locked, update needs to wait. Other\\n // sortition pool members are incentivized to call\\n // `updateOperatorStatus` for the problematic operator because they\\n // will increase their rewards this way.\\n if (sortitionPool.isOperatorInPool(operator)) {\\n if (sortitionPool.isLocked()) {\\n emit InvoluntaryAuthorizationDecreaseFailed(\\n stakingProvider,\\n operator,\\n fromAmount,\\n toAmount\\n );\\n } else {\\n updateOperatorStatus(\\n self,\\n tokenStaking,\\n sortitionPool,\\n operator\\n );\\n }\\n }\\n }\\n }\\n\\n /// @notice Lets the operator join the sortition pool. The operator address\\n /// must be known - before calling this function, it has to be\\n /// appointed by the staking provider by calling `registerOperator`.\\n /// Also, the operator must have the minimum authorization required\\n /// by the beacon. Function reverts if there is no minimum stake\\n /// authorized or if the operator is not known. If there was an\\n /// authorization decrease requested, it is activated by starting\\n /// the authorization decrease delay.\\n function joinSortitionPool(\\n Data storage self,\\n IStaking tokenStaking,\\n SortitionPool sortitionPool\\n ) public {\\n address operator = msg.sender;\\n\\n address stakingProvider = self.operatorToStakingProvider[operator];\\n require(stakingProvider != address(0), \\\"Unknown operator\\\");\\n\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n uint96 _eligibleStake = eligibleStake(\\n self,\\n tokenStaking,\\n stakingProvider,\\n decrease.decreasingBy\\n );\\n\\n require(_eligibleStake != 0, \\\"Authorization below the minimum\\\");\\n\\n emit OperatorJoinedSortitionPool(stakingProvider, operator);\\n\\n sortitionPool.insertOperator(operator, _eligibleStake);\\n\\n // If there is a pending authorization decrease request, activate it.\\n // At this point, the sortition pool state is up to date so the\\n // authorization decrease delay can start counting.\\n if (decrease.decreasingAt == type(uint64).max) {\\n decrease.decreasingAt =\\n // solhint-disable-next-line not-rely-on-time\\n uint64(block.timestamp) +\\n self.parameters.authorizationDecreaseDelay;\\n }\\n }\\n\\n /// @notice Updates status of the operator in the sortition pool. If there\\n /// was an authorization decrease requested, it is activated by\\n /// starting the authorization decrease delay.\\n /// Function reverts if the operator is not known.\\n function updateOperatorStatus(\\n Data storage self,\\n IStaking tokenStaking,\\n SortitionPool sortitionPool,\\n address operator\\n ) public {\\n address stakingProvider = self.operatorToStakingProvider[operator];\\n require(stakingProvider != address(0), \\\"Unknown operator\\\");\\n\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n emit OperatorStatusUpdated(stakingProvider, operator);\\n\\n if (sortitionPool.isOperatorInPool(operator)) {\\n uint96 _eligibleStake = eligibleStake(\\n self,\\n tokenStaking,\\n stakingProvider,\\n decrease.decreasingBy\\n );\\n\\n sortitionPool.updateOperatorStatus(operator, _eligibleStake);\\n }\\n\\n // If there is a pending authorization decrease request, activate it.\\n // At this point, the sortition pool state is up to date so the\\n // authorization decrease delay can start counting.\\n if (decrease.decreasingAt == type(uint64).max) {\\n decrease.decreasingAt =\\n // solhint-disable-next-line not-rely-on-time\\n uint64(block.timestamp) +\\n self.parameters.authorizationDecreaseDelay;\\n }\\n }\\n\\n /// @notice Checks if the operator's authorized stake is in sync with\\n /// operator's weight in the sortition pool.\\n /// If the operator is not in the sortition pool and their\\n /// authorized stake is non-zero, function returns false.\\n function isOperatorUpToDate(\\n Data storage self,\\n IStaking tokenStaking,\\n SortitionPool sortitionPool,\\n address operator\\n ) external view returns (bool) {\\n address stakingProvider = self.operatorToStakingProvider[operator];\\n require(stakingProvider != address(0), \\\"Unknown operator\\\");\\n\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n uint96 _eligibleStake = eligibleStake(\\n self,\\n tokenStaking,\\n stakingProvider,\\n decrease.decreasingBy\\n );\\n\\n if (!sortitionPool.isOperatorInPool(operator)) {\\n return _eligibleStake == 0;\\n } else {\\n return sortitionPool.isOperatorUpToDate(operator, _eligibleStake);\\n }\\n }\\n\\n /// @notice Returns the current value of the staking provider's eligible\\n /// stake. Eligible stake is defined as the currently authorized\\n /// stake minus the pending authorization decrease. Eligible stake\\n /// is what is used for operator's weight in the pool. If the\\n /// authorized stake minus the pending authorization decrease is\\n /// below the minimum authorization, eligible stake is 0.\\n /// @dev This function can be exposed to the public in contrast to the\\n /// second variant accepting `decreasingBy` as a parameter.\\n function eligibleStake(\\n Data storage self,\\n IStaking tokenStaking,\\n address stakingProvider\\n ) external view returns (uint96) {\\n return\\n eligibleStake(\\n self,\\n tokenStaking,\\n stakingProvider,\\n pendingAuthorizationDecrease(self, stakingProvider)\\n );\\n }\\n\\n /// @notice Returns the current value of the staking provider's eligible\\n /// stake. Eligible stake is defined as the currently authorized\\n /// stake minus the pending authorization decrease. Eligible stake\\n /// is what is used for operator's weight in the pool. If the\\n /// authorized stake minus the pending authorization decrease is\\n /// below the minimum authorization, eligible stake is 0.\\n /// @dev This function is not intended to be exposes to the public.\\n /// `decreasingBy` must be fetched from `pendingDecreases` mapping and\\n /// it is passed as a parameter to optimize gas usage of functions that\\n /// call `eligibleStake` and need to use `AuthorizationDecrease`\\n /// fetched from `pendingDecreases` for some additional logic.\\n function eligibleStake(\\n Data storage self,\\n IStaking tokenStaking,\\n address stakingProvider,\\n uint96 decreasingBy\\n ) public view returns (uint96) {\\n uint96 authorizedStake = tokenStaking.authorizedStake(\\n stakingProvider,\\n address(this)\\n );\\n\\n uint96 _eligibleStake = authorizedStake > decreasingBy\\n ? authorizedStake - decreasingBy\\n : 0;\\n\\n if (_eligibleStake < self.parameters.minimumAuthorization) {\\n return 0;\\n } else {\\n return _eligibleStake;\\n }\\n }\\n\\n /// @notice Returns the amount of stake that is pending authorization\\n /// decrease for the given staking provider. If no authorization\\n /// decrease has been requested, returns zero.\\n function pendingAuthorizationDecrease(\\n Data storage self,\\n address stakingProvider\\n ) public view returns (uint96) {\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n return decrease.decreasingBy;\\n }\\n\\n /// @notice Returns the remaining time in seconds that needs to pass before\\n /// the requested authorization decrease can be approved.\\n /// If the sortition pool state was not updated yet by the operator\\n /// after requesting the authorization decrease, returns\\n /// `type(uint64).max`.\\n function remainingAuthorizationDecreaseDelay(\\n Data storage self,\\n address stakingProvider\\n ) external view returns (uint64) {\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n if (decrease.decreasingAt == type(uint64).max) {\\n return type(uint64).max;\\n }\\n\\n // solhint-disable-next-line not-rely-on-time\\n uint64 _now = uint64(block.timestamp);\\n return _now > decrease.decreasingAt ? 0 : decrease.decreasingAt - _now;\\n }\\n}\\n\",\"keccak256\":\"0xe146f4a3c662e971317d0189b2fca613f9f83a163ef682ed1e536e6c1f919a08\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BeaconDkg.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\nimport \\\"./BytesLib.sol\\\";\\nimport {BeaconDkgValidator as DKGValidator} from \\\"../BeaconDkgValidator.sol\\\";\\n\\nlibrary BeaconDkg {\\n using BytesLib for bytes;\\n using ECDSA for bytes32;\\n\\n struct Parameters {\\n // Time in blocks during which a submitted result can be challenged.\\n uint256 resultChallengePeriodLength;\\n // Extra gas required to be left at the end of the challenge DKG result\\n // transaction.\\n uint256 resultChallengeExtraGas;\\n // Time in blocks during which a result is expected to be submitted.\\n uint256 resultSubmissionTimeout;\\n // Time in blocks during which only the result submitter is allowed to\\n // approve it. Once this period ends and the submitter have not approved\\n // the result, anyone can do it.\\n uint256 submitterPrecedencePeriodLength;\\n }\\n\\n struct Data {\\n // Address of the Sortition Pool contract.\\n SortitionPool sortitionPool;\\n // Address of the DKGValidator contract.\\n DKGValidator dkgValidator;\\n // DKG parameters. The parameters should persist between DKG executions.\\n // They should be updated with dedicated set functions only when DKG is not\\n // in progress.\\n Parameters parameters;\\n // Time in blocks at which DKG started.\\n uint256 startBlock;\\n // Seed used to start DKG.\\n uint256 seed;\\n // Time in blocks that should be added to result submission period calculation.\\n // It is used in case of a challenge to adjust DKG timeout calculation.\\n uint256 resultSubmissionStartBlockOffset;\\n // Hash of submitted DKG result.\\n bytes32 submittedResultHash;\\n // Block number from the moment of the DKG result submission.\\n uint256 submittedResultBlock;\\n }\\n\\n /// @notice DKG result.\\n struct Result {\\n // Claimed submitter candidate group member index.\\n // Must be in range [1, groupSize].\\n uint256 submitterMemberIndex;\\n // Generated candidate group public key\\n bytes groupPubKey;\\n // Array of misbehaved members indices (disqualified or inactive).\\n // Indices must be in range [1, groupSize], unique, and sorted in ascending\\n // order.\\n uint8[] misbehavedMembersIndices;\\n // Concatenation of signatures from members supporting the result.\\n // The message to be signed by each member is keccak256 hash of the\\n // calculated group public key, misbehaved members indices and DKG\\n // start block. The calculated hash should be prefixed with prefixed with\\n // `\\\\x19Ethereum signed message:\\\\n` before signing, so the message to\\n // sign is:\\n // `\\\\x19Ethereum signed message:\\\\n${keccak256(\\n // groupPubKey, misbehavedMembersIndices, dkgStartBlock\\n // )}`\\n bytes signatures;\\n // Indices of members corresponding to each signature. Indices must be\\n // be in range [1, groupSize], unique, and sorted in ascending order.\\n uint256[] signingMembersIndices;\\n // Identifiers of candidate group members as outputted by the group\\n // selection protocol.\\n uint32[] members;\\n // Keccak256 hash of group members identifiers that actively took part\\n // in DKG (excluding IA/DQ members).\\n bytes32 membersHash;\\n }\\n\\n /// @notice States for phases of group creation. The states doesn't include\\n /// timeouts which should be tracked and notified individually.\\n enum State {\\n // Group creation is not in progress. It is a state set after group creation\\n // completion either by timeout or by a result approval.\\n IDLE,\\n // Group creation is awaiting the seed and sortition pool is locked.\\n AWAITING_SEED,\\n // Off-chain DKG protocol execution is in progress. A result is being calculated\\n // by the clients in this state. It's not yet possible to submit the result.\\n KEY_GENERATION,\\n // After off-chain DKG protocol execution the contract awaits result submission.\\n // This is a state to which group creation returns in case of a result\\n // challenge notification.\\n AWAITING_RESULT,\\n // DKG result was submitted and awaits an approval or a challenge. If a result\\n // gets challenge the state returns to `AWAITING_RESULT`. If a result gets\\n // approval the state changes to `IDLE`.\\n CHALLENGE\\n }\\n\\n /// @dev Size of a group in the threshold relay.\\n uint256 public constant groupSize = 64;\\n\\n /// @notice Time in blocks after which DKG result is complete and ready to be\\n // published by clients.\\n uint256 public constant offchainDkgTime = 5 * (1 + 5) + 2 * (1 + 10) + 20;\\n\\n event DkgStarted(uint256 indexed seed);\\n\\n // To recreate the members that actively took part in dkg, the selected members\\n // array should be filtered out from misbehavedMembersIndices.\\n event DkgResultSubmitted(\\n bytes32 indexed resultHash,\\n uint256 indexed seed,\\n Result result\\n );\\n\\n event DkgTimedOut();\\n\\n event DkgResultApproved(\\n bytes32 indexed resultHash,\\n address indexed approver\\n );\\n\\n event DkgResultChallenged(\\n bytes32 indexed resultHash,\\n address indexed challenger,\\n string reason\\n );\\n\\n event DkgStateLocked();\\n\\n event DkgSeedTimedOut();\\n\\n /// @notice Initializes SortitionPool and DKGValidator addresses.\\n /// Can be performed only once.\\n /// @param _sortitionPool Sortition Pool reference\\n /// @param _dkgValidator DKGValidator reference\\n function init(\\n Data storage self,\\n SortitionPool _sortitionPool,\\n DKGValidator _dkgValidator\\n ) internal {\\n require(\\n address(self.sortitionPool) == address(0),\\n \\\"Sortition Pool address already set\\\"\\n );\\n\\n require(\\n address(self.dkgValidator) == address(0),\\n \\\"DKG Validator address already set\\\"\\n );\\n\\n self.sortitionPool = _sortitionPool;\\n self.dkgValidator = _dkgValidator;\\n }\\n\\n /// @notice Determines the current state of group creation. It doesn't take\\n /// timeouts into consideration. The timeouts should be tracked and\\n /// notified separately.\\n function currentState(Data storage self)\\n internal\\n view\\n returns (State state)\\n {\\n state = State.IDLE;\\n\\n if (self.sortitionPool.isLocked()) {\\n state = State.AWAITING_SEED;\\n\\n if (self.startBlock > 0) {\\n state = State.KEY_GENERATION;\\n\\n if (block.number > self.startBlock + offchainDkgTime) {\\n state = State.AWAITING_RESULT;\\n\\n if (self.submittedResultBlock > 0) {\\n state = State.CHALLENGE;\\n }\\n }\\n }\\n }\\n }\\n\\n /// @notice Locks the sortition pool and starts awaiting for the\\n /// group creation seed.\\n function lockState(Data storage self) internal {\\n require(currentState(self) == State.IDLE, \\\"Current state is not IDLE\\\");\\n\\n emit DkgStateLocked();\\n\\n self.sortitionPool.lock();\\n }\\n\\n function start(Data storage self, uint256 seed) internal {\\n require(\\n currentState(self) == State.AWAITING_SEED,\\n \\\"Current state is not AWAITING_SEED\\\"\\n );\\n\\n emit DkgStarted(seed);\\n\\n self.startBlock = block.number;\\n self.seed = seed;\\n }\\n\\n /// @notice Allows to submit a DKG result. The submitted result does not go\\n /// through a validation and before it gets accepted, it needs to\\n /// wait through the challenge period during which everyone has\\n /// a chance to challenge the result as invalid one. Submitter of\\n /// the result needs to be in the sortition pool and if the result\\n /// gets challenged, the submitter will get slashed.\\n function submitResult(Data storage self, Result calldata result) external {\\n require(\\n currentState(self) == State.AWAITING_RESULT,\\n \\\"Current state is not AWAITING_RESULT\\\"\\n );\\n require(!hasDkgTimedOut(self), \\\"DKG timeout already passed\\\");\\n\\n SortitionPool sortitionPool = self.sortitionPool;\\n\\n // Submitter must be an operator in the sortition pool.\\n // Declared submitter's member index in the DKG result needs to match\\n // the address calling this function.\\n require(\\n sortitionPool.isOperatorInPool(msg.sender),\\n \\\"Submitter not in the sortition pool\\\"\\n );\\n require(\\n sortitionPool.getIDOperator(\\n result.members[result.submitterMemberIndex - 1]\\n ) == msg.sender,\\n \\\"Unexpected submitter index\\\"\\n );\\n\\n self.submittedResultHash = keccak256(abi.encode(result));\\n self.submittedResultBlock = block.number;\\n\\n emit DkgResultSubmitted(self.submittedResultHash, self.seed, result);\\n }\\n\\n /// @notice Checks if DKG timed out. The DKG timeout period includes time required\\n /// for off-chain protocol execution and time for the result publication.\\n /// After this time a result cannot be submitted and DKG can be notified\\n /// about the timeout. DKG period is adjusted by result submission\\n /// offset that include blocks that were mined while invalid result\\n /// has been registered until it got challenged.\\n /// @return True if DKG timed out, false otherwise.\\n function hasDkgTimedOut(Data storage self) internal view returns (bool) {\\n return\\n currentState(self) == State.AWAITING_RESULT &&\\n block.number >\\n (self.startBlock +\\n offchainDkgTime +\\n self.resultSubmissionStartBlockOffset +\\n self.parameters.resultSubmissionTimeout);\\n }\\n\\n /// @notice Notifies about DKG timeout.\\n function notifyTimeout(Data storage self) internal {\\n require(hasDkgTimedOut(self), \\\"DKG has not timed out\\\");\\n\\n emit DkgTimedOut();\\n\\n complete(self);\\n }\\n\\n /// @notice Notifies about the seed was not delivered and restores the\\n /// initial DKG state (IDLE).\\n function notifySeedTimedOut(Data storage self) internal {\\n require(\\n currentState(self) == State.AWAITING_SEED,\\n \\\"Current state is not AWAITING_SEED\\\"\\n );\\n\\n emit DkgSeedTimedOut();\\n\\n complete(self);\\n }\\n\\n /// @notice Approves DKG result. Can be called when the challenge period for\\n /// the submitted result is finished. Considers the submitted result\\n /// as valid. For the first `submitterPrecedencePeriodLength`\\n /// blocks after the end of the challenge period can be called only\\n /// by the DKG result submitter. After that time, can be called by\\n /// anyone.\\n /// @dev Can be called after a challenge period for the submitted result.\\n /// @param result Result to approve. Must match the submitted result stored\\n /// during `submitResult`.\\n /// @return misbehavedMembers Identifiers of members who misbehaved during DKG.\\n function approveResult(Data storage self, Result calldata result)\\n external\\n returns (uint32[] memory misbehavedMembers)\\n {\\n require(\\n currentState(self) == State.CHALLENGE,\\n \\\"Current state is not CHALLENGE\\\"\\n );\\n\\n uint256 challengePeriodEnd = self.submittedResultBlock +\\n self.parameters.resultChallengePeriodLength;\\n\\n require(\\n block.number > challengePeriodEnd,\\n \\\"Challenge period has not passed yet\\\"\\n );\\n\\n require(\\n keccak256(abi.encode(result)) == self.submittedResultHash,\\n \\\"Result under approval is different than the submitted one\\\"\\n );\\n\\n // Extract submitter member address. Submitter member index is in\\n // range [1, groupSize] so we need to -1 when fetching identifier from members\\n // array.\\n address submitterMember = self.sortitionPool.getIDOperator(\\n result.members[result.submitterMemberIndex - 1]\\n );\\n\\n require(\\n msg.sender == submitterMember ||\\n block.number >\\n challengePeriodEnd +\\n self.parameters.submitterPrecedencePeriodLength,\\n \\\"Only the DKG result submitter can approve the result at this moment\\\"\\n );\\n\\n // Extract misbehaved members identifiers. Misbehaved members indices\\n // are in range [1, groupSize], so we need to -1 when fetching identifiers from\\n // members array.\\n misbehavedMembers = new uint32[](\\n result.misbehavedMembersIndices.length\\n );\\n for (uint256 i = 0; i < result.misbehavedMembersIndices.length; i++) {\\n misbehavedMembers[i] = result.members[\\n result.misbehavedMembersIndices[i] - 1\\n ];\\n }\\n\\n emit DkgResultApproved(self.submittedResultHash, msg.sender);\\n\\n return misbehavedMembers;\\n }\\n\\n /// @notice Challenges DKG result. If the submitted result is proved to be\\n /// invalid it reverts the DKG back to the result submission phase.\\n /// @dev Can be called during a challenge period for the submitted result.\\n /// @param result Result to challenge. Must match the submitted result\\n /// stored during `submitResult`.\\n /// @return maliciousResultHash Hash of the malicious result.\\n /// @return maliciousSubmitter Identifier of the malicious submitter.\\n function challengeResult(Data storage self, Result calldata result)\\n external\\n returns (bytes32 maliciousResultHash, uint32 maliciousSubmitter)\\n {\\n require(\\n currentState(self) == State.CHALLENGE,\\n \\\"Current state is not CHALLENGE\\\"\\n );\\n\\n require(\\n block.number <=\\n self.submittedResultBlock +\\n self.parameters.resultChallengePeriodLength,\\n \\\"Challenge period has already passed\\\"\\n );\\n\\n require(\\n keccak256(abi.encode(result)) == self.submittedResultHash,\\n \\\"Result under challenge is different than the submitted one\\\"\\n );\\n\\n // https://github.com/crytic/slither/issues/982\\n // slither-disable-next-line unused-return\\n try\\n self.dkgValidator.validate(result, self.seed, self.startBlock)\\n returns (\\n // slither-disable-next-line uninitialized-local,variable-scope\\n bool isValid,\\n // slither-disable-next-line uninitialized-local,variable-scope\\n string memory errorMsg\\n ) {\\n if (isValid) {\\n revert(\\\"unjustified challenge\\\");\\n }\\n\\n emit DkgResultChallenged(\\n self.submittedResultHash,\\n msg.sender,\\n errorMsg\\n );\\n } catch {\\n // if the validation reverted we consider the DKG result as invalid\\n emit DkgResultChallenged(\\n self.submittedResultHash,\\n msg.sender,\\n \\\"validation reverted\\\"\\n );\\n }\\n\\n // Consider result hash as malicious.\\n maliciousResultHash = self.submittedResultHash;\\n maliciousSubmitter = result.members[result.submitterMemberIndex - 1];\\n\\n // Adjust DKG result submission block start, so submission stage starts\\n // from the beginning.\\n self.resultSubmissionStartBlockOffset =\\n block.number -\\n self.startBlock -\\n offchainDkgTime;\\n\\n submittedResultCleanup(self);\\n\\n return (maliciousResultHash, maliciousSubmitter);\\n }\\n\\n /// @notice Due to EIP150, 1/64 of the gas is not forwarded to the call, and\\n /// will be kept to execute the remaining operations in the function\\n /// after the call inside the try-catch.\\n ///\\n /// To ensure there is no way for the caller to manipulate gas limit\\n /// in such a way that the call inside try-catch fails with out-of-gas\\n /// and the rest of the function is executed with the remaining\\n /// 1/64 of gas, we require an extra gas amount to be left at the\\n /// end of the call to the function challenging DKG result and\\n /// wrapping the call to BeaconDkgValidator and TokenStaking\\n /// contracts inside a try-catch.\\n function requireChallengeExtraGas(Data storage self) internal view {\\n require(\\n gasleft() >= self.parameters.resultChallengeExtraGas,\\n \\\"Not enough extra gas left\\\"\\n );\\n }\\n\\n /// @notice Updates DKG-related parameters\\n /// @param _resultChallengePeriodLength New value of the result challenge\\n /// period length. It is the number of blocks for which a DKG result\\n /// can be challenged.\\n /// @param _resultChallengeExtraGas New value of the result challenge extra\\n /// gas. It is the extra gas required to be left at the end of the\\n /// challenge DKG result transaction.\\n /// @param _resultSubmissionTimeout New value of the result submission\\n /// timeout in seconds. It is a timeout for a group to provide a DKG\\n /// result.\\n /// @param _submitterPrecedencePeriodLength New value of the submitter\\n /// precedence period length in blocks. It is the time during which\\n /// only the original DKG result submitter can approve it.\\n function setParameters(\\n Data storage self,\\n uint256 _resultChallengePeriodLength,\\n uint256 _resultChallengeExtraGas,\\n uint256 _resultSubmissionTimeout,\\n uint256 _submitterPrecedencePeriodLength\\n ) internal {\\n require(currentState(self) == State.IDLE, \\\"Current state is not IDLE\\\");\\n\\n require(\\n _resultChallengePeriodLength > 0,\\n \\\"Result challenge period length should be greater than zero\\\"\\n );\\n require(\\n _resultSubmissionTimeout > 0,\\n \\\"Result submission timeout should be greater than zero\\\"\\n );\\n require(\\n _submitterPrecedencePeriodLength < _resultSubmissionTimeout,\\n \\\"Submitter precedence period length should be less than the result submission timeout\\\"\\n );\\n\\n self\\n .parameters\\n .resultChallengePeriodLength = _resultChallengePeriodLength;\\n self.parameters.resultChallengeExtraGas = _resultChallengeExtraGas;\\n self.parameters.resultSubmissionTimeout = _resultSubmissionTimeout;\\n self\\n .parameters\\n .submitterPrecedencePeriodLength = _submitterPrecedencePeriodLength;\\n }\\n\\n /// @notice Completes DKG by cleaning up state.\\n /// @dev Should be called after DKG times out or a result is approved.\\n function complete(Data storage self) internal {\\n delete self.startBlock;\\n delete self.seed;\\n delete self.resultSubmissionStartBlockOffset;\\n submittedResultCleanup(self);\\n self.sortitionPool.unlock();\\n }\\n\\n /// @notice Cleans up submitted result state either after DKG completion\\n /// (as part of `complete` method) or after justified challenge.\\n function submittedResultCleanup(Data storage self) private {\\n delete self.submittedResultHash;\\n delete self.submittedResultBlock;\\n }\\n}\\n\",\"keccak256\":\"0x86bea35ab775ec969bc91208305f6f85aa9dd49bb74f8e57e7d453797e8ad98e\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BeaconInactivity.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./BytesLib.sol\\\";\\nimport \\\"./Groups.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\n\\nlibrary BeaconInactivity {\\n using BytesLib for bytes;\\n using ECDSA for bytes32;\\n\\n struct Claim {\\n // ID of the group raising the inactivity claim.\\n uint64 groupId;\\n // Indices of members accused of being inactive. Indices must be in\\n // range [1, groupMembers.length], unique, and sorted in ascending order.\\n uint256[] inactiveMembersIndices;\\n // Concatenation of signatures from members supporting the claim.\\n // The message to be signed by each member is keccak256 hash of the\\n // concatenation of the chain ID, inactivity claim nonce for the given\\n // group, group public key, and inactive members indices. The calculated\\n // hash should be prefixed with `\\\\x19Ethereum signed message:\\\\n` before\\n // signing, so the message to sign is:\\n // `\\\\x19Ethereum signed message:\\\\n${keccak256(\\n // chainID | nonce | groupPubKey | inactiveMembersIndices\\n // )}`\\n bytes signatures;\\n // Indices of members corresponding to each signature. Indices must be\\n // in range [1, groupMembers.length], unique, and sorted in ascending\\n // order.\\n uint256[] signingMembersIndices;\\n }\\n\\n /// @notice The minimum number of group members needed to interact according\\n /// to the protocol to produce a valid inactivity claim.\\n uint256 public constant groupThreshold = 33;\\n\\n /// @notice Size in bytes of a single signature produced by member\\n /// supporting the inactivity claim.\\n uint256 public constant signatureByteSize = 65;\\n\\n /// @notice Verifies the inactivity claim according to the rules defined in\\n /// `Claim` struct documentation. Reverts if verification fails.\\n /// @dev Group members hash is validated upstream in\\n /// RandomBeacon.notifyOperatorInactivity()\\n /// @param sortitionPool Sortition pool reference\\n /// @param claim Inactivity claim\\n /// @param groupPubKey Public key of the group raising the claim\\n /// @param nonce Current nonce for group used in the claim\\n /// @param groupMembers Identifiers of group members\\n /// @return inactiveMembers Identifiers of members who are inactive\\n function verifyClaim(\\n SortitionPool sortitionPool,\\n Claim calldata claim,\\n bytes memory groupPubKey,\\n uint256 nonce,\\n uint32[] calldata groupMembers\\n ) external view returns (uint32[] memory inactiveMembers) {\\n // Validate inactive members indices. Maximum indices count is equal to\\n // the group size and is not limited deliberately to leave a theoretical\\n // possibility to accuse more members than `groupSize - groupThreshold`.\\n validateMembersIndices(\\n claim.inactiveMembersIndices,\\n groupMembers.length\\n );\\n\\n // Validate signatures array is properly formed and number of\\n // signatures and signers is correct.\\n uint256 signaturesCount = claim.signatures.length / signatureByteSize;\\n require(claim.signatures.length != 0, \\\"No signatures provided\\\");\\n require(\\n claim.signatures.length % signatureByteSize == 0,\\n \\\"Malformed signatures array\\\"\\n );\\n require(\\n signaturesCount == claim.signingMembersIndices.length,\\n \\\"Unexpected signatures count\\\"\\n );\\n require(signaturesCount >= groupThreshold, \\\"Too few signatures\\\");\\n require(signaturesCount <= groupMembers.length, \\\"Too many signatures\\\");\\n\\n // Validate signing members indices. Note that `signingMembersIndices`\\n // were already partially validated during `signatures` parameter\\n // validation.\\n validateMembersIndices(\\n claim.signingMembersIndices,\\n groupMembers.length\\n );\\n\\n // Usage of group public key and not group ID is important because it\\n // provides uniqueness of signed messages and prevent against reusing\\n // them in future in case some other application has a group with the\\n // same ID and subset of members.\\n bytes32 signedMessageHash = keccak256(\\n abi.encode(\\n block.chainid,\\n nonce,\\n groupPubKey,\\n claim.inactiveMembersIndices\\n )\\n ).toEthSignedMessageHash();\\n\\n address[] memory groupMembersAddresses = sortitionPool.getIDOperators(\\n groupMembers\\n );\\n\\n // Verify each signature.\\n bytes memory checkedSignature;\\n bool senderSignatureExists = false;\\n for (uint256 i = 0; i < signaturesCount; i++) {\\n uint256 memberIndex = claim.signingMembersIndices[i];\\n checkedSignature = claim.signatures.slice(\\n signatureByteSize * i,\\n signatureByteSize\\n );\\n address recoveredAddress = signedMessageHash.recover(\\n checkedSignature\\n );\\n\\n require(\\n groupMembersAddresses[memberIndex - 1] == recoveredAddress,\\n \\\"Invalid signature\\\"\\n );\\n\\n if (!senderSignatureExists && msg.sender == recoveredAddress) {\\n senderSignatureExists = true;\\n }\\n }\\n\\n require(senderSignatureExists, \\\"Sender must be claim signer\\\");\\n\\n inactiveMembers = new uint32[](claim.inactiveMembersIndices.length);\\n for (uint256 i = 0; i < claim.inactiveMembersIndices.length; i++) {\\n uint256 memberIndex = claim.inactiveMembersIndices[i];\\n inactiveMembers[i] = groupMembers[memberIndex - 1];\\n }\\n\\n return inactiveMembers;\\n }\\n\\n /// @notice Validates members indices array. Array is considered valid\\n /// if its size and each single index are in [1, groupSize] range,\\n /// indexes are unique, and sorted in an ascending order.\\n /// Reverts if validation fails.\\n /// @param indices Array to validate\\n /// @param groupSize Group size used as reference\\n function validateMembersIndices(\\n uint256[] calldata indices,\\n uint256 groupSize\\n ) internal pure {\\n require(\\n indices.length > 0 && indices.length <= groupSize,\\n \\\"Corrupted members indices\\\"\\n );\\n\\n // Check if first and last indices are in range [1, groupSize].\\n // This check combined with the loop below makes sure every single\\n // index is in the correct range.\\n require(\\n indices[0] > 0 && indices[indices.length - 1] <= groupSize,\\n \\\"Corrupted members indices\\\"\\n );\\n\\n for (uint256 i = 0; i < indices.length - 1; i++) {\\n // Check whether given index is smaller than the next one. This\\n // way we are sure indexes are ordered in the ascending order\\n // and there are no duplicates.\\n require(indices[i] < indices[i + 1], \\\"Corrupted members indices\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x8dffb20eb4ffd2e388080c5fbcb648e33480aca3dab4be2254cf30c5e72413bf\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BytesLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\n/*\\nVersion pulled from keep-core v1:\\nhttps://github.com/keep-network/keep-core/blob/f297202db00c027978ad8e7103a356503de5773c/solidity-v1/contracts/utils/BytesLib.sol\\n\\nTo compile it with solidity 0.8 `_preBytes_slot` was replaced with `_preBytes.slot`.\\n*/\\n\\n/*\\nhttps://github.com/GNSPS/solidity-bytes-utils/\\nThis is free and unencumbered software released into the public domain.\\nAnyone is free to copy, modify, publish, use, compile, sell, or\\ndistribute this software, either in source code form or as a compiled\\nbinary, for any purpose, commercial or non-commercial, and by any\\nmeans.\\nIn jurisdictions that recognize copyright laws, the author or authors\\nof this software dedicate any and all copyright interest in the\\nsoftware to the public domain. We make this dedication for the benefit\\nof the public at large and to the detriment of our heirs and\\nsuccessors. We intend this dedication to be an overt act of\\nrelinquishment in perpetuity of all present and future rights to this\\nsoftware under copyright law.\\nTHE SOFTWARE IS PROVIDED \\\"AS IS\\\", WITHOUT WARRANTY OF ANY KIND,\\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\\nIN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\\nOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\\nOTHER DEALINGS IN THE SOFTWARE.\\nFor more information, please refer to \\n*/\\n\\n/** @title BytesLib **/\\n/** @author https://github.com/GNSPS **/\\n\\nlibrary BytesLib {\\n function concatStorage(bytes storage _preBytes, bytes memory _postBytes)\\n internal\\n {\\n assembly {\\n // Read the first 32 bytes of _preBytes storage, which is the length\\n // of the array. (We don't need to use the offset into the slot\\n // because arrays use the entire slot.)\\n let fslot := sload(_preBytes.slot)\\n // Arrays of 31 bytes or less have an even value in their slot,\\n // while longer arrays have an odd value. The actual length is\\n // the slot divided by two for odd values, and the lowest order\\n // byte divided by two for even values.\\n // If the slot is even, bitwise and the slot with 255 and divide by\\n // two to get the length. If the slot is odd, bitwise and the slot\\n // with -1 and divide by two.\\n let slength := div(\\n and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)),\\n 2\\n )\\n let mlength := mload(_postBytes)\\n let newlength := add(slength, mlength)\\n // slength can contain both the length and contents of the array\\n // if length < 32 bytes so let's prepare for that\\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\\n switch add(lt(slength, 32), lt(newlength, 32))\\n case 2 {\\n // Since the new array still fits in the slot, we just need to\\n // update the contents of the slot.\\n // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length\\n sstore(\\n _preBytes.slot,\\n // all the modifications to the slot are inside this\\n // next block\\n add(\\n // we can just add to the slot contents because the\\n // bytes we want to change are the LSBs\\n fslot,\\n add(\\n mul(\\n div(\\n // load the bytes from memory\\n mload(add(_postBytes, 0x20)),\\n // zero all bytes to the right\\n exp(0x100, sub(32, mlength))\\n ),\\n // and now shift left the number of bytes to\\n // leave space for the length in the slot\\n exp(0x100, sub(32, newlength))\\n ),\\n // increase length by the double of the memory\\n // bytes length\\n mul(mlength, 2)\\n )\\n )\\n )\\n }\\n case 1 {\\n // The stored value fits in the slot, but the combined value\\n // will exceed it.\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\\n\\n // save new length\\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\\n\\n // The contents of the _postBytes array start 32 bytes into\\n // the structure. Our first read should obtain the `submod`\\n // bytes that can fit into the unused space in the last word\\n // of the stored array. To get this, we read 32 bytes starting\\n // from `submod`, so the data we read overlaps with the array\\n // contents by `submod` bytes. Masking the lowest-order\\n // `submod` bytes allows us to add that value directly to the\\n // stored value.\\n\\n let submod := sub(32, slength)\\n let mc := add(_postBytes, submod)\\n let end := add(_postBytes, mlength)\\n let mask := sub(exp(0x100, submod), 1)\\n\\n sstore(\\n sc,\\n add(\\n and(\\n fslot,\\n 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00\\n ),\\n and(mload(mc), mask)\\n )\\n )\\n\\n for {\\n mc := add(mc, 0x20)\\n sc := add(sc, 1)\\n } lt(mc, end) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n sstore(sc, mload(mc))\\n }\\n\\n mask := exp(0x100, sub(mc, end))\\n\\n sstore(sc, mul(div(mload(mc), mask), mask))\\n }\\n default {\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n // Start copying to the last used word of the stored array.\\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\\n\\n // save new length\\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\\n\\n // Copy over the first `submod` bytes of the new data as in\\n // case 1 above.\\n let slengthmod := mod(slength, 32)\\n let submod := sub(32, slengthmod)\\n let mc := add(_postBytes, submod)\\n let end := add(_postBytes, mlength)\\n let mask := sub(exp(0x100, submod), 1)\\n\\n sstore(sc, add(sload(sc), and(mload(mc), mask)))\\n\\n for {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } lt(mc, end) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n sstore(sc, mload(mc))\\n }\\n\\n mask := exp(0x100, sub(mc, end))\\n\\n sstore(sc, mul(div(mload(mc), mask), mask))\\n }\\n }\\n }\\n\\n function equalStorage(bytes storage _preBytes, bytes memory _postBytes)\\n internal\\n view\\n returns (bool)\\n {\\n bool success = true;\\n\\n assembly {\\n // we know _preBytes_offset is 0\\n let fslot := sload(_preBytes.slot)\\n // Decode the length of the stored array like in concatStorage().\\n let slength := div(\\n and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)),\\n 2\\n )\\n let mlength := mload(_postBytes)\\n\\n // if lengths don't match the arrays are not equal\\n switch eq(slength, mlength)\\n case 1 {\\n // slength can contain both the length and contents of the array\\n // if length < 32 bytes so let's prepare for that\\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\\n if iszero(iszero(slength)) {\\n switch lt(slength, 32)\\n case 1 {\\n // blank the last byte which is the length\\n fslot := mul(div(fslot, 0x100), 0x100)\\n\\n if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {\\n // unsuccess:\\n success := 0\\n }\\n }\\n default {\\n // cb is a circuit breaker in the for loop since there's\\n // no said feature for inline assembly loops\\n // cb = 1 - don't breaker\\n // cb = 0 - break\\n let cb := 1\\n\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n let sc := keccak256(0x0, 0x20)\\n\\n let mc := add(_postBytes, 0x20)\\n let end := add(mc, mlength)\\n\\n // the next line is the loop condition:\\n // while(uint(mc < end) + cb == 2)\\n for {\\n\\n } eq(add(lt(mc, end), cb), 2) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n if iszero(eq(sload(sc), mload(mc))) {\\n // unsuccess:\\n success := 0\\n cb := 0\\n }\\n }\\n }\\n }\\n }\\n default {\\n // unsuccess:\\n success := 0\\n }\\n }\\n\\n return success;\\n }\\n\\n function concat(bytes memory _preBytes, bytes memory _postBytes)\\n internal\\n pure\\n returns (bytes memory)\\n {\\n bytes memory tempBytes;\\n\\n assembly {\\n // Get a location of some free memory and store it in tempBytes as\\n // Solidity does for memory variables.\\n tempBytes := mload(0x40)\\n\\n // Store the length of the first bytes array at the beginning of\\n // the memory for tempBytes.\\n let length := mload(_preBytes)\\n mstore(tempBytes, length)\\n\\n // Maintain a memory counter for the current write location in the\\n // temp bytes array by adding the 32 bytes for the array length to\\n // the starting location.\\n let mc := add(tempBytes, 0x20)\\n // Stop copying when the memory counter reaches the length of the\\n // first bytes array.\\n let end := add(mc, length)\\n\\n for {\\n // Initialize a copy counter to the start of the _preBytes data,\\n // 32 bytes into its memory.\\n let cc := add(_preBytes, 0x20)\\n } lt(mc, end) {\\n // Increase both counters by 32 bytes each iteration.\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n // Write the _preBytes data into the tempBytes memory 32 bytes\\n // at a time.\\n mstore(mc, mload(cc))\\n }\\n\\n // Add the length of _postBytes to the current length of tempBytes\\n // and store it as the new length in the first 32 bytes of the\\n // tempBytes memory.\\n length := mload(_postBytes)\\n mstore(tempBytes, add(length, mload(tempBytes)))\\n\\n // Move the memory counter back from a multiple of 0x20 to the\\n // actual end of the _preBytes data.\\n mc := end\\n // Stop copying when the memory counter reaches the new combined\\n // length of the arrays.\\n end := add(mc, length)\\n\\n for {\\n let cc := add(_postBytes, 0x20)\\n } lt(mc, end) {\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n mstore(mc, mload(cc))\\n }\\n\\n // Update the free-memory pointer by padding our last write location\\n // to 32 bytes: add 31 bytes to the end of tempBytes to move to the\\n // next 32 byte block, then round down to the nearest multiple of\\n // 32. If the sum of the length of the two arrays is zero then add\\n // one before rounding down to leave a blank 32 bytes (the length block with 0).\\n mstore(\\n 0x40,\\n and(\\n add(add(end, iszero(add(length, mload(_preBytes)))), 31),\\n not(31) // Round down to the nearest 32 bytes.\\n )\\n )\\n }\\n\\n return tempBytes;\\n }\\n\\n function slice(\\n bytes memory _bytes,\\n uint256 _start,\\n uint256 _length\\n ) internal pure returns (bytes memory res) {\\n uint256 _end = _start + _length;\\n require(_end > _start && _bytes.length >= _end, \\\"Slice out of bounds\\\");\\n\\n assembly {\\n // Alloc bytes array with additional 32 bytes afterspace and assign it's size\\n res := mload(0x40)\\n mstore(0x40, add(add(res, 64), _length))\\n mstore(res, _length)\\n\\n // Compute distance between source and destination pointers\\n let diff := sub(res, add(_bytes, _start))\\n\\n for {\\n let src := add(add(_bytes, 32), _start)\\n let end := add(src, _length)\\n } lt(src, end) {\\n src := add(src, 32)\\n } {\\n mstore(add(src, diff), mload(src))\\n }\\n }\\n }\\n\\n function toAddress(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (address)\\n {\\n uint256 _totalLen = _start + 20;\\n require(\\n _totalLen > _start && _bytes.length >= _totalLen,\\n \\\"Address conversion out of bounds.\\\"\\n );\\n address tempAddress;\\n\\n assembly {\\n tempAddress := div(\\n mload(add(add(_bytes, 0x20), _start)),\\n 0x1000000000000000000000000\\n )\\n }\\n\\n return tempAddress;\\n }\\n\\n function toUint8(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (uint8)\\n {\\n require(\\n _bytes.length >= (_start + 1),\\n \\\"Uint8 conversion out of bounds.\\\"\\n );\\n uint8 tempUint;\\n\\n assembly {\\n tempUint := mload(add(add(_bytes, 0x1), _start))\\n }\\n\\n return tempUint;\\n }\\n\\n function toUint(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (uint256)\\n {\\n uint256 _totalLen = _start + 32;\\n require(\\n _totalLen > _start && _bytes.length >= _totalLen,\\n \\\"Uint conversion out of bounds.\\\"\\n );\\n uint256 tempUint;\\n\\n assembly {\\n tempUint := mload(add(add(_bytes, 0x20), _start))\\n }\\n\\n return tempUint;\\n }\\n\\n function equal(bytes memory _preBytes, bytes memory _postBytes)\\n internal\\n pure\\n returns (bool)\\n {\\n bool success = true;\\n\\n assembly {\\n let length := mload(_preBytes)\\n\\n // if lengths don't match the arrays are not equal\\n switch eq(length, mload(_postBytes))\\n case 1 {\\n // cb is a circuit breaker in the for loop since there's\\n // no said feature for inline assembly loops\\n // cb = 1 - don't breaker\\n // cb = 0 - break\\n let cb := 1\\n\\n let mc := add(_preBytes, 0x20)\\n let end := add(mc, length)\\n\\n for {\\n let cc := add(_postBytes, 0x20)\\n // the next line is the loop condition:\\n // while(uint(mc < end) + cb == 2)\\n } eq(add(lt(mc, end), cb), 2) {\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n // if any of these checks fails then arrays are not equal\\n if iszero(eq(mload(mc), mload(cc))) {\\n // unsuccess:\\n success := 0\\n cb := 0\\n }\\n }\\n }\\n default {\\n // unsuccess:\\n success := 0\\n }\\n }\\n\\n return success;\\n }\\n\\n function toBytes32(bytes memory _source)\\n internal\\n pure\\n returns (bytes32 result)\\n {\\n if (_source.length == 0) {\\n return 0x0;\\n }\\n\\n assembly {\\n result := mload(add(_source, 32))\\n }\\n }\\n\\n function keccak256Slice(\\n bytes memory _bytes,\\n uint256 _start,\\n uint256 _length\\n ) internal pure returns (bytes32 result) {\\n uint256 _end = _start + _length;\\n require(_end > _start && _bytes.length >= _end, \\\"Slice out of bounds\\\");\\n\\n assembly {\\n result := keccak256(add(add(_bytes, 32), _start), _length)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3b76e2fe36eb777440250dcf2ea7a689375e8af22f3cc33521095ff6954becdb\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/Callback.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../api/IRandomBeaconConsumer.sol\\\";\\n\\n/// @title Callback library\\n/// @dev Library for handling calls to random beacon consumer.\\nlibrary Callback {\\n struct Data {\\n IRandomBeaconConsumer callbackContract;\\n }\\n\\n event CallbackFailed(uint256 entry, uint256 entrySubmittedBlock);\\n\\n /// @notice Sets callback contract.\\n /// @param callbackContract Callback contract.\\n function setCallbackContract(\\n Data storage self,\\n IRandomBeaconConsumer callbackContract\\n ) internal {\\n self.callbackContract = callbackContract;\\n }\\n\\n /// @notice Executes consumer specified callback for the relay entry request.\\n /// @param entry The generated random number.\\n /// @param callbackGasLimit Callback gas limit.\\n function executeCallback(\\n Data storage self,\\n uint256 entry,\\n uint256 callbackGasLimit\\n ) internal {\\n if (address(self.callbackContract) != address(0)) {\\n try\\n self.callbackContract.__beaconCallback{gas: callbackGasLimit}(\\n entry,\\n block.number\\n )\\n {} catch {\\n // slither-disable-next-line reentrancy-events\\n emit CallbackFailed(entry, block.number);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x258d635d74d8906c73d1c2d0929f033c7e548cdaf9c9a71a7e82b4ab70e5ad29\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/Groups.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\n/// @notice This library is used as a registry of created groups.\\n/// @dev This library should be used along with DKG library that ensures linear\\n/// groups creation (only one group creation happens at a time). A candidate\\n/// group has to be popped or activated before adding a new candidate group.\\nlibrary Groups {\\n struct Group {\\n bytes groupPubKey;\\n uint256 registrationBlockNumber;\\n // Keccak256 hash of group members identifiers array. Group members do not\\n // include operators selected by the sortition pool that misbehaved during DKG.\\n // See how `misbehavedMembersIndices` are used in `hashGroupMembers` function.\\n bytes32 membersHash;\\n // When selected group does not create a relay entry on-time it should\\n // be marked as terminated.\\n bool terminated;\\n }\\n\\n struct Data {\\n // Mapping of keccak256 hashes of group public keys to groups details.\\n mapping(bytes32 => Group) groupsData;\\n // Holds keccak256 hashes of group public keys in the order of registration.\\n bytes32[] groupsRegistry;\\n // Group ids that were active but failed creating a relay entry. When an\\n // active-terminated group qualifies to become 'expired', then it will\\n // be removed from this array.\\n uint64[] activeTerminatedGroups;\\n // Points to the first active group, it is also the expired groups counter.\\n uint64 expiredGroupOffset;\\n // Group lifetime in blocks. When a group reached its lifetime, it\\n // is no longer selected for new relay requests but may still be\\n // responsible for submitting relay entry if relay request assigned\\n // to that group is still pending.\\n uint256 groupLifetime;\\n }\\n\\n event GroupRegistered(uint64 indexed groupId, bytes indexed groupPubKey);\\n\\n /// @notice Performs preliminary validation of a new group public key.\\n /// The group public key must be unique and have 128 bytes in length.\\n /// If the validation fails, the function reverts. This function\\n /// must be called first for a public key of a group added with\\n /// `addGroup` function.\\n /// @param groupPubKey Candidate group public key\\n function validatePublicKey(Data storage self, bytes calldata groupPubKey)\\n internal\\n view\\n {\\n require(groupPubKey.length == 128, \\\"Invalid length of the public key\\\");\\n\\n bytes32 groupPubKeyHash = keccak256(groupPubKey);\\n\\n require(\\n self.groupsData[groupPubKeyHash].registrationBlockNumber == 0,\\n \\\"Group with this public key was already registered\\\"\\n );\\n }\\n\\n /// @notice Adds a new candidate group. The group is stored with group public\\n /// key and group members, but is not yet activated.\\n /// @dev The group members list is stored with all misbehaved members filtered out.\\n /// The code calling this function should ensure that the number of\\n /// candidate (not activated) groups is never more than one.\\n /// @param groupPubKey Generated candidate group public key\\n /// @param membersHash Keccak256 hash of members that actively took part in DKG.\\n function addGroup(\\n Data storage self,\\n bytes calldata groupPubKey,\\n bytes32 membersHash\\n ) internal {\\n bytes32 groupPubKeyHash = keccak256(groupPubKey);\\n\\n // We use group from storage that is assumed to be a struct set to the\\n // default values. We need to remember to overwrite fields in case a\\n // candidate group was already registered before and popped.\\n Group storage group = self.groupsData[groupPubKeyHash];\\n group.groupPubKey = groupPubKey;\\n group.membersHash = membersHash;\\n group.registrationBlockNumber = block.number;\\n\\n self.groupsRegistry.push(groupPubKeyHash);\\n\\n emit GroupRegistered(\\n uint64(self.groupsRegistry.length - 1),\\n groupPubKey\\n );\\n }\\n\\n /// @notice Goes through groups starting from the oldest one that is still\\n /// active and checks if it hasn't expired. If so, updates the information\\n /// about expired groups so that all expired groups are marked as such.\\n function expireOldGroups(Data storage self) internal {\\n // Move expiredGroupOffset as long as there are some groups that should\\n // be marked as expired. It is possible that expired group offset will\\n // move out of the groups array by one position. It means that all groups\\n // are expired (it points to the first active group) and that place in\\n // groups array - currently empty - will be possibly filled later by\\n // a new group.\\n while (\\n self.expiredGroupOffset < self.groupsRegistry.length &&\\n groupLifetimeOf(\\n self,\\n self.groupsRegistry[self.expiredGroupOffset]\\n ) <\\n block.number\\n ) {\\n self.expiredGroupOffset++;\\n }\\n\\n // Go through all activeTerminatedGroups and if some of the terminated\\n // groups are expired, remove them from activeTerminatedGroups collection\\n // and rearrange the array to preserve the original order.\\n // This is needed because we evaluate the shift of selected group index\\n // based on how many non-expired groups have been terminated. Hence it is\\n // important that a number of terminated groups matches the length of\\n // activeTerminatedGroups[].\\n uint256 i = 0;\\n while (i < self.activeTerminatedGroups.length) {\\n if (self.expiredGroupOffset > self.activeTerminatedGroups[i]) {\\n // When 'i'th group qualifies for expiration, we need to remove\\n // it from the activeTerminatedGroups array manually by rearranging\\n // the order starting from 'i'th group.\\n for (\\n uint256 j = i;\\n j < self.activeTerminatedGroups.length - 1;\\n j++\\n ) {\\n self.activeTerminatedGroups[j] = self\\n .activeTerminatedGroups[j + 1];\\n }\\n // Resizing the array length by 1. The last element was copied\\n // over in the loop above to an index \\\"second to last\\\". This is\\n // why we can safely remove it from here.\\n self.activeTerminatedGroups.pop();\\n } else {\\n i++;\\n }\\n }\\n }\\n\\n /// @notice Terminates group with the provided index. Reverts if the group\\n /// is already terminated.\\n /// @param groupId Index in the groupRegistry array.\\n function terminateGroup(Data storage self, uint64 groupId) internal {\\n require(\\n !isGroupTerminated(self, groupId),\\n \\\"Group has been already terminated\\\"\\n );\\n self.groupsData[self.groupsRegistry[groupId]].terminated = true;\\n // Expanding array for a new terminated group that is added below during\\n // sortition in ascending order.\\n self.activeTerminatedGroups.push();\\n\\n // Sorting activeTerminatedGroups by groupId in ascending order so a\\n // non-terminated group is properly selected.\\n uint256 i;\\n for (\\n i = self.activeTerminatedGroups.length - 1;\\n i > 0 && self.activeTerminatedGroups[i - 1] > groupId;\\n i--\\n ) {\\n self.activeTerminatedGroups[i] = self.activeTerminatedGroups[i - 1];\\n }\\n self.activeTerminatedGroups[i] = groupId;\\n }\\n\\n /// @notice Returns an index of a randomly selected active group. Terminated\\n /// and expired groups are not considered as active.\\n /// Before new group is selected, information about expired groups\\n /// is updated. At least one active group needs to be present for this\\n /// function to succeed.\\n /// @param seed Random number used as a group selection seed.\\n function selectGroup(Data storage self, uint256 seed)\\n internal\\n returns (uint64)\\n {\\n expireOldGroups(self);\\n\\n require(numberOfActiveGroups(self) > 0, \\\"No active groups\\\");\\n\\n uint64 selectedGroup = uint64(seed % numberOfActiveGroups(self));\\n uint64 result = shiftByTerminatedGroups(\\n self,\\n shiftByExpiredGroups(self, selectedGroup)\\n );\\n return result;\\n }\\n\\n /// @notice Setter for group lifetime.\\n /// @param lifetime Lifetime of a group in blocks.\\n function setGroupLifetime(Data storage self, uint256 lifetime) internal {\\n self.groupLifetime = lifetime;\\n }\\n\\n /// @notice Checks if group with the given index is terminated.\\n function isGroupTerminated(Data storage self, uint64 groupId)\\n internal\\n view\\n returns (bool)\\n {\\n return self.groupsData[self.groupsRegistry[groupId]].terminated;\\n }\\n\\n /// @notice Gets the cutoff time until which the given group is considered\\n /// to be active assuming it hasn't been terminated before.\\n function groupLifetimeOf(Data storage self, bytes32 groupPubKeyHash)\\n internal\\n view\\n returns (uint256)\\n {\\n return\\n self.groupsData[groupPubKeyHash].registrationBlockNumber +\\n self.groupLifetime;\\n }\\n\\n /// @notice Checks if group with the given index is active and non-terminated.\\n function isGroupActive(Data storage self, uint64 groupId)\\n internal\\n view\\n returns (bool)\\n {\\n return\\n groupLifetimeOf(self, self.groupsRegistry[groupId]) >=\\n block.number &&\\n !isGroupTerminated(self, groupId);\\n }\\n\\n function getGroup(Data storage self, uint64 groupId)\\n internal\\n view\\n returns (Group storage)\\n {\\n return self.groupsData[self.groupsRegistry[groupId]];\\n }\\n\\n function getGroup(Data storage self, bytes memory groupPubKey)\\n internal\\n view\\n returns (Group storage)\\n {\\n return self.groupsData[keccak256(groupPubKey)];\\n }\\n\\n /// @notice Gets the number of active groups. Expired and terminated\\n /// groups are not counted as active.\\n function numberOfActiveGroups(Data storage self)\\n internal\\n view\\n returns (uint64)\\n {\\n if (self.groupsRegistry.length == 0) {\\n return 0;\\n }\\n\\n uint256 activeGroups = self.groupsRegistry.length -\\n self.expiredGroupOffset -\\n self.activeTerminatedGroups.length;\\n\\n return uint64(activeGroups);\\n }\\n\\n /// @notice Evaluates the shift of a selected group index based on the number\\n /// of expired groups.\\n function shiftByExpiredGroups(Data storage self, uint64 selectedIndex)\\n internal\\n view\\n returns (uint64)\\n {\\n return self.expiredGroupOffset + selectedIndex;\\n }\\n\\n /// @notice Evaluates the shift of a selected group index based on the number\\n /// of non-expired but terminated groups.\\n function shiftByTerminatedGroups(Data storage self, uint64 selectedIndex)\\n internal\\n view\\n returns (uint64)\\n {\\n uint64 shiftedIndex = selectedIndex;\\n for (uint64 i = 0; i < self.activeTerminatedGroups.length; i++) {\\n if (self.activeTerminatedGroups[i] <= shiftedIndex) {\\n shiftedIndex++;\\n }\\n }\\n\\n return shiftedIndex;\\n }\\n}\\n\",\"keccak256\":\"0x27a3cee268e5afa5ee3a00089aa82faffff7c3882aa94919499de4ef55dcfb0c\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/ModUtils.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\nlibrary ModUtils {\\n /// @dev Wraps the modular exponent pre-compile introduced in Byzantium.\\n /// Returns base^exponent mod p.\\n function modExp(\\n uint256 base,\\n uint256 exponent,\\n uint256 p\\n ) internal view returns (uint256 o) {\\n assembly {\\n // Args for the precompile: [ \\n // ]\\n let output := mload(0x40)\\n let args := add(output, 0x20)\\n mstore(args, 0x20)\\n mstore(add(args, 0x20), 0x20)\\n mstore(add(args, 0x40), 0x20)\\n mstore(add(args, 0x60), base)\\n mstore(add(args, 0x80), exponent)\\n mstore(add(args, 0xa0), p)\\n\\n // 0x05 is the modular exponent contract address\\n if iszero(staticcall(not(0), 0x05, args, 0xc0, output, 0x20)) {\\n revert(0, 0)\\n }\\n o := mload(output)\\n }\\n }\\n\\n /// @dev Calculates and returns the square root of a mod p if such a square\\n /// root exists. The modulus p must be an odd prime. If a square root\\n /// does not exist, function returns 0.\\n function modSqrt(uint256 a, uint256 p) internal view returns (uint256) {\\n unchecked {\\n if (legendre(a, p) != 1) {\\n return 0;\\n }\\n\\n if (a == 0) {\\n return 0;\\n }\\n\\n if (p % 4 == 3) {\\n return modExp(a, (p + 1) / 4, p);\\n }\\n\\n uint256 s = p - 1;\\n uint256 e = 0;\\n\\n while (s % 2 == 0) {\\n s = s / 2;\\n e = e + 1;\\n }\\n\\n // Note the smaller int- finding n with Legendre symbol or -1\\n // should be quick\\n uint256 n = 2;\\n while (legendre(n, p) != -1) {\\n n = n + 1;\\n }\\n\\n uint256 x = modExp(a, (s + 1) / 2, p);\\n uint256 b = modExp(a, s, p);\\n uint256 g = modExp(n, s, p);\\n uint256 r = e;\\n uint256 gs = 0;\\n uint256 m = 0;\\n uint256 t = b;\\n\\n while (true) {\\n t = b;\\n m = 0;\\n\\n for (m = 0; m < r; m++) {\\n if (t == 1) {\\n break;\\n }\\n t = modExp(t, 2, p);\\n }\\n\\n if (m == 0) {\\n return x;\\n }\\n\\n gs = modExp(g, uint256(2)**(r - m - 1), p);\\n g = (gs * gs) % p;\\n x = (x * gs) % p;\\n b = (b * g) % p;\\n r = m;\\n }\\n }\\n }\\n\\n /// @dev Calculates the Legendre symbol of the given a mod p.\\n /// @return Returns 1 if a is a quadratic residue mod p, -1 if it is\\n /// a non-quadratic residue, and 0 if a is 0.\\n function legendre(uint256 a, uint256 p) internal view returns (int256) {\\n unchecked {\\n uint256 raised = modExp(a, (p - 1) / uint256(2), p);\\n\\n if (raised == 0 || raised == 1) {\\n return int256(raised);\\n } else if (raised == p - 1) {\\n return -1;\\n }\\n\\n require(false, \\\"Failed to calculate legendre.\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x57bb4ab4f257715c6daafa1a4e4bc6dd9edfe45afca797e5b8e98db577826505\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/Relay.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"./AltBn128.sol\\\";\\nimport \\\"./BLS.sol\\\";\\nimport \\\"./Groups.sol\\\";\\n\\nlibrary Relay {\\n using SafeERC20 for IERC20;\\n\\n struct Data {\\n // Total count of all requests.\\n uint64 requestCount;\\n // Data of current request.\\n // Request identifier.\\n uint64 currentRequestID;\\n // Identifier of group responsible for signing.\\n uint64 currentRequestGroupID;\\n // Request start block.\\n uint64 currentRequestStartBlock;\\n // Previous entry value.\\n AltBn128.G1Point previousEntry;\\n // Time in blocks during which a result is expected to be submitted.\\n uint32 relayEntrySoftTimeout;\\n // Hard timeout in blocks for a group to submit the relay entry.\\n uint32 relayEntryHardTimeout;\\n // Slashing amount for not submitting relay entry\\n uint96 relayEntrySubmissionFailureSlashingAmount;\\n }\\n\\n /// @notice Seed used as the first relay entry value.\\n /// It's a G1 point G * PI =\\n /// G * 31415926535897932384626433832795028841971693993751058209749445923078164062862\\n /// Where G is the generator of G1 abstract cyclic group.\\n bytes public constant relaySeed =\\n hex\\\"15c30f4b6cf6dbbcbdcc10fe22f54c8170aea44e198139b776d512d8f027319a1b9e8bfaf1383978231ce98e42bafc8129f473fc993cf60ce327f7d223460663\\\";\\n\\n event RelayEntryRequested(\\n uint256 indexed requestId,\\n uint64 groupId,\\n bytes previousEntry\\n );\\n\\n event RelayEntrySubmitted(\\n uint256 indexed requestId,\\n address submitter,\\n bytes entry\\n );\\n\\n event RelayEntryTimedOut(\\n uint256 indexed requestId,\\n uint64 terminatedGroupId\\n );\\n\\n /// @notice Initializes the very first `previousEntry` with an initial\\n /// `relaySeed` value. Can be performed only once.\\n function initSeedEntry(Data storage self) internal {\\n require(\\n self.previousEntry.x == 0 && self.previousEntry.y == 0,\\n \\\"Seed entry already initialized\\\"\\n );\\n self.previousEntry = AltBn128.g1Unmarshal(relaySeed);\\n }\\n\\n /// @notice Creates a request to generate a new relay entry, which will\\n /// include a random number (by signing the previous entry's\\n /// random number).\\n /// @param groupId Identifier of the group chosen to handle the request.\\n function requestEntry(Data storage self, uint64 groupId) internal {\\n require(\\n !isRequestInProgress(self),\\n \\\"Another relay request in progress\\\"\\n );\\n\\n uint64 currentRequestId = ++self.requestCount;\\n\\n self.currentRequestID = currentRequestId;\\n self.currentRequestGroupID = groupId;\\n self.currentRequestStartBlock = uint64(block.number);\\n\\n emit RelayEntryRequested(\\n currentRequestId,\\n groupId,\\n AltBn128.g1Marshal(self.previousEntry)\\n );\\n }\\n\\n /// @notice Creates a new relay entry. Gas-optimized version that can be\\n /// called only before the soft timeout. This should be the majority\\n /// of cases.\\n /// @param entry Group BLS signature over the previous entry.\\n /// @param groupPubKey Public key of the group which signed the relay entry.\\n function submitEntryBeforeSoftTimeout(\\n Data storage self,\\n bytes calldata entry,\\n bytes storage groupPubKey\\n ) internal {\\n require(\\n block.number < softTimeoutBlock(self),\\n \\\"Relay entry soft timeout passed\\\"\\n );\\n _submitEntry(self, entry, groupPubKey);\\n }\\n\\n /// @notice Creates a new relay entry. Can be called at any time.\\n /// In case the soft timeout has not been exceeded, it is more\\n /// gas-efficient to call the second variation of `submitEntry`.\\n /// @param entry Group BLS signature over the previous entry.\\n /// @param groupPubKey Public key of the group which signed the relay entry.\\n /// @return slashingAmount Amount by which group members should be slashed\\n /// in case the relay entry was submitted after the soft timeout.\\n /// The value is zero if entry was submitted on time.\\n function submitEntry(\\n Data storage self,\\n bytes calldata entry,\\n bytes storage groupPubKey\\n ) internal returns (uint96) {\\n // If the soft timeout has been exceeded apply stake slashing for\\n // all group members. Otherwise, no slashing.\\n uint96 slashingAmount = calculateSlashingAmount(self);\\n\\n _submitEntry(self, entry, groupPubKey);\\n\\n return slashingAmount;\\n }\\n\\n function _submitEntry(\\n Data storage self,\\n bytes calldata entry,\\n bytes storage groupPubKey\\n ) internal {\\n require(isRequestInProgress(self), \\\"No relay request in progress\\\");\\n require(!hasRequestTimedOut(self), \\\"Relay request timed out\\\");\\n\\n require(\\n BLS._verify(\\n AltBn128.g2Unmarshal(groupPubKey),\\n self.previousEntry,\\n AltBn128.g1Unmarshal(entry)\\n ),\\n \\\"Invalid entry\\\"\\n );\\n\\n emit RelayEntrySubmitted(self.currentRequestID, msg.sender, entry);\\n\\n self.previousEntry = AltBn128.g1Unmarshal(entry);\\n self.currentRequestID = 0;\\n self.currentRequestGroupID = 0;\\n self.currentRequestStartBlock = 0;\\n }\\n\\n /// @notice Calculates the slashing amount for all group members.\\n /// @dev Must be used when a soft timeout was hit.\\n /// @return Amount by which group members should be slashed\\n /// in case the relay entry was submitted after the soft timeout.\\n function calculateSlashingAmount(Data storage self)\\n internal\\n view\\n returns (uint96)\\n {\\n uint256 softTimeout = softTimeoutBlock(self);\\n\\n if (block.number > softTimeout) {\\n uint256 submissionDelay = block.number - softTimeout;\\n // The slashing amount is a result of a calculated portion of the submission\\n // delay blocks. The max delay can be set up to relayEntryHardTimeout, which\\n // in consequence sets the max slashing amount.\\n if (submissionDelay > self.relayEntryHardTimeout) {\\n submissionDelay = self.relayEntryHardTimeout;\\n }\\n\\n return\\n uint96(\\n (submissionDelay *\\n self.relayEntrySubmissionFailureSlashingAmount) /\\n self.relayEntryHardTimeout\\n );\\n }\\n\\n return 0;\\n }\\n\\n /// @notice Updates relay-related parameters\\n /// @param _relayEntrySoftTimeout New relay entry soft timeout value.\\n /// It is the time in blocks during which a result is expected to be\\n /// submitted so that the group is not slashed.\\n /// @param _relayEntryHardTimeout New relay entry hard timeout value.\\n /// It is the time in blocks for a group to submit the relay entry\\n /// before slashing for the full slashing amount happens.\\n function setTimeouts(\\n Data storage self,\\n uint256 _relayEntrySoftTimeout,\\n uint256 _relayEntryHardTimeout\\n ) internal {\\n require(!isRequestInProgress(self), \\\"Relay request in progress\\\");\\n\\n self.relayEntrySoftTimeout = uint32(_relayEntrySoftTimeout);\\n self.relayEntryHardTimeout = uint32(_relayEntryHardTimeout);\\n }\\n\\n /// @notice Set relayEntrySubmissionFailureSlashingAmount parameter.\\n /// @param newRelayEntrySubmissionFailureSlashingAmount New value of\\n /// the parameter.\\n function setRelayEntrySubmissionFailureSlashingAmount(\\n Data storage self,\\n uint96 newRelayEntrySubmissionFailureSlashingAmount\\n ) internal {\\n require(!isRequestInProgress(self), \\\"Relay request in progress\\\");\\n\\n self\\n .relayEntrySubmissionFailureSlashingAmount = newRelayEntrySubmissionFailureSlashingAmount;\\n }\\n\\n /// @notice Retries the current relay request in case a relay entry\\n /// timeout was reported.\\n /// @param newGroupId ID of the group chosen to retry the current request.\\n function retryOnEntryTimeout(Data storage self, uint64 newGroupId)\\n internal\\n {\\n require(hasRequestTimedOut(self), \\\"Relay request did not time out\\\");\\n\\n uint64 currentRequestId = self.currentRequestID;\\n uint64 previousGroupId = self.currentRequestGroupID;\\n\\n emit RelayEntryTimedOut(currentRequestId, previousGroupId);\\n\\n self.currentRequestGroupID = newGroupId;\\n self.currentRequestStartBlock = uint64(block.number);\\n\\n emit RelayEntryRequested(\\n currentRequestId,\\n newGroupId,\\n AltBn128.g1Marshal(self.previousEntry)\\n );\\n }\\n\\n /// @notice Cleans up the current relay request in case a relay entry\\n /// timeout was reported.\\n function cleanupOnEntryTimeout(Data storage self) internal {\\n require(hasRequestTimedOut(self), \\\"Relay request did not time out\\\");\\n\\n emit RelayEntryTimedOut(\\n self.currentRequestID,\\n self.currentRequestGroupID\\n );\\n\\n self.currentRequestID = 0;\\n self.currentRequestGroupID = 0;\\n self.currentRequestStartBlock = 0;\\n }\\n\\n /// @notice Returns whether a relay entry request is currently in progress.\\n /// @return True if there is a request in progress. False otherwise.\\n function isRequestInProgress(Data storage self)\\n internal\\n view\\n returns (bool)\\n {\\n return self.currentRequestID != 0;\\n }\\n\\n /// @notice Returns whether the current relay request has timed out.\\n /// @return True if the request timed out. False otherwise.\\n function hasRequestTimedOut(Data storage self)\\n internal\\n view\\n returns (bool)\\n {\\n uint256 _relayEntryTimeout = self.relayEntrySoftTimeout +\\n self.relayEntryHardTimeout;\\n\\n return\\n isRequestInProgress(self) &&\\n block.number > self.currentRequestStartBlock + _relayEntryTimeout;\\n }\\n\\n /// @notice Calculates soft timeout block for the pending relay request.\\n /// @return The soft timeout block\\n function softTimeoutBlock(Data storage self)\\n internal\\n view\\n returns (uint256)\\n {\\n return self.currentRequestStartBlock + self.relayEntrySoftTimeout;\\n }\\n}\\n\",\"keccak256\":\"0x0ff1513ef6dceda503d19d1798d9de97510ec3c033b9a59aa240ce2a3052e6d3\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "storageLayout": { + "storage": [ + { + "astId": 3888, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "_owner", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 12208, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newGovernanceDelay", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 12210, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "governanceDelayChangeInitiated", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 12212, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newRandomBeaconGovernance", + "offset": 0, + "slot": "3", + "type": "t_address" + }, + { + "astId": 12214, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "randomBeaconGovernanceTransferInitiated", + "offset": 0, + "slot": "4", + "type": "t_uint256" + }, + { + "astId": 12216, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newRelayEntrySoftTimeout", + "offset": 0, + "slot": "5", + "type": "t_uint256" + }, + { + "astId": 12218, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "relayEntrySoftTimeoutChangeInitiated", + "offset": 0, + "slot": "6", + "type": "t_uint256" + }, + { + "astId": 12220, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newRelayEntryHardTimeout", + "offset": 0, + "slot": "7", + "type": "t_uint256" + }, + { + "astId": 12222, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "relayEntryHardTimeoutChangeInitiated", + "offset": 0, + "slot": "8", + "type": "t_uint256" + }, + { + "astId": 12224, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newCallbackGasLimit", + "offset": 0, + "slot": "9", + "type": "t_uint256" + }, + { + "astId": 12226, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "callbackGasLimitChangeInitiated", + "offset": 0, + "slot": "10", + "type": "t_uint256" + }, + { + "astId": 12228, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newGroupCreationFrequency", + "offset": 0, + "slot": "11", + "type": "t_uint256" + }, + { + "astId": 12230, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "groupCreationFrequencyChangeInitiated", + "offset": 0, + "slot": "12", + "type": "t_uint256" + }, + { + "astId": 12232, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newGroupLifetime", + "offset": 0, + "slot": "13", + "type": "t_uint256" + }, + { + "astId": 12234, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "groupLifetimeChangeInitiated", + "offset": 0, + "slot": "14", + "type": "t_uint256" + }, + { + "astId": 12236, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newDkgResultChallengePeriodLength", + "offset": 0, + "slot": "15", + "type": "t_uint256" + }, + { + "astId": 12238, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "dkgResultChallengePeriodLengthChangeInitiated", + "offset": 0, + "slot": "16", + "type": "t_uint256" + }, + { + "astId": 12240, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newDkgResultChallengeExtraGas", + "offset": 0, + "slot": "17", + "type": "t_uint256" + }, + { + "astId": 12242, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "dkgResultChallengeExtraGasChangeInitiated", + "offset": 0, + "slot": "18", + "type": "t_uint256" + }, + { + "astId": 12244, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newDkgResultSubmissionTimeout", + "offset": 0, + "slot": "19", + "type": "t_uint256" + }, + { + "astId": 12246, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "dkgResultSubmissionTimeoutChangeInitiated", + "offset": 0, + "slot": "20", + "type": "t_uint256" + }, + { + "astId": 12248, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newDkgSubmitterPrecedencePeriodLength", + "offset": 0, + "slot": "21", + "type": "t_uint256" + }, + { + "astId": 12250, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "dkgSubmitterPrecedencePeriodLengthChangeInitiated", + "offset": 0, + "slot": "22", + "type": "t_uint256" + }, + { + "astId": 12252, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newRelayEntrySubmissionFailureSlashingAmount", + "offset": 0, + "slot": "23", + "type": "t_uint96" + }, + { + "astId": 12254, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "relayEntrySubmissionFailureSlashingAmountChangeInitiated", + "offset": 0, + "slot": "24", + "type": "t_uint256" + }, + { + "astId": 12256, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newMaliciousDkgResultSlashingAmount", + "offset": 0, + "slot": "25", + "type": "t_uint96" + }, + { + "astId": 12258, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "maliciousDkgResultSlashingAmountChangeInitiated", + "offset": 0, + "slot": "26", + "type": "t_uint256" + }, + { + "astId": 12260, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newUnauthorizedSigningSlashingAmount", + "offset": 0, + "slot": "27", + "type": "t_uint96" + }, + { + "astId": 12262, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "unauthorizedSigningSlashingAmountChangeInitiated", + "offset": 0, + "slot": "28", + "type": "t_uint256" + }, + { + "astId": 12264, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newSortitionPoolRewardsBanDuration", + "offset": 0, + "slot": "29", + "type": "t_uint256" + }, + { + "astId": 12266, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "sortitionPoolRewardsBanDurationChangeInitiated", + "offset": 0, + "slot": "30", + "type": "t_uint256" + }, + { + "astId": 12268, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newRelayEntryTimeoutNotificationRewardMultiplier", + "offset": 0, + "slot": "31", + "type": "t_uint256" + }, + { + "astId": 12270, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "relayEntryTimeoutNotificationRewardMultiplierChangeInitiated", + "offset": 0, + "slot": "32", + "type": "t_uint256" + }, + { + "astId": 12272, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newUnauthorizedSigningNotificationRewardMultiplier", + "offset": 0, + "slot": "33", + "type": "t_uint256" + }, + { + "astId": 12274, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "unauthorizedSigningNotificationRewardMultiplierChangeInitiated", + "offset": 0, + "slot": "34", + "type": "t_uint256" + }, + { + "astId": 12276, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newMinimumAuthorization", + "offset": 0, + "slot": "35", + "type": "t_uint96" + }, + { + "astId": 12278, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "minimumAuthorizationChangeInitiated", + "offset": 0, + "slot": "36", + "type": "t_uint256" + }, + { + "astId": 12280, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newAuthorizationDecreaseDelay", + "offset": 0, + "slot": "37", + "type": "t_uint64" + }, + { + "astId": 12282, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "authorizationDecreaseDelayChangeInitiated", + "offset": 0, + "slot": "38", + "type": "t_uint256" + }, + { + "astId": 12284, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newAuthorizationDecreaseChangePeriod", + "offset": 0, + "slot": "39", + "type": "t_uint64" + }, + { + "astId": 12286, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "authorizationDecreaseChangePeriodChangeInitiated", + "offset": 0, + "slot": "40", + "type": "t_uint256" + }, + { + "astId": 12288, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newDkgMaliciousResultNotificationRewardMultiplier", + "offset": 0, + "slot": "41", + "type": "t_uint256" + }, + { + "astId": 12290, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "dkgMaliciousResultNotificationRewardMultiplierChangeInitiated", + "offset": 0, + "slot": "42", + "type": "t_uint256" + }, + { + "astId": 12292, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newDkgResultSubmissionGas", + "offset": 0, + "slot": "43", + "type": "t_uint256" + }, + { + "astId": 12294, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "dkgResultSubmissionGasChangeInitiated", + "offset": 0, + "slot": "44", + "type": "t_uint256" + }, + { + "astId": 12296, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newDkgResultApprovalGasOffset", + "offset": 0, + "slot": "45", + "type": "t_uint256" + }, + { + "astId": 12298, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "dkgResultApprovalGasOffsetChangeInitiated", + "offset": 0, + "slot": "46", + "type": "t_uint256" + }, + { + "astId": 12300, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newNotifyOperatorInactivityGasOffset", + "offset": 0, + "slot": "47", + "type": "t_uint256" + }, + { + "astId": 12302, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "notifyOperatorInactivityGasOffsetChangeInitiated", + "offset": 0, + "slot": "48", + "type": "t_uint256" + }, + { + "astId": 12304, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "newRelayEntrySubmissionGasOffset", + "offset": 0, + "slot": "49", + "type": "t_uint256" + }, + { + "astId": 12306, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "relayEntrySubmissionGasOffsetChangeInitiated", + "offset": 0, + "slot": "50", + "type": "t_uint256" + }, + { + "astId": 12311, + "contract": "contracts/RandomBeaconGovernance.sol:RandomBeaconGovernance", + "label": "governanceDelay", + "offset": 0, + "slot": "51", + "type": "t_uint256" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "encoding": "inplace", + "label": "uint64", + "numberOfBytes": "8" + }, + "t_uint96": { + "encoding": "inplace", + "label": "uint96", + "numberOfBytes": "12" + } + } + }, + "userdoc": { + "kind": "user", + "methods": { + "beginAuthorizationDecreaseChangePeriodUpdate(uint64)": { + "notice": "Begins the authorization decrease change period update process." + }, + "beginAuthorizationDecreaseDelayUpdate(uint64)": { + "notice": "Begins the authorization decrease delay update process." + }, + "beginCallbackGasLimitUpdate(uint256)": { + "notice": "Begins the callback gas limit update process." + }, + "beginDkgMaliciousResultNotificationRewardMultiplierUpdate(uint256)": { + "notice": "Begins the DKG malicious result notification reward multiplier update process." + }, + "beginDkgResultApprovalGasOffsetUpdate(uint256)": { + "notice": "Begins the DKG result approval gas offset update process." + }, + "beginDkgResultChallengeExtraGasUpdate(uint256)": { + "notice": "Begins the DKG result challenge extra gas update process." + }, + "beginDkgResultChallengePeriodLengthUpdate(uint256)": { + "notice": "Begins the DKG result challenge period length update process." + }, + "beginDkgResultSubmissionGasUpdate(uint256)": { + "notice": "Begins the DKG result submission gas update process." + }, + "beginDkgResultSubmissionTimeoutUpdate(uint256)": { + "notice": "Begins the DKG result submission timeout update process." + }, + "beginDkgSubmitterPrecedencePeriodLengthUpdate(uint256)": { + "notice": "Begins the DKG submitter precedence period length." + }, + "beginGovernanceDelayUpdate(uint256)": { + "notice": "Begins the governance delay update process." + }, + "beginGroupCreationFrequencyUpdate(uint256)": { + "notice": "Begins the group creation frequency update process." + }, + "beginGroupLifetimeUpdate(uint256)": { + "notice": "Begins the group lifetime update process. Group lifetime needs to be shorter than the authorization decrease delay to ensure every active group is backed by enough stake. A new group lifetime value is in blocks and has to be calculated based on the average block time and authorization decrease delay which value is in seconds." + }, + "beginMaliciousDkgResultSlashingAmountUpdate(uint96)": { + "notice": "Begins the malicious DKG result slashing amount update process." + }, + "beginMinimumAuthorizationUpdate(uint96)": { + "notice": "Begins the minimum authorization amount update process." + }, + "beginNotifyOperatorInactivityGasOffsetUpdate(uint256)": { + "notice": "Begins the notify operator inactivity gas offset update process." + }, + "beginRandomBeaconGovernanceTransfer(address)": { + "notice": "Begins the random beacon governance transfer process." + }, + "beginRelayEntryHardTimeoutUpdate(uint256)": { + "notice": "Begins the relay entry hard timeout update process." + }, + "beginRelayEntrySoftTimeoutUpdate(uint256)": { + "notice": "Begins the relay entry soft timeout update process." + }, + "beginRelayEntrySubmissionFailureSlashingAmountUpdate(uint96)": { + "notice": "Begins the relay entry submission failure slashing amount update process." + }, + "beginRelayEntrySubmissionGasOffsetUpdate(uint256)": { + "notice": "Begins the relay entry submission gas offset update process." + }, + "beginRelayEntryTimeoutNotificationRewardMultiplierUpdate(uint256)": { + "notice": "Begins the relay entry timeout notification reward multiplier update process." + }, + "beginSortitionPoolRewardsBanDurationUpdate(uint256)": { + "notice": "Begins the sortition pool rewards ban duration update process." + }, + "beginUnauthorizedSigningNotificationRewardMultiplierUpdate(uint256)": { + "notice": "Begins the unauthorized signing notification reward multiplier update process." + }, + "beginUnauthorizedSigningSlashingAmountUpdate(uint96)": { + "notice": "Begins the unauthorized signing slashing amount update process." + }, + "finalizeAuthorizationDecreaseChangePeriodUpdate()": { + "notice": "Finalizes the authorization decrease change period update process." + }, + "finalizeAuthorizationDecreaseDelayUpdate()": { + "notice": "Finalizes the authorization decrease delay update process." + }, + "finalizeCallbackGasLimitUpdate()": { + "notice": "Finalizes the callback gas limit update process." + }, + "finalizeDkgMaliciousResultNotificationRewardMultiplierUpdate()": { + "notice": "Finalizes the DKG malicious result notification reward multiplier update process." + }, + "finalizeDkgResultApprovalGasOffsetUpdate()": { + "notice": "Finalizes the DKG result approval gas offset update process." + }, + "finalizeDkgResultChallengeExtraGasUpdate()": { + "notice": "Finalizes the DKG result challenge extra gas update process." + }, + "finalizeDkgResultChallengePeriodLengthUpdate()": { + "notice": "Finalizes the DKG result challenge period length update process." + }, + "finalizeDkgResultSubmissionGasUpdate()": { + "notice": "Finalizes DKG result submission gas update process." + }, + "finalizeDkgResultSubmissionTimeoutUpdate()": { + "notice": "Finalizes the DKG result submission timeout update process." + }, + "finalizeDkgSubmitterPrecedencePeriodLengthUpdate()": { + "notice": "Finalizes the DKG submitter precedence period length." + }, + "finalizeGovernanceDelayUpdate()": { + "notice": "Finalizes the governance delay update process." + }, + "finalizeGroupCreationFrequencyUpdate()": { + "notice": "Finalizes the group creation frequency update process." + }, + "finalizeGroupLifetimeUpdate()": { + "notice": "Finalizes the group creation frequency update process." + }, + "finalizeMaliciousDkgResultSlashingAmountUpdate()": { + "notice": "Finalizes the malicious DKG result slashing amount update process." + }, + "finalizeMinimumAuthorizationUpdate()": { + "notice": "Finalizes the minimum authorization amount update process." + }, + "finalizeNotifyOperatorInactivityGasOffsetUpdate()": { + "notice": "Finalizes the notify operator inactivity gas offset update process." + }, + "finalizeRandomBeaconGovernanceTransfer()": { + "notice": "Finalizes the random beacon governance transfer process." + }, + "finalizeRelayEntryHardTimeoutUpdate()": { + "notice": "Finalizes the relay entry hard timeout update process." + }, + "finalizeRelayEntrySoftTimeoutUpdate()": { + "notice": "Finalizes the relay entry soft timeout update process." + }, + "finalizeRelayEntrySubmissionFailureSlashingAmountUpdate()": { + "notice": "Finalizes the relay entry submission failure slashing amount update process." + }, + "finalizeRelayEntrySubmissionGasOffsetUpdate()": { + "notice": "Finalizes relay entry submission gas offset update process." + }, + "finalizeRelayEntryTimeoutNotificationRewardMultiplierUpdate()": { + "notice": "Finalizes the relay entry timeout notification reward multiplier update process." + }, + "finalizeSortitionPoolRewardsBanDurationUpdate()": { + "notice": "Finalizes the sortition pool rewards ban duration update process." + }, + "finalizeUnauthorizedSigningNotificationRewardMultiplierUpdate()": { + "notice": "Finalizes the unauthorized signing notification reward multiplier update process." + }, + "finalizeUnauthorizedSigningSlashingAmountUpdate()": { + "notice": "Finalizes the unauthorized signing slashing amount update process." + }, + "getRemainingAuthorizationDecreaseChangePeriodUpdateTime()": { + "notice": "Get the time remaining until the authorization decrease change period can be updated." + }, + "getRemainingAuthorizationDecreaseDelayUpdateTime()": { + "notice": "Get the time remaining until the authorization decrease delay can be updated." + }, + "getRemainingCallbackGasLimitUpdateTime()": { + "notice": "Get the time remaining until the callback gas limit can be updated." + }, + "getRemainingDkgMaliciousResultNotificationRewardMultiplierUpdateTime()": { + "notice": "Get the time remaining until the DKG malicious result notification reward multiplier duration can be updated." + }, + "getRemainingDkgResultApprovalGasOffsetUpdateTime()": { + "notice": "Get the time remaining until the DKG approval gas offset duration can be updated." + }, + "getRemainingDkgResultChallengeExtraGasUpdateTime()": { + "notice": "Get the time remaining until the DKG result challenge extra gas can be updated." + }, + "getRemainingDkgResultChallengePeriodLengthUpdateTime()": { + "notice": "Get the time remaining until the DKG result challenge period length can be updated." + }, + "getRemainingDkgResultSubmissionGasUpdateTime()": { + "notice": "Get the time remaining until the DKG result submission gas duration can be updated." + }, + "getRemainingDkgResultSubmissionTimeoutUpdateTime()": { + "notice": "Get the time remaining until the DKG result submission timeout can be updated." + }, + "getRemainingDkgSubmitterPrecedencePeriodLengthUpdateTime()": { + "notice": "Get the time remaining until the wallet owner can be updated." + }, + "getRemainingGovernanceDelayUpdateTime()": { + "notice": "Get the time remaining until the governance delay can be updated." + }, + "getRemainingGroupCreationFrequencyUpdateTime()": { + "notice": "Get the time remaining until the group creation frequency can be updated." + }, + "getRemainingGroupLifetimeUpdateTime()": { + "notice": "Get the time remaining until the group lifetime can be updated." + }, + "getRemainingMaliciousDkgResultSlashingAmountUpdateTime()": { + "notice": "Get the time remaining until the malicious DKG result slashing amount can be updated." + }, + "getRemainingMimimumAuthorizationUpdateTime()": { + "notice": "Get the time remaining until the minimum authorization amount can be updated." + }, + "getRemainingNotifyOperatorInactivityGasOffsetUpdateTime()": { + "notice": "Get the time remaining until the operator inactivity notification gas offset duration can be updated." + }, + "getRemainingRandomBeaconGovernanceTransferDelayTime()": { + "notice": "Get the time remaining until the random beacon governance can be transferred." + }, + "getRemainingRelayEntryHardTimeoutUpdateTime()": { + "notice": "Get the time remaining until the relay entry hard timeout can be updated." + }, + "getRemainingRelayEntrySoftTimeoutUpdateTime()": { + "notice": "Get the time remaining until the relay entry submission soft timeout can be updated." + }, + "getRemainingRelayEntrySubmissionFailureSlashingAmountUpdateTime()": { + "notice": "Get the time remaining until the relay entry submission failure slashing amount can be updated." + }, + "getRemainingRelayEntrySubmissionGasOffsetUpdateTime()": { + "notice": "Get the time remaining until the relay entry submission gas offset duration can be updated." + }, + "getRemainingRelayEntryTimeoutNotificationRewardMultiplierUpdateTime()": { + "notice": "Get the time remaining until the relay entry timeout notification reward multiplier duration can be updated." + }, + "getRemainingSortitionPoolRewardsBanDurationUpdateTime()": { + "notice": "Get the time remaining until the sortition pool rewards ban duration can be updated." + }, + "getRemainingUnauthorizedSigningNotificationRewardMultiplierUpdateTime()": { + "notice": "Get the time remaining until the unauthorized signing notification reward multiplier duration can be updated." + }, + "getRemainingUnauthorizedSigningSlashingAmountUpdateTime()": { + "notice": "Get the time remaining until the unauthorized signing slashing amount can be updated." + }, + "setRequesterAuthorization(address,bool)": { + "notice": "Set authorization for requesters that can request a relay entry. It can be done by the governance only." + }, + "withdrawIneligibleRewards(address)": { + "notice": "Withdraws rewards belonging to operators marked as ineligible for sortition pool rewards." + } + }, + "notice": "Owns the `RandomBeacon` contract and is responsible for updating its governable parameters in respect to governance delay individual for each parameter.", + "version": 1 + } +} diff --git a/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/ReimbursementPool.sol/ReimbursementPool.json b/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/ReimbursementPool.sol/ReimbursementPool.json new file mode 100644 index 0000000000..74e11b2897 --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/ReimbursementPool.sol/ReimbursementPool.json @@ -0,0 +1,476 @@ +{ + "contractName": "ReimbursementPool", + "sourceName": "contracts/ReimbursementPool.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "_staticGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxGasPrice", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "thirdPartyContract", + "type": "address" + } + ], + "name": "AuthorizedContract", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "withdrawnAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "FundsWithdrawn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newMaxGasPrice", + "type": "uint256" + } + ], + "name": "MaxGasPriceUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "refundAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "SendingEtherFailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newStaticGas", + "type": "uint256" + } + ], + "name": "StaticGasUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "thirdPartyContract", + "type": "address" + } + ], + "name": "UnauthorizedContract", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_contract", + "type": "address" + } + ], + "name": "authorize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isAuthorized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxGasPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "gasSpent", + "type": "uint256" + }, + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "refund", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxGasPrice", + "type": "uint256" + } + ], + "name": "setMaxGasPrice", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_staticGas", + "type": "uint256" + } + ], + "name": "setStaticGas", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "staticGas", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_contract", + "type": "address" + } + ], + "name": "unauthorize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "withdrawAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b50604051610a49380380610a4983398101604081905261002f9161009a565b6100383361004a565b600180556003919091556004556100be565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080604083850312156100ad57600080fd5b505080516020909101519092909150565b61097c806100cd6000396000f3fe6080604052600436106100c55760003560e01c8063b6a5d7de1161007f578063f0b37c0411610059578063f0b37c04146101ef578063f2fde38b1461020f578063fa09e6301461022f578063fe9fbb801461024f57600080fd5b8063b6a5d7de14610199578063d2fa635e146101b9578063e25b5345146101d957600080fd5b8062f714ce146100d15780633de39c11146100f35780633e2174041461011c578063715018a61461013c5780637ad226dc146101515780638da5cb5b1461017157600080fd5b366100cc57005b600080fd5b3480156100dd57600080fd5b506100f16100ec366004610858565b61028f565b005b3480156100ff57600080fd5b5061010960045481565b6040519081526020015b60405180910390f35b34801561012857600080fd5b506100f1610137366004610884565b6103f2565b34801561014857600080fd5b506100f1610436565b34801561015d57600080fd5b506100f161016c366004610858565b61044a565b34801561017d57600080fd5b506000546040516001600160a01b039091168152602001610113565b3480156101a557600080fd5b506100f16101b436600461089d565b610615565b3480156101c557600080fd5b506100f16101d4366004610884565b610671565b3480156101e557600080fd5b5061010960035481565b3480156101fb57600080fd5b506100f161020a36600461089d565b6106ae565b34801561021b57600080fd5b506100f161022a36600461089d565b610707565b34801561023b57600080fd5b506100f161024a36600461089d565b610780565b34801561025b57600080fd5b5061027f61026a36600461089d565b60026020526000908152604090205460ff1681565b6040519015158152602001610113565b610297610792565b814710156102ec5760405162461bcd60e51b815260206004820152601d60248201527f496e73756666696369656e7420636f6e74726163742062616c616e636500000060448201526064015b60405180910390fd5b6001600160a01b0381166103125760405162461bcd60e51b81526004016102e3906108bf565b604080518381526001600160a01b03831660208201527f6141b54b56b8a52a8c6f5cd2a857f6117b18ffbf4d46bd3106f300a839cbf5ea910160405180910390a16000816001600160a01b03168360405160006040518083038185875af1925050503d80600081146103a0576040519150601f19603f3d011682016040523d82523d6000602084013e6103a5565b606091505b50509050806103ed5760405162461bcd60e51b81526020600482015260146024820152732330b4b632b2103a379039b2b7321022ba3432b960611b60448201526064016102e3565b505050565b6103fa610792565b60038190556040518181527fa86b6e9a406df021f05f513a796a1d5bea0bd3e18fe1d3f6082a3cccfc898d14906020015b60405180910390a150565b61043e610792565b61044860006107ec565b565b60026001540361049c5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016102e3565b60026001819055336000908152602091909152604090205460ff166105135760405162461bcd60e51b815260206004820152602760248201527f436f6e7472616374206973206e6f7420617574686f72697a656420666f722061604482015266081c99599d5b9960ca1b60648201526084016102e3565b6001600160a01b0381166105395760405162461bcd60e51b81526004016102e3906108bf565b60006004543a1061054c5760045461054e565b3a5b9050600081600354856105619190610916565b61056b919061092f565b90506000836001600160a01b03168260405160006040518083038185875af1925050503d80600081146105ba576040519150601f19603f3d011682016040523d82523d6000602084013e6105bf565b606091505b505090508061060a57604080518381526001600160a01b03861660208201527fd955712c3ae4c3c40451db84ea0c4531c61cc0ea75c13fe9168ae0e07d71e050910160405180910390a15b505060018055505050565b61061d610792565b6001600160a01b038116600081815260026020908152604091829020805460ff1916600117905590519182527f2c74592fddad593c2c4403101ce9b30930711ab87571268ddd1e1989ee1d7917910161042b565b610679610792565b60048190556040518181527fa7a07f821dfdfca8e4baa9ccc4bbe7b782baac5946918bd19f1c9c761db414109060200161042b565b6106b6610792565b6001600160a01b038116600081815260026020908152604091829020805460ff1916905590519182527fe195aa139c7c69ba98f719c94aecd784e12fabc0789ef81335150078bc087317910161042b565b61070f610792565b6001600160a01b0381166107745760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016102e3565b61077d816107ec565b50565b610788610792565b61077d478261028f565b6000546001600160a01b031633146104485760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102e3565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80356001600160a01b038116811461085357600080fd5b919050565b6000806040838503121561086b57600080fd5b8235915061087b6020840161083c565b90509250929050565b60006020828403121561089657600080fd5b5035919050565b6000602082840312156108af57600080fd5b6108b88261083c565b9392505050565b60208082526021908201527f5265636569766572277320616464726573732063616e6e6f74206265207a65726040820152606f60f81b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b8082018082111561092957610929610900565b92915050565b80820281158282048414176109295761092961090056fea2646970667358221220578df9772b15d4ba1bc520679b4729538fcffa2275405fa7f9472c205cf79f2764736f6c63430008110033", + "deployedBytecode": "0x6080604052600436106100c55760003560e01c8063b6a5d7de1161007f578063f0b37c0411610059578063f0b37c04146101ef578063f2fde38b1461020f578063fa09e6301461022f578063fe9fbb801461024f57600080fd5b8063b6a5d7de14610199578063d2fa635e146101b9578063e25b5345146101d957600080fd5b8062f714ce146100d15780633de39c11146100f35780633e2174041461011c578063715018a61461013c5780637ad226dc146101515780638da5cb5b1461017157600080fd5b366100cc57005b600080fd5b3480156100dd57600080fd5b506100f16100ec366004610858565b61028f565b005b3480156100ff57600080fd5b5061010960045481565b6040519081526020015b60405180910390f35b34801561012857600080fd5b506100f1610137366004610884565b6103f2565b34801561014857600080fd5b506100f1610436565b34801561015d57600080fd5b506100f161016c366004610858565b61044a565b34801561017d57600080fd5b506000546040516001600160a01b039091168152602001610113565b3480156101a557600080fd5b506100f16101b436600461089d565b610615565b3480156101c557600080fd5b506100f16101d4366004610884565b610671565b3480156101e557600080fd5b5061010960035481565b3480156101fb57600080fd5b506100f161020a36600461089d565b6106ae565b34801561021b57600080fd5b506100f161022a36600461089d565b610707565b34801561023b57600080fd5b506100f161024a36600461089d565b610780565b34801561025b57600080fd5b5061027f61026a36600461089d565b60026020526000908152604090205460ff1681565b6040519015158152602001610113565b610297610792565b814710156102ec5760405162461bcd60e51b815260206004820152601d60248201527f496e73756666696369656e7420636f6e74726163742062616c616e636500000060448201526064015b60405180910390fd5b6001600160a01b0381166103125760405162461bcd60e51b81526004016102e3906108bf565b604080518381526001600160a01b03831660208201527f6141b54b56b8a52a8c6f5cd2a857f6117b18ffbf4d46bd3106f300a839cbf5ea910160405180910390a16000816001600160a01b03168360405160006040518083038185875af1925050503d80600081146103a0576040519150601f19603f3d011682016040523d82523d6000602084013e6103a5565b606091505b50509050806103ed5760405162461bcd60e51b81526020600482015260146024820152732330b4b632b2103a379039b2b7321022ba3432b960611b60448201526064016102e3565b505050565b6103fa610792565b60038190556040518181527fa86b6e9a406df021f05f513a796a1d5bea0bd3e18fe1d3f6082a3cccfc898d14906020015b60405180910390a150565b61043e610792565b61044860006107ec565b565b60026001540361049c5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016102e3565b60026001819055336000908152602091909152604090205460ff166105135760405162461bcd60e51b815260206004820152602760248201527f436f6e7472616374206973206e6f7420617574686f72697a656420666f722061604482015266081c99599d5b9960ca1b60648201526084016102e3565b6001600160a01b0381166105395760405162461bcd60e51b81526004016102e3906108bf565b60006004543a1061054c5760045461054e565b3a5b9050600081600354856105619190610916565b61056b919061092f565b90506000836001600160a01b03168260405160006040518083038185875af1925050503d80600081146105ba576040519150601f19603f3d011682016040523d82523d6000602084013e6105bf565b606091505b505090508061060a57604080518381526001600160a01b03861660208201527fd955712c3ae4c3c40451db84ea0c4531c61cc0ea75c13fe9168ae0e07d71e050910160405180910390a15b505060018055505050565b61061d610792565b6001600160a01b038116600081815260026020908152604091829020805460ff1916600117905590519182527f2c74592fddad593c2c4403101ce9b30930711ab87571268ddd1e1989ee1d7917910161042b565b610679610792565b60048190556040518181527fa7a07f821dfdfca8e4baa9ccc4bbe7b782baac5946918bd19f1c9c761db414109060200161042b565b6106b6610792565b6001600160a01b038116600081815260026020908152604091829020805460ff1916905590519182527fe195aa139c7c69ba98f719c94aecd784e12fabc0789ef81335150078bc087317910161042b565b61070f610792565b6001600160a01b0381166107745760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016102e3565b61077d816107ec565b50565b610788610792565b61077d478261028f565b6000546001600160a01b031633146104485760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102e3565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80356001600160a01b038116811461085357600080fd5b919050565b6000806040838503121561086b57600080fd5b8235915061087b6020840161083c565b90509250929050565b60006020828403121561089657600080fd5b5035919050565b6000602082840312156108af57600080fd5b6108b88261083c565b9392505050565b60208082526021908201527f5265636569766572277320616464726573732063616e6e6f74206265207a65726040820152606f60f81b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b8082018082111561092957610929610900565b92915050565b80820281158282048414176109295761092961090056fea2646970667358221220578df9772b15d4ba1bc520679b4729538fcffa2275405fa7f9472c205cf79f2764736f6c63430008110033", + "linkReferences": {}, + "deployedLinkReferences": {}, + "devdoc": { + "kind": "dev", + "methods": { + "authorize(address)": { + "params": { + "_contract": "Authorized contract." + } + }, + "owner()": { + "details": "Returns the address of the current owner." + }, + "refund(uint256,address)": { + "details": "Ignoring the result of sending ETH to a receiver is made on purpose. For EOA receiving ETH should always work. If a receiver is a smart contract, then we do not want to fail a transaction, because in some cases the refund is done at the very end of multiple calls where all the previous calls were already paid off. It is a receiver's smart contract resposibility to make sure it can receive ETH.Only authorized contracts are allowed calling this function.", + "params": { + "gasSpent": "Gas spent on a transaction that needs to be reimbursed.", + "receiver": "Address where the reimbursment is sent." + } + }, + "renounceOwnership()": { + "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner." + }, + "setMaxGasPrice(uint256)": { + "params": { + "_maxGasPrice": "Max gas price used to reimburse tx submitters." + } + }, + "setStaticGas(uint256)": { + "params": { + "_staticGas": "Static gas cost." + } + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." + }, + "unauthorize(address)": { + "params": { + "_contract": "Authorized contract." + } + }, + "withdraw(uint256,address)": { + "params": { + "amount": "Amount to withdraw from the pool.", + "receiver": "An address where ETH is sent." + } + }, + "withdrawAll(address)": { + "params": { + "receiver": "An address where ETH is sent." + } + } + }, + "version": 1 + }, + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_staticGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxGasPrice\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"thirdPartyContract\",\"type\":\"address\"}],\"name\":\"AuthorizedContract\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"withdrawnAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newMaxGasPrice\",\"type\":\"uint256\"}],\"name\":\"MaxGasPriceUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"refundAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"SendingEtherFailed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newStaticGas\",\"type\":\"uint256\"}],\"name\":\"StaticGasUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"thirdPartyContract\",\"type\":\"address\"}],\"name\":\"UnauthorizedContract\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_contract\",\"type\":\"address\"}],\"name\":\"authorize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isAuthorized\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxGasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"gasSpent\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxGasPrice\",\"type\":\"uint256\"}],\"name\":\"setMaxGasPrice\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_staticGas\",\"type\":\"uint256\"}],\"name\":\"setStaticGas\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"staticGas\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_contract\",\"type\":\"address\"}],\"name\":\"unauthorize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"withdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"authorize(address)\":{\"params\":{\"_contract\":\"Authorized contract.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"refund(uint256,address)\":{\"details\":\"Ignoring the result of sending ETH to a receiver is made on purpose. For EOA receiving ETH should always work. If a receiver is a smart contract, then we do not want to fail a transaction, because in some cases the refund is done at the very end of multiple calls where all the previous calls were already paid off. It is a receiver's smart contract resposibility to make sure it can receive ETH.Only authorized contracts are allowed calling this function.\",\"params\":{\"gasSpent\":\"Gas spent on a transaction that needs to be reimbursed.\",\"receiver\":\"Address where the reimbursment is sent.\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setMaxGasPrice(uint256)\":{\"params\":{\"_maxGasPrice\":\"Max gas price used to reimburse tx submitters.\"}},\"setStaticGas(uint256)\":{\"params\":{\"_staticGas\":\"Static gas cost.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"unauthorize(address)\":{\"params\":{\"_contract\":\"Authorized contract.\"}},\"withdraw(uint256,address)\":{\"params\":{\"amount\":\"Amount to withdraw from the pool.\",\"receiver\":\"An address where ETH is sent.\"}},\"withdrawAll(address)\":{\"params\":{\"receiver\":\"An address where ETH is sent.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"authorize(address)\":{\"notice\":\"Authorize a contract that can interact with this reimbursment pool. Can be authorized by the owner only.\"},\"isAuthorized(address)\":{\"notice\":\"Authorized contracts that can interact with the reimbursment pool. Authorization can be granted and removed by the owner.\"},\"maxGasPrice()\":{\"notice\":\"Max gas price used to reimburse a transaction submitter. Protects against malicious operator-miners.\"},\"refund(uint256,address)\":{\"notice\":\"Refunds ETH to a spender for executing specific transactions.\"},\"setMaxGasPrice(uint256)\":{\"notice\":\"Setting a max gas price for transactions. Can be set by the owner only.\"},\"setStaticGas(uint256)\":{\"notice\":\"Setting a static gas cost for executing a transaction. Can be set by the owner only.\"},\"staticGas()\":{\"notice\":\"Static gas includes: - cost of the refund function - base transaction cost\"},\"unauthorize(address)\":{\"notice\":\"Unauthorize a contract that was previously authorized to interact with this reimbursment pool. Can be unauthorized by the owner only.\"},\"withdraw(uint256,address)\":{\"notice\":\"Withdraws ETH amount from this pool which are sent to a given address. Can be set by the owner only.\"},\"withdrawAll(address)\":{\"notice\":\"Withdraws all ETH from this pool which are sent to a given address. Can be set by the owner only.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/ReimbursementPool.sol\":\"ReimbursementPool\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/security/ReentrancyGuard.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Contract module that helps prevent reentrant calls to a function.\\n *\\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\\n * available, which can be applied to functions to make sure there are no nested\\n * (reentrant) calls to them.\\n *\\n * Note that because there is a single `nonReentrant` guard, functions marked as\\n * `nonReentrant` may not call one another. This can be worked around by making\\n * those functions `private`, and then adding `external` `nonReentrant` entry\\n * points to them.\\n *\\n * TIP: If you would like to learn more about reentrancy and alternative ways\\n * to protect against it, check out our blog post\\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\\n */\\nabstract contract ReentrancyGuard {\\n // Booleans are more expensive than uint256 or any type that takes up a full\\n // word because each write operation emits an extra SLOAD to first read the\\n // slot's contents, replace the bits taken up by the boolean, and then write\\n // back. This is the compiler's defense against contract upgrades and\\n // pointer aliasing, and it cannot be disabled.\\n\\n // The values being non-zero value makes deployment a bit more expensive,\\n // but in exchange the refund on every call to nonReentrant will be lower in\\n // amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to\\n // increase the likelihood of the full refund coming into effect.\\n uint256 private constant _NOT_ENTERED = 1;\\n uint256 private constant _ENTERED = 2;\\n\\n uint256 private _status;\\n\\n constructor() {\\n _status = _NOT_ENTERED;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and making it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_status != _ENTERED, \\\"ReentrancyGuard: reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n _status = _ENTERED;\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _status = _NOT_ENTERED;\\n }\\n}\\n\",\"keccak256\":\"0x0e9621f60b2faabe65549f7ed0f24e8853a45c1b7990d47e8160e523683f3935\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"contracts/ReimbursementPool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/security/ReentrancyGuard.sol\\\";\\n\\ncontract ReimbursementPool is Ownable, ReentrancyGuard {\\n /// @notice Authorized contracts that can interact with the reimbursment pool.\\n /// Authorization can be granted and removed by the owner.\\n mapping(address => bool) public isAuthorized;\\n\\n /// @notice Static gas includes:\\n /// - cost of the refund function\\n /// - base transaction cost\\n uint256 public staticGas;\\n\\n /// @notice Max gas price used to reimburse a transaction submitter. Protects\\n /// against malicious operator-miners.\\n uint256 public maxGasPrice;\\n\\n event StaticGasUpdated(uint256 newStaticGas);\\n\\n event MaxGasPriceUpdated(uint256 newMaxGasPrice);\\n\\n event SendingEtherFailed(uint256 refundAmount, address receiver);\\n\\n event AuthorizedContract(address thirdPartyContract);\\n\\n event UnauthorizedContract(address thirdPartyContract);\\n\\n event FundsWithdrawn(uint256 withdrawnAmount, address receiver);\\n\\n constructor(uint256 _staticGas, uint256 _maxGasPrice) {\\n staticGas = _staticGas;\\n maxGasPrice = _maxGasPrice;\\n }\\n\\n /// @notice Receive ETH\\n receive() external payable {}\\n\\n /// @notice Refunds ETH to a spender for executing specific transactions.\\n /// @dev Ignoring the result of sending ETH to a receiver is made on purpose.\\n /// For EOA receiving ETH should always work. If a receiver is a smart\\n /// contract, then we do not want to fail a transaction, because in some\\n /// cases the refund is done at the very end of multiple calls where all\\n /// the previous calls were already paid off. It is a receiver's smart\\n /// contract resposibility to make sure it can receive ETH.\\n /// @dev Only authorized contracts are allowed calling this function.\\n /// @param gasSpent Gas spent on a transaction that needs to be reimbursed.\\n /// @param receiver Address where the reimbursment is sent.\\n function refund(uint256 gasSpent, address receiver) external nonReentrant {\\n require(\\n isAuthorized[msg.sender],\\n \\\"Contract is not authorized for a refund\\\"\\n );\\n require(receiver != address(0), \\\"Receiver's address cannot be zero\\\");\\n\\n uint256 gasPrice = tx.gasprice < maxGasPrice\\n ? tx.gasprice\\n : maxGasPrice;\\n\\n uint256 refundAmount = (gasSpent + staticGas) * gasPrice;\\n\\n /* solhint-disable avoid-low-level-calls */\\n // slither-disable-next-line low-level-calls,unchecked-lowlevel\\n (bool sent, ) = receiver.call{value: refundAmount}(\\\"\\\");\\n /* solhint-enable avoid-low-level-calls */\\n if (!sent) {\\n // slither-disable-next-line reentrancy-events\\n emit SendingEtherFailed(refundAmount, receiver);\\n }\\n }\\n\\n /// @notice Authorize a contract that can interact with this reimbursment pool.\\n /// Can be authorized by the owner only.\\n /// @param _contract Authorized contract.\\n function authorize(address _contract) external onlyOwner {\\n isAuthorized[_contract] = true;\\n\\n emit AuthorizedContract(_contract);\\n }\\n\\n /// @notice Unauthorize a contract that was previously authorized to interact\\n /// with this reimbursment pool. Can be unauthorized by the\\n /// owner only.\\n /// @param _contract Authorized contract.\\n function unauthorize(address _contract) external onlyOwner {\\n delete isAuthorized[_contract];\\n\\n emit UnauthorizedContract(_contract);\\n }\\n\\n /// @notice Setting a static gas cost for executing a transaction. Can be set\\n /// by the owner only.\\n /// @param _staticGas Static gas cost.\\n function setStaticGas(uint256 _staticGas) external onlyOwner {\\n staticGas = _staticGas;\\n\\n emit StaticGasUpdated(_staticGas);\\n }\\n\\n /// @notice Setting a max gas price for transactions. Can be set by the\\n /// owner only.\\n /// @param _maxGasPrice Max gas price used to reimburse tx submitters.\\n function setMaxGasPrice(uint256 _maxGasPrice) external onlyOwner {\\n maxGasPrice = _maxGasPrice;\\n\\n emit MaxGasPriceUpdated(_maxGasPrice);\\n }\\n\\n /// @notice Withdraws all ETH from this pool which are sent to a given\\n /// address. Can be set by the owner only.\\n /// @param receiver An address where ETH is sent.\\n function withdrawAll(address receiver) external onlyOwner {\\n withdraw(address(this).balance, receiver);\\n }\\n\\n /// @notice Withdraws ETH amount from this pool which are sent to a given\\n /// address. Can be set by the owner only.\\n /// @param amount Amount to withdraw from the pool.\\n /// @param receiver An address where ETH is sent.\\n function withdraw(uint256 amount, address receiver) public onlyOwner {\\n require(\\n address(this).balance >= amount,\\n \\\"Insufficient contract balance\\\"\\n );\\n require(receiver != address(0), \\\"Receiver's address cannot be zero\\\");\\n\\n emit FundsWithdrawn(amount, receiver);\\n\\n /* solhint-disable avoid-low-level-calls */\\n // slither-disable-next-line low-level-calls,arbitrary-send\\n (bool sent, ) = receiver.call{value: amount}(\\\"\\\");\\n /* solhint-enable avoid-low-level-calls */\\n require(sent, \\\"Failed to send Ether\\\");\\n }\\n}\\n\",\"keccak256\":\"0xd6c24368cc4c6349b8b614e878ca961cad8254b8e8db1cc0abe452a70022ce50\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "storageLayout": { + "storage": [ + { + "astId": 3888, + "contract": "contracts/ReimbursementPool.sol:ReimbursementPool", + "label": "_owner", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 4004, + "contract": "contracts/ReimbursementPool.sol:ReimbursementPool", + "label": "_status", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 14735, + "contract": "contracts/ReimbursementPool.sol:ReimbursementPool", + "label": "isAuthorized", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_address,t_bool)" + }, + { + "astId": 14738, + "contract": "contracts/ReimbursementPool.sol:ReimbursementPool", + "label": "staticGas", + "offset": 0, + "slot": "3", + "type": "t_uint256" + }, + { + "astId": 14741, + "contract": "contracts/ReimbursementPool.sol:ReimbursementPool", + "label": "maxGasPrice", + "offset": 0, + "slot": "4", + "type": "t_uint256" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + }, + "userdoc": { + "kind": "user", + "methods": { + "authorize(address)": { + "notice": "Authorize a contract that can interact with this reimbursment pool. Can be authorized by the owner only." + }, + "isAuthorized(address)": { + "notice": "Authorized contracts that can interact with the reimbursment pool. Authorization can be granted and removed by the owner." + }, + "maxGasPrice()": { + "notice": "Max gas price used to reimburse a transaction submitter. Protects against malicious operator-miners." + }, + "refund(uint256,address)": { + "notice": "Refunds ETH to a spender for executing specific transactions." + }, + "setMaxGasPrice(uint256)": { + "notice": "Setting a max gas price for transactions. Can be set by the owner only." + }, + "setStaticGas(uint256)": { + "notice": "Setting a static gas cost for executing a transaction. Can be set by the owner only." + }, + "staticGas()": { + "notice": "Static gas includes: - cost of the refund function - base transaction cost" + }, + "unauthorize(address)": { + "notice": "Unauthorize a contract that was previously authorized to interact with this reimbursment pool. Can be unauthorized by the owner only." + }, + "withdraw(uint256,address)": { + "notice": "Withdraws ETH amount from this pool which are sent to a given address. Can be set by the owner only." + }, + "withdrawAll(address)": { + "notice": "Withdraws all ETH from this pool which are sent to a given address. Can be set by the owner only." + } + }, + "version": 1 + } +} diff --git a/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/libraries/BLS.sol/BLS.json b/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/libraries/BLS.sol/BLS.json new file mode 100644 index 0000000000..e433dda4ee --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/libraries/BLS.sol/BLS.json @@ -0,0 +1,208 @@ +{ + "contractName": "BLS", + "sourceName": "contracts/libraries/BLS.sol", + "abi": [ + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "uint256", + "name": "x", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "y", + "type": "uint256" + } + ], + "internalType": "struct AltBn128.gfP2", + "name": "x", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "x", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "y", + "type": "uint256" + } + ], + "internalType": "struct AltBn128.gfP2", + "name": "y", + "type": "tuple" + } + ], + "internalType": "struct AltBn128.G2Point", + "name": "publicKey", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "x", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "y", + "type": "uint256" + } + ], + "internalType": "struct AltBn128.G1Point", + "name": "message", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "x", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "y", + "type": "uint256" + } + ], + "internalType": "struct AltBn128.G1Point", + "name": "signature", + "type": "tuple" + } + ], + "name": "_verify", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "message", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "secretKey", + "type": "uint256" + } + ], + "name": "sign", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "message", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "verify", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "message", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "verifyBytes", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": "0x610be261003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100565760003560e01c8063afef5d331461005b578063b6087a0f14610084578063de8f50a1146100a7578063e71b17c4146100ba575b600080fd5b61006e61006936600461093c565b6100cd565b60405161007b91906109a5565b60405180910390f35b610097610092366004610a08565b6100fe565b604051901515815260200161007b565b6100976100b5366004610a7b565b610167565b6100976100c8366004610a7b565b610199565b606060006100da846101c9565b905060006100e8828561028c565b90506100f3816102d3565b925050505b92915050565b600061015f60405180604001604052808460000151815260200184602001516101447f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4790565b61014e9190610b19565b905261015861030d565b85876103cd565b949350505050565b60008061017383610474565b9050610190610181866104fd565b61018a86610474565b836100fe565b95945050505050565b6000806101a5846101c9565b905060006101b2826102d3565b90506101bf868286610167565b9695505050505050565b604080518082019091526000808252602082015260006002836040516101ef9190610b2c565b602060405180830381855afa15801561020c573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061022f9190610b48565b90507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47810660005b6102608261059e565b90508015610281576040805180820190915291825260208201529392505050565b600182019150610257565b604080518082019091526000808252602082015260405183518152602084015160208201528260408201526040826060836007600019fa6102cc57600080fd5b5092915050565b6040805181815260608181018352916000919060208201818036833750508451602095860151958301525060408101939093525090919050565b61031561082c565b50604080516080810182527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c28183019081527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed6060830152815281518083019092527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b82527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa60208381019190915281019190915290565b6000806040516020810187518152602088015160208201528651805160408301526020810151606083015250602087015180516080830152602081015160a083015250855160c0820152602086015160e08201528451805161010083015260208101516101208301525060208501518051610140830152602081015161016083015250602082610180836008600019fa61046657600080fd5b505115159695505050505050565b604080518082019091526000808252602082015281516040146104de5760405162461bcd60e51b815260206004820152601760248201527f496e76616c6964204731206279746573206c656e67746800000000000000000060448201526064015b60405180910390fd5b5060208181015160409283015183518085019094529083529082015290565b61050561082c565b81516080146105565760405162461bcd60e51b815260206004820152601760248201527f496e76616c6964204732206279746573206c656e67746800000000000000000060448201526064016104d5565b50602081810151604080840151606080860151608096870151845197880185528785019586529187019290925292855281518083019092528152808301919091529082015290565b60006100f87f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47806105d1856003836105ec565b6105dc906003610b77565b6105e69190610b8a565b90610637565b60006040516020810160208152602080820152602060408201528560608201528460808201528360a082015260208260c0836005600019fa61062d57600080fd5b5051949350505050565b6000610643838361079f565b600114610652575060006100f8565b82600003610662575060006100f8565b600482066003036106855761067e8360046001850104846105ec565b90506100f8565b600019820160005b600282066000036106a65760028204915060010161068d565b60025b6106b3818661079f565b600019146106c3576001016106a9565b60006106d68760026001870104886105ec565b905060006106e58886896105ec565b905060006106f484878a6105ec565b905084600080845b5060009050845b8382101561072c576001811461072c5761071f8160028e6105ec565b6001909201919050610703565b8160000361074657869a50505050505050505050506100f8565b6107598560018487030360020a8e6105ec565b92508b8384028161076c5761076c610b61565b0694508b8388028161078057610780610b61565b0696508b8587028161079457610794610b61565b0695508193506106fc565b6000806107b4846002600019860104856105ec565b90508015806107c35750806001145b156107cf5790506100f8565b6001830381036107e4576000199150506100f8565b60405162461bcd60e51b815260206004820152601d60248201527f4661696c656420746f2063616c63756c617465206c6567656e6472652e00000060448201526064016104d5565b6040805160808101825260009181018281526060820192909252908190815260200161086b604051806040016040528060008152602001600081525090565b905290565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156108a9576108a9610870565b60405290565b600082601f8301126108c057600080fd5b813567ffffffffffffffff808211156108db576108db610870565b604051601f8301601f19908116603f0116810190828211818310171561090357610903610870565b8160405283815286602085880101111561091c57600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561094f57600080fd5b823567ffffffffffffffff81111561096657600080fd5b610972858286016108af565b95602094909401359450505050565b60005b8381101561099c578181015183820152602001610984565b50506000910152565b60208152600082518060208401526109c4816040850160208701610981565b601f01601f19169190910160400192915050565b6000604082840312156109ea57600080fd5b6109f2610886565b9050813581526020820135602082015292915050565b6000806000838503610100811215610a1f57600080fd5b6080811215610a2d57600080fd5b50610a36610886565b610a4086866109d8565b8152610a4f86604087016109d8565b60208201529250610a6385608086016109d8565b9150610a728560c086016109d8565b90509250925092565b600080600060608486031215610a9057600080fd5b833567ffffffffffffffff80821115610aa857600080fd5b610ab4878388016108af565b94506020860135915080821115610aca57600080fd5b610ad6878388016108af565b93506040860135915080821115610aec57600080fd5b50610af9868287016108af565b9150509250925092565b634e487b7160e01b600052601160045260246000fd5b818103818111156100f8576100f8610b03565b60008251610b3e818460208701610981565b9190910192915050565b600060208284031215610b5a57600080fd5b5051919050565b634e487b7160e01b600052601260045260246000fd5b808201808211156100f8576100f8610b03565b600082610ba757634e487b7160e01b600052601260045260246000fd5b50069056fea2646970667358221220829ab3657ffe2f8b9548cdb9e0e6a52b8b9f02bddf27516291dd0366d3df603864736f6c63430008110033", + "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600436106100565760003560e01c8063afef5d331461005b578063b6087a0f14610084578063de8f50a1146100a7578063e71b17c4146100ba575b600080fd5b61006e61006936600461093c565b6100cd565b60405161007b91906109a5565b60405180910390f35b610097610092366004610a08565b6100fe565b604051901515815260200161007b565b6100976100b5366004610a7b565b610167565b6100976100c8366004610a7b565b610199565b606060006100da846101c9565b905060006100e8828561028c565b90506100f3816102d3565b925050505b92915050565b600061015f60405180604001604052808460000151815260200184602001516101447f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4790565b61014e9190610b19565b905261015861030d565b85876103cd565b949350505050565b60008061017383610474565b9050610190610181866104fd565b61018a86610474565b836100fe565b95945050505050565b6000806101a5846101c9565b905060006101b2826102d3565b90506101bf868286610167565b9695505050505050565b604080518082019091526000808252602082015260006002836040516101ef9190610b2c565b602060405180830381855afa15801561020c573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061022f9190610b48565b90507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47810660005b6102608261059e565b90508015610281576040805180820190915291825260208201529392505050565b600182019150610257565b604080518082019091526000808252602082015260405183518152602084015160208201528260408201526040826060836007600019fa6102cc57600080fd5b5092915050565b6040805181815260608181018352916000919060208201818036833750508451602095860151958301525060408101939093525090919050565b61031561082c565b50604080516080810182527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c28183019081527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed6060830152815281518083019092527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b82527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa60208381019190915281019190915290565b6000806040516020810187518152602088015160208201528651805160408301526020810151606083015250602087015180516080830152602081015160a083015250855160c0820152602086015160e08201528451805161010083015260208101516101208301525060208501518051610140830152602081015161016083015250602082610180836008600019fa61046657600080fd5b505115159695505050505050565b604080518082019091526000808252602082015281516040146104de5760405162461bcd60e51b815260206004820152601760248201527f496e76616c6964204731206279746573206c656e67746800000000000000000060448201526064015b60405180910390fd5b5060208181015160409283015183518085019094529083529082015290565b61050561082c565b81516080146105565760405162461bcd60e51b815260206004820152601760248201527f496e76616c6964204732206279746573206c656e67746800000000000000000060448201526064016104d5565b50602081810151604080840151606080860151608096870151845197880185528785019586529187019290925292855281518083019092528152808301919091529082015290565b60006100f87f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47806105d1856003836105ec565b6105dc906003610b77565b6105e69190610b8a565b90610637565b60006040516020810160208152602080820152602060408201528560608201528460808201528360a082015260208260c0836005600019fa61062d57600080fd5b5051949350505050565b6000610643838361079f565b600114610652575060006100f8565b82600003610662575060006100f8565b600482066003036106855761067e8360046001850104846105ec565b90506100f8565b600019820160005b600282066000036106a65760028204915060010161068d565b60025b6106b3818661079f565b600019146106c3576001016106a9565b60006106d68760026001870104886105ec565b905060006106e58886896105ec565b905060006106f484878a6105ec565b905084600080845b5060009050845b8382101561072c576001811461072c5761071f8160028e6105ec565b6001909201919050610703565b8160000361074657869a50505050505050505050506100f8565b6107598560018487030360020a8e6105ec565b92508b8384028161076c5761076c610b61565b0694508b8388028161078057610780610b61565b0696508b8587028161079457610794610b61565b0695508193506106fc565b6000806107b4846002600019860104856105ec565b90508015806107c35750806001145b156107cf5790506100f8565b6001830381036107e4576000199150506100f8565b60405162461bcd60e51b815260206004820152601d60248201527f4661696c656420746f2063616c63756c617465206c6567656e6472652e00000060448201526064016104d5565b6040805160808101825260009181018281526060820192909252908190815260200161086b604051806040016040528060008152602001600081525090565b905290565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156108a9576108a9610870565b60405290565b600082601f8301126108c057600080fd5b813567ffffffffffffffff808211156108db576108db610870565b604051601f8301601f19908116603f0116810190828211818310171561090357610903610870565b8160405283815286602085880101111561091c57600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561094f57600080fd5b823567ffffffffffffffff81111561096657600080fd5b610972858286016108af565b95602094909401359450505050565b60005b8381101561099c578181015183820152602001610984565b50506000910152565b60208152600082518060208401526109c4816040850160208701610981565b601f01601f19169190910160400192915050565b6000604082840312156109ea57600080fd5b6109f2610886565b9050813581526020820135602082015292915050565b6000806000838503610100811215610a1f57600080fd5b6080811215610a2d57600080fd5b50610a36610886565b610a4086866109d8565b8152610a4f86604087016109d8565b60208201529250610a6385608086016109d8565b9150610a728560c086016109d8565b90509250925092565b600080600060608486031215610a9057600080fd5b833567ffffffffffffffff80821115610aa857600080fd5b610ab4878388016108af565b94506020860135915080821115610aca57600080fd5b610ad6878388016108af565b93506040860135915080821115610aec57600080fd5b50610af9868287016108af565b9150509250925092565b634e487b7160e01b600052601160045260246000fd5b818103818111156100f8576100f8610b03565b60008251610b3e818460208701610981565b9190910192915050565b600060208284031215610b5a57600080fd5b5051919050565b634e487b7160e01b600052601260045260246000fd5b808201808211156100f8576100f8610b03565b600082610ba757634e487b7160e01b600052601260045260246000fd5b50069056fea2646970667358221220829ab3657ffe2f8b9548cdb9e0e6a52b8b9f02bddf27516291dd0366d3df603864736f6c63430008110033", + "linkReferences": {}, + "deployedLinkReferences": {}, + "devdoc": { + "details": "Library for verification of 2-pairing-check BLS signatures, including basic, aggregated, or reconstructed threshold BLS signatures, generated using the AltBn128 curve.", + "kind": "dev", + "methods": { + "sign(bytes,uint256)": { + "details": "Creates a signature over message using the provided secret key." + }, + "verify(bytes,bytes,bytes)": { + "details": "Verify performs the pairing operation to check if the signature is correct for the provided message and the corresponding public key. Public key must be a valid point on G2 curve in an uncompressed format. Message must be a valid point on G1 curve in an uncompressed format. Signature must be a valid point on G1 curve in an uncompressed format." + }, + "verifyBytes(bytes,bytes,bytes)": { + "details": "Wraps the functionality of BLS.verify, but hashes a message to a point on G1 and marshal to bytes first to allow raw bytes verification." + } + }, + "title": "BLS signatures verification", + "version": 1 + }, + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct AltBn128.gfP2\",\"name\":\"x\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct AltBn128.gfP2\",\"name\":\"y\",\"type\":\"tuple\"}],\"internalType\":\"struct AltBn128.G2Point\",\"name\":\"publicKey\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct AltBn128.G1Point\",\"name\":\"message\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct AltBn128.G1Point\",\"name\":\"signature\",\"type\":\"tuple\"}],\"name\":\"_verify\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"secretKey\",\"type\":\"uint256\"}],\"name\":\"sign\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"verifyBytes\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Library for verification of 2-pairing-check BLS signatures, including basic, aggregated, or reconstructed threshold BLS signatures, generated using the AltBn128 curve.\",\"kind\":\"dev\",\"methods\":{\"sign(bytes,uint256)\":{\"details\":\"Creates a signature over message using the provided secret key.\"},\"verify(bytes,bytes,bytes)\":{\"details\":\"Verify performs the pairing operation to check if the signature is correct for the provided message and the corresponding public key. Public key must be a valid point on G2 curve in an uncompressed format. Message must be a valid point on G1 curve in an uncompressed format. Signature must be a valid point on G1 curve in an uncompressed format.\"},\"verifyBytes(bytes,bytes,bytes)\":{\"details\":\"Wraps the functionality of BLS.verify, but hashes a message to a point on G1 and marshal to bytes first to allow raw bytes verification.\"}},\"title\":\"BLS signatures verification\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/libraries/BLS.sol\":\"BLS\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/libraries/AltBn128.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./ModUtils.sol\\\";\\n\\n/// @title Operations on alt_bn128\\n/// @dev Implementations of common elliptic curve operations on Ethereum's\\n/// (poorly named) alt_bn128 curve. Whenever possible, use post-Byzantium\\n/// pre-compiled contracts to offset gas costs. Note that these\\n/// pre-compiles might not be available on all (eg private) chains.\\nlibrary AltBn128 {\\n using ModUtils for uint256;\\n\\n // G1Point implements a point in G1 group.\\n struct G1Point {\\n uint256 x;\\n uint256 y;\\n }\\n\\n // gfP2 implements a field of size p\\u00b2 as a quadratic extension of the base\\n // field.\\n struct gfP2 {\\n uint256 x;\\n uint256 y;\\n }\\n\\n // G2Point implements a point in G2 group.\\n struct G2Point {\\n gfP2 x;\\n gfP2 y;\\n }\\n\\n // p is a prime over which we form a basic field\\n // Taken from go-ethereum/crypto/bn256/cloudflare/constants.go\\n uint256 internal constant p =\\n 21888242871839275222246405745257275088696311157297823662689037894645226208583;\\n\\n /// @dev Gets generator of G1 group.\\n /// Taken from go-ethereum/crypto/bn256/cloudflare/curve.go\\n uint256 internal constant g1x = 1;\\n uint256 internal constant g1y = 2;\\n\\n /// @dev Gets generator of G2 group.\\n /// Taken from go-ethereum/crypto/bn256/cloudflare/twist.go\\n uint256 internal constant g2xx =\\n 11559732032986387107991004021392285783925812861821192530917403151452391805634;\\n uint256 internal constant g2xy =\\n 10857046999023057135944570762232829481370756359578518086990519993285655852781;\\n uint256 internal constant g2yx =\\n 4082367875863433681332203403145435568316851327593401208105741076214120093531;\\n uint256 internal constant g2yy =\\n 8495653923123431417604973247489272438418190587263600148770280649306958101930;\\n\\n /// @dev Gets twist curve B constant.\\n /// Taken from go-ethereum/crypto/bn256/cloudflare/twist.go\\n uint256 internal constant twistBx =\\n 266929791119991161246907387137283842545076965332900288569378510910307636690;\\n uint256 internal constant twistBy =\\n 19485874751759354771024239261021720505790618469301721065564631296452457478373;\\n\\n /// @dev Gets root of the point where x and y are equal.\\n uint256 internal constant hexRootX =\\n 21573744529824266246521972077326577680729363968861965890554801909984373949499;\\n uint256 internal constant hexRootY =\\n 16854739155576650954933913186877292401521110422362946064090026408937773542853;\\n\\n /// @dev g1YFromX computes a Y value for a G1 point based on an X value.\\n /// This computation is simply evaluating the curve equation for Y on a\\n /// given X, and allows a point on the curve to be represented by just\\n /// an X value + a sign bit.\\n function g1YFromX(uint256 x) internal view returns (uint256) {\\n return ((x.modExp(3, p) + 3) % p).modSqrt(p);\\n }\\n\\n /// @dev Hash a byte array message, m, and map it deterministically to a\\n /// point on G1. Note that this approach was chosen for its simplicity\\n /// and lower gas cost on the EVM, rather than good distribution of\\n /// points on G1.\\n function g1HashToPoint(bytes memory m)\\n internal\\n view\\n returns (G1Point memory)\\n {\\n unchecked {\\n bytes32 h = sha256(m);\\n uint256 x = uint256(h) % p;\\n uint256 y;\\n\\n while (true) {\\n y = g1YFromX(x);\\n if (y > 0) {\\n return G1Point(x, y);\\n }\\n x += 1;\\n }\\n }\\n }\\n\\n /// @dev Decompress a point on G1 from a single uint256.\\n function g1Decompress(bytes32 m) internal view returns (G1Point memory) {\\n unchecked {\\n bytes32 mX = bytes32(0);\\n bytes1 leadX = m[0] & 0x7f;\\n // slither-disable-next-line incorrect-shift\\n uint256 mask = 0xff << (31 * 8);\\n mX = (m & ~bytes32(mask)) | (leadX >> 0);\\n\\n uint256 x = uint256(mX);\\n uint256 y = g1YFromX(x);\\n\\n if (parity(y) != (m[0] & 0x80) >> 7) {\\n y = p - y;\\n }\\n\\n require(\\n isG1PointOnCurve(G1Point(x, y)),\\n \\\"Malformed bn256.G1 point.\\\"\\n );\\n\\n return G1Point(x, y);\\n }\\n }\\n\\n /// @dev Wraps the point addition pre-compile introduced in Byzantium.\\n /// Returns the sum of two points on G1. Revert if the provided points\\n /// are not on the curve.\\n function g1Add(G1Point memory a, G1Point memory b)\\n internal\\n view\\n returns (G1Point memory c)\\n {\\n assembly {\\n let arg := mload(0x40)\\n mstore(arg, mload(a))\\n mstore(add(arg, 0x20), mload(add(a, 0x20)))\\n mstore(add(arg, 0x40), mload(b))\\n mstore(add(arg, 0x60), mload(add(b, 0x20)))\\n // 0x60 is the ECADD precompile address\\n if iszero(staticcall(not(0), 0x06, arg, 0x80, c, 0x40)) {\\n revert(0, 0)\\n }\\n }\\n }\\n\\n /// @dev Returns true if G1 point is on the curve.\\n function isG1PointOnCurve(G1Point memory point)\\n internal\\n view\\n returns (bool)\\n {\\n return point.y.modExp(2, p) == (point.x.modExp(3, p) + 3) % p;\\n }\\n\\n /// @dev Wraps the scalar point multiplication pre-compile introduced in\\n /// Byzantium. The result of a point from G1 multiplied by a scalar\\n /// should match the point added to itself the same number of times.\\n /// Revert if the provided point isn't on the curve.\\n function scalarMultiply(G1Point memory p_1, uint256 scalar)\\n internal\\n view\\n returns (G1Point memory p_2)\\n {\\n assembly {\\n let arg := mload(0x40)\\n mstore(arg, mload(p_1))\\n mstore(add(arg, 0x20), mload(add(p_1, 0x20)))\\n mstore(add(arg, 0x40), scalar)\\n // 0x07 is the ECMUL precompile address\\n if iszero(staticcall(not(0), 0x07, arg, 0x60, p_2, 0x40)) {\\n revert(0, 0)\\n }\\n }\\n }\\n\\n /// @dev Wraps the pairing check pre-compile introduced in Byzantium.\\n /// Returns the result of a pairing check of 2 pairs\\n /// (G1 p1, G2 p2) (G1 p3, G2 p4)\\n function pairing(\\n G1Point memory p1,\\n G2Point memory p2,\\n G1Point memory p3,\\n G2Point memory p4\\n ) internal view returns (bool result) {\\n uint256 _c;\\n assembly {\\n let c := mload(0x40)\\n let arg := add(c, 0x20)\\n\\n mstore(arg, mload(p1))\\n mstore(add(arg, 0x20), mload(add(p1, 0x20)))\\n\\n let p2x := mload(p2)\\n mstore(add(arg, 0x40), mload(p2x))\\n mstore(add(arg, 0x60), mload(add(p2x, 0x20)))\\n\\n let p2y := mload(add(p2, 0x20))\\n mstore(add(arg, 0x80), mload(p2y))\\n mstore(add(arg, 0xa0), mload(add(p2y, 0x20)))\\n\\n mstore(add(arg, 0xc0), mload(p3))\\n mstore(add(arg, 0xe0), mload(add(p3, 0x20)))\\n\\n let p4x := mload(p4)\\n mstore(add(arg, 0x100), mload(p4x))\\n mstore(add(arg, 0x120), mload(add(p4x, 0x20)))\\n\\n let p4y := mload(add(p4, 0x20))\\n mstore(add(arg, 0x140), mload(p4y))\\n mstore(add(arg, 0x160), mload(add(p4y, 0x20)))\\n\\n // call(gasLimit, to, value, inputOffset, inputSize, outputOffset, outputSize)\\n if iszero(staticcall(not(0), 0x08, arg, 0x180, c, 0x20)) {\\n revert(0, 0)\\n }\\n _c := mload(c)\\n }\\n return _c != 0;\\n }\\n\\n function getP() internal pure returns (uint256) {\\n return p;\\n }\\n\\n function g1() internal pure returns (G1Point memory) {\\n return G1Point(g1x, g1y);\\n }\\n\\n function g2() internal pure returns (G2Point memory) {\\n return G2Point(gfP2(g2xx, g2xy), gfP2(g2yx, g2yy));\\n }\\n\\n /// @dev g2YFromX computes a Y value for a G2 point based on an X value.\\n /// This computation is simply evaluating the curve equation for Y on a\\n /// given X, and allows a point on the curve to be represented by just\\n /// an X value + a sign bit.\\n function g2YFromX(gfP2 memory _x) internal pure returns (gfP2 memory y) {\\n (uint256 xx, uint256 xy) = _gfP2CubeAddTwistB(_x.x, _x.y);\\n\\n // Using formula y = x ^ (p^2 + 15) / 32 from\\n // https://github.com/ethereum/beacon_chain/blob/master/beacon_chain/utils/bls.py\\n // (p^2 + 15) / 32 results into a big 512bit value, so breaking it to two uint256 as (a * a + b)\\n uint256 a = 3869331240733915743250440106392954448556483137451914450067252501901456824595;\\n uint256 b = 146360017852723390495514512480590656176144969185739259173561346299185050597;\\n\\n (uint256 xbx, uint256 xby) = _gfP2Pow(xx, xy, b);\\n (uint256 yax, uint256 yay) = _gfP2Pow(xx, xy, a);\\n (uint256 ya2x, uint256 ya2y) = _gfP2Pow(yax, yay, a);\\n (y.x, y.y) = _gfP2Multiply(ya2x, ya2y, xbx, xby);\\n\\n // Multiply y by hexRoot constant to find correct y.\\n while (!_g2X2y(xx, xy, y.x, y.y)) {\\n (y.x, y.y) = _gfP2Multiply(y.x, y.y, hexRootX, hexRootY);\\n }\\n }\\n\\n /// @dev Compress a point on G1 to a single uint256 for serialization.\\n function g1Compress(G1Point memory point) internal pure returns (bytes32) {\\n bytes32 m = bytes32(point.x);\\n\\n bytes1 leadM = m[0] | (parity(point.y) << 7);\\n // slither-disable-next-line incorrect-shift\\n uint256 mask = 0xff << (31 * 8);\\n m = (m & ~bytes32(mask)) | (leadM >> 0);\\n\\n return m;\\n }\\n\\n /// @dev Compress a point on G2 to a pair of uint256 for serialization.\\n function g2Compress(G2Point memory point)\\n internal\\n pure\\n returns (bytes memory)\\n {\\n bytes32 m = bytes32(point.x.x);\\n\\n bytes1 leadM = m[0] | (parity(point.y.x) << 7);\\n // slither-disable-next-line incorrect-shift\\n uint256 mask = 0xff << (31 * 8);\\n m = (m & ~bytes32(mask)) | (leadM >> 0);\\n\\n return abi.encodePacked(m, bytes32(point.x.y));\\n }\\n\\n /// @dev Unmarshals a point on G1 from bytes in an uncompressed form.\\n function g1Unmarshal(bytes memory m)\\n internal\\n pure\\n returns (G1Point memory)\\n {\\n require(m.length == 64, \\\"Invalid G1 bytes length\\\");\\n\\n bytes32 x;\\n bytes32 y;\\n\\n assembly {\\n x := mload(add(m, 0x20))\\n y := mload(add(m, 0x40))\\n }\\n\\n return G1Point(uint256(x), uint256(y));\\n }\\n\\n /// @dev Marshals a point on G1 to bytes form.\\n function g1Marshal(G1Point memory point)\\n internal\\n pure\\n returns (bytes memory)\\n {\\n bytes memory m = new bytes(64);\\n bytes32 x = bytes32(point.x);\\n bytes32 y = bytes32(point.y);\\n\\n assembly {\\n mstore(add(m, 32), x)\\n mstore(add(m, 64), y)\\n }\\n\\n return m;\\n }\\n\\n /// @dev Unmarshals a point on G2 from bytes in an uncompressed form.\\n function g2Unmarshal(bytes memory m)\\n internal\\n pure\\n returns (G2Point memory)\\n {\\n require(m.length == 128, \\\"Invalid G2 bytes length\\\");\\n\\n uint256 xx;\\n uint256 xy;\\n uint256 yx;\\n uint256 yy;\\n\\n assembly {\\n xx := mload(add(m, 0x20))\\n xy := mload(add(m, 0x40))\\n yx := mload(add(m, 0x60))\\n yy := mload(add(m, 0x80))\\n }\\n\\n return G2Point(gfP2(xx, xy), gfP2(yx, yy));\\n }\\n\\n /// @dev Decompress a point on G2 from a pair of uint256.\\n function g2Decompress(bytes memory m)\\n internal\\n pure\\n returns (G2Point memory)\\n {\\n require(m.length == 64, \\\"Invalid G2 compressed bytes length\\\");\\n\\n bytes32 x1;\\n bytes32 x2;\\n uint256 temp;\\n\\n // Extract two bytes32 from bytes array\\n assembly {\\n temp := add(m, 32)\\n x1 := mload(temp)\\n temp := add(m, 64)\\n x2 := mload(temp)\\n }\\n\\n bytes32 mX = bytes32(0);\\n bytes1 leadX = x1[0] & 0x7f;\\n // slither-disable-next-line incorrect-shift\\n uint256 mask = 0xff << (31 * 8);\\n mX = (x1 & ~bytes32(mask)) | (leadX >> 0);\\n\\n gfP2 memory x = gfP2(uint256(mX), uint256(x2));\\n gfP2 memory y = g2YFromX(x);\\n\\n if (parity(y.x) != (m[0] & 0x80) >> 7) {\\n y.x = p - y.x;\\n y.y = p - y.y;\\n }\\n\\n return G2Point(x, y);\\n }\\n\\n /// @dev Returns the sum of two gfP2 field elements.\\n function gfP2Add(gfP2 memory a, gfP2 memory b)\\n internal\\n pure\\n returns (gfP2 memory)\\n {\\n return gfP2(addmod(a.x, b.x, p), addmod(a.y, b.y, p));\\n }\\n\\n /// @dev Returns multiplication of two gfP2 field elements.\\n function gfP2Multiply(gfP2 memory a, gfP2 memory b)\\n internal\\n pure\\n returns (gfP2 memory)\\n {\\n return\\n gfP2(\\n addmod(mulmod(a.x, b.y, p), mulmod(b.x, a.y, p), p),\\n addmod(mulmod(a.y, b.y, p), p - mulmod(a.x, b.x, p), p)\\n );\\n }\\n\\n /// @dev Returns gfP2 element to the power of the provided exponent.\\n function gfP2Pow(gfP2 memory _a, uint256 _exp)\\n internal\\n pure\\n returns (gfP2 memory result)\\n {\\n (uint256 x, uint256 y) = _gfP2Pow(_a.x, _a.y, _exp);\\n return gfP2(x, y);\\n }\\n\\n function gfP2Square(gfP2 memory a) internal pure returns (gfP2 memory) {\\n return gfP2Multiply(a, a);\\n }\\n\\n function gfP2Cube(gfP2 memory a) internal pure returns (gfP2 memory) {\\n return gfP2Multiply(a, gfP2Square(a));\\n }\\n\\n function gfP2CubeAddTwistB(gfP2 memory a)\\n internal\\n pure\\n returns (gfP2 memory)\\n {\\n (uint256 x, uint256 y) = _gfP2CubeAddTwistB(a.x, a.y);\\n return gfP2(x, y);\\n }\\n\\n /// @dev Returns true if G2 point's y^2 equals x.\\n function g2X2y(gfP2 memory x, gfP2 memory y) internal pure returns (bool) {\\n gfP2 memory y2;\\n y2 = gfP2Square(y);\\n\\n return (y2.x == x.x && y2.y == x.y);\\n }\\n\\n /// @dev Returns true if G2 point is on the curve.\\n function isG2PointOnCurve(G2Point memory point)\\n internal\\n pure\\n returns (bool)\\n {\\n (uint256 y2x, uint256 y2y) = _gfP2Square(point.y.x, point.y.y);\\n (uint256 x3x, uint256 x3y) = _gfP2CubeAddTwistB(point.x.x, point.x.y);\\n\\n return (y2x == x3x && y2y == x3y);\\n }\\n\\n function twistB() private pure returns (gfP2 memory) {\\n return gfP2(twistBx, twistBy);\\n }\\n\\n function hexRoot() private pure returns (gfP2 memory) {\\n return gfP2(hexRootX, hexRootY);\\n }\\n\\n /// @dev Calculates whether the provided number is even or odd.\\n /// @return 0x01 if y is an even number and 0x00 if it's odd.\\n function parity(uint256 value) private pure returns (bytes1) {\\n return bytes32(value)[31] & 0x01;\\n }\\n\\n function _gfP2Add(\\n uint256 ax,\\n uint256 ay,\\n uint256 bx,\\n uint256 by\\n ) private pure returns (uint256 x, uint256 y) {\\n x = addmod(ax, bx, p);\\n y = addmod(ay, by, p);\\n }\\n\\n function _gfP2Multiply(\\n uint256 ax,\\n uint256 ay,\\n uint256 bx,\\n uint256 by\\n ) private pure returns (uint256 x, uint256 y) {\\n x = addmod(mulmod(ax, by, p), mulmod(bx, ay, p), p);\\n y = addmod(mulmod(ay, by, p), p - mulmod(ax, bx, p), p);\\n }\\n\\n function _gfP2CubeAddTwistB(uint256 ax, uint256 ay)\\n private\\n pure\\n returns (uint256 x, uint256 y)\\n {\\n (uint256 a3x, uint256 a3y) = _gfP2Cube(ax, ay);\\n return _gfP2Add(a3x, a3y, twistBx, twistBy);\\n }\\n\\n function _gfP2Pow(\\n uint256 _ax,\\n uint256 _ay,\\n uint256 _exp\\n ) private pure returns (uint256 x, uint256 y) {\\n uint256 exp = _exp;\\n x = 0;\\n y = 1;\\n uint256 ax = _ax;\\n uint256 ay = _ay;\\n\\n // Reduce exp dividing by 2 gradually to 0 while computing final\\n // result only when exp is an odd number.\\n while (exp > 0) {\\n if (parity(exp) == 0x01) {\\n (x, y) = _gfP2Multiply(x, y, ax, ay);\\n }\\n\\n unchecked {\\n exp = exp / 2;\\n }\\n (ax, ay) = _gfP2Multiply(ax, ay, ax, ay);\\n }\\n }\\n\\n function _gfP2Square(uint256 _ax, uint256 _ay)\\n private\\n pure\\n returns (uint256 x, uint256 y)\\n {\\n return _gfP2Multiply(_ax, _ay, _ax, _ay);\\n }\\n\\n function _gfP2Cube(uint256 _ax, uint256 _ay)\\n private\\n pure\\n returns (uint256 x, uint256 y)\\n {\\n (uint256 _bx, uint256 _by) = _gfP2Square(_ax, _ay);\\n return _gfP2Multiply(_ax, _ay, _bx, _by);\\n }\\n\\n function _g2X2y(\\n uint256 xx,\\n uint256 xy,\\n uint256 yx,\\n uint256 yy\\n ) private pure returns (bool) {\\n (uint256 y2x, uint256 y2y) = _gfP2Square(yx, yy);\\n\\n return (y2x == xx && y2y == xy);\\n }\\n}\\n\",\"keccak256\":\"0x8a100028820ff5c424f4bb780fbedec1da2576fbc6d5aa4e7309d986b730a319\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BLS.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./AltBn128.sol\\\";\\n\\n/// @title BLS signatures verification\\n/// @dev Library for verification of 2-pairing-check BLS signatures, including\\n/// basic, aggregated, or reconstructed threshold BLS signatures, generated\\n/// using the AltBn128 curve.\\nlibrary BLS {\\n /// @dev Creates a signature over message using the provided secret key.\\n function sign(bytes memory message, uint256 secretKey)\\n external\\n view\\n returns (bytes memory)\\n {\\n AltBn128.G1Point memory p_1 = AltBn128.g1HashToPoint(message);\\n AltBn128.G1Point memory p_2 = AltBn128.scalarMultiply(p_1, secretKey);\\n\\n return AltBn128.g1Marshal(p_2);\\n }\\n\\n /// @dev Wraps the functionality of BLS.verify, but hashes a message to\\n /// a point on G1 and marshal to bytes first to allow raw bytes\\n /// verification.\\n function verifyBytes(\\n bytes memory publicKey,\\n bytes memory message,\\n bytes memory signature\\n ) external view returns (bool) {\\n AltBn128.G1Point memory point = AltBn128.g1HashToPoint(message);\\n bytes memory messageAsPoint = AltBn128.g1Marshal(point);\\n\\n return verify(publicKey, messageAsPoint, signature);\\n }\\n\\n /// @dev Verify performs the pairing operation to check if the signature\\n /// is correct for the provided message and the corresponding public\\n /// key. Public key must be a valid point on G2 curve in an\\n /// uncompressed format. Message must be a valid point on G1 curve in\\n /// an uncompressed format. Signature must be a valid point on G1\\n /// curve in an uncompressed format.\\n function verify(\\n bytes memory publicKey,\\n bytes memory message,\\n bytes memory signature\\n ) public view returns (bool) {\\n AltBn128.G1Point memory _signature = AltBn128.g1Unmarshal(signature);\\n\\n return\\n _verify(\\n AltBn128.g2Unmarshal(publicKey),\\n AltBn128.g1Unmarshal(message),\\n _signature\\n );\\n }\\n\\n function _verify(\\n AltBn128.G2Point memory publicKey,\\n AltBn128.G1Point memory message,\\n AltBn128.G1Point memory signature\\n ) public view returns (bool) {\\n return\\n AltBn128.pairing(\\n AltBn128.G1Point(signature.x, AltBn128.getP() - signature.y),\\n AltBn128.g2(),\\n message,\\n publicKey\\n );\\n }\\n}\\n\",\"keccak256\":\"0x08c7e739c63c31f5f45fb390695eca9e98a9525589ace41526f25060f46e43d4\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/ModUtils.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\nlibrary ModUtils {\\n /// @dev Wraps the modular exponent pre-compile introduced in Byzantium.\\n /// Returns base^exponent mod p.\\n function modExp(\\n uint256 base,\\n uint256 exponent,\\n uint256 p\\n ) internal view returns (uint256 o) {\\n assembly {\\n // Args for the precompile: [ \\n // ]\\n let output := mload(0x40)\\n let args := add(output, 0x20)\\n mstore(args, 0x20)\\n mstore(add(args, 0x20), 0x20)\\n mstore(add(args, 0x40), 0x20)\\n mstore(add(args, 0x60), base)\\n mstore(add(args, 0x80), exponent)\\n mstore(add(args, 0xa0), p)\\n\\n // 0x05 is the modular exponent contract address\\n if iszero(staticcall(not(0), 0x05, args, 0xc0, output, 0x20)) {\\n revert(0, 0)\\n }\\n o := mload(output)\\n }\\n }\\n\\n /// @dev Calculates and returns the square root of a mod p if such a square\\n /// root exists. The modulus p must be an odd prime. If a square root\\n /// does not exist, function returns 0.\\n function modSqrt(uint256 a, uint256 p) internal view returns (uint256) {\\n unchecked {\\n if (legendre(a, p) != 1) {\\n return 0;\\n }\\n\\n if (a == 0) {\\n return 0;\\n }\\n\\n if (p % 4 == 3) {\\n return modExp(a, (p + 1) / 4, p);\\n }\\n\\n uint256 s = p - 1;\\n uint256 e = 0;\\n\\n while (s % 2 == 0) {\\n s = s / 2;\\n e = e + 1;\\n }\\n\\n // Note the smaller int- finding n with Legendre symbol or -1\\n // should be quick\\n uint256 n = 2;\\n while (legendre(n, p) != -1) {\\n n = n + 1;\\n }\\n\\n uint256 x = modExp(a, (s + 1) / 2, p);\\n uint256 b = modExp(a, s, p);\\n uint256 g = modExp(n, s, p);\\n uint256 r = e;\\n uint256 gs = 0;\\n uint256 m = 0;\\n uint256 t = b;\\n\\n while (true) {\\n t = b;\\n m = 0;\\n\\n for (m = 0; m < r; m++) {\\n if (t == 1) {\\n break;\\n }\\n t = modExp(t, 2, p);\\n }\\n\\n if (m == 0) {\\n return x;\\n }\\n\\n gs = modExp(g, uint256(2)**(r - m - 1), p);\\n g = (gs * gs) % p;\\n x = (x * gs) % p;\\n b = (b * g) % p;\\n r = m;\\n }\\n }\\n }\\n\\n /// @dev Calculates the Legendre symbol of the given a mod p.\\n /// @return Returns 1 if a is a quadratic residue mod p, -1 if it is\\n /// a non-quadratic residue, and 0 if a is 0.\\n function legendre(uint256 a, uint256 p) internal view returns (int256) {\\n unchecked {\\n uint256 raised = modExp(a, (p - 1) / uint256(2), p);\\n\\n if (raised == 0 || raised == 1) {\\n return int256(raised);\\n } else if (raised == p - 1) {\\n return -1;\\n }\\n\\n require(false, \\\"Failed to calculate legendre.\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x57bb4ab4f257715c6daafa1a4e4bc6dd9edfe45afca797e5b8e98db577826505\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "storageLayout": { + "storage": [], + "types": null + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + } +} diff --git a/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/libraries/BeaconAuthorization.sol/BeaconAuthorization.json b/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/libraries/BeaconAuthorization.sol/BeaconAuthorization.json new file mode 100644 index 0000000000..9091f82cfa --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/libraries/BeaconAuthorization.sol/BeaconAuthorization.json @@ -0,0 +1,258 @@ +{ + "contractName": "BeaconAuthorization", + "sourceName": "contracts/libraries/BeaconAuthorization.sol", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "AuthorizationDecreaseApproved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "decreasingAt", + "type": "uint64" + } + ], + "name": "AuthorizationDecreaseRequested", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + } + ], + "name": "AuthorizationIncreased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + } + ], + "name": "InvoluntaryAuthorizationDecreaseFailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "OperatorJoinedSortitionPool", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "OperatorRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "OperatorStatusUpdated", + "type": "event" + } + ], + "bytecode": "0x61167561003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100d85760003560e01c8063b86b341e11610096578063d563485c11610070578063d563485c14610233578063db82504e14610253578063ee7ae2a914610273578063f4dbcff41461028657600080fd5b8063b86b341e146101b2578063bf865212146101dd578063c6e1c8391461021357600080fd5b80624f4ac7146100dd578063251db5981461010d57806345e592941461012f578063475592631461014f578063520502841461016f578063520c3d3114610192575b600080fd5b6100f06100eb3660046112f2565b6102f1565b6040516001600160401b0390911681526020015b60405180910390f35b81801561011957600080fd5b5061012d610128366004611322565b61038b565b005b81801561013b57600080fd5b5061012d61014a366004611379565b6105d1565b81801561015b57600080fd5b5061012d61016a3660046112f2565b61073d565b61018261017d3660046113f2565b6109a0565b6040519015158152602001610104565b81801561019e57600080fd5b5061012d6101ad366004611322565b610b16565b6101c56101c0366004611322565b610cf0565b6040516001600160601b039091168152602001610104565b6101c56101eb3660046112f2565b6001600160a01b0316600090815260039190910160205260409020546001600160601b031690565b81801561021f57600080fd5b5061012d61022e3660046113f2565b610d23565b81801561023f57600080fd5b5061012d61024e366004611445565b610f02565b81801561025f57600080fd5b5061012d61026e366004611445565b610fcf565b6101c561028136600461148d565b61120a565b81801561029257600080fd5b5061012d6102a13660046114e1565b83546001600160601b03939093166001600160a01b031990931692909217600160601b6001600160401b03928316021767ffffffffffffffff60a01b1916600160a01b9290911691909102179055565b6001600160a01b03811660009081526003830160205260408120805467fffffffffffffffe19600160601b9091046001600160401b03160161033d576001600160401b03915050610385565b805442906001600160401b03600160601b90910481169082161161037d578154610378908290600160601b90046001600160401b0316611546565b610380565b60005b925050505b92915050565b6001600160a01b038116600090815260038401602052604090208054600160601b90046001600160401b03166104145760405162461bcd60e51b8152602060048201526024808201527f417574686f72697a6174696f6e206465637265617365206e6f742072657175656044820152631cdd195960e21b60648201526084015b60405180910390fd5b805467fffffffffffffffe19600160601b9091046001600160401b0316016104935760405162461bcd60e51b815260206004820152602c60248201527f417574686f72697a6174696f6e2064656372656173652072657175657374206e60448201526b1bdd081858dd1a5d985d195960a21b606482015260840161040b565b8054600160601b90046001600160401b03164210156105045760405162461bcd60e51b815260206004820152602760248201527f417574686f72697a6174696f6e2064656372656173652064656c6179206e6f74604482015266081c185cdcd95960ca1b606482015260840161040b565b6040516001600160a01b038316907f50270a522c2fef97b6b7385c2aa4a4518adda681530e0a1fe9f5e840f6f2cd9d90600090a2604051633af0572d60e11b81526001600160a01b0383811660048301528416906375e0ae5a906024016020604051808303816000875af1158015610580573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a4919061156d565b50506001600160a01b031660009081526003909201602052506040902080546001600160a01b0319169055565b6001600160a01b03808416600090815260018801602052604090205416806105f95750610735565b6040516307b8c36760e51b81526001600160a01b03828116600483015286169063f7186ce090602401602060405180830381865afa15801561063f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106639190611591565b1561073357846001600160a01b031663a4e2d6346040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ca9190611591565b1561072757604080516001600160601b038086168252841660208201526001600160a01b0380841692908716917f1b09380d63e78fd72c1d79a805a7e2dfadf02b22418e24bebff51376b7df33b0910160405180910390a3610733565b61073387878784610d23565b505b505050505050565b336001600160a01b0382166107945760405162461bcd60e51b815260206004820181905260248201527f4f70657261746f722063616e206e6f74206265207a65726f2061646472657373604482015260640161040b565b6001600160a01b03818116600090815260018501602052604090205416156108145760405162461bcd60e51b815260206004820152602d60248201527f4f70657261746f7220616c72656164792073657420666f72207468652073746160448201526c35b4b73390383937bb34b232b960991b606482015260840161040b565b6001600160a01b038281166000908152600285016020526040902054161561087e5760405162461bcd60e51b815260206004820152601f60248201527f4f70657261746f72206164647265737320616c726561647920696e2075736500604482015260640161040b565b6001600160a01b038116600090815260038401602052604090208054600160601b90046001600160401b0316156109115760405162461bcd60e51b815260206004820152603160248201527f546865726520697320612070656e64696e6720617574686f72697a6174696f6e60448201527008191958dc99585cd9481c995c5d595cdd607a1b606482015260840161040b565b826001600160a01b0316826001600160a01b03167fa453db612af59e5521d6ab9284dc3e2d06af286eb1b1b7b771fce4716c19f2c160405160405180910390a3506001600160a01b03908116600081815260018501602090815260408083208054959096166001600160a01b031995861681179096559482526002909501909452919092208054909216179055565b6001600160a01b038082166000908152600286016020526040812054909116806109dc5760405162461bcd60e51b815260040161040b906115b3565b6001600160a01b038116600090815260038701602052604081208054909190610a13908990899086906001600160601b031661120a565b6040516307b8c36760e51b81526001600160a01b0387811660048301529192509087169063f7186ce090602401602060405180830381865afa158015610a5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a819190611591565b610a99576001600160601b0316159250610b0e915050565b6040516304de824f60e41b81526001600160a01b03871690634de824f090610ac790889085906004016115dd565b602060405180830381865afa158015610ae4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b089190611591565b93505050505b949350505050565b3360008181526002850160205260409020546001600160a01b031680610b4e5760405162461bcd60e51b815260040161040b906115b3565b6001600160a01b038116600090815260038601602052604081208054909190610b85908890889086906001600160601b031661120a565b9050806001600160601b0316600003610be05760405162461bcd60e51b815260206004820152601f60248201527f417574686f72697a6174696f6e2062656c6f7720746865206d696e696d756d00604482015260640161040b565b836001600160a01b0316836001600160a01b03167f5075aaa89894a888eb2cac81a27320c60855febb0cf1706b66bdc754e640d43360405160405180910390a3604051630483483160e31b81526001600160a01b0386169063241a418890610c4e90879085906004016115dd565b600060405180830381600087803b158015610c6857600080fd5b505af1158015610c7c573d6000803e3d6000fd5b5050835467fffffffffffffffe19600160601b9091046001600160401b03160191506107339050578654610cc090600160601b90046001600160401b0316426115ff565b82546001600160401b0391909116600160601b0267ffffffffffffffff60601b1990911617825550505050505050565b6001600160a01b0381166000908152600384016020526040812054610b0e908590859085906001600160601b031661120a565b6001600160a01b0380821660009081526002860160205260409020541680610d5d5760405162461bcd60e51b815260040161040b906115b3565b6001600160a01b03808216600081815260038801602052604080822090519093861692917f1231fe5ee649a593b524a494cd53146a196380a872115a0d0fe16c0735afdf2691a36040516307b8c36760e51b81526001600160a01b03848116600483015285169063f7186ce090602401602060405180830381865afa158015610dea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e0e9190611591565b15610e95578054600090610e30908890889086906001600160601b031661120a565b60405163dc7520c560e01b81529091506001600160a01b0386169063dc7520c590610e6190879085906004016115dd565b600060405180830381600087803b158015610e7b57600080fd5b505af1158015610e8f573d6000803e3d6000fd5b50505050505b805467fffffffffffffffe19600160601b9091046001600160401b031601610735578554610ed390600160601b90046001600160401b0316426115ff565b81546001600160401b0391909116600160601b0267ffffffffffffffff60601b19909116178155505050505050565b83546001600160601b039081169082161015610f605760405162461bcd60e51b815260206004820152601f60248201527f417574686f72697a6174696f6e2062656c6f7720746865206d696e696d756d00604482015260640161040b565b6001600160a01b0383811660008181526001870160209081526040918290205482516001600160601b03888116825287169281019290925282519416938493927f87f9f9f59204f53d57a89a817c6083a17979cd0531791c91e18551a56e3cfdd7928290030190a35050505050565b6001600160601b0381161580610ff3575083546001600160601b0390811690821610155b61105d5760405162461bcd60e51b815260206004820152603560248201527f417574686f72697a6174696f6e20616d6f756e742073686f756c642062652030604482015274206f722061626f766520746865206d696e696d756d60581b606482015260840161040b565b6001600160a01b0380841660009081526001860160205260408120549091169081611089575042611093565b506001600160401b035b600061109f848661161f565b6001600160a01b03871660009081526003890160205260409020805491925090600160601b90046001600160401b031680158015906110e757506001600160401b0381811614155b1561117a57885461110890600160a01b90046001600160401b031682611546565b6001600160401b031642101561117a5760405162461bcd60e51b815260206004820152603160248201527f4e6f7420656e6f7567682074696d65207061737365642073696e636520746865604482015270081bdc9a59da5b985b081c995c5d595cdd607a1b606482015260840161040b565b81546001600160401b038516600160601b81026001600160a01b03199092166001600160601b0386811691909117929092178455604080518a8416815292891660208401528201526001600160a01b0386811691908a16907f545cbf267cef6fe43f11f6219417ab43a0e8e345adbaae5f626d9bc325e8535a9060600160405180910390a3505050505050505050565b604051637004922d60e11b81526001600160a01b038381166004830152306024830152600091829186169063e009245a90604401602060405180830381865afa15801561125b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127f919061156d565b90506000836001600160601b0316826001600160601b0316116112a35760006112ad565b6112ad848361161f565b87549091506001600160601b0390811690821610156112d157600092505050610b0e565b9150610b0e9050565b6001600160a01b03811681146112ef57600080fd5b50565b6000806040838503121561130557600080fd5b823591506020830135611317816112da565b809150509250929050565b60008060006060848603121561133757600080fd5b833592506020840135611349816112da565b91506040840135611359816112da565b809150509250925092565b6001600160601b03811681146112ef57600080fd5b60008060008060008060c0878903121561139257600080fd5b8635955060208701356113a4816112da565b945060408701356113b4816112da565b935060608701356113c4816112da565b925060808701356113d481611364565b915060a08701356113e481611364565b809150509295509295509295565b6000806000806080858703121561140857600080fd5b84359350602085013561141a816112da565b9250604085013561142a816112da565b9150606085013561143a816112da565b939692955090935050565b6000806000806080858703121561145b57600080fd5b84359350602085013561146d816112da565b9250604085013561147d81611364565b9150606085013561143a81611364565b600080600080608085870312156114a357600080fd5b8435935060208501356114b5816112da565b9250604085013561147d816112da565b80356001600160401b03811681146114dc57600080fd5b919050565b600080600080608085870312156114f757600080fd5b84359350602085013561150981611364565b9250611517604086016114c5565b9150611525606086016114c5565b905092959194509250565b634e487b7160e01b600052601160045260246000fd5b6001600160401b0382811682821603908082111561156657611566611530565b5092915050565b60006020828403121561157f57600080fd5b815161158a81611364565b9392505050565b6000602082840312156115a357600080fd5b8151801515811461158a57600080fd5b60208082526010908201526f2ab735b737bbb71037b832b930ba37b960811b604082015260600190565b6001600160a01b039290921682526001600160601b0316602082015260400190565b6001600160401b0381811683821601908082111561156657611566611530565b6001600160601b038281168282160390808211156115665761156661153056fea264697066735822122041e6fbf54d81e891b2e7016f9d9bae1ca0beea482da4cc00d21eb702caaa884364736f6c63430008110033", + "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600436106100d85760003560e01c8063b86b341e11610096578063d563485c11610070578063d563485c14610233578063db82504e14610253578063ee7ae2a914610273578063f4dbcff41461028657600080fd5b8063b86b341e146101b2578063bf865212146101dd578063c6e1c8391461021357600080fd5b80624f4ac7146100dd578063251db5981461010d57806345e592941461012f578063475592631461014f578063520502841461016f578063520c3d3114610192575b600080fd5b6100f06100eb3660046112f2565b6102f1565b6040516001600160401b0390911681526020015b60405180910390f35b81801561011957600080fd5b5061012d610128366004611322565b61038b565b005b81801561013b57600080fd5b5061012d61014a366004611379565b6105d1565b81801561015b57600080fd5b5061012d61016a3660046112f2565b61073d565b61018261017d3660046113f2565b6109a0565b6040519015158152602001610104565b81801561019e57600080fd5b5061012d6101ad366004611322565b610b16565b6101c56101c0366004611322565b610cf0565b6040516001600160601b039091168152602001610104565b6101c56101eb3660046112f2565b6001600160a01b0316600090815260039190910160205260409020546001600160601b031690565b81801561021f57600080fd5b5061012d61022e3660046113f2565b610d23565b81801561023f57600080fd5b5061012d61024e366004611445565b610f02565b81801561025f57600080fd5b5061012d61026e366004611445565b610fcf565b6101c561028136600461148d565b61120a565b81801561029257600080fd5b5061012d6102a13660046114e1565b83546001600160601b03939093166001600160a01b031990931692909217600160601b6001600160401b03928316021767ffffffffffffffff60a01b1916600160a01b9290911691909102179055565b6001600160a01b03811660009081526003830160205260408120805467fffffffffffffffe19600160601b9091046001600160401b03160161033d576001600160401b03915050610385565b805442906001600160401b03600160601b90910481169082161161037d578154610378908290600160601b90046001600160401b0316611546565b610380565b60005b925050505b92915050565b6001600160a01b038116600090815260038401602052604090208054600160601b90046001600160401b03166104145760405162461bcd60e51b8152602060048201526024808201527f417574686f72697a6174696f6e206465637265617365206e6f742072657175656044820152631cdd195960e21b60648201526084015b60405180910390fd5b805467fffffffffffffffe19600160601b9091046001600160401b0316016104935760405162461bcd60e51b815260206004820152602c60248201527f417574686f72697a6174696f6e2064656372656173652072657175657374206e60448201526b1bdd081858dd1a5d985d195960a21b606482015260840161040b565b8054600160601b90046001600160401b03164210156105045760405162461bcd60e51b815260206004820152602760248201527f417574686f72697a6174696f6e2064656372656173652064656c6179206e6f74604482015266081c185cdcd95960ca1b606482015260840161040b565b6040516001600160a01b038316907f50270a522c2fef97b6b7385c2aa4a4518adda681530e0a1fe9f5e840f6f2cd9d90600090a2604051633af0572d60e11b81526001600160a01b0383811660048301528416906375e0ae5a906024016020604051808303816000875af1158015610580573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a4919061156d565b50506001600160a01b031660009081526003909201602052506040902080546001600160a01b0319169055565b6001600160a01b03808416600090815260018801602052604090205416806105f95750610735565b6040516307b8c36760e51b81526001600160a01b03828116600483015286169063f7186ce090602401602060405180830381865afa15801561063f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106639190611591565b1561073357846001600160a01b031663a4e2d6346040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ca9190611591565b1561072757604080516001600160601b038086168252841660208201526001600160a01b0380841692908716917f1b09380d63e78fd72c1d79a805a7e2dfadf02b22418e24bebff51376b7df33b0910160405180910390a3610733565b61073387878784610d23565b505b505050505050565b336001600160a01b0382166107945760405162461bcd60e51b815260206004820181905260248201527f4f70657261746f722063616e206e6f74206265207a65726f2061646472657373604482015260640161040b565b6001600160a01b03818116600090815260018501602052604090205416156108145760405162461bcd60e51b815260206004820152602d60248201527f4f70657261746f7220616c72656164792073657420666f72207468652073746160448201526c35b4b73390383937bb34b232b960991b606482015260840161040b565b6001600160a01b038281166000908152600285016020526040902054161561087e5760405162461bcd60e51b815260206004820152601f60248201527f4f70657261746f72206164647265737320616c726561647920696e2075736500604482015260640161040b565b6001600160a01b038116600090815260038401602052604090208054600160601b90046001600160401b0316156109115760405162461bcd60e51b815260206004820152603160248201527f546865726520697320612070656e64696e6720617574686f72697a6174696f6e60448201527008191958dc99585cd9481c995c5d595cdd607a1b606482015260840161040b565b826001600160a01b0316826001600160a01b03167fa453db612af59e5521d6ab9284dc3e2d06af286eb1b1b7b771fce4716c19f2c160405160405180910390a3506001600160a01b03908116600081815260018501602090815260408083208054959096166001600160a01b031995861681179096559482526002909501909452919092208054909216179055565b6001600160a01b038082166000908152600286016020526040812054909116806109dc5760405162461bcd60e51b815260040161040b906115b3565b6001600160a01b038116600090815260038701602052604081208054909190610a13908990899086906001600160601b031661120a565b6040516307b8c36760e51b81526001600160a01b0387811660048301529192509087169063f7186ce090602401602060405180830381865afa158015610a5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a819190611591565b610a99576001600160601b0316159250610b0e915050565b6040516304de824f60e41b81526001600160a01b03871690634de824f090610ac790889085906004016115dd565b602060405180830381865afa158015610ae4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b089190611591565b93505050505b949350505050565b3360008181526002850160205260409020546001600160a01b031680610b4e5760405162461bcd60e51b815260040161040b906115b3565b6001600160a01b038116600090815260038601602052604081208054909190610b85908890889086906001600160601b031661120a565b9050806001600160601b0316600003610be05760405162461bcd60e51b815260206004820152601f60248201527f417574686f72697a6174696f6e2062656c6f7720746865206d696e696d756d00604482015260640161040b565b836001600160a01b0316836001600160a01b03167f5075aaa89894a888eb2cac81a27320c60855febb0cf1706b66bdc754e640d43360405160405180910390a3604051630483483160e31b81526001600160a01b0386169063241a418890610c4e90879085906004016115dd565b600060405180830381600087803b158015610c6857600080fd5b505af1158015610c7c573d6000803e3d6000fd5b5050835467fffffffffffffffe19600160601b9091046001600160401b03160191506107339050578654610cc090600160601b90046001600160401b0316426115ff565b82546001600160401b0391909116600160601b0267ffffffffffffffff60601b1990911617825550505050505050565b6001600160a01b0381166000908152600384016020526040812054610b0e908590859085906001600160601b031661120a565b6001600160a01b0380821660009081526002860160205260409020541680610d5d5760405162461bcd60e51b815260040161040b906115b3565b6001600160a01b03808216600081815260038801602052604080822090519093861692917f1231fe5ee649a593b524a494cd53146a196380a872115a0d0fe16c0735afdf2691a36040516307b8c36760e51b81526001600160a01b03848116600483015285169063f7186ce090602401602060405180830381865afa158015610dea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e0e9190611591565b15610e95578054600090610e30908890889086906001600160601b031661120a565b60405163dc7520c560e01b81529091506001600160a01b0386169063dc7520c590610e6190879085906004016115dd565b600060405180830381600087803b158015610e7b57600080fd5b505af1158015610e8f573d6000803e3d6000fd5b50505050505b805467fffffffffffffffe19600160601b9091046001600160401b031601610735578554610ed390600160601b90046001600160401b0316426115ff565b81546001600160401b0391909116600160601b0267ffffffffffffffff60601b19909116178155505050505050565b83546001600160601b039081169082161015610f605760405162461bcd60e51b815260206004820152601f60248201527f417574686f72697a6174696f6e2062656c6f7720746865206d696e696d756d00604482015260640161040b565b6001600160a01b0383811660008181526001870160209081526040918290205482516001600160601b03888116825287169281019290925282519416938493927f87f9f9f59204f53d57a89a817c6083a17979cd0531791c91e18551a56e3cfdd7928290030190a35050505050565b6001600160601b0381161580610ff3575083546001600160601b0390811690821610155b61105d5760405162461bcd60e51b815260206004820152603560248201527f417574686f72697a6174696f6e20616d6f756e742073686f756c642062652030604482015274206f722061626f766520746865206d696e696d756d60581b606482015260840161040b565b6001600160a01b0380841660009081526001860160205260408120549091169081611089575042611093565b506001600160401b035b600061109f848661161f565b6001600160a01b03871660009081526003890160205260409020805491925090600160601b90046001600160401b031680158015906110e757506001600160401b0381811614155b1561117a57885461110890600160a01b90046001600160401b031682611546565b6001600160401b031642101561117a5760405162461bcd60e51b815260206004820152603160248201527f4e6f7420656e6f7567682074696d65207061737365642073696e636520746865604482015270081bdc9a59da5b985b081c995c5d595cdd607a1b606482015260840161040b565b81546001600160401b038516600160601b81026001600160a01b03199092166001600160601b0386811691909117929092178455604080518a8416815292891660208401528201526001600160a01b0386811691908a16907f545cbf267cef6fe43f11f6219417ab43a0e8e345adbaae5f626d9bc325e8535a9060600160405180910390a3505050505050505050565b604051637004922d60e11b81526001600160a01b038381166004830152306024830152600091829186169063e009245a90604401602060405180830381865afa15801561125b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127f919061156d565b90506000836001600160601b0316826001600160601b0316116112a35760006112ad565b6112ad848361161f565b87549091506001600160601b0390811690821610156112d157600092505050610b0e565b9150610b0e9050565b6001600160a01b03811681146112ef57600080fd5b50565b6000806040838503121561130557600080fd5b823591506020830135611317816112da565b809150509250929050565b60008060006060848603121561133757600080fd5b833592506020840135611349816112da565b91506040840135611359816112da565b809150509250925092565b6001600160601b03811681146112ef57600080fd5b60008060008060008060c0878903121561139257600080fd5b8635955060208701356113a4816112da565b945060408701356113b4816112da565b935060608701356113c4816112da565b925060808701356113d481611364565b915060a08701356113e481611364565b809150509295509295509295565b6000806000806080858703121561140857600080fd5b84359350602085013561141a816112da565b9250604085013561142a816112da565b9150606085013561143a816112da565b939692955090935050565b6000806000806080858703121561145b57600080fd5b84359350602085013561146d816112da565b9250604085013561147d81611364565b9150606085013561143a81611364565b600080600080608085870312156114a357600080fd5b8435935060208501356114b5816112da565b9250604085013561147d816112da565b80356001600160401b03811681146114dc57600080fd5b919050565b600080600080608085870312156114f757600080fd5b84359350602085013561150981611364565b9250611517604086016114c5565b9150611525606086016114c5565b905092959194509250565b634e487b7160e01b600052601160045260246000fd5b6001600160401b0382811682821603908082111561156657611566611530565b5092915050565b60006020828403121561157f57600080fd5b815161158a81611364565b9392505050565b6000602082840312156115a357600080fd5b8151801515811461158a57600080fd5b60208082526010908201526f2ab735b737bbb71037b832b930ba37b960811b604082015260600190565b6001600160a01b039290921682526001600160601b0316602082015260400190565b6001600160401b0381811683821601908082111561156657611566611530565b6001600160601b038281168282160390808211156115665761156661153056fea264697066735822122041e6fbf54d81e891b2e7016f9d9bae1ca0beea482da4cc00d21eb702caaa884364736f6c63430008110033", + "linkReferences": {}, + "deployedLinkReferences": {}, + "devdoc": { + "kind": "dev", + "methods": { + "authorizationDecreaseRequested(BeaconAuthorization.Data storage,address,uint96,uint96)": { + "details": "Should only be callable by T staking contract." + }, + "authorizationIncreased(BeaconAuthorization.Data storage,address,uint96,uint96)": { + "details": "Should only be callable by T staking contract." + }, + "eligibleStake(BeaconAuthorization.Data storage,IStaking,address)": { + "details": "This function can be exposed to the public in contrast to the second variant accepting `decreasingBy` as a parameter." + }, + "eligibleStake(BeaconAuthorization.Data storage,IStaking,address,uint96)": { + "details": "This function is not intended to be exposes to the public. `decreasingBy` must be fetched from `pendingDecreases` mapping and it is passed as a parameter to optimize gas usage of functions that call `eligibleStake` and need to use `AuthorizationDecrease` fetched from `pendingDecreases` for some additional logic." + }, + "involuntaryAuthorizationDecrease(BeaconAuthorization.Data storage,IStaking,SortitionPool,address,uint96,uint96)": { + "details": "Should only be callable by T staking contract." + }, + "setParameters(BeaconAuthorization.Data storage,uint96,uint64,uint64)": { + "params": { + "_authorizationDecreaseChangePeriod": "New value of the authorization decrease change period. It is the time in seconds, before authorization decrease delay end, during which the pending authorization decrease request can be overwritten. If set to 0, pending authorization decrease request can not be overwritten until the entire `authorizationDecreaseDelay` ends. If set to value equal `authorizationDecreaseDelay`, request can always be overwritten.", + "_authorizationDecreaseDelay": "New value of the authorization decrease delay. It is the time in seconds that needs to pass between the time authorization decrease is requested and the time the authorization decrease can be approved, no matter the authorization decrease amount.", + "_minimumAuthorization": "New value of the minimum authorization for the beacon. Without at least the minimum authorization, staking provider is not eligible to join and operate in the network." + } + } + }, + "version": 1 + }, + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"}],\"name\":\"AuthorizationDecreaseApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"fromAmount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"toAmount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"decreasingAt\",\"type\":\"uint64\"}],\"name\":\"AuthorizationDecreaseRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"fromAmount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"toAmount\",\"type\":\"uint96\"}],\"name\":\"AuthorizationIncreased\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"fromAmount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"toAmount\",\"type\":\"uint96\"}],\"name\":\"InvoluntaryAuthorizationDecreaseFailed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"OperatorJoinedSortitionPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"OperatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"OperatorStatusUpdated\",\"type\":\"event\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"authorizationDecreaseRequested(BeaconAuthorization.Data storage,address,uint96,uint96)\":{\"details\":\"Should only be callable by T staking contract.\"},\"authorizationIncreased(BeaconAuthorization.Data storage,address,uint96,uint96)\":{\"details\":\"Should only be callable by T staking contract.\"},\"eligibleStake(BeaconAuthorization.Data storage,IStaking,address)\":{\"details\":\"This function can be exposed to the public in contrast to the second variant accepting `decreasingBy` as a parameter.\"},\"eligibleStake(BeaconAuthorization.Data storage,IStaking,address,uint96)\":{\"details\":\"This function is not intended to be exposes to the public. `decreasingBy` must be fetched from `pendingDecreases` mapping and it is passed as a parameter to optimize gas usage of functions that call `eligibleStake` and need to use `AuthorizationDecrease` fetched from `pendingDecreases` for some additional logic.\"},\"involuntaryAuthorizationDecrease(BeaconAuthorization.Data storage,IStaking,SortitionPool,address,uint96,uint96)\":{\"details\":\"Should only be callable by T staking contract.\"},\"setParameters(BeaconAuthorization.Data storage,uint96,uint64,uint64)\":{\"params\":{\"_authorizationDecreaseChangePeriod\":\"New value of the authorization decrease change period. It is the time in seconds, before authorization decrease delay end, during which the pending authorization decrease request can be overwritten. If set to 0, pending authorization decrease request can not be overwritten until the entire `authorizationDecreaseDelay` ends. If set to value equal `authorizationDecreaseDelay`, request can always be overwritten.\",\"_authorizationDecreaseDelay\":\"New value of the authorization decrease delay. It is the time in seconds that needs to pass between the time authorization decrease is requested and the time the authorization decrease can be approved, no matter the authorization decrease amount.\",\"_minimumAuthorization\":\"New value of the minimum authorization for the beacon. Without at least the minimum authorization, staking provider is not eligible to join and operate in the network.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"approveAuthorizationDecrease(BeaconAuthorization.Data storage,IStaking,address)\":{\"notice\":\"Approves the previously registered authorization decrease request. Reverts if authorization decrease delay have not passed yet or if the authorization decrease was not requested for the given staking provider.\"},\"authorizationDecreaseRequested(BeaconAuthorization.Data storage,address,uint96,uint96)\":{\"notice\":\"Used by T staking contract to inform the beacon that the authorization decrease for the given staking provider has been requested. Reverts if the amount after deauthorization would be non-zero and lower than the minimum authorization. Reverts if another authorization decrease request is pending for the staking provider and not enough time passed since the original request (see `authorizationDecreaseChangePeriod`). If the operator is not known (`registerOperator` was not called) it lets to `approveAuthorizationDecrease` immediately. If the operator is known (`registerOperator` was called), the operator needs to update state of the sortition pool with a call to `joinSortitionPool` or `updateOperatorStatus`. After the sortition pool state is in sync, authorization decrease delay starts. After authorization decrease delay passes, authorization decrease request needs to be approved with a call to `approveAuthorizationDecrease` function. If there is a pending authorization decrease request, it is overwritten, but only if enough time passed since the original request. Otherwise, the function reverts.\"},\"authorizationIncreased(BeaconAuthorization.Data storage,address,uint96,uint96)\":{\"notice\":\"Used by T staking contract to inform the beacon that the authorized stake amount for the given staking provider increased. Reverts if the authorization amount is below the minimum. The function is not updating the sortition pool. Sortition pool state needs to be updated by the operator with a call to `joinSortitionPool` or `updateOperatorStatus`.\"},\"eligibleStake(BeaconAuthorization.Data storage,IStaking,address)\":{\"notice\":\"Returns the current value of the staking provider's eligible stake. Eligible stake is defined as the currently authorized stake minus the pending authorization decrease. Eligible stake is what is used for operator's weight in the pool. If the authorized stake minus the pending authorization decrease is below the minimum authorization, eligible stake is 0.\"},\"eligibleStake(BeaconAuthorization.Data storage,IStaking,address,uint96)\":{\"notice\":\"Returns the current value of the staking provider's eligible stake. Eligible stake is defined as the currently authorized stake minus the pending authorization decrease. Eligible stake is what is used for operator's weight in the pool. If the authorized stake minus the pending authorization decrease is below the minimum authorization, eligible stake is 0.\"},\"involuntaryAuthorizationDecrease(BeaconAuthorization.Data storage,IStaking,SortitionPool,address,uint96,uint96)\":{\"notice\":\"Used by T staking contract to inform the beacon the authorization has been decreased for the given staking provider involuntarily, as a result of slashing. If the operator is not known (`registerOperator` was not called) the function does nothing. The operator was never in a sortition pool so there is nothing to update. If the operator is known, sortition pool is unlocked, and the operator is in the sortition pool, the sortition pool state is updated. If the sortition pool is locked, update needs to be postponed. Every other staker is incentivized to call `updateOperatorStatus` for the problematic operator to increase their own rewards in the pool.\"},\"isOperatorUpToDate(BeaconAuthorization.Data storage,IStaking,SortitionPool,address)\":{\"notice\":\"Checks if the operator's authorized stake is in sync with operator's weight in the sortition pool. If the operator is not in the sortition pool and their authorized stake is non-zero, function returns false.\"},\"joinSortitionPool(BeaconAuthorization.Data storage,IStaking,SortitionPool)\":{\"notice\":\"Lets the operator join the sortition pool. The operator address must be known - before calling this function, it has to be appointed by the staking provider by calling `registerOperator`. Also, the operator must have the minimum authorization required by the beacon. Function reverts if there is no minimum stake authorized or if the operator is not known. If there was an authorization decrease requested, it is activated by starting the authorization decrease delay.\"},\"pendingAuthorizationDecrease(BeaconAuthorization.Data storage,address)\":{\"notice\":\"Returns the amount of stake that is pending authorization decrease for the given staking provider. If no authorization decrease has been requested, returns zero.\"},\"registerOperator(BeaconAuthorization.Data storage,address)\":{\"notice\":\"Used by staking provider to set operator address that will operate a node. The given staking provider can set operator address only one time. The operator address can not be changed and must be unique. Reverts if the operator is already set for the staking provider or if the operator address is already in use. Reverts if there is a pending authorization decrease for the staking provider.\"},\"remainingAuthorizationDecreaseDelay(BeaconAuthorization.Data storage,address)\":{\"notice\":\"Returns the remaining time in seconds that needs to pass before the requested authorization decrease can be approved. If the sortition pool state was not updated yet by the operator after requesting the authorization decrease, returns `type(uint64).max`.\"},\"setParameters(BeaconAuthorization.Data storage,uint96,uint64,uint64)\":{\"notice\":\"Updates authorization-related parameters.\"},\"updateOperatorStatus(BeaconAuthorization.Data storage,IStaking,SortitionPool,address)\":{\"notice\":\"Updates status of the operator in the sortition pool. If there was an authorization decrease requested, it is activated by starting the authorization decrease delay. Function reverts if the operator is not known.\"}},\"notice\":\"Library managing the state of stake authorizations for the operator contract and the presence of operators in the sortition pool based on the stake authorized for them.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/libraries/BeaconAuthorization.sol\":\"BeaconAuthorization\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@keep-network/sortition-pools/contracts/Branch.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\n/// @notice The implicit 8-ary trees of the sortition pool\\n/// rely on packing 8 \\\"slots\\\" of 32-bit values into each uint256.\\n/// The Branch library permits efficient calculations on these slots.\\nlibrary Branch {\\n /// @notice Calculate the right shift required\\n /// to make the 32 least significant bits of an uint256\\n /// be the bits of the `position`th slot\\n /// when treating the uint256 as a uint32[8].\\n ///\\n /// @dev Not used for efficiency reasons,\\n /// but left to illustrate the meaning of a common pattern.\\n /// I wish solidity had macros, even C macros.\\n function slotShift(uint256 position) internal pure returns (uint256) {\\n unchecked {\\n return position * Constants.SLOT_WIDTH;\\n }\\n }\\n\\n /// @notice Return the `position`th slot of the `node`,\\n /// treating `node` as a uint32[32].\\n function getSlot(uint256 node, uint256 position)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Doing a bitwise AND with `SLOT_MAX`\\n // clears all but the 32 least significant bits.\\n // Because of the right shift by `slotShift(position)` bits,\\n // those 32 bits contain the 32 bits in the `position`th slot of `node`.\\n return (node >> shiftBits) & Constants.SLOT_MAX;\\n }\\n }\\n\\n /// @notice Return `node` with the `position`th slot set to zero.\\n function clearSlot(uint256 node, uint256 position)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Shifting `SLOT_MAX` left by `slotShift(position)` bits\\n // gives us a number where all bits of the `position`th slot are set,\\n // and all other bits are unset.\\n //\\n // Using a bitwise NOT on this number,\\n // we get a uint256 where all bits are set\\n // except for those of the `position`th slot.\\n //\\n // Bitwise ANDing the original `node` with this number\\n // sets the bits of `position`th slot to zero,\\n // leaving all other bits unchanged.\\n return node & ~(Constants.SLOT_MAX << shiftBits);\\n }\\n }\\n\\n /// @notice Return `node` with the `position`th slot set to `weight`.\\n ///\\n /// @param weight The weight of of the node.\\n /// Safely truncated to a 32-bit number,\\n /// but this should never be called with an overflowing weight regardless.\\n function setSlot(\\n uint256 node,\\n uint256 position,\\n uint256 weight\\n ) internal pure returns (uint256) {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Clear the `position`th slot like in `clearSlot()`.\\n uint256 clearedNode = node & ~(Constants.SLOT_MAX << shiftBits);\\n // Bitwise AND `weight` with `SLOT_MAX`\\n // to clear all but the 32 least significant bits.\\n //\\n // Shift this left by `slotShift(position)` bits\\n // to obtain a uint256 with all bits unset\\n // except in the `position`th slot\\n // which contains the 32-bit value of `weight`.\\n uint256 shiftedWeight = (weight & Constants.SLOT_MAX) << shiftBits;\\n // When we bitwise OR these together,\\n // all other slots except the `position`th one come from the left argument,\\n // and the `position`th gets filled with `weight` from the right argument.\\n return clearedNode | shiftedWeight;\\n }\\n }\\n\\n /// @notice Calculate the summed weight of all slots in the `node`.\\n function sumWeight(uint256 node) internal pure returns (uint256 sum) {\\n unchecked {\\n sum = node & Constants.SLOT_MAX;\\n // Iterate through each slot\\n // by shifting `node` right in increments of 32 bits,\\n // and adding the 32 least significant bits to the `sum`.\\n uint256 newNode = node >> Constants.SLOT_WIDTH;\\n while (newNode > 0) {\\n sum += (newNode & Constants.SLOT_MAX);\\n newNode = newNode >> Constants.SLOT_WIDTH;\\n }\\n return sum;\\n }\\n }\\n\\n /// @notice Pick a slot in `node` that corresponds to `index`.\\n /// Treats the node like an array of virtual stakers,\\n /// the number of virtual stakers in each slot corresponding to its weight,\\n /// and picks which slot contains the `index`th virtual staker.\\n ///\\n /// @dev Requires that `index` be lower than `sumWeight(node)`.\\n /// However, this is not enforced for performance reasons.\\n /// If `index` exceeds the permitted range,\\n /// `pickWeightedSlot()` returns the rightmost slot\\n /// and an excessively high `newIndex`.\\n ///\\n /// @return slot The slot of `node` containing the `index`th virtual staker.\\n ///\\n /// @return newIndex The index of the `index`th virtual staker of `node`\\n /// within the returned slot.\\n function pickWeightedSlot(uint256 node, uint256 index)\\n internal\\n pure\\n returns (uint256 slot, uint256 newIndex)\\n {\\n unchecked {\\n newIndex = index;\\n uint256 newNode = node;\\n uint256 currentSlotWeight = newNode & Constants.SLOT_MAX;\\n while (newIndex >= currentSlotWeight) {\\n newIndex -= currentSlotWeight;\\n slot++;\\n newNode = newNode >> Constants.SLOT_WIDTH;\\n currentSlotWeight = newNode & Constants.SLOT_MAX;\\n }\\n return (slot, newIndex);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa7fb1c9c9789f30493e9a40e24a24f46875dc5e7630b4f67478167759f6d1882\"},\"@keep-network/sortition-pools/contracts/Chaosnet.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\n/// @title Chaosnet\\n/// @notice This is a beta staker program for stakers willing to go the extra\\n/// mile with monitoring, share their logs with the dev team, and allow to more\\n/// carefully monitor the bootstrapping network. As the network matures, the\\n/// beta program will be ended.\\ncontract Chaosnet {\\n /// @notice Indicates if the chaosnet is active. The chaosnet is active\\n /// after the contract deployment and can be ended with a call to\\n /// `deactivateChaosnet()`. Once deactivated chaosnet can not be activated\\n /// again.\\n bool public isChaosnetActive;\\n\\n /// @notice Indicates if the given operator is a beta operator for chaosnet.\\n mapping(address => bool) public isBetaOperator;\\n\\n /// @notice Address controlling chaosnet status and beta operator addresses.\\n address public chaosnetOwner;\\n\\n event BetaOperatorsAdded(address[] operators);\\n\\n event ChaosnetOwnerRoleTransferred(\\n address oldChaosnetOwner,\\n address newChaosnetOwner\\n );\\n\\n event ChaosnetDeactivated();\\n\\n constructor() {\\n _transferChaosnetOwner(msg.sender);\\n isChaosnetActive = true;\\n }\\n\\n modifier onlyChaosnetOwner() {\\n require(msg.sender == chaosnetOwner, \\\"Not the chaosnet owner\\\");\\n _;\\n }\\n\\n modifier onlyOnChaosnet() {\\n require(isChaosnetActive, \\\"Chaosnet is not active\\\");\\n _;\\n }\\n\\n /// @notice Adds beta operator to chaosnet. Can be called only by the\\n /// chaosnet owner when the chaosnet is active. Once the operator is added\\n /// as a beta operator, it can not be removed.\\n function addBetaOperators(address[] calldata operators)\\n public\\n onlyOnChaosnet\\n onlyChaosnetOwner\\n {\\n for (uint256 i = 0; i < operators.length; i++) {\\n isBetaOperator[operators[i]] = true;\\n }\\n\\n emit BetaOperatorsAdded(operators);\\n }\\n\\n /// @notice Deactivates the chaosnet. Can be called only by the chaosnet\\n /// owner. Once deactivated chaosnet can not be activated again.\\n function deactivateChaosnet() public onlyOnChaosnet onlyChaosnetOwner {\\n isChaosnetActive = false;\\n emit ChaosnetDeactivated();\\n }\\n\\n /// @notice Transfers the chaosnet owner role to another non-zero address.\\n function transferChaosnetOwnerRole(address newChaosnetOwner)\\n public\\n onlyChaosnetOwner\\n {\\n require(\\n newChaosnetOwner != address(0),\\n \\\"New chaosnet owner must not be zero address\\\"\\n );\\n _transferChaosnetOwner(newChaosnetOwner);\\n }\\n\\n function _transferChaosnetOwner(address newChaosnetOwner) internal {\\n address oldChaosnetOwner = chaosnetOwner;\\n chaosnetOwner = newChaosnetOwner;\\n emit ChaosnetOwnerRoleTransferred(oldChaosnetOwner, newChaosnetOwner);\\n }\\n}\\n\",\"keccak256\":\"0xeaf7bdd5626f88c329793a012621039692ce1b6e1f13013997ddb13d7e3032df\"},\"@keep-network/sortition-pools/contracts/Constants.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nlibrary Constants {\\n ////////////////////////////////////////////////////////////////////////////\\n // Parameters for configuration\\n\\n // How many bits a position uses per level of the tree;\\n // each branch of the tree contains 2**SLOT_BITS slots.\\n uint256 constant SLOT_BITS = 3;\\n uint256 constant LEVELS = 7;\\n ////////////////////////////////////////////////////////////////////////////\\n\\n ////////////////////////////////////////////////////////////////////////////\\n // Derived constants, do not touch\\n uint256 constant SLOT_COUNT = 2**SLOT_BITS;\\n uint256 constant SLOT_WIDTH = 256 / SLOT_COUNT;\\n uint256 constant LAST_SLOT = SLOT_COUNT - 1;\\n uint256 constant SLOT_MAX = (2**SLOT_WIDTH) - 1;\\n uint256 constant POOL_CAPACITY = SLOT_COUNT**LEVELS;\\n\\n uint256 constant ID_WIDTH = SLOT_WIDTH;\\n uint256 constant ID_MAX = SLOT_MAX;\\n\\n uint256 constant BLOCKHEIGHT_WIDTH = 96 - ID_WIDTH;\\n uint256 constant BLOCKHEIGHT_MAX = (2**BLOCKHEIGHT_WIDTH) - 1;\\n\\n uint256 constant SLOT_POINTER_MAX = (2**SLOT_BITS) - 1;\\n uint256 constant LEAF_FLAG = 1 << 255;\\n\\n uint256 constant WEIGHT_WIDTH = 256 / SLOT_COUNT;\\n ////////////////////////////////////////////////////////////////////////////\\n}\\n\",\"keccak256\":\"0xaef690ced707935745ff1482b7bb9bd9eb77bf6a39c717465e64cf12db8a7d39\"},\"@keep-network/sortition-pools/contracts/Leaf.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary Leaf {\\n function make(\\n address _operator,\\n uint256 _creationBlock,\\n uint256 _id\\n ) internal pure returns (uint256) {\\n assert(_creationBlock <= type(uint64).max);\\n assert(_id <= type(uint32).max);\\n // Converting a bytesX type into a larger type\\n // adds zero bytes on the right.\\n uint256 op = uint256(bytes32(bytes20(_operator)));\\n // Bitwise AND the id to erase\\n // all but the 32 least significant bits\\n uint256 uid = _id & Constants.ID_MAX;\\n // Erase all but the 64 least significant bits,\\n // then shift left by 32 bits to make room for the id\\n uint256 cb = (_creationBlock & Constants.BLOCKHEIGHT_MAX) <<\\n Constants.ID_WIDTH;\\n // Bitwise OR them all together to get\\n // [address operator || uint64 creationBlock || uint32 id]\\n return (op | cb | uid);\\n }\\n\\n function operator(uint256 leaf) internal pure returns (address) {\\n // Converting a bytesX type into a smaller type\\n // truncates it on the right.\\n return address(bytes20(bytes32(leaf)));\\n }\\n\\n /// @notice Return the block number the leaf was created in.\\n function creationBlock(uint256 leaf) internal pure returns (uint256) {\\n return ((leaf >> Constants.ID_WIDTH) & Constants.BLOCKHEIGHT_MAX);\\n }\\n\\n function id(uint256 leaf) internal pure returns (uint32) {\\n // Id is stored in the 32 least significant bits.\\n // Bitwise AND ensures that we only get the contents of those bits.\\n return uint32(leaf & Constants.ID_MAX);\\n }\\n}\\n\",\"keccak256\":\"0xbd107a1a43e48884885e5e966ffcbcd8fa5e89863715d717bb4006e9f89cdc2b\"},\"@keep-network/sortition-pools/contracts/Position.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary Position {\\n // Return the last 3 bits of a position number,\\n // corresponding to its slot in its parent\\n function slot(uint256 a) internal pure returns (uint256) {\\n return a & Constants.SLOT_POINTER_MAX;\\n }\\n\\n // Return the parent of a position number\\n function parent(uint256 a) internal pure returns (uint256) {\\n return a >> Constants.SLOT_BITS;\\n }\\n\\n // Return the location of the child of a at the given slot\\n function child(uint256 a, uint256 s) internal pure returns (uint256) {\\n return (a << Constants.SLOT_BITS) | (s & Constants.SLOT_POINTER_MAX); // slot(s)\\n }\\n\\n // Return the uint p as a flagged position uint:\\n // the least significant 21 bits contain the position\\n // and the 22nd bit is set as a flag\\n // to distinguish the position 0x000000 from an empty field.\\n function setFlag(uint256 p) internal pure returns (uint256) {\\n return p | Constants.LEAF_FLAG;\\n }\\n\\n // Turn a flagged position into an unflagged position\\n // by removing the flag at the 22nd least significant bit.\\n //\\n // We shouldn't _actually_ need this\\n // as all position-manipulating code should ignore non-position bits anyway\\n // but it's cheap to call so might as well do it.\\n function unsetFlag(uint256 p) internal pure returns (uint256) {\\n return p & (~Constants.LEAF_FLAG);\\n }\\n}\\n\",\"keccak256\":\"0xd3a927908080ac21353a92a6bce3d69e94a5c30f6b51f16b271b6cc679f110e2\"},\"@keep-network/sortition-pools/contracts/RNG.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Leaf.sol\\\";\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary RNG {\\n /// @notice Get an index in the range `[0 .. range-1]`\\n /// and the new state of the RNG,\\n /// using the provided `state` of the RNG.\\n ///\\n /// @param range The upper bound of the index, exclusive.\\n ///\\n /// @param state The previous state of the RNG.\\n /// The initial state needs to be obtained\\n /// from a trusted randomness oracle (the random beacon),\\n /// or from a chain of earlier calls to `RNG.getIndex()`\\n /// on an originally trusted seed.\\n ///\\n /// @dev Calculates the number of bits required for the desired range,\\n /// takes the least significant bits of `state`\\n /// and checks if the obtained index is within the desired range.\\n /// The original state is hashed with `keccak256` to get a new state.\\n /// If the index is outside the range,\\n /// the function retries until it gets a suitable index.\\n ///\\n /// @return index A random integer between `0` and `range - 1`, inclusive.\\n ///\\n /// @return newState The new state of the RNG.\\n /// When `getIndex()` is called one or more times,\\n /// care must be taken to always use the output `state`\\n /// of the most recent call as the input `state` of a subsequent call.\\n /// At the end of a transaction calling `RNG.getIndex()`,\\n /// the previous stored state must be overwritten with the latest output.\\n function getIndex(\\n uint256 range,\\n bytes32 state,\\n uint256 bits\\n ) internal view returns (uint256, bytes32) {\\n bool found = false;\\n uint256 index = 0;\\n bytes32 newState = state;\\n while (!found) {\\n index = truncate(bits, uint256(newState));\\n newState = keccak256(abi.encodePacked(newState, address(this)));\\n if (index < range) {\\n found = true;\\n }\\n }\\n return (index, newState);\\n }\\n\\n /// @notice Calculate how many bits are required\\n /// for an index in the range `[0 .. range-1]`.\\n ///\\n /// @param range The upper bound of the desired range, exclusive.\\n ///\\n /// @return uint The smallest number of bits\\n /// that can contain the number `range-1`.\\n function bitsRequired(uint256 range) internal pure returns (uint256) {\\n unchecked {\\n if (range == 1) {\\n return 0;\\n }\\n\\n uint256 bits = Constants.WEIGHT_WIDTH - 1;\\n\\n // Left shift by `bits`,\\n // so we have a 1 in the (bits + 1)th least significant bit\\n // and 0 in other bits.\\n // If this number is equal or greater than `range`,\\n // the range [0, range-1] fits in `bits` bits.\\n //\\n // Because we loop from high bits to low bits,\\n // we find the highest number of bits that doesn't fit the range,\\n // and return that number + 1.\\n while (1 << bits >= range) {\\n bits--;\\n }\\n\\n return bits + 1;\\n }\\n }\\n\\n /// @notice Truncate `input` to the `bits` least significant bits.\\n function truncate(uint256 bits, uint256 input)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n return input & ((1 << bits) - 1);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x67f87f589cd5123ffa32f883ea2f09b0e56258508bae82b8c655b3c27c71eb5e\"},\"@keep-network/sortition-pools/contracts/Rewards.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\n/// @title Rewards\\n/// @notice Rewards are allocated proportionally to operators\\n/// present in the pool at payout based on their weight in the pool.\\n///\\n/// To facilitate this, we use a global accumulator value\\n/// to track the total rewards one unit of weight would've earned\\n/// since the creation of the pool.\\n///\\n/// Whenever a reward is paid, the accumulator is increased\\n/// by the size of the reward divided by the total weight\\n/// of all eligible operators in the pool.\\n///\\n/// Each operator has an individual accumulator value,\\n/// set to equal the global accumulator when the operator joins the pool.\\n/// This accumulator reflects the amount of rewards\\n/// that have already been accounted for with that operator.\\n///\\n/// Whenever an operator's weight in the pool changes,\\n/// we can update the amount of rewards the operator has earned\\n/// by subtracting the operator's accumulator from the global accumulator.\\n/// This gives us the amount of rewards one unit of weight has earned\\n/// since the last time the operator's rewards have been updated.\\n/// Then we multiply that by the operator's previous (pre-change) weight\\n/// to determine how much rewards in total the operator has earned,\\n/// and add this to the operator's earned rewards.\\n/// Finally, we set the operator's accumulator to the global accumulator value.\\ncontract Rewards {\\n struct OperatorRewards {\\n // The state of the global accumulator\\n // when the operator's rewards were last updated\\n uint96 accumulated;\\n // The amount of rewards collected by the operator after the latest update.\\n // The amount the operator could withdraw may equal `available`\\n // or it may be greater, if more rewards have been paid in since then.\\n // To evaulate the most recent amount including rewards potentially paid\\n // since the last update, use `availableRewards` function.\\n uint96 available;\\n // If nonzero, the operator is ineligible for rewards\\n // and may only re-enable rewards after the specified timestamp.\\n // XXX: unsigned 32-bit integer unix seconds, will break around 2106\\n uint32 ineligibleUntil;\\n // Locally cached weight of the operator,\\n // used to reduce the cost of setting operators ineligible.\\n uint32 weight;\\n }\\n\\n // The global accumulator of how much rewards\\n // a hypothetical operator of weight 1 would have earned\\n // since the creation of the pool.\\n uint96 internal globalRewardAccumulator;\\n // If the amount of reward tokens paid in\\n // does not divide cleanly by pool weight,\\n // the difference is recorded as rounding dust\\n // and added to the next reward.\\n uint96 internal rewardRoundingDust;\\n\\n // The amount of rewards that would've been earned by ineligible operators\\n // had they not been ineligible.\\n uint96 public ineligibleEarnedRewards;\\n\\n // Ineligibility times are calculated from this offset,\\n // set at contract creation.\\n uint256 internal immutable ineligibleOffsetStart;\\n\\n mapping(uint32 => OperatorRewards) internal operatorRewards;\\n\\n constructor() {\\n // solhint-disable-next-line not-rely-on-time\\n ineligibleOffsetStart = block.timestamp;\\n }\\n\\n /// @notice Return whether the operator is eligible for rewards or not.\\n function isEligibleForRewards(uint32 operator) internal view returns (bool) {\\n return operatorRewards[operator].ineligibleUntil == 0;\\n }\\n\\n /// @notice Return the time the operator's reward eligibility can be restored.\\n function rewardsEligibilityRestorableAt(uint32 operator)\\n internal\\n view\\n returns (uint256)\\n {\\n uint32 until = operatorRewards[operator].ineligibleUntil;\\n require(until != 0, \\\"Operator already eligible\\\");\\n return (uint256(until) + ineligibleOffsetStart);\\n }\\n\\n /// @notice Return whether the operator is able to restore their eligibility\\n /// for rewards right away.\\n function canRestoreRewardEligibility(uint32 operator)\\n internal\\n view\\n returns (bool)\\n {\\n // solhint-disable-next-line not-rely-on-time\\n return rewardsEligibilityRestorableAt(operator) <= block.timestamp;\\n }\\n\\n /// @notice Internal function for updating the global state of rewards.\\n function addRewards(uint96 rewardAmount, uint32 currentPoolWeight) internal {\\n require(currentPoolWeight > 0, \\\"No recipients in pool\\\");\\n\\n uint96 totalAmount = rewardAmount + rewardRoundingDust;\\n uint96 perWeightReward = totalAmount / currentPoolWeight;\\n uint96 newRoundingDust = totalAmount % currentPoolWeight;\\n\\n globalRewardAccumulator += perWeightReward;\\n rewardRoundingDust = newRoundingDust;\\n }\\n\\n /// @notice Internal function for updating the operator's reward state.\\n function updateOperatorRewards(uint32 operator, uint32 newWeight) internal {\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n if (o.ineligibleUntil == 0) {\\n // If operator is not ineligible, update their earned rewards\\n o.available += accruedRewards;\\n } else {\\n // If ineligible, put the rewards into the ineligible pot\\n ineligibleEarnedRewards += accruedRewards;\\n }\\n // In any case, update their accumulator and weight\\n o.accumulated = acc;\\n o.weight = newWeight;\\n operatorRewards[operator] = o;\\n }\\n\\n /// @notice Set the amount of withdrawable tokens to zero\\n /// and return the previous withdrawable amount.\\n /// @dev Does not update the withdrawable amount,\\n /// but should usually be accompanied by an update.\\n function withdrawOperatorRewards(uint32 operator)\\n internal\\n returns (uint96 withdrawable)\\n {\\n OperatorRewards storage o = operatorRewards[operator];\\n withdrawable = o.available;\\n o.available = 0;\\n }\\n\\n /// @notice Set the amount of ineligible-earned tokens to zero\\n /// and return the previous amount.\\n function withdrawIneligibleRewards() internal returns (uint96 withdrawable) {\\n withdrawable = ineligibleEarnedRewards;\\n ineligibleEarnedRewards = 0;\\n }\\n\\n /// @notice Set the given operators as ineligible for rewards.\\n /// The operators can restore their eligibility at the given time.\\n function setIneligible(uint32[] memory operators, uint256 until) internal {\\n OperatorRewards memory o = OperatorRewards(0, 0, 0, 0);\\n uint96 globalAcc = globalRewardAccumulator;\\n uint96 accrued = 0;\\n // Record ineligibility as seconds after contract creation\\n uint32 _until = uint32(until - ineligibleOffsetStart);\\n\\n for (uint256 i = 0; i < operators.length; i++) {\\n uint32 operator = operators[i];\\n OperatorRewards storage r = operatorRewards[operator];\\n o.available = r.available;\\n o.accumulated = r.accumulated;\\n o.ineligibleUntil = r.ineligibleUntil;\\n o.weight = r.weight;\\n\\n if (o.ineligibleUntil != 0) {\\n // If operator is already ineligible,\\n // don't earn rewards or shorten its ineligibility\\n if (o.ineligibleUntil < _until) {\\n o.ineligibleUntil = _until;\\n }\\n } else {\\n // The operator becomes ineligible -> earn rewards\\n o.ineligibleUntil = _until;\\n accrued = (globalAcc - o.accumulated) * uint96(o.weight);\\n o.available += accrued;\\n }\\n o.accumulated = globalAcc;\\n\\n r.available = o.available;\\n r.accumulated = o.accumulated;\\n r.ineligibleUntil = o.ineligibleUntil;\\n r.weight = o.weight;\\n }\\n }\\n\\n /// @notice Restore the given operator's eligibility for rewards.\\n function restoreEligibility(uint32 operator) internal {\\n // solhint-disable-next-line not-rely-on-time\\n require(canRestoreRewardEligibility(operator), \\\"Operator still ineligible\\\");\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n ineligibleEarnedRewards += accruedRewards;\\n o.accumulated = acc;\\n o.ineligibleUntil = 0;\\n operatorRewards[operator] = o;\\n }\\n\\n /// @notice Returns the amount of rewards currently available for withdrawal\\n /// for the given operator.\\n function availableRewards(uint32 operator) internal view returns (uint96) {\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n if (o.ineligibleUntil == 0) {\\n // If operator is not ineligible, calculate newly accrued rewards and add\\n // them to the available ones, calculated during the last update.\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n return o.available + accruedRewards;\\n } else {\\n // If ineligible, return only the rewards calculated during the last\\n // update.\\n return o.available;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3a10abb408b44335a092387b2c7ee01db3b27997f1f2c888d9b7a2d92934c4e2\"},\"@keep-network/sortition-pools/contracts/SortitionPool.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"@thesis/solidity-contracts/contracts/token/IERC20WithPermit.sol\\\";\\nimport \\\"@thesis/solidity-contracts/contracts/token/IReceiveApproval.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\nimport \\\"./RNG.sol\\\";\\nimport \\\"./SortitionTree.sol\\\";\\nimport \\\"./Rewards.sol\\\";\\nimport \\\"./Chaosnet.sol\\\";\\n\\n/// @title Sortition Pool\\n/// @notice A logarithmic data structure used to store the pool of eligible\\n/// operators weighted by their stakes. It allows to select a group of operators\\n/// based on the provided pseudo-random seed.\\ncontract SortitionPool is\\n SortitionTree,\\n Rewards,\\n Ownable,\\n Chaosnet,\\n IReceiveApproval\\n{\\n using Branch for uint256;\\n using Leaf for uint256;\\n using Position for uint256;\\n\\n IERC20WithPermit public immutable rewardToken;\\n\\n uint256 public immutable poolWeightDivisor;\\n\\n bool public isLocked;\\n\\n event IneligibleForRewards(uint32[] ids, uint256 until);\\n\\n event RewardEligibilityRestored(address indexed operator, uint32 indexed id);\\n\\n /// @notice Reverts if called while pool is locked.\\n modifier onlyUnlocked() {\\n require(!isLocked, \\\"Sortition pool locked\\\");\\n _;\\n }\\n\\n /// @notice Reverts if called while pool is unlocked.\\n modifier onlyLocked() {\\n require(isLocked, \\\"Sortition pool unlocked\\\");\\n _;\\n }\\n\\n constructor(IERC20WithPermit _rewardToken, uint256 _poolWeightDivisor) {\\n rewardToken = _rewardToken;\\n poolWeightDivisor = _poolWeightDivisor;\\n }\\n\\n function receiveApproval(\\n address sender,\\n uint256 amount,\\n address token,\\n bytes calldata\\n ) external override {\\n require(token == address(rewardToken), \\\"Unsupported token\\\");\\n rewardToken.transferFrom(sender, address(this), amount);\\n Rewards.addRewards(uint96(amount), uint32(root.sumWeight()));\\n }\\n\\n /// @notice Withdraws all available rewards for the given operator to the\\n /// given beneficiary.\\n /// @dev Can be called only be the owner. Does not validate if the provided\\n /// beneficiary is associated with the provided operator - this needs to\\n /// be done by the owner calling this function.\\n /// @return The amount of rewards withdrawn in this call.\\n function withdrawRewards(address operator, address beneficiary)\\n public\\n onlyOwner\\n returns (uint96)\\n {\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(getPoolWeight(operator)));\\n uint96 earned = Rewards.withdrawOperatorRewards(id);\\n rewardToken.transfer(beneficiary, uint256(earned));\\n return earned;\\n }\\n\\n /// @notice Withdraws rewards not allocated to operators marked as ineligible\\n /// to the given recipient address.\\n /// @dev Can be called only by the owner.\\n function withdrawIneligible(address recipient) public onlyOwner {\\n uint96 earned = Rewards.withdrawIneligibleRewards();\\n rewardToken.transfer(recipient, uint256(earned));\\n }\\n\\n /// @notice Locks the sortition pool. In locked state, members cannot be\\n /// inserted and removed from the pool. Members statuses cannot\\n /// be updated as well.\\n /// @dev Can be called only by the contract owner.\\n function lock() public onlyOwner {\\n isLocked = true;\\n }\\n\\n /// @notice Unlocks the sortition pool. Removes all restrictions set by\\n /// the `lock` method.\\n /// @dev Can be called only by the contract owner.\\n function unlock() public onlyOwner {\\n isLocked = false;\\n }\\n\\n /// @notice Inserts an operator to the pool. Reverts if the operator is\\n /// already present. Reverts if the operator is not eligible because of their\\n /// authorized stake. Reverts if the chaosnet is active and the operator is\\n /// not a beta operator.\\n /// @dev Can be called only by the contract owner.\\n /// @param operator Address of the inserted operator.\\n /// @param authorizedStake Inserted operator's authorized stake for the application.\\n function insertOperator(address operator, uint256 authorizedStake)\\n public\\n onlyOwner\\n onlyUnlocked\\n {\\n uint256 weight = getWeight(authorizedStake);\\n require(weight > 0, \\\"Operator not eligible\\\");\\n\\n if (isChaosnetActive) {\\n require(isBetaOperator[operator], \\\"Not beta operator for chaosnet\\\");\\n }\\n\\n _insertOperator(operator, weight);\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(weight));\\n }\\n\\n /// @notice Update the operator's weight if present and eligible,\\n /// or remove from the pool if present and ineligible.\\n /// @dev Can be called only by the contract owner.\\n /// @param operator Address of the updated operator.\\n /// @param authorizedStake Operator's authorized stake for the application.\\n function updateOperatorStatus(address operator, uint256 authorizedStake)\\n public\\n onlyOwner\\n onlyUnlocked\\n {\\n uint256 weight = getWeight(authorizedStake);\\n\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(weight));\\n\\n if (weight == 0) {\\n _removeOperator(operator);\\n } else {\\n updateOperator(operator, weight);\\n }\\n }\\n\\n /// @notice Set the given operators as ineligible for rewards.\\n /// The operators can restore their eligibility at the given time.\\n function setRewardIneligibility(uint32[] calldata operators, uint256 until)\\n public\\n onlyOwner\\n {\\n Rewards.setIneligible(operators, until);\\n emit IneligibleForRewards(operators, until);\\n }\\n\\n /// @notice Restores reward eligibility for the operator.\\n function restoreRewardEligibility(address operator) public {\\n uint32 id = getOperatorID(operator);\\n Rewards.restoreEligibility(id);\\n emit RewardEligibilityRestored(operator, id);\\n }\\n\\n /// @notice Returns whether the operator is eligible for rewards or not.\\n function isEligibleForRewards(address operator) public view returns (bool) {\\n uint32 id = getOperatorID(operator);\\n return Rewards.isEligibleForRewards(id);\\n }\\n\\n /// @notice Returns the time the operator's reward eligibility can be restored.\\n function rewardsEligibilityRestorableAt(address operator)\\n public\\n view\\n returns (uint256)\\n {\\n uint32 id = getOperatorID(operator);\\n return Rewards.rewardsEligibilityRestorableAt(id);\\n }\\n\\n /// @notice Returns whether the operator is able to restore their eligibility\\n /// for rewards right away.\\n function canRestoreRewardEligibility(address operator)\\n public\\n view\\n returns (bool)\\n {\\n uint32 id = getOperatorID(operator);\\n return Rewards.canRestoreRewardEligibility(id);\\n }\\n\\n /// @notice Returns the amount of rewards withdrawable for the given operator.\\n function getAvailableRewards(address operator) public view returns (uint96) {\\n uint32 id = getOperatorID(operator);\\n return availableRewards(id);\\n }\\n\\n /// @notice Return whether the operator is present in the pool.\\n function isOperatorInPool(address operator) public view returns (bool) {\\n return getFlaggedLeafPosition(operator) != 0;\\n }\\n\\n /// @notice Return whether the operator's weight in the pool\\n /// matches their eligible weight.\\n function isOperatorUpToDate(address operator, uint256 authorizedStake)\\n public\\n view\\n returns (bool)\\n {\\n return getWeight(authorizedStake) == getPoolWeight(operator);\\n }\\n\\n /// @notice Return the weight of the operator in the pool,\\n /// which may or may not be out of date.\\n function getPoolWeight(address operator) public view returns (uint256) {\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n if (flaggedPosition == 0) {\\n return 0;\\n } else {\\n uint256 leafPosition = flaggedPosition.unsetFlag();\\n uint256 leafWeight = getLeafWeight(leafPosition);\\n return leafWeight;\\n }\\n }\\n\\n /// @notice Selects a new group of operators of the provided size based on\\n /// the provided pseudo-random seed. At least one operator has to be\\n /// registered in the pool, otherwise the function fails reverting the\\n /// transaction.\\n /// @param groupSize Size of the requested group\\n /// @param seed Pseudo-random number used to select operators to group\\n /// @return selected Members of the selected group\\n function selectGroup(uint256 groupSize, bytes32 seed)\\n public\\n view\\n onlyLocked\\n returns (uint32[] memory)\\n {\\n uint256 _root = root;\\n\\n bytes32 rngState = seed;\\n uint256 rngRange = _root.sumWeight();\\n require(rngRange > 0, \\\"Not enough operators in pool\\\");\\n uint256 currentIndex;\\n\\n uint256 bits = RNG.bitsRequired(rngRange);\\n\\n uint32[] memory selected = new uint32[](groupSize);\\n\\n for (uint256 i = 0; i < groupSize; i++) {\\n (currentIndex, rngState) = RNG.getIndex(rngRange, rngState, bits);\\n\\n uint256 leafPosition = pickWeightedLeaf(currentIndex, _root);\\n\\n uint256 leaf = leaves[leafPosition];\\n selected[i] = leaf.id();\\n }\\n return selected;\\n }\\n\\n function getWeight(uint256 authorization) internal view returns (uint256) {\\n return authorization / poolWeightDivisor;\\n }\\n}\\n\",\"keccak256\":\"0xab42e7c5b1828f42a73f699eb2dc96d4f793572a6323b8b1fbd7c5e0c065bda7\"},\"@keep-network/sortition-pools/contracts/SortitionTree.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Branch.sol\\\";\\nimport \\\"./Position.sol\\\";\\nimport \\\"./Leaf.sol\\\";\\nimport \\\"./Constants.sol\\\";\\n\\ncontract SortitionTree {\\n using Branch for uint256;\\n using Position for uint256;\\n using Leaf for uint256;\\n\\n // implicit tree\\n // root 8\\n // level2 64\\n // level3 512\\n // level4 4k\\n // level5 32k\\n // level6 256k\\n // level7 2M\\n uint256 internal root;\\n\\n // A 2-index mapping from layer => (index (0-index) => branch). For example,\\n // to access the 6th branch in the 2nd layer (right below the root node; the\\n // first branch layer), call branches[2][5]. Mappings are used in place of\\n // arrays for efficiency. The root is the first layer, the branches occupy\\n // layers 2 through 7, and layer 8 is for the leaves. Following this\\n // convention, the first index in `branches` is `2`, and the last index is\\n // `7`.\\n mapping(uint256 => mapping(uint256 => uint256)) internal branches;\\n\\n // A 0-index mapping from index => leaf, acting as an array. For example, to\\n // access the 42nd leaf, call leaves[41].\\n mapping(uint256 => uint256) internal leaves;\\n\\n // the flagged (see setFlag() and unsetFlag() in Position.sol) positions\\n // of all operators present in the pool\\n mapping(address => uint256) internal flaggedLeafPosition;\\n\\n // the leaf after the rightmost occupied leaf of each stack\\n uint256 internal rightmostLeaf;\\n\\n // the empty leaves in each stack\\n // between 0 and the rightmost occupied leaf\\n uint256[] internal emptyLeaves;\\n\\n // Each operator has an uint32 ID number\\n // which is allocated when they first join the pool\\n // and remains unchanged even if they leave and rejoin the pool.\\n mapping(address => uint32) internal operatorID;\\n\\n // The idAddress array records the address corresponding to each ID number.\\n // The ID number 0 is initialized with a zero address and is not used.\\n address[] internal idAddress;\\n\\n constructor() {\\n root = 0;\\n rightmostLeaf = 0;\\n idAddress.push();\\n }\\n\\n /// @notice Return the ID number of the given operator address. An ID number\\n /// of 0 means the operator has not been allocated an ID number yet.\\n /// @param operator Address of the operator.\\n /// @return the ID number of the given operator address\\n function getOperatorID(address operator) public view returns (uint32) {\\n return operatorID[operator];\\n }\\n\\n /// @notice Get the operator address corresponding to the given ID number. A\\n /// zero address means the ID number has not been allocated yet.\\n /// @param id ID of the operator\\n /// @return the address of the operator\\n function getIDOperator(uint32 id) public view returns (address) {\\n return idAddress.length > id ? idAddress[id] : address(0);\\n }\\n\\n /// @notice Gets the operator addresses corresponding to the given ID\\n /// numbers. A zero address means the ID number has not been allocated yet.\\n /// This function works just like getIDOperator except that it allows to fetch\\n /// operator addresses for multiple IDs in one call.\\n /// @param ids the array of the operator ids\\n /// @return an array of the associated operator addresses\\n function getIDOperators(uint32[] calldata ids)\\n public\\n view\\n returns (address[] memory)\\n {\\n uint256 idCount = idAddress.length;\\n\\n address[] memory operators = new address[](ids.length);\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint32 id = ids[i];\\n operators[i] = idCount > id ? idAddress[id] : address(0);\\n }\\n return operators;\\n }\\n\\n /// @notice Checks if operator is already registered in the pool.\\n /// @param operator the address of the operator\\n /// @return whether or not the operator is already registered in the pool\\n function isOperatorRegistered(address operator) public view returns (bool) {\\n return getFlaggedLeafPosition(operator) != 0;\\n }\\n\\n /// @notice Sum the number of operators in each trunk.\\n /// @return the number of operators in the pool\\n function operatorsInPool() public view returns (uint256) {\\n // Get the number of leaves that might be occupied;\\n // if `rightmostLeaf` equals `firstLeaf()` the tree must be empty,\\n // otherwise the difference between these numbers\\n // gives the number of leaves that may be occupied.\\n uint256 nPossiblyUsedLeaves = rightmostLeaf;\\n // Get the number of empty leaves\\n // not accounted for by the `rightmostLeaf`\\n uint256 nEmptyLeaves = emptyLeaves.length;\\n\\n return (nPossiblyUsedLeaves - nEmptyLeaves);\\n }\\n\\n /// @notice Convenience method to return the total weight of the pool\\n /// @return the total weight of the pool\\n function totalWeight() public view returns (uint256) {\\n return root.sumWeight();\\n }\\n\\n /// @notice Give the operator a new ID number.\\n /// Does not check if the operator already has an ID number.\\n /// @param operator the address of the operator\\n /// @return a new ID for that operator\\n function allocateOperatorID(address operator) internal returns (uint256) {\\n uint256 id = idAddress.length;\\n\\n require(id <= type(uint32).max, \\\"Pool capacity exceeded\\\");\\n\\n operatorID[operator] = uint32(id);\\n idAddress.push(operator);\\n return id;\\n }\\n\\n /// @notice Inserts an operator into the sortition pool\\n /// @param operator the address of an operator to insert\\n /// @param weight how much weight that operator has in the pool\\n function _insertOperator(address operator, uint256 weight) internal {\\n require(\\n !isOperatorRegistered(operator),\\n \\\"Operator is already registered in the pool\\\"\\n );\\n\\n // Fetch the operator's ID, and if they don't have one, allocate them one.\\n uint256 id = getOperatorID(operator);\\n if (id == 0) {\\n id = allocateOperatorID(operator);\\n }\\n\\n // Determine which leaf to insert them into\\n uint256 position = getEmptyLeafPosition();\\n // Record the block the operator was inserted in\\n uint256 theLeaf = Leaf.make(operator, block.number, id);\\n\\n // Update the leaf, and propagate the weight changes all the way up to the\\n // root.\\n root = setLeaf(position, theLeaf, weight, root);\\n\\n // Without position flags,\\n // the position 0x000000 would be treated as empty\\n flaggedLeafPosition[operator] = position.setFlag();\\n }\\n\\n /// @notice Remove an operator (and their weight) from the pool.\\n /// @param operator the address of the operator to remove\\n function _removeOperator(address operator) internal {\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n require(flaggedPosition != 0, \\\"Operator is not registered in the pool\\\");\\n uint256 unflaggedPosition = flaggedPosition.unsetFlag();\\n\\n // Update the leaf, and propagate the weight changes all the way up to the\\n // root.\\n root = removeLeaf(unflaggedPosition, root);\\n removeLeafPositionRecord(operator);\\n }\\n\\n /// @notice Update an operator's weight in the pool.\\n /// @param operator the address of the operator to update\\n /// @param weight the new weight\\n function updateOperator(address operator, uint256 weight) internal {\\n require(\\n isOperatorRegistered(operator),\\n \\\"Operator is not registered in the pool\\\"\\n );\\n\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n uint256 unflaggedPosition = flaggedPosition.unsetFlag();\\n root = updateLeaf(unflaggedPosition, weight, root);\\n }\\n\\n /// @notice Helper method to remove a leaf position record for an operator.\\n /// @param operator the address of the operator to remove the record for\\n function removeLeafPositionRecord(address operator) internal {\\n flaggedLeafPosition[operator] = 0;\\n }\\n\\n /// @notice Removes the data and weight from a particular leaf.\\n /// @param position the leaf index to remove\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function removeLeaf(uint256 position, uint256 _root)\\n internal\\n returns (uint256)\\n {\\n uint256 rightmostSubOne = rightmostLeaf - 1;\\n bool isRightmost = position == rightmostSubOne;\\n\\n // Clears out the data in the leaf node, and then propagates the weight\\n // changes all the way up to the root.\\n uint256 newRoot = setLeaf(position, 0, 0, _root);\\n\\n // Infer if need to fall back on emptyLeaves yet\\n if (isRightmost) {\\n rightmostLeaf = rightmostSubOne;\\n } else {\\n emptyLeaves.push(position);\\n }\\n return newRoot;\\n }\\n\\n /// @notice Updates the tree to give a particular leaf a new weight.\\n /// @param position the index of the leaf to update\\n /// @param weight the new weight\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function updateLeaf(\\n uint256 position,\\n uint256 weight,\\n uint256 _root\\n ) internal returns (uint256) {\\n if (getLeafWeight(position) != weight) {\\n return updateTree(position, weight, _root);\\n } else {\\n return _root;\\n }\\n }\\n\\n /// @notice Places a leaf into a particular position, with a given weight and\\n /// propagates that change.\\n /// @param position the index to place the leaf in\\n /// @param theLeaf the new leaf to place in the position\\n /// @param leafWeight the weight of the leaf\\n /// @param _root the root containing the new leaf\\n /// @return the updated root node\\n function setLeaf(\\n uint256 position,\\n uint256 theLeaf,\\n uint256 leafWeight,\\n uint256 _root\\n ) internal returns (uint256) {\\n // set leaf\\n leaves[position] = theLeaf;\\n\\n return (updateTree(position, leafWeight, _root));\\n }\\n\\n /// @notice Propagates a weight change at a position through the tree,\\n /// eventually returning the updated root.\\n /// @param position the index of leaf to update\\n /// @param weight the new weight of the leaf\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function updateTree(\\n uint256 position,\\n uint256 weight,\\n uint256 _root\\n ) internal returns (uint256) {\\n uint256 childSlot;\\n uint256 treeNode;\\n uint256 newNode;\\n uint256 nodeWeight = weight;\\n\\n uint256 parent = position;\\n // set levels 7 to 2\\n for (uint256 level = Constants.LEVELS; level >= 2; level--) {\\n childSlot = parent.slot();\\n parent = parent.parent();\\n treeNode = branches[level][parent];\\n newNode = treeNode.setSlot(childSlot, nodeWeight);\\n branches[level][parent] = newNode;\\n nodeWeight = newNode.sumWeight();\\n }\\n\\n // set level Root\\n childSlot = parent.slot();\\n return _root.setSlot(childSlot, nodeWeight);\\n }\\n\\n /// @notice Retrieves the next available empty leaf position. Tries to fill\\n /// left to right first, ignoring leaf removals, and then fills\\n /// most-recent-removals first.\\n /// @return the position of the empty leaf\\n function getEmptyLeafPosition() internal returns (uint256) {\\n uint256 rLeaf = rightmostLeaf;\\n bool spaceOnRight = (rLeaf + 1) < Constants.POOL_CAPACITY;\\n if (spaceOnRight) {\\n rightmostLeaf = rLeaf + 1;\\n return rLeaf;\\n } else {\\n uint256 emptyLeafCount = emptyLeaves.length;\\n require(emptyLeafCount > 0, \\\"Pool is full\\\");\\n uint256 emptyLeaf = emptyLeaves[emptyLeafCount - 1];\\n emptyLeaves.pop();\\n return emptyLeaf;\\n }\\n }\\n\\n /// @notice Gets the flagged leaf position for an operator.\\n /// @param operator the address of the operator\\n /// @return the leaf position of that operator\\n function getFlaggedLeafPosition(address operator)\\n internal\\n view\\n returns (uint256)\\n {\\n return flaggedLeafPosition[operator];\\n }\\n\\n /// @notice Gets the weight of a leaf at a particular position.\\n /// @param position the index of the leaf\\n /// @return the weight of the leaf at that position\\n function getLeafWeight(uint256 position) internal view returns (uint256) {\\n uint256 slot = position.slot();\\n uint256 parent = position.parent();\\n\\n // A leaf's weight information is stored a 32-bit slot in the branch layer\\n // directly above the leaf layer. To access it, we calculate that slot and\\n // parent position, and always know the hard-coded layer index.\\n uint256 node = branches[Constants.LEVELS][parent];\\n return node.getSlot(slot);\\n }\\n\\n /// @notice Picks a leaf given a random index.\\n /// @param index a number in `[0, _root.totalWeight())` used to decide\\n /// between leaves\\n /// @param _root the root of the tree\\n function pickWeightedLeaf(uint256 index, uint256 _root)\\n internal\\n view\\n returns (uint256 leafPosition)\\n {\\n uint256 currentIndex = index;\\n uint256 currentNode = _root;\\n uint256 currentPosition = 0;\\n uint256 currentSlot;\\n\\n require(index < currentNode.sumWeight(), \\\"Index exceeds weight\\\");\\n\\n // get root slot\\n (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex);\\n\\n // get slots from levels 2 to 7\\n for (uint256 level = 2; level <= Constants.LEVELS; level++) {\\n currentPosition = currentPosition.child(currentSlot);\\n currentNode = branches[level][currentPosition];\\n (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex);\\n }\\n\\n // get leaf position\\n leafPosition = currentPosition.child(currentSlot);\\n }\\n}\\n\",\"keccak256\":\"0x51daeca62ef52be78a1a9de4d2a1c5900c873165f59eda14d5965d7d7da90a03\"},\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IApproveAndCall.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\n/// @notice An interface that should be implemented by tokens supporting\\n/// `approveAndCall`/`receiveApproval` pattern.\\ninterface IApproveAndCall {\\n /// @notice Executes `receiveApproval` function on spender as specified in\\n /// `IReceiveApproval` interface. Approves spender to withdraw from\\n /// the caller multiple times, up to the `amount`. If this\\n /// function is called again, it overwrites the current allowance\\n /// with `amount`. Reverts if the approval reverted or if\\n /// `receiveApproval` call on the spender reverted.\\n function approveAndCall(\\n address spender,\\n uint256 amount,\\n bytes memory extraData\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x393d18ef81a57dcc96fff4c340cc2945deaebb37b9796c322cf2bc96872c3df8\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IERC20WithPermit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\\\";\\n\\nimport \\\"./IApproveAndCall.sol\\\";\\n\\n/// @title IERC20WithPermit\\n/// @notice Burnable ERC20 token with EIP2612 permit functionality. User can\\n/// authorize a transfer of their token with a signature conforming\\n/// EIP712 standard instead of an on-chain transaction from their\\n/// address. Anyone can submit this signature on the user's behalf by\\n/// calling the permit function, as specified in EIP2612 standard,\\n/// paying gas fees, and possibly performing other actions in the same\\n/// transaction.\\ninterface IERC20WithPermit is IERC20, IERC20Metadata, IApproveAndCall {\\n /// @notice EIP2612 approval made with secp256k1 signature.\\n /// Users can authorize a transfer of their tokens with a signature\\n /// conforming EIP712 standard, rather than an on-chain transaction\\n /// from their address. Anyone can submit this signature on the\\n /// user's behalf by calling the permit function, paying gas fees,\\n /// and possibly performing other actions in the same transaction.\\n /// @dev The deadline argument can be set to `type(uint256).max to create\\n /// permits that effectively never expire.\\n function permit(\\n address owner,\\n address spender,\\n uint256 amount,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /// @notice Destroys `amount` tokens from the caller.\\n function burn(uint256 amount) external;\\n\\n /// @notice Destroys `amount` of tokens from `account`, deducting the amount\\n /// from caller's allowance.\\n function burnFrom(address account, uint256 amount) external;\\n\\n /// @notice Returns hash of EIP712 Domain struct with the token name as\\n /// a signing domain and token contract as a verifying contract.\\n /// Used to construct EIP2612 signature provided to `permit`\\n /// function.\\n /* solhint-disable-next-line func-name-mixedcase */\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n\\n /// @notice Returns the current nonce for EIP2612 permission for the\\n /// provided token owner for a replay protection. Used to construct\\n /// EIP2612 signature provided to `permit` function.\\n function nonce(address owner) external view returns (uint256);\\n\\n /// @notice Returns EIP2612 Permit message hash. Used to construct EIP2612\\n /// signature provided to `permit` function.\\n /* solhint-disable-next-line func-name-mixedcase */\\n function PERMIT_TYPEHASH() external pure returns (bytes32);\\n}\\n\",\"keccak256\":\"0xdac9a5086c19a7128b505a7be1ab0ac1aa314f6989cb88d2417e9d7383f89fa9\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IReceiveApproval.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\n/// @notice An interface that should be implemented by contracts supporting\\n/// `approveAndCall`/`receiveApproval` pattern.\\ninterface IReceiveApproval {\\n /// @notice Receives approval to spend tokens. Called as a result of\\n /// `approveAndCall` call on the token.\\n function receiveApproval(\\n address from,\\n uint256 amount,\\n address token,\\n bytes calldata extraData\\n ) external;\\n}\\n\",\"keccak256\":\"0x6a30d83ad230548b1e7839737affc8489a035314209de14b89dbef7fb0f66395\",\"license\":\"MIT\"},\"@threshold-network/solidity-contracts/contracts/staking/IStaking.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-or-later\\n\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n\\npragma solidity ^0.8.9;\\n\\n/// @title Interface of Threshold Network staking contract\\n/// @notice The staking contract enables T owners to have their wallets offline\\n/// and their stake managed by staking providers on their behalf.\\n/// The staking contract does not define operator role. The operator\\n/// responsible for running off-chain client software is appointed by\\n/// the staking provider in the particular application utilizing the\\n/// staking contract. All off-chain client software should be able\\n/// to run without exposing operator's or staking provider\\u2019s private\\n/// key and should not require any owner\\u2019s keys at all. The stake\\n/// delegation optimizes the network throughput without compromising the\\n/// security of the owners\\u2019 stake.\\ninterface IStaking {\\n enum StakeType {\\n NU,\\n KEEP,\\n T\\n }\\n\\n //\\n //\\n // Delegating a stake\\n //\\n //\\n\\n /// @notice Creates a delegation with `msg.sender` owner with the given\\n /// staking provider, beneficiary, and authorizer. Transfers the\\n /// given amount of T to the staking contract.\\n /// @dev The owner of the delegation needs to have the amount approved to\\n /// transfer to the staking contract.\\n function stake(\\n address stakingProvider,\\n address payable beneficiary,\\n address authorizer,\\n uint96 amount\\n ) external;\\n\\n /// @notice Allows the Governance to set the minimum required stake amount.\\n /// This amount is required to protect against griefing the staking\\n /// contract and individual applications are allowed to require\\n /// higher minimum stakes if necessary.\\n function setMinimumStakeAmount(uint96 amount) external;\\n\\n //\\n //\\n // Authorizing an application\\n //\\n //\\n\\n /// @notice Allows the Governance to approve the particular application\\n /// before individual stake authorizers are able to authorize it.\\n function approveApplication(address application) external;\\n\\n /// @notice Increases the authorization of the given staking provider for\\n /// the given application by the given amount. Can only be called by\\n /// the authorizer for that staking provider.\\n /// @dev Calls `authorizationIncreased(address stakingProvider, uint256 amount)`\\n /// on the given application to notify the application about\\n /// authorization change. See `IApplication`.\\n function increaseAuthorization(\\n address stakingProvider,\\n address application,\\n uint96 amount\\n ) external;\\n\\n /// @notice Requests decrease of the authorization for the given staking\\n /// provider on the given application by the provided amount.\\n /// It may not change the authorized amount immediatelly. When\\n /// it happens depends on the application. Can only be called by the\\n /// given staking provider\\u2019s authorizer. Overwrites pending\\n /// authorization decrease for the given staking provider and\\n /// application if the application agrees for that. If the\\n /// application does not agree for overwriting, the function\\n /// reverts.\\n /// @dev Calls `authorizationDecreaseRequested(address stakingProvider, uint256 amount)`\\n /// on the given application. See `IApplication`.\\n function requestAuthorizationDecrease(\\n address stakingProvider,\\n address application,\\n uint96 amount\\n ) external;\\n\\n /// @notice Requests decrease of all authorizations for the given staking\\n /// provider on all applications by all authorized amount.\\n /// It may not change the authorized amount immediatelly. When\\n /// it happens depends on the application. Can only be called by the\\n /// given staking provider\\u2019s authorizer. Overwrites pending\\n /// authorization decrease for the given staking provider and\\n /// application.\\n /// @dev Calls `authorizationDecreaseRequested(address stakingProvider, uint256 amount)`\\n /// for each authorized application. See `IApplication`.\\n function requestAuthorizationDecrease(address stakingProvider) external;\\n\\n /// @notice Called by the application at its discretion to approve the\\n /// previously requested authorization decrease request. Can only be\\n /// called by the application that was previously requested to\\n /// decrease the authorization for that staking provider.\\n /// Returns resulting authorized amount for the application.\\n function approveAuthorizationDecrease(address stakingProvider)\\n external\\n returns (uint96);\\n\\n /// @notice Decreases the authorization for the given `stakingProvider` on\\n /// the given disabled `application`, for all authorized amount.\\n /// Can be called by anyone.\\n function forceDecreaseAuthorization(\\n address stakingProvider,\\n address application\\n ) external;\\n\\n /// @notice Pauses the given application\\u2019s eligibility to slash stakes.\\n /// Besides that stakers can't change authorization to the application.\\n /// Can be called only by the Panic Button of the particular\\n /// application. The paused application can not slash stakes until\\n /// it is approved again by the Governance using `approveApplication`\\n /// function. Should be used only in case of an emergency.\\n function pauseApplication(address application) external;\\n\\n /// @notice Disables the given application. The disabled application can't\\n /// slash stakers. Also stakers can't increase authorization to that\\n /// application but can decrease without waiting by calling\\n /// `requestAuthorizationDecrease` at any moment. Can be called only\\n /// by the governance. The disabled application can't be approved\\n /// again. Should be used only in case of an emergency.\\n function disableApplication(address application) external;\\n\\n /// @notice Sets the Panic Button role for the given application to the\\n /// provided address. Can only be called by the Governance. If the\\n /// Panic Button for the given application should be disabled, the\\n /// role address should be set to 0x0 address.\\n function setPanicButton(address application, address panicButton) external;\\n\\n /// @notice Sets the maximum number of applications one staking provider can\\n /// have authorized. Used to protect against DoSing slashing queue.\\n /// Can only be called by the Governance.\\n function setAuthorizationCeiling(uint256 ceiling) external;\\n\\n //\\n //\\n // Stake top-up\\n //\\n //\\n\\n /// @notice Increases the amount of the stake for the given staking provider.\\n /// If `autoIncrease` flag is true then the amount will be added for\\n /// all authorized applications.\\n /// @dev The sender of this transaction needs to have the amount approved to\\n /// transfer to the staking contract.\\n function topUp(address stakingProvider, uint96 amount) external;\\n\\n /// @notice Toggle `autoIncrease` flag. If true then the complete amount\\n /// in top-up will be added to already authorized applications.\\n function toggleAutoAuthorizationIncrease(address stakingProvider) external;\\n\\n //\\n //\\n // Undelegating a stake (unstaking)\\n //\\n //\\n\\n /// @notice Reduces the liquid T stake amount by the provided amount and\\n /// withdraws T to the owner. Reverts if there is at least one\\n /// authorization higher than the sum of the legacy stake and\\n /// remaining liquid T stake or if the unstake amount is higher than\\n /// the liquid T stake amount. Can be called only by the delegation\\n /// owner or the staking provider.\\n function unstakeT(address stakingProvider, uint96 amount) external;\\n\\n /// @notice Sets the legacy KEEP staking contract active stake amount cached\\n /// in T staking contract to 0. Reverts if the amount of liquid T\\n /// staked in T staking contract is lower than the highest\\n /// application authorization. This function allows to unstake from\\n /// KEEP staking contract and still being able to operate in T\\n /// network and earning rewards based on the liquid T staked. Can be\\n /// called only by the delegation owner or the staking provider.\\n function unstakeKeep(address stakingProvider) external;\\n\\n /// @notice Sets to 0 the amount of T that is cached from the legacy\\n /// NU staking contract. Reverts if there is at least one\\n /// authorization higher than the sum of remaining legacy NU stake\\n /// and native T stake for that staking provider or if the unstaked\\n /// amount is higher than the cached legacy stake amount. If succeeded,\\n /// the legacy NU stake can be partially or fully undelegated on\\n /// the legacy NU staking contract. This function allows to unstake\\n /// from NU staking contract while still being able to operate in\\n /// T network and earning rewards based on the native T staked.\\n /// Can be called only by the stake owner or the staking provider.\\n function unstakeNu(address stakingProvider) external;\\n\\n /// @notice Sets cached legacy stake amount to 0, sets the liquid T stake\\n /// amount to 0 and withdraws all liquid T from the stake to the\\n /// owner. Reverts if there is at least one non-zero authorization.\\n /// Can be called only by the delegation owner or the staking\\n /// provider.\\n function unstakeAll(address stakingProvider) external;\\n\\n //\\n //\\n // Keeping information in sync\\n //\\n //\\n\\n /// @notice Sets reward in T tokens for notification of misbehaviour\\n /// of one staking provider. Can only be called by the governance.\\n function setNotificationReward(uint96 reward) external;\\n\\n /// @notice Transfer some amount of T tokens as reward for notifications\\n /// of misbehaviour\\n function pushNotificationReward(uint96 reward) external;\\n\\n /// @notice Withdraw some amount of T tokens from notifiers treasury.\\n /// Can only be called by the governance.\\n function withdrawNotificationReward(address recipient, uint96 amount)\\n external;\\n\\n /// @notice Adds staking providers to the slashing queue along with the\\n /// amount that should be slashed from each one of them. Can only be\\n /// called by application authorized for all staking providers in\\n /// the array.\\n function slash(uint96 amount, address[] memory stakingProviders) external;\\n\\n /// @notice Adds staking providers to the slashing queue along with the\\n /// amount. The notifier will receive reward per each staking\\n /// provider from notifiers treasury. Can only be called by\\n /// application authorized for all staking providers in the array.\\n function seize(\\n uint96 amount,\\n uint256 rewardMultipier,\\n address notifier,\\n address[] memory stakingProviders\\n ) external;\\n\\n /// @notice Takes the given number of queued slashing operations and\\n /// processes them. Receives 5% of the slashed amount.\\n /// Executes `involuntaryAllocationDecrease` function on each\\n /// affected application.\\n function processSlashing(uint256 count) external;\\n\\n //\\n //\\n // Auxiliary functions\\n //\\n //\\n\\n /// @notice Returns the authorized stake amount of the staking provider for\\n /// the application.\\n function authorizedStake(address stakingProvider, address application)\\n external\\n view\\n returns (uint96);\\n\\n /// @notice Returns staked amount of T, Keep and Nu for the specified\\n /// staking provider.\\n /// @dev All values are in T denomination\\n function stakes(address stakingProvider)\\n external\\n view\\n returns (\\n uint96 tStake,\\n uint96 keepInTStake,\\n uint96 nuInTStake\\n );\\n\\n /// @notice Returns start staking timestamp.\\n /// @dev This value is set at most once.\\n function getStartStakingTimestamp(address stakingProvider)\\n external\\n view\\n returns (uint256);\\n\\n /// @notice Returns auto-increase flag.\\n function getAutoIncreaseFlag(address stakingProvider)\\n external\\n view\\n returns (bool);\\n\\n /// @notice Returns staked amount of NU for the specified staking provider.\\n function stakedNu(address stakingProvider) external view returns (uint256);\\n\\n /// @notice Gets the stake owner, the beneficiary and the authorizer\\n /// for the specified staking provider address.\\n /// @return owner Stake owner address.\\n /// @return beneficiary Beneficiary address.\\n /// @return authorizer Authorizer address.\\n function rolesOf(address stakingProvider)\\n external\\n view\\n returns (\\n address owner,\\n address payable beneficiary,\\n address authorizer\\n );\\n\\n /// @notice Returns length of application array\\n function getApplicationsLength() external view returns (uint256);\\n\\n /// @notice Returns length of slashing queue\\n function getSlashingQueueLength() external view returns (uint256);\\n\\n /// @notice Returns minimum possible stake for T, KEEP or NU in T\\n /// denomination.\\n /// @dev For example, suppose the given staking provider has 10 T, 20 T worth\\n /// of KEEP, and 30 T worth of NU all staked, and the maximum\\n /// application authorization is 40 T, then `getMinStaked` for\\n /// that staking provider returns:\\n /// * 0 T if KEEP stake type specified i.e.\\n /// min = 40 T max - (10 T) = 30 T\\n /// * 10 T if NU stake type specified i.e.\\n /// min = 40 T max - (10 T) = 30 T\\n /// * 0 T if T stake type specified i.e.\\n /// min = 40 T max = 40 T\\n /// In other words, the minimum stake amount for the specified\\n /// stake type is the minimum amount of stake of the given type\\n /// needed to satisfy the maximum application authorization given\\n /// the staked amounts of the T stake types for that staking provider.\\n function getMinStaked(address stakingProvider, StakeType stakeTypes)\\n external\\n view\\n returns (uint96);\\n\\n /// @notice Returns available amount to authorize for the specified application\\n function getAvailableToAuthorize(\\n address stakingProvider,\\n address application\\n ) external view returns (uint96);\\n}\\n\",\"keccak256\":\"0xc8fbea45ba10de0383d6e7b2dd0f3931971e1b702e4a308ff8325bb23fdff81c\",\"license\":\"GPL-3.0-or-later\"},\"contracts/libraries/BeaconAuthorization.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\n// Initial version copied from Keep Network ECDSA Wallets:\\n// https://github.com/keep-network/keep-core/blob/5286ebc8ff99b2aa6569f9dd97fd6995f25b4630/solidity/ecdsa/contracts/libraries/EcdsaAuthorization.sol\\n//\\n// With the following differences:\\n// - functions' visibility was changed to public/external to deploy it as a linked\\n// library.\\n// - documentation was updated to be more generic.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\nimport \\\"@threshold-network/solidity-contracts/contracts/staking/IStaking.sol\\\";\\n\\n/// @notice Library managing the state of stake authorizations for the operator\\n/// contract and the presence of operators in the sortition\\n/// pool based on the stake authorized for them.\\nlibrary BeaconAuthorization {\\n struct Parameters {\\n // The minimum authorization required by the beacon so that\\n // operator can join the sortition pool and do the work.\\n uint96 minimumAuthorization;\\n // Authorization decrease delay in seconds between the time\\n // authorization decrease is requested and the time the authorization\\n // decrease can be approved. It is always the same value, no matter if\\n // authorization decrease amount is small, significant, or if it is\\n // a decrease to zero.\\n uint64 authorizationDecreaseDelay;\\n // The time period before the authorization decrease delay end,\\n // during which the authorization decrease request can be overwritten.\\n //\\n // When the request is overwritten, the authorization decrease delay is\\n // reset.\\n //\\n // For example, if `authorizationDecraseChangePeriod` is set to 4\\n // days, `authorizationDecreaseDelay` is set to 14 days, and someone\\n // requested authorization decrease, it means they can not\\n // request another decrease for the first 10 days. After 10 days pass,\\n // they can request again and overwrite the previous authorization\\n // decrease request. The delay time will reset for them and they\\n // will have to wait another 10 days to alter it and 14 days to\\n // approve it.\\n //\\n // This value protects against malicious operators who manipulate\\n // their weight by overwriting authorization decrease request, and\\n // lowering or increasing their eligible stake this way.\\n //\\n // If set to a value equal to `authorizationDecreaseDelay, it means\\n // that authorization decrease request can be always overwritten.\\n // If set to zero, it means authorization decrease request can not be\\n // overwritten until the delay end, and one needs to wait for the entire\\n // authorization decrease delay to approve their decrease and request\\n // for another one or to overwrite the pending one.\\n //\\n // (1) authorization decrease requested timestamp\\n // (2) from this moment authorization decrease request can be\\n // overwritten\\n // (3) from this moment authorization decrease request can be\\n // approved, assuming it was NOT overwritten in (2)\\n //\\n // (1) (2) (3)\\n // --x------------------------------x--------------------------x---->\\n // | \\\\________________________/\\n // | authorizationDecreaseChangePeriod\\n // \\\\______________________________________________________/\\n // authorizationDecreaseDelay\\n //\\n uint64 authorizationDecreaseChangePeriod;\\n }\\n\\n struct AuthorizationDecrease {\\n uint96 decreasingBy; // amount\\n uint64 decreasingAt; // timestamp\\n }\\n\\n struct Data {\\n Parameters parameters;\\n mapping(address => address) stakingProviderToOperator;\\n mapping(address => address) operatorToStakingProvider;\\n mapping(address => AuthorizationDecrease) pendingDecreases;\\n }\\n\\n event OperatorRegistered(\\n address indexed stakingProvider,\\n address indexed operator\\n );\\n\\n event AuthorizationIncreased(\\n address indexed stakingProvider,\\n address indexed operator,\\n uint96 fromAmount,\\n uint96 toAmount\\n );\\n\\n event AuthorizationDecreaseRequested(\\n address indexed stakingProvider,\\n address indexed operator,\\n uint96 fromAmount,\\n uint96 toAmount,\\n uint64 decreasingAt\\n );\\n\\n event AuthorizationDecreaseApproved(address indexed stakingProvider);\\n\\n event InvoluntaryAuthorizationDecreaseFailed(\\n address indexed stakingProvider,\\n address indexed operator,\\n uint96 fromAmount,\\n uint96 toAmount\\n );\\n\\n event OperatorJoinedSortitionPool(\\n address indexed stakingProvider,\\n address indexed operator\\n );\\n\\n event OperatorStatusUpdated(\\n address indexed stakingProvider,\\n address indexed operator\\n );\\n\\n /// @notice Updates authorization-related parameters.\\n /// @param _minimumAuthorization New value of the minimum authorization for\\n /// the beacon. Without at least the minimum authorization, staking\\n /// provider is not eligible to join and operate in the network.\\n /// @param _authorizationDecreaseDelay New value of the authorization\\n /// decrease delay. It is the time in seconds that needs to pass\\n /// between the time authorization decrease is requested and the time\\n /// the authorization decrease can be approved, no matter the\\n /// authorization decrease amount.\\n /// @param _authorizationDecreaseChangePeriod New value of the authorization\\n /// decrease change period. It is the time in seconds, before\\n /// authorization decrease delay end, during which the pending\\n /// authorization decrease request can be overwritten.\\n /// If set to 0, pending authorization decrease request can not be\\n /// overwritten until the entire `authorizationDecreaseDelay` ends.\\n /// If set to value equal `authorizationDecreaseDelay`, request can\\n /// always be overwritten.\\n function setParameters(\\n Data storage self,\\n uint96 _minimumAuthorization,\\n uint64 _authorizationDecreaseDelay,\\n uint64 _authorizationDecreaseChangePeriod\\n ) external {\\n self.parameters.minimumAuthorization = _minimumAuthorization;\\n self\\n .parameters\\n .authorizationDecreaseDelay = _authorizationDecreaseDelay;\\n self\\n .parameters\\n .authorizationDecreaseChangePeriod = _authorizationDecreaseChangePeriod;\\n }\\n\\n /// @notice Used by staking provider to set operator address that will\\n /// operate a node. The given staking provider can set operator\\n /// address only one time. The operator address can not be changed\\n /// and must be unique. Reverts if the operator is already set for\\n /// the staking provider or if the operator address is already in\\n /// use. Reverts if there is a pending authorization decrease for\\n /// the staking provider.\\n function registerOperator(Data storage self, address operator) public {\\n address stakingProvider = msg.sender;\\n\\n require(operator != address(0), \\\"Operator can not be zero address\\\");\\n require(\\n self.stakingProviderToOperator[stakingProvider] == address(0),\\n \\\"Operator already set for the staking provider\\\"\\n );\\n require(\\n self.operatorToStakingProvider[operator] == address(0),\\n \\\"Operator address already in use\\\"\\n );\\n\\n // Authorization request for a staking provider who has not yet\\n // registered their operator can be approved immediately.\\n // We need to make sure that the approval happens before operator\\n // is registered to do not let the operator join the sortition pool\\n // with an unresolved authorization decrease request that can be\\n // approved at any point.\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n require(\\n decrease.decreasingAt == 0,\\n \\\"There is a pending authorization decrease request\\\"\\n );\\n\\n emit OperatorRegistered(stakingProvider, operator);\\n\\n self.stakingProviderToOperator[stakingProvider] = operator;\\n self.operatorToStakingProvider[operator] = stakingProvider;\\n }\\n\\n /// @notice Used by T staking contract to inform the beacon that the\\n /// authorized stake amount for the given staking provider increased.\\n ///\\n /// Reverts if the authorization amount is below the minimum.\\n ///\\n /// The function is not updating the sortition pool. Sortition pool\\n /// state needs to be updated by the operator with a call to\\n /// `joinSortitionPool` or `updateOperatorStatus`.\\n ///\\n /// @dev Should only be callable by T staking contract.\\n function authorizationIncreased(\\n Data storage self,\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external {\\n require(\\n toAmount >= self.parameters.minimumAuthorization,\\n \\\"Authorization below the minimum\\\"\\n );\\n\\n // Note that this function does not require the operator address to be\\n // set for the given staking provider. This allows the stake owner\\n // who is also an authorizer to increase the authorization before the\\n // staking provider sets the operator. This allows delegating stake\\n // and increasing authorization immediately one after another without\\n // having to wait for the staking provider to do their part.\\n\\n address operator = self.stakingProviderToOperator[stakingProvider];\\n emit AuthorizationIncreased(\\n stakingProvider,\\n operator,\\n fromAmount,\\n toAmount\\n );\\n }\\n\\n /// @notice Used by T staking contract to inform the beacon that the\\n /// authorization decrease for the given staking provider has been\\n /// requested.\\n ///\\n /// Reverts if the amount after deauthorization would be non-zero\\n /// and lower than the minimum authorization.\\n ///\\n /// Reverts if another authorization decrease request is pending for\\n /// the staking provider and not enough time passed since the\\n /// original request (see `authorizationDecreaseChangePeriod`).\\n ///\\n /// If the operator is not known (`registerOperator` was not called)\\n /// it lets to `approveAuthorizationDecrease` immediately. If the\\n /// operator is known (`registerOperator` was called), the operator\\n /// needs to update state of the sortition pool with a call to\\n /// `joinSortitionPool` or `updateOperatorStatus`. After the\\n /// sortition pool state is in sync, authorization decrease delay\\n /// starts.\\n ///\\n /// After authorization decrease delay passes, authorization\\n /// decrease request needs to be approved with a call to\\n /// `approveAuthorizationDecrease` function.\\n ///\\n /// If there is a pending authorization decrease request, it is\\n /// overwritten, but only if enough time passed since the original\\n /// request. Otherwise, the function reverts.\\n ///\\n /// @dev Should only be callable by T staking contract.\\n function authorizationDecreaseRequested(\\n Data storage self,\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) public {\\n require(\\n toAmount == 0 || toAmount >= self.parameters.minimumAuthorization,\\n \\\"Authorization amount should be 0 or above the minimum\\\"\\n );\\n\\n address operator = self.stakingProviderToOperator[stakingProvider];\\n\\n uint64 decreasingAt;\\n\\n if (operator == address(0)) {\\n // Operator is not known. It means `registerOperator` was not\\n // called yet, and there is no chance the operator could\\n // call `joinSortitionPool`. We can let to approve authorization\\n // decrease immediately because that operator was never in the\\n // sortition pool.\\n\\n // solhint-disable-next-line not-rely-on-time\\n decreasingAt = uint64(block.timestamp);\\n } else {\\n // Operator is known. It means that this operator is or was in\\n // the sortition pool. Before authorization decrease delay starts,\\n // the operator needs to update the state of the sortition pool\\n // with a call to `joinSortitionPool` or `updateOperatorStatus`.\\n // For now, we set `decreasingAt` as \\\"never decreasing\\\" and let\\n // it be updated by `joinSortitionPool` or `updateOperatorStatus`\\n // once we know the sortition pool is in sync.\\n decreasingAt = type(uint64).max;\\n }\\n\\n uint96 decreasingBy = fromAmount - toAmount;\\n\\n AuthorizationDecrease storage decreaseRequest = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n uint64 pendingDecreaseAt = decreaseRequest.decreasingAt;\\n if (pendingDecreaseAt != 0 && pendingDecreaseAt != type(uint64).max) {\\n // If there is already a pending authorization decrease request for\\n // this staking provider and that request has been activated\\n // (sortition pool was updated), require enough time to pass before\\n // it can be overwritten.\\n require(\\n // solhint-disable-next-line not-rely-on-time\\n block.timestamp >=\\n pendingDecreaseAt -\\n self.parameters.authorizationDecreaseChangePeriod,\\n \\\"Not enough time passed since the original request\\\"\\n );\\n }\\n\\n decreaseRequest.decreasingBy = decreasingBy;\\n decreaseRequest.decreasingAt = decreasingAt;\\n\\n emit AuthorizationDecreaseRequested(\\n stakingProvider,\\n operator,\\n fromAmount,\\n toAmount,\\n decreasingAt\\n );\\n }\\n\\n /// @notice Approves the previously registered authorization decrease\\n /// request. Reverts if authorization decrease delay have not passed\\n /// yet or if the authorization decrease was not requested for the\\n /// given staking provider.\\n function approveAuthorizationDecrease(\\n Data storage self,\\n IStaking tokenStaking,\\n address stakingProvider\\n ) public {\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n require(\\n decrease.decreasingAt > 0,\\n \\\"Authorization decrease not requested\\\"\\n );\\n require(\\n decrease.decreasingAt != type(uint64).max,\\n \\\"Authorization decrease request not activated\\\"\\n );\\n require(\\n // solhint-disable-next-line not-rely-on-time\\n block.timestamp >= decrease.decreasingAt,\\n \\\"Authorization decrease delay not passed\\\"\\n );\\n\\n emit AuthorizationDecreaseApproved(stakingProvider);\\n\\n // slither-disable-next-line unused-return\\n tokenStaking.approveAuthorizationDecrease(stakingProvider);\\n delete self.pendingDecreases[stakingProvider];\\n }\\n\\n /// @notice Used by T staking contract to inform the beacon the\\n /// authorization has been decreased for the given staking provider\\n /// involuntarily, as a result of slashing.\\n ///\\n /// If the operator is not known (`registerOperator` was not called)\\n /// the function does nothing. The operator was never in a sortition\\n /// pool so there is nothing to update.\\n ///\\n /// If the operator is known, sortition pool is unlocked, and the\\n /// operator is in the sortition pool, the sortition pool state is\\n /// updated. If the sortition pool is locked, update needs to be\\n /// postponed. Every other staker is incentivized to call\\n /// `updateOperatorStatus` for the problematic operator to increase\\n /// their own rewards in the pool.\\n ///\\n /// @dev Should only be callable by T staking contract.\\n function involuntaryAuthorizationDecrease(\\n Data storage self,\\n IStaking tokenStaking,\\n SortitionPool sortitionPool,\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external {\\n address operator = self.stakingProviderToOperator[stakingProvider];\\n\\n if (operator == address(0)) {\\n // Operator is not known. It means `registerOperator` was not\\n // called yet, and there is no chance the operator could\\n // call `joinSortitionPool`. We can just ignore this update because\\n // operator was never in the sortition pool.\\n return;\\n } else {\\n // Operator is known. It means that this operator is or was in the\\n // sortition pool and the sortition pool may need to be updated.\\n //\\n // If the sortition pool is not locked and the operator is in the\\n // sortition pool, we are updating it.\\n //\\n // To keep stakes synchronized between applications when staking\\n // providers are slashed, without the risk of running out of gas,\\n // the staking contract queues up slashings and let users process\\n // the transactions. When an application slashes one or more staking\\n // providers, it adds them to the slashing queue on the staking\\n // contract. A queue entry contains the staking provider\\u2019s address\\n // and the amount they are due to be slashed.\\n //\\n // When there is at least one staking provider in the slashing\\n // queue, any account can submit a transaction processing one or\\n // more staking providers' slashings, and collecting a reward for\\n // doing so. A queued slashing is processed by updating the staking\\n // provider\\u2019s stake to the post-slashing amount, updating authorized\\n // amount for each affected application, and notifying all affected\\n // applications that the staking provider\\u2019s authorized stake has\\n // been reduced due to slashing.\\n //\\n // The entire idea is that the process transaction is expensive\\n // because each application needs to be updated, so the reward for\\n // the processor is hefty and comes from the slashed tokens.\\n // Practically, it means that if the sortition pool is unlocked, and\\n // can be updated, it should be updated because we already paid\\n // someone for updating it.\\n //\\n // If the sortition pool is locked, update needs to wait. Other\\n // sortition pool members are incentivized to call\\n // `updateOperatorStatus` for the problematic operator because they\\n // will increase their rewards this way.\\n if (sortitionPool.isOperatorInPool(operator)) {\\n if (sortitionPool.isLocked()) {\\n emit InvoluntaryAuthorizationDecreaseFailed(\\n stakingProvider,\\n operator,\\n fromAmount,\\n toAmount\\n );\\n } else {\\n updateOperatorStatus(\\n self,\\n tokenStaking,\\n sortitionPool,\\n operator\\n );\\n }\\n }\\n }\\n }\\n\\n /// @notice Lets the operator join the sortition pool. The operator address\\n /// must be known - before calling this function, it has to be\\n /// appointed by the staking provider by calling `registerOperator`.\\n /// Also, the operator must have the minimum authorization required\\n /// by the beacon. Function reverts if there is no minimum stake\\n /// authorized or if the operator is not known. If there was an\\n /// authorization decrease requested, it is activated by starting\\n /// the authorization decrease delay.\\n function joinSortitionPool(\\n Data storage self,\\n IStaking tokenStaking,\\n SortitionPool sortitionPool\\n ) public {\\n address operator = msg.sender;\\n\\n address stakingProvider = self.operatorToStakingProvider[operator];\\n require(stakingProvider != address(0), \\\"Unknown operator\\\");\\n\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n uint96 _eligibleStake = eligibleStake(\\n self,\\n tokenStaking,\\n stakingProvider,\\n decrease.decreasingBy\\n );\\n\\n require(_eligibleStake != 0, \\\"Authorization below the minimum\\\");\\n\\n emit OperatorJoinedSortitionPool(stakingProvider, operator);\\n\\n sortitionPool.insertOperator(operator, _eligibleStake);\\n\\n // If there is a pending authorization decrease request, activate it.\\n // At this point, the sortition pool state is up to date so the\\n // authorization decrease delay can start counting.\\n if (decrease.decreasingAt == type(uint64).max) {\\n decrease.decreasingAt =\\n // solhint-disable-next-line not-rely-on-time\\n uint64(block.timestamp) +\\n self.parameters.authorizationDecreaseDelay;\\n }\\n }\\n\\n /// @notice Updates status of the operator in the sortition pool. If there\\n /// was an authorization decrease requested, it is activated by\\n /// starting the authorization decrease delay.\\n /// Function reverts if the operator is not known.\\n function updateOperatorStatus(\\n Data storage self,\\n IStaking tokenStaking,\\n SortitionPool sortitionPool,\\n address operator\\n ) public {\\n address stakingProvider = self.operatorToStakingProvider[operator];\\n require(stakingProvider != address(0), \\\"Unknown operator\\\");\\n\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n emit OperatorStatusUpdated(stakingProvider, operator);\\n\\n if (sortitionPool.isOperatorInPool(operator)) {\\n uint96 _eligibleStake = eligibleStake(\\n self,\\n tokenStaking,\\n stakingProvider,\\n decrease.decreasingBy\\n );\\n\\n sortitionPool.updateOperatorStatus(operator, _eligibleStake);\\n }\\n\\n // If there is a pending authorization decrease request, activate it.\\n // At this point, the sortition pool state is up to date so the\\n // authorization decrease delay can start counting.\\n if (decrease.decreasingAt == type(uint64).max) {\\n decrease.decreasingAt =\\n // solhint-disable-next-line not-rely-on-time\\n uint64(block.timestamp) +\\n self.parameters.authorizationDecreaseDelay;\\n }\\n }\\n\\n /// @notice Checks if the operator's authorized stake is in sync with\\n /// operator's weight in the sortition pool.\\n /// If the operator is not in the sortition pool and their\\n /// authorized stake is non-zero, function returns false.\\n function isOperatorUpToDate(\\n Data storage self,\\n IStaking tokenStaking,\\n SortitionPool sortitionPool,\\n address operator\\n ) external view returns (bool) {\\n address stakingProvider = self.operatorToStakingProvider[operator];\\n require(stakingProvider != address(0), \\\"Unknown operator\\\");\\n\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n uint96 _eligibleStake = eligibleStake(\\n self,\\n tokenStaking,\\n stakingProvider,\\n decrease.decreasingBy\\n );\\n\\n if (!sortitionPool.isOperatorInPool(operator)) {\\n return _eligibleStake == 0;\\n } else {\\n return sortitionPool.isOperatorUpToDate(operator, _eligibleStake);\\n }\\n }\\n\\n /// @notice Returns the current value of the staking provider's eligible\\n /// stake. Eligible stake is defined as the currently authorized\\n /// stake minus the pending authorization decrease. Eligible stake\\n /// is what is used for operator's weight in the pool. If the\\n /// authorized stake minus the pending authorization decrease is\\n /// below the minimum authorization, eligible stake is 0.\\n /// @dev This function can be exposed to the public in contrast to the\\n /// second variant accepting `decreasingBy` as a parameter.\\n function eligibleStake(\\n Data storage self,\\n IStaking tokenStaking,\\n address stakingProvider\\n ) external view returns (uint96) {\\n return\\n eligibleStake(\\n self,\\n tokenStaking,\\n stakingProvider,\\n pendingAuthorizationDecrease(self, stakingProvider)\\n );\\n }\\n\\n /// @notice Returns the current value of the staking provider's eligible\\n /// stake. Eligible stake is defined as the currently authorized\\n /// stake minus the pending authorization decrease. Eligible stake\\n /// is what is used for operator's weight in the pool. If the\\n /// authorized stake minus the pending authorization decrease is\\n /// below the minimum authorization, eligible stake is 0.\\n /// @dev This function is not intended to be exposes to the public.\\n /// `decreasingBy` must be fetched from `pendingDecreases` mapping and\\n /// it is passed as a parameter to optimize gas usage of functions that\\n /// call `eligibleStake` and need to use `AuthorizationDecrease`\\n /// fetched from `pendingDecreases` for some additional logic.\\n function eligibleStake(\\n Data storage self,\\n IStaking tokenStaking,\\n address stakingProvider,\\n uint96 decreasingBy\\n ) public view returns (uint96) {\\n uint96 authorizedStake = tokenStaking.authorizedStake(\\n stakingProvider,\\n address(this)\\n );\\n\\n uint96 _eligibleStake = authorizedStake > decreasingBy\\n ? authorizedStake - decreasingBy\\n : 0;\\n\\n if (_eligibleStake < self.parameters.minimumAuthorization) {\\n return 0;\\n } else {\\n return _eligibleStake;\\n }\\n }\\n\\n /// @notice Returns the amount of stake that is pending authorization\\n /// decrease for the given staking provider. If no authorization\\n /// decrease has been requested, returns zero.\\n function pendingAuthorizationDecrease(\\n Data storage self,\\n address stakingProvider\\n ) public view returns (uint96) {\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n return decrease.decreasingBy;\\n }\\n\\n /// @notice Returns the remaining time in seconds that needs to pass before\\n /// the requested authorization decrease can be approved.\\n /// If the sortition pool state was not updated yet by the operator\\n /// after requesting the authorization decrease, returns\\n /// `type(uint64).max`.\\n function remainingAuthorizationDecreaseDelay(\\n Data storage self,\\n address stakingProvider\\n ) external view returns (uint64) {\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n if (decrease.decreasingAt == type(uint64).max) {\\n return type(uint64).max;\\n }\\n\\n // solhint-disable-next-line not-rely-on-time\\n uint64 _now = uint64(block.timestamp);\\n return _now > decrease.decreasingAt ? 0 : decrease.decreasingAt - _now;\\n }\\n}\\n\",\"keccak256\":\"0xe146f4a3c662e971317d0189b2fca613f9f83a163ef682ed1e536e6c1f919a08\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "storageLayout": { + "storage": [], + "types": null + }, + "userdoc": { + "kind": "user", + "methods": { + "approveAuthorizationDecrease(BeaconAuthorization.Data storage,IStaking,address)": { + "notice": "Approves the previously registered authorization decrease request. Reverts if authorization decrease delay have not passed yet or if the authorization decrease was not requested for the given staking provider." + }, + "authorizationDecreaseRequested(BeaconAuthorization.Data storage,address,uint96,uint96)": { + "notice": "Used by T staking contract to inform the beacon that the authorization decrease for the given staking provider has been requested. Reverts if the amount after deauthorization would be non-zero and lower than the minimum authorization. Reverts if another authorization decrease request is pending for the staking provider and not enough time passed since the original request (see `authorizationDecreaseChangePeriod`). If the operator is not known (`registerOperator` was not called) it lets to `approveAuthorizationDecrease` immediately. If the operator is known (`registerOperator` was called), the operator needs to update state of the sortition pool with a call to `joinSortitionPool` or `updateOperatorStatus`. After the sortition pool state is in sync, authorization decrease delay starts. After authorization decrease delay passes, authorization decrease request needs to be approved with a call to `approveAuthorizationDecrease` function. If there is a pending authorization decrease request, it is overwritten, but only if enough time passed since the original request. Otherwise, the function reverts." + }, + "authorizationIncreased(BeaconAuthorization.Data storage,address,uint96,uint96)": { + "notice": "Used by T staking contract to inform the beacon that the authorized stake amount for the given staking provider increased. Reverts if the authorization amount is below the minimum. The function is not updating the sortition pool. Sortition pool state needs to be updated by the operator with a call to `joinSortitionPool` or `updateOperatorStatus`." + }, + "eligibleStake(BeaconAuthorization.Data storage,IStaking,address)": { + "notice": "Returns the current value of the staking provider's eligible stake. Eligible stake is defined as the currently authorized stake minus the pending authorization decrease. Eligible stake is what is used for operator's weight in the pool. If the authorized stake minus the pending authorization decrease is below the minimum authorization, eligible stake is 0." + }, + "eligibleStake(BeaconAuthorization.Data storage,IStaking,address,uint96)": { + "notice": "Returns the current value of the staking provider's eligible stake. Eligible stake is defined as the currently authorized stake minus the pending authorization decrease. Eligible stake is what is used for operator's weight in the pool. If the authorized stake minus the pending authorization decrease is below the minimum authorization, eligible stake is 0." + }, + "involuntaryAuthorizationDecrease(BeaconAuthorization.Data storage,IStaking,SortitionPool,address,uint96,uint96)": { + "notice": "Used by T staking contract to inform the beacon the authorization has been decreased for the given staking provider involuntarily, as a result of slashing. If the operator is not known (`registerOperator` was not called) the function does nothing. The operator was never in a sortition pool so there is nothing to update. If the operator is known, sortition pool is unlocked, and the operator is in the sortition pool, the sortition pool state is updated. If the sortition pool is locked, update needs to be postponed. Every other staker is incentivized to call `updateOperatorStatus` for the problematic operator to increase their own rewards in the pool." + }, + "isOperatorUpToDate(BeaconAuthorization.Data storage,IStaking,SortitionPool,address)": { + "notice": "Checks if the operator's authorized stake is in sync with operator's weight in the sortition pool. If the operator is not in the sortition pool and their authorized stake is non-zero, function returns false." + }, + "joinSortitionPool(BeaconAuthorization.Data storage,IStaking,SortitionPool)": { + "notice": "Lets the operator join the sortition pool. The operator address must be known - before calling this function, it has to be appointed by the staking provider by calling `registerOperator`. Also, the operator must have the minimum authorization required by the beacon. Function reverts if there is no minimum stake authorized or if the operator is not known. If there was an authorization decrease requested, it is activated by starting the authorization decrease delay." + }, + "pendingAuthorizationDecrease(BeaconAuthorization.Data storage,address)": { + "notice": "Returns the amount of stake that is pending authorization decrease for the given staking provider. If no authorization decrease has been requested, returns zero." + }, + "registerOperator(BeaconAuthorization.Data storage,address)": { + "notice": "Used by staking provider to set operator address that will operate a node. The given staking provider can set operator address only one time. The operator address can not be changed and must be unique. Reverts if the operator is already set for the staking provider or if the operator address is already in use. Reverts if there is a pending authorization decrease for the staking provider." + }, + "remainingAuthorizationDecreaseDelay(BeaconAuthorization.Data storage,address)": { + "notice": "Returns the remaining time in seconds that needs to pass before the requested authorization decrease can be approved. If the sortition pool state was not updated yet by the operator after requesting the authorization decrease, returns `type(uint64).max`." + }, + "setParameters(BeaconAuthorization.Data storage,uint96,uint64,uint64)": { + "notice": "Updates authorization-related parameters." + }, + "updateOperatorStatus(BeaconAuthorization.Data storage,IStaking,SortitionPool,address)": { + "notice": "Updates status of the operator in the sortition pool. If there was an authorization decrease requested, it is activated by starting the authorization decrease delay. Function reverts if the operator is not known." + } + }, + "notice": "Library managing the state of stake authorizations for the operator contract and the presence of operators in the sortition pool based on the stake authorized for them.", + "version": 1 + } +} diff --git a/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/libraries/BeaconDkg.sol/BeaconDkg.json b/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/libraries/BeaconDkg.sol/BeaconDkg.json new file mode 100644 index 0000000000..7e35968dfa --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/libraries/BeaconDkg.sol/BeaconDkg.json @@ -0,0 +1,226 @@ +{ + "contractName": "BeaconDkg", + "sourceName": "contracts/libraries/BeaconDkg.sol", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "approver", + "type": "address" + } + ], + "name": "DkgResultApproved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "indexed": false, + "internalType": "string", + "name": "reason", + "type": "string" + } + ], + "name": "DkgResultChallenged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "seed", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "indexed": false, + "internalType": "struct BeaconDkg.Result", + "name": "result", + "type": "tuple" + } + ], + "name": "DkgResultSubmitted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "DkgSeedTimedOut", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "seed", + "type": "uint256" + } + ], + "name": "DkgStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "DkgStateLocked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "DkgTimedOut", + "type": "event" + }, + { + "inputs": [], + "name": "groupSize", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "offchainDkgTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": "0x6112ca61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100615760003560e01c80630a1ba38e1461006657806346bf00db1461008157806363b635ea146100bb578063716ae957146100c3578063a29355e0146100f0575b600080fd5b61006e604881565b6040519081526020015b60405180910390f35b81801561008d57600080fd5b506100a161009c366004610cd5565b610112565b6040805192835263ffffffff909116602083015201610078565b61006e604081565b8180156100cf57600080fd5b506100e36100de366004610cd5565b61048c565b6040516100789190610d23565b8180156100fc57600080fd5b5061011061010b366004610cd5565b6108b5565b005b600080600461012085610bc5565b600481111561013157610131610d6d565b146101835760405162461bcd60e51b815260206004820152601e60248201527f43757272656e74207374617465206973206e6f74204348414c4c454e4745000060448201526064015b60405180910390fd5b6002840154600a8501546101979190610d99565b4311156101f25760405162461bcd60e51b815260206004820152602360248201527f4368616c6c656e676520706572696f642068617320616c7265616479207061736044820152621cd95960ea1b606482015260840161017a565b8360090154836040516020016102089190610ff9565b60405160208183030381529060405280519060200120146102915760405162461bcd60e51b815260206004820152603a60248201527f526573756c7420756e646572206368616c6c656e67652069732064696666657260448201527f656e74207468616e20746865207375626d6974746564206f6e65000000000000606482015260840161017a565b6001840154600785015460068601546040516373b33d5d60e11b81526001600160a01b039093169263e7667aba926102cd928892600401611013565b600060405180830381865afa92505050801561030b57506040513d6000823e601f3d908101601f191682016040526103089190810190611082565b60015b61038057336001600160a01b031684600901547f703feb01415a2995816e8d082fd7aad0eacada1a2f63fdb3226e47f8a0285436604051610373906020808252601390820152721d985b1a59185d1a5bdb881c995d995c9d1959606a1b604082015260600190565b60405180910390a361040f565b81156103c65760405162461bcd60e51b8152602060048201526015602482015274756e6a7573746966696564206368616c6c656e676560581b604482015260640161017a565b336001600160a01b031686600901547f703feb01415a2995816e8d082fd7aad0eacada1a2f63fdb3226e47f8a0285436836040516104049190611142565b60405180910390a350505b6009840154915061042360a0840184611175565b61042f600186356111bf565b81811061043e5761043e6111d2565b905060200201602081019061045391906111e8565b9050604884600601544361046791906111bf565b61047191906111bf565b6008850155600060098501819055600a8501555b9250929050565b6060600461049984610bc5565b60048111156104aa576104aa610d6d565b146104f75760405162461bcd60e51b815260206004820152601e60248201527f43757272656e74207374617465206973206e6f74204348414c4c454e47450000604482015260640161017a565b6002830154600a84015460009161050d91610d99565b905080431161056a5760405162461bcd60e51b815260206004820152602360248201527f4368616c6c656e676520706572696f6420686173206e6f7420706173736564206044820152621e595d60ea1b606482015260840161017a565b8360090154836040516020016105809190610ff9565b60405160208183030381529060405280519060200120146106095760405162461bcd60e51b815260206004820152603960248201527f526573756c7420756e64657220617070726f76616c206973206469666665726560448201527f6e74207468616e20746865207375626d6974746564206f6e6500000000000000606482015260840161017a565b83546000906001600160a01b0316638871ca5d61062960a0870187611175565b610635600189356111bf565b818110610644576106446111d2565b905060200201602081019061065991906111e8565b6040516001600160e01b031960e084901b16815263ffffffff919091166004820152602401602060405180830381865afa15801561069b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106bf9190611203565b9050336001600160a01b03821614806106e5575060058501546106e29083610d99565b43115b6107635760405162461bcd60e51b815260206004820152604360248201527f4f6e6c792074686520444b4720726573756c74207375626d697474657220636160448201527f6e20617070726f76652074686520726573756c742061742074686973206d6f6d606482015262195b9d60ea1b608482015260a40161017a565b6107706040850185611175565b905067ffffffffffffffff81111561078a5761078a611048565b6040519080825280602002602001820160405280156107b3578160200160208202803683370190505b50925060005b6107c66040860186611175565b905081101561087a576107dc60a0860186611175565b60016107eb6040890189611175565b858181106107fb576107fb6111d2565b9050602002016020810190610810919061122c565b61081a9190611247565b60ff1681811061082c5761082c6111d2565b905060200201602081019061084191906111e8565b848281518110610853576108536111d2565b63ffffffff909216602092830291909101909101528061087281611260565b9150506107b9565b5060098501546040513391907fe6e9d5eba171e82025efb3f3d44fd35905e7283d104284cb9f3bbc5bf1e4276f90600090a350505b92915050565b60036108c083610bc5565b60048111156108d1576108d1610d6d565b1461092a5760405162461bcd60e51b8152602060048201526024808201527f43757272656e74207374617465206973206e6f74204157414954494e475f524560448201526314d5531560e21b606482015260840161017a565b61093382610c78565b156109805760405162461bcd60e51b815260206004820152601a60248201527f444b472074696d656f757420616c726561647920706173736564000000000000604482015260640161017a565b81546040516307b8c36760e51b81523360048201526001600160a01b0390911690819063f7186ce090602401602060405180830381865afa1580156109c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ed9190611279565b610a455760405162461bcd60e51b815260206004820152602360248201527f5375626d6974746572206e6f7420696e2074686520736f72746974696f6e20706044820152621bdbdb60ea1b606482015260840161017a565b336001600160a01b038216638871ca5d610a6260a0860186611175565b610a6e600188356111bf565b818110610a7d57610a7d6111d2565b9050602002016020810190610a9291906111e8565b6040516001600160e01b031960e084901b16815263ffffffff919091166004820152602401602060405180830381865afa158015610ad4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610af89190611203565b6001600160a01b031614610b4e5760405162461bcd60e51b815260206004820152601a60248201527f556e6578706563746564207375626d697474657220696e646578000000000000604482015260640161017a565b81604051602001610b5f9190610ff9565b60408051601f198184030181529082905280516020909101206009850181905543600a8601556007850154917f8e7fd4293d7db11807147d8890c287fad3396fbb09a4e92273fc7856076c153a90610bb8908690610ff9565b60405180910390a3505050565b805460408051632938b58d60e21b815290516000926001600160a01b03169163a4e2d6349160048083019260209291908290030181865afa158015610c0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c329190611279565b15610c735750600681015460019015610c73576002905060488260060154610c5a9190610d99565b431115610c735750600a81015460039015610c73575060045b919050565b60006003610c8583610bc5565b6004811115610c9657610c96610d6d565b1480156108af5750600482015460088301546006840154610cb990604890610d99565b610cc39190610d99565b610ccd9190610d99565b431192915050565b60008060408385031215610ce857600080fd5b82359150602083013567ffffffffffffffff811115610d0657600080fd5b830160e08186031215610d1857600080fd5b809150509250929050565b6020808252825182820181905260009190848201906040850190845b81811015610d6157835163ffffffff1683529284019291840191600101610d3f565b50909695505050505050565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b808201808211156108af576108af610d83565b6000808335601e19843603018112610dc357600080fd5b830160208101925035905067ffffffffffffffff811115610de357600080fd5b80360382131561048557600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000808335601e19843603018112610e3257600080fd5b830160208101925035905067ffffffffffffffff811115610e5257600080fd5b8060051b360382131561048557600080fd5b803560ff81168114610c7357600080fd5b81835260006001600160fb1b03831115610e8e57600080fd5b8260051b80836020870137939093016020019392505050565b803563ffffffff81168114610c7357600080fd5b8183526000602080850194508260005b85811015610ef45763ffffffff610ee183610ea7565b1687529582019590820190600101610ecb565b509495945050505050565b8035825260006020610f1381840184610dac565b60e083870152610f2760e087018284610df2565b915050610f376040850185610e1b565b868303604088015280835290916000919084015b81831015610f735760ff610f5e85610e64565b16815292840192600192909201918401610f4b565b610f806060880188610dac565b955093508781036060890152610f97818686610df2565b945050505050610faa6080840184610e1b565b8583036080870152610fbd838284610e75565b92505050610fce60a0840184610e1b565b85830360a0870152610fe1838284610ebb565b9250505060c083013560c08501528091505092915050565b60208152600061100c6020830184610eff565b9392505050565b6060815260006110266060830186610eff565b60208301949094525060400152919050565b80518015158114610c7357600080fd5b634e487b7160e01b600052604160045260246000fd5b60005b83811015611079578181015183820152602001611061565b50506000910152565b6000806040838503121561109557600080fd5b61109e83611038565b9150602083015167ffffffffffffffff808211156110bb57600080fd5b818501915085601f8301126110cf57600080fd5b8151818111156110e1576110e1611048565b604051601f8201601f19908116603f0116810190838211818310171561110957611109611048565b8160405282815288602084870101111561112257600080fd5b61113383602083016020880161105e565b80955050505050509250929050565b602081526000825180602084015261116181604085016020870161105e565b601f01601f19169190910160400192915050565b6000808335601e1984360301811261118c57600080fd5b83018035915067ffffffffffffffff8211156111a757600080fd5b6020019150600581901b360382131561048557600080fd5b818103818111156108af576108af610d83565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156111fa57600080fd5b61100c82610ea7565b60006020828403121561121557600080fd5b81516001600160a01b038116811461100c57600080fd5b60006020828403121561123e57600080fd5b61100c82610e64565b60ff82811682821603908111156108af576108af610d83565b60006001820161127257611272610d83565b5060010190565b60006020828403121561128b57600080fd5b61100c8261103856fea26469706673582212200d5dae1b2939600e386623ef7defde718cd565d9d3a7e956d5adf754ff7891af64736f6c63430008110033", + "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600436106100615760003560e01c80630a1ba38e1461006657806346bf00db1461008157806363b635ea146100bb578063716ae957146100c3578063a29355e0146100f0575b600080fd5b61006e604881565b6040519081526020015b60405180910390f35b81801561008d57600080fd5b506100a161009c366004610cd5565b610112565b6040805192835263ffffffff909116602083015201610078565b61006e604081565b8180156100cf57600080fd5b506100e36100de366004610cd5565b61048c565b6040516100789190610d23565b8180156100fc57600080fd5b5061011061010b366004610cd5565b6108b5565b005b600080600461012085610bc5565b600481111561013157610131610d6d565b146101835760405162461bcd60e51b815260206004820152601e60248201527f43757272656e74207374617465206973206e6f74204348414c4c454e4745000060448201526064015b60405180910390fd5b6002840154600a8501546101979190610d99565b4311156101f25760405162461bcd60e51b815260206004820152602360248201527f4368616c6c656e676520706572696f642068617320616c7265616479207061736044820152621cd95960ea1b606482015260840161017a565b8360090154836040516020016102089190610ff9565b60405160208183030381529060405280519060200120146102915760405162461bcd60e51b815260206004820152603a60248201527f526573756c7420756e646572206368616c6c656e67652069732064696666657260448201527f656e74207468616e20746865207375626d6974746564206f6e65000000000000606482015260840161017a565b6001840154600785015460068601546040516373b33d5d60e11b81526001600160a01b039093169263e7667aba926102cd928892600401611013565b600060405180830381865afa92505050801561030b57506040513d6000823e601f3d908101601f191682016040526103089190810190611082565b60015b61038057336001600160a01b031684600901547f703feb01415a2995816e8d082fd7aad0eacada1a2f63fdb3226e47f8a0285436604051610373906020808252601390820152721d985b1a59185d1a5bdb881c995d995c9d1959606a1b604082015260600190565b60405180910390a361040f565b81156103c65760405162461bcd60e51b8152602060048201526015602482015274756e6a7573746966696564206368616c6c656e676560581b604482015260640161017a565b336001600160a01b031686600901547f703feb01415a2995816e8d082fd7aad0eacada1a2f63fdb3226e47f8a0285436836040516104049190611142565b60405180910390a350505b6009840154915061042360a0840184611175565b61042f600186356111bf565b81811061043e5761043e6111d2565b905060200201602081019061045391906111e8565b9050604884600601544361046791906111bf565b61047191906111bf565b6008850155600060098501819055600a8501555b9250929050565b6060600461049984610bc5565b60048111156104aa576104aa610d6d565b146104f75760405162461bcd60e51b815260206004820152601e60248201527f43757272656e74207374617465206973206e6f74204348414c4c454e47450000604482015260640161017a565b6002830154600a84015460009161050d91610d99565b905080431161056a5760405162461bcd60e51b815260206004820152602360248201527f4368616c6c656e676520706572696f6420686173206e6f7420706173736564206044820152621e595d60ea1b606482015260840161017a565b8360090154836040516020016105809190610ff9565b60405160208183030381529060405280519060200120146106095760405162461bcd60e51b815260206004820152603960248201527f526573756c7420756e64657220617070726f76616c206973206469666665726560448201527f6e74207468616e20746865207375626d6974746564206f6e6500000000000000606482015260840161017a565b83546000906001600160a01b0316638871ca5d61062960a0870187611175565b610635600189356111bf565b818110610644576106446111d2565b905060200201602081019061065991906111e8565b6040516001600160e01b031960e084901b16815263ffffffff919091166004820152602401602060405180830381865afa15801561069b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106bf9190611203565b9050336001600160a01b03821614806106e5575060058501546106e29083610d99565b43115b6107635760405162461bcd60e51b815260206004820152604360248201527f4f6e6c792074686520444b4720726573756c74207375626d697474657220636160448201527f6e20617070726f76652074686520726573756c742061742074686973206d6f6d606482015262195b9d60ea1b608482015260a40161017a565b6107706040850185611175565b905067ffffffffffffffff81111561078a5761078a611048565b6040519080825280602002602001820160405280156107b3578160200160208202803683370190505b50925060005b6107c66040860186611175565b905081101561087a576107dc60a0860186611175565b60016107eb6040890189611175565b858181106107fb576107fb6111d2565b9050602002016020810190610810919061122c565b61081a9190611247565b60ff1681811061082c5761082c6111d2565b905060200201602081019061084191906111e8565b848281518110610853576108536111d2565b63ffffffff909216602092830291909101909101528061087281611260565b9150506107b9565b5060098501546040513391907fe6e9d5eba171e82025efb3f3d44fd35905e7283d104284cb9f3bbc5bf1e4276f90600090a350505b92915050565b60036108c083610bc5565b60048111156108d1576108d1610d6d565b1461092a5760405162461bcd60e51b8152602060048201526024808201527f43757272656e74207374617465206973206e6f74204157414954494e475f524560448201526314d5531560e21b606482015260840161017a565b61093382610c78565b156109805760405162461bcd60e51b815260206004820152601a60248201527f444b472074696d656f757420616c726561647920706173736564000000000000604482015260640161017a565b81546040516307b8c36760e51b81523360048201526001600160a01b0390911690819063f7186ce090602401602060405180830381865afa1580156109c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ed9190611279565b610a455760405162461bcd60e51b815260206004820152602360248201527f5375626d6974746572206e6f7420696e2074686520736f72746974696f6e20706044820152621bdbdb60ea1b606482015260840161017a565b336001600160a01b038216638871ca5d610a6260a0860186611175565b610a6e600188356111bf565b818110610a7d57610a7d6111d2565b9050602002016020810190610a9291906111e8565b6040516001600160e01b031960e084901b16815263ffffffff919091166004820152602401602060405180830381865afa158015610ad4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610af89190611203565b6001600160a01b031614610b4e5760405162461bcd60e51b815260206004820152601a60248201527f556e6578706563746564207375626d697474657220696e646578000000000000604482015260640161017a565b81604051602001610b5f9190610ff9565b60408051601f198184030181529082905280516020909101206009850181905543600a8601556007850154917f8e7fd4293d7db11807147d8890c287fad3396fbb09a4e92273fc7856076c153a90610bb8908690610ff9565b60405180910390a3505050565b805460408051632938b58d60e21b815290516000926001600160a01b03169163a4e2d6349160048083019260209291908290030181865afa158015610c0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c329190611279565b15610c735750600681015460019015610c73576002905060488260060154610c5a9190610d99565b431115610c735750600a81015460039015610c73575060045b919050565b60006003610c8583610bc5565b6004811115610c9657610c96610d6d565b1480156108af5750600482015460088301546006840154610cb990604890610d99565b610cc39190610d99565b610ccd9190610d99565b431192915050565b60008060408385031215610ce857600080fd5b82359150602083013567ffffffffffffffff811115610d0657600080fd5b830160e08186031215610d1857600080fd5b809150509250929050565b6020808252825182820181905260009190848201906040850190845b81811015610d6157835163ffffffff1683529284019291840191600101610d3f565b50909695505050505050565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b808201808211156108af576108af610d83565b6000808335601e19843603018112610dc357600080fd5b830160208101925035905067ffffffffffffffff811115610de357600080fd5b80360382131561048557600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000808335601e19843603018112610e3257600080fd5b830160208101925035905067ffffffffffffffff811115610e5257600080fd5b8060051b360382131561048557600080fd5b803560ff81168114610c7357600080fd5b81835260006001600160fb1b03831115610e8e57600080fd5b8260051b80836020870137939093016020019392505050565b803563ffffffff81168114610c7357600080fd5b8183526000602080850194508260005b85811015610ef45763ffffffff610ee183610ea7565b1687529582019590820190600101610ecb565b509495945050505050565b8035825260006020610f1381840184610dac565b60e083870152610f2760e087018284610df2565b915050610f376040850185610e1b565b868303604088015280835290916000919084015b81831015610f735760ff610f5e85610e64565b16815292840192600192909201918401610f4b565b610f806060880188610dac565b955093508781036060890152610f97818686610df2565b945050505050610faa6080840184610e1b565b8583036080870152610fbd838284610e75565b92505050610fce60a0840184610e1b565b85830360a0870152610fe1838284610ebb565b9250505060c083013560c08501528091505092915050565b60208152600061100c6020830184610eff565b9392505050565b6060815260006110266060830186610eff565b60208301949094525060400152919050565b80518015158114610c7357600080fd5b634e487b7160e01b600052604160045260246000fd5b60005b83811015611079578181015183820152602001611061565b50506000910152565b6000806040838503121561109557600080fd5b61109e83611038565b9150602083015167ffffffffffffffff808211156110bb57600080fd5b818501915085601f8301126110cf57600080fd5b8151818111156110e1576110e1611048565b604051601f8201601f19908116603f0116810190838211818310171561110957611109611048565b8160405282815288602084870101111561112257600080fd5b61113383602083016020880161105e565b80955050505050509250929050565b602081526000825180602084015261116181604085016020870161105e565b601f01601f19169190910160400192915050565b6000808335601e1984360301811261118c57600080fd5b83018035915067ffffffffffffffff8211156111a757600080fd5b6020019150600581901b360382131561048557600080fd5b818103818111156108af576108af610d83565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156111fa57600080fd5b61100c82610ea7565b60006020828403121561121557600080fd5b81516001600160a01b038116811461100c57600080fd5b60006020828403121561123e57600080fd5b61100c82610e64565b60ff82811682821603908111156108af576108af610d83565b60006001820161127257611272610d83565b5060010190565b60006020828403121561128b57600080fd5b61100c8261103856fea26469706673582212200d5dae1b2939600e386623ef7defde718cd565d9d3a7e956d5adf754ff7891af64736f6c63430008110033", + "linkReferences": {}, + "deployedLinkReferences": {}, + "devdoc": { + "kind": "dev", + "methods": { + "approveResult(BeaconDkg.Data storage,BeaconDkg.Result)": { + "details": "Can be called after a challenge period for the submitted result.", + "params": { + "result": "Result to approve. Must match the submitted result stored during `submitResult`." + }, + "returns": { + "misbehavedMembers": "Identifiers of members who misbehaved during DKG." + } + }, + "challengeResult(BeaconDkg.Data storage,BeaconDkg.Result)": { + "details": "Can be called during a challenge period for the submitted result.", + "params": { + "result": "Result to challenge. Must match the submitted result stored during `submitResult`." + }, + "returns": { + "maliciousResultHash": "Hash of the malicious result.", + "maliciousSubmitter": "Identifier of the malicious submitter." + } + } + }, + "stateVariables": { + "groupSize": { + "details": "Size of a group in the threshold relay." + } + }, + "version": 1 + }, + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"resultHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"approver\",\"type\":\"address\"}],\"name\":\"DkgResultApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"resultHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"reason\",\"type\":\"string\"}],\"name\":\"DkgResultChallenged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"resultHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"submitterMemberIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"},{\"internalType\":\"uint8[]\",\"name\":\"misbehavedMembersIndices\",\"type\":\"uint8[]\"},{\"internalType\":\"bytes\",\"name\":\"signatures\",\"type\":\"bytes\"},{\"internalType\":\"uint256[]\",\"name\":\"signingMembersIndices\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32[]\",\"name\":\"members\",\"type\":\"uint32[]\"},{\"internalType\":\"bytes32\",\"name\":\"membersHash\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"struct BeaconDkg.Result\",\"name\":\"result\",\"type\":\"tuple\"}],\"name\":\"DkgResultSubmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"DkgSeedTimedOut\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"}],\"name\":\"DkgStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"DkgStateLocked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"DkgTimedOut\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"groupSize\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"offchainDkgTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"approveResult(BeaconDkg.Data storage,BeaconDkg.Result)\":{\"details\":\"Can be called after a challenge period for the submitted result.\",\"params\":{\"result\":\"Result to approve. Must match the submitted result stored during `submitResult`.\"},\"returns\":{\"misbehavedMembers\":\"Identifiers of members who misbehaved during DKG.\"}},\"challengeResult(BeaconDkg.Data storage,BeaconDkg.Result)\":{\"details\":\"Can be called during a challenge period for the submitted result.\",\"params\":{\"result\":\"Result to challenge. Must match the submitted result stored during `submitResult`.\"},\"returns\":{\"maliciousResultHash\":\"Hash of the malicious result.\",\"maliciousSubmitter\":\"Identifier of the malicious submitter.\"}}},\"stateVariables\":{\"groupSize\":{\"details\":\"Size of a group in the threshold relay.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"approveResult(BeaconDkg.Data storage,BeaconDkg.Result)\":{\"notice\":\"Approves DKG result. Can be called when the challenge period for the submitted result is finished. Considers the submitted result as valid. For the first `submitterPrecedencePeriodLength` blocks after the end of the challenge period can be called only by the DKG result submitter. After that time, can be called by anyone.\"},\"challengeResult(BeaconDkg.Data storage,BeaconDkg.Result)\":{\"notice\":\"Challenges DKG result. If the submitted result is proved to be invalid it reverts the DKG back to the result submission phase.\"},\"offchainDkgTime()\":{\"notice\":\"Time in blocks after which DKG result is complete and ready to be\"},\"submitResult(BeaconDkg.Data storage,BeaconDkg.Result)\":{\"notice\":\"Allows to submit a DKG result. The submitted result does not go through a validation and before it gets accepted, it needs to wait through the challenge period during which everyone has a chance to challenge the result as invalid one. Submitter of the result needs to be in the sortition pool and if the result gets challenged, the submitter will get slashed.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/libraries/BeaconDkg.sol\":\"BeaconDkg\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@keep-network/sortition-pools/contracts/Branch.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\n/// @notice The implicit 8-ary trees of the sortition pool\\n/// rely on packing 8 \\\"slots\\\" of 32-bit values into each uint256.\\n/// The Branch library permits efficient calculations on these slots.\\nlibrary Branch {\\n /// @notice Calculate the right shift required\\n /// to make the 32 least significant bits of an uint256\\n /// be the bits of the `position`th slot\\n /// when treating the uint256 as a uint32[8].\\n ///\\n /// @dev Not used for efficiency reasons,\\n /// but left to illustrate the meaning of a common pattern.\\n /// I wish solidity had macros, even C macros.\\n function slotShift(uint256 position) internal pure returns (uint256) {\\n unchecked {\\n return position * Constants.SLOT_WIDTH;\\n }\\n }\\n\\n /// @notice Return the `position`th slot of the `node`,\\n /// treating `node` as a uint32[32].\\n function getSlot(uint256 node, uint256 position)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Doing a bitwise AND with `SLOT_MAX`\\n // clears all but the 32 least significant bits.\\n // Because of the right shift by `slotShift(position)` bits,\\n // those 32 bits contain the 32 bits in the `position`th slot of `node`.\\n return (node >> shiftBits) & Constants.SLOT_MAX;\\n }\\n }\\n\\n /// @notice Return `node` with the `position`th slot set to zero.\\n function clearSlot(uint256 node, uint256 position)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Shifting `SLOT_MAX` left by `slotShift(position)` bits\\n // gives us a number where all bits of the `position`th slot are set,\\n // and all other bits are unset.\\n //\\n // Using a bitwise NOT on this number,\\n // we get a uint256 where all bits are set\\n // except for those of the `position`th slot.\\n //\\n // Bitwise ANDing the original `node` with this number\\n // sets the bits of `position`th slot to zero,\\n // leaving all other bits unchanged.\\n return node & ~(Constants.SLOT_MAX << shiftBits);\\n }\\n }\\n\\n /// @notice Return `node` with the `position`th slot set to `weight`.\\n ///\\n /// @param weight The weight of of the node.\\n /// Safely truncated to a 32-bit number,\\n /// but this should never be called with an overflowing weight regardless.\\n function setSlot(\\n uint256 node,\\n uint256 position,\\n uint256 weight\\n ) internal pure returns (uint256) {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Clear the `position`th slot like in `clearSlot()`.\\n uint256 clearedNode = node & ~(Constants.SLOT_MAX << shiftBits);\\n // Bitwise AND `weight` with `SLOT_MAX`\\n // to clear all but the 32 least significant bits.\\n //\\n // Shift this left by `slotShift(position)` bits\\n // to obtain a uint256 with all bits unset\\n // except in the `position`th slot\\n // which contains the 32-bit value of `weight`.\\n uint256 shiftedWeight = (weight & Constants.SLOT_MAX) << shiftBits;\\n // When we bitwise OR these together,\\n // all other slots except the `position`th one come from the left argument,\\n // and the `position`th gets filled with `weight` from the right argument.\\n return clearedNode | shiftedWeight;\\n }\\n }\\n\\n /// @notice Calculate the summed weight of all slots in the `node`.\\n function sumWeight(uint256 node) internal pure returns (uint256 sum) {\\n unchecked {\\n sum = node & Constants.SLOT_MAX;\\n // Iterate through each slot\\n // by shifting `node` right in increments of 32 bits,\\n // and adding the 32 least significant bits to the `sum`.\\n uint256 newNode = node >> Constants.SLOT_WIDTH;\\n while (newNode > 0) {\\n sum += (newNode & Constants.SLOT_MAX);\\n newNode = newNode >> Constants.SLOT_WIDTH;\\n }\\n return sum;\\n }\\n }\\n\\n /// @notice Pick a slot in `node` that corresponds to `index`.\\n /// Treats the node like an array of virtual stakers,\\n /// the number of virtual stakers in each slot corresponding to its weight,\\n /// and picks which slot contains the `index`th virtual staker.\\n ///\\n /// @dev Requires that `index` be lower than `sumWeight(node)`.\\n /// However, this is not enforced for performance reasons.\\n /// If `index` exceeds the permitted range,\\n /// `pickWeightedSlot()` returns the rightmost slot\\n /// and an excessively high `newIndex`.\\n ///\\n /// @return slot The slot of `node` containing the `index`th virtual staker.\\n ///\\n /// @return newIndex The index of the `index`th virtual staker of `node`\\n /// within the returned slot.\\n function pickWeightedSlot(uint256 node, uint256 index)\\n internal\\n pure\\n returns (uint256 slot, uint256 newIndex)\\n {\\n unchecked {\\n newIndex = index;\\n uint256 newNode = node;\\n uint256 currentSlotWeight = newNode & Constants.SLOT_MAX;\\n while (newIndex >= currentSlotWeight) {\\n newIndex -= currentSlotWeight;\\n slot++;\\n newNode = newNode >> Constants.SLOT_WIDTH;\\n currentSlotWeight = newNode & Constants.SLOT_MAX;\\n }\\n return (slot, newIndex);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa7fb1c9c9789f30493e9a40e24a24f46875dc5e7630b4f67478167759f6d1882\"},\"@keep-network/sortition-pools/contracts/Chaosnet.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\n/// @title Chaosnet\\n/// @notice This is a beta staker program for stakers willing to go the extra\\n/// mile with monitoring, share their logs with the dev team, and allow to more\\n/// carefully monitor the bootstrapping network. As the network matures, the\\n/// beta program will be ended.\\ncontract Chaosnet {\\n /// @notice Indicates if the chaosnet is active. The chaosnet is active\\n /// after the contract deployment and can be ended with a call to\\n /// `deactivateChaosnet()`. Once deactivated chaosnet can not be activated\\n /// again.\\n bool public isChaosnetActive;\\n\\n /// @notice Indicates if the given operator is a beta operator for chaosnet.\\n mapping(address => bool) public isBetaOperator;\\n\\n /// @notice Address controlling chaosnet status and beta operator addresses.\\n address public chaosnetOwner;\\n\\n event BetaOperatorsAdded(address[] operators);\\n\\n event ChaosnetOwnerRoleTransferred(\\n address oldChaosnetOwner,\\n address newChaosnetOwner\\n );\\n\\n event ChaosnetDeactivated();\\n\\n constructor() {\\n _transferChaosnetOwner(msg.sender);\\n isChaosnetActive = true;\\n }\\n\\n modifier onlyChaosnetOwner() {\\n require(msg.sender == chaosnetOwner, \\\"Not the chaosnet owner\\\");\\n _;\\n }\\n\\n modifier onlyOnChaosnet() {\\n require(isChaosnetActive, \\\"Chaosnet is not active\\\");\\n _;\\n }\\n\\n /// @notice Adds beta operator to chaosnet. Can be called only by the\\n /// chaosnet owner when the chaosnet is active. Once the operator is added\\n /// as a beta operator, it can not be removed.\\n function addBetaOperators(address[] calldata operators)\\n public\\n onlyOnChaosnet\\n onlyChaosnetOwner\\n {\\n for (uint256 i = 0; i < operators.length; i++) {\\n isBetaOperator[operators[i]] = true;\\n }\\n\\n emit BetaOperatorsAdded(operators);\\n }\\n\\n /// @notice Deactivates the chaosnet. Can be called only by the chaosnet\\n /// owner. Once deactivated chaosnet can not be activated again.\\n function deactivateChaosnet() public onlyOnChaosnet onlyChaosnetOwner {\\n isChaosnetActive = false;\\n emit ChaosnetDeactivated();\\n }\\n\\n /// @notice Transfers the chaosnet owner role to another non-zero address.\\n function transferChaosnetOwnerRole(address newChaosnetOwner)\\n public\\n onlyChaosnetOwner\\n {\\n require(\\n newChaosnetOwner != address(0),\\n \\\"New chaosnet owner must not be zero address\\\"\\n );\\n _transferChaosnetOwner(newChaosnetOwner);\\n }\\n\\n function _transferChaosnetOwner(address newChaosnetOwner) internal {\\n address oldChaosnetOwner = chaosnetOwner;\\n chaosnetOwner = newChaosnetOwner;\\n emit ChaosnetOwnerRoleTransferred(oldChaosnetOwner, newChaosnetOwner);\\n }\\n}\\n\",\"keccak256\":\"0xeaf7bdd5626f88c329793a012621039692ce1b6e1f13013997ddb13d7e3032df\"},\"@keep-network/sortition-pools/contracts/Constants.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nlibrary Constants {\\n ////////////////////////////////////////////////////////////////////////////\\n // Parameters for configuration\\n\\n // How many bits a position uses per level of the tree;\\n // each branch of the tree contains 2**SLOT_BITS slots.\\n uint256 constant SLOT_BITS = 3;\\n uint256 constant LEVELS = 7;\\n ////////////////////////////////////////////////////////////////////////////\\n\\n ////////////////////////////////////////////////////////////////////////////\\n // Derived constants, do not touch\\n uint256 constant SLOT_COUNT = 2**SLOT_BITS;\\n uint256 constant SLOT_WIDTH = 256 / SLOT_COUNT;\\n uint256 constant LAST_SLOT = SLOT_COUNT - 1;\\n uint256 constant SLOT_MAX = (2**SLOT_WIDTH) - 1;\\n uint256 constant POOL_CAPACITY = SLOT_COUNT**LEVELS;\\n\\n uint256 constant ID_WIDTH = SLOT_WIDTH;\\n uint256 constant ID_MAX = SLOT_MAX;\\n\\n uint256 constant BLOCKHEIGHT_WIDTH = 96 - ID_WIDTH;\\n uint256 constant BLOCKHEIGHT_MAX = (2**BLOCKHEIGHT_WIDTH) - 1;\\n\\n uint256 constant SLOT_POINTER_MAX = (2**SLOT_BITS) - 1;\\n uint256 constant LEAF_FLAG = 1 << 255;\\n\\n uint256 constant WEIGHT_WIDTH = 256 / SLOT_COUNT;\\n ////////////////////////////////////////////////////////////////////////////\\n}\\n\",\"keccak256\":\"0xaef690ced707935745ff1482b7bb9bd9eb77bf6a39c717465e64cf12db8a7d39\"},\"@keep-network/sortition-pools/contracts/Leaf.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary Leaf {\\n function make(\\n address _operator,\\n uint256 _creationBlock,\\n uint256 _id\\n ) internal pure returns (uint256) {\\n assert(_creationBlock <= type(uint64).max);\\n assert(_id <= type(uint32).max);\\n // Converting a bytesX type into a larger type\\n // adds zero bytes on the right.\\n uint256 op = uint256(bytes32(bytes20(_operator)));\\n // Bitwise AND the id to erase\\n // all but the 32 least significant bits\\n uint256 uid = _id & Constants.ID_MAX;\\n // Erase all but the 64 least significant bits,\\n // then shift left by 32 bits to make room for the id\\n uint256 cb = (_creationBlock & Constants.BLOCKHEIGHT_MAX) <<\\n Constants.ID_WIDTH;\\n // Bitwise OR them all together to get\\n // [address operator || uint64 creationBlock || uint32 id]\\n return (op | cb | uid);\\n }\\n\\n function operator(uint256 leaf) internal pure returns (address) {\\n // Converting a bytesX type into a smaller type\\n // truncates it on the right.\\n return address(bytes20(bytes32(leaf)));\\n }\\n\\n /// @notice Return the block number the leaf was created in.\\n function creationBlock(uint256 leaf) internal pure returns (uint256) {\\n return ((leaf >> Constants.ID_WIDTH) & Constants.BLOCKHEIGHT_MAX);\\n }\\n\\n function id(uint256 leaf) internal pure returns (uint32) {\\n // Id is stored in the 32 least significant bits.\\n // Bitwise AND ensures that we only get the contents of those bits.\\n return uint32(leaf & Constants.ID_MAX);\\n }\\n}\\n\",\"keccak256\":\"0xbd107a1a43e48884885e5e966ffcbcd8fa5e89863715d717bb4006e9f89cdc2b\"},\"@keep-network/sortition-pools/contracts/Position.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary Position {\\n // Return the last 3 bits of a position number,\\n // corresponding to its slot in its parent\\n function slot(uint256 a) internal pure returns (uint256) {\\n return a & Constants.SLOT_POINTER_MAX;\\n }\\n\\n // Return the parent of a position number\\n function parent(uint256 a) internal pure returns (uint256) {\\n return a >> Constants.SLOT_BITS;\\n }\\n\\n // Return the location of the child of a at the given slot\\n function child(uint256 a, uint256 s) internal pure returns (uint256) {\\n return (a << Constants.SLOT_BITS) | (s & Constants.SLOT_POINTER_MAX); // slot(s)\\n }\\n\\n // Return the uint p as a flagged position uint:\\n // the least significant 21 bits contain the position\\n // and the 22nd bit is set as a flag\\n // to distinguish the position 0x000000 from an empty field.\\n function setFlag(uint256 p) internal pure returns (uint256) {\\n return p | Constants.LEAF_FLAG;\\n }\\n\\n // Turn a flagged position into an unflagged position\\n // by removing the flag at the 22nd least significant bit.\\n //\\n // We shouldn't _actually_ need this\\n // as all position-manipulating code should ignore non-position bits anyway\\n // but it's cheap to call so might as well do it.\\n function unsetFlag(uint256 p) internal pure returns (uint256) {\\n return p & (~Constants.LEAF_FLAG);\\n }\\n}\\n\",\"keccak256\":\"0xd3a927908080ac21353a92a6bce3d69e94a5c30f6b51f16b271b6cc679f110e2\"},\"@keep-network/sortition-pools/contracts/RNG.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Leaf.sol\\\";\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary RNG {\\n /// @notice Get an index in the range `[0 .. range-1]`\\n /// and the new state of the RNG,\\n /// using the provided `state` of the RNG.\\n ///\\n /// @param range The upper bound of the index, exclusive.\\n ///\\n /// @param state The previous state of the RNG.\\n /// The initial state needs to be obtained\\n /// from a trusted randomness oracle (the random beacon),\\n /// or from a chain of earlier calls to `RNG.getIndex()`\\n /// on an originally trusted seed.\\n ///\\n /// @dev Calculates the number of bits required for the desired range,\\n /// takes the least significant bits of `state`\\n /// and checks if the obtained index is within the desired range.\\n /// The original state is hashed with `keccak256` to get a new state.\\n /// If the index is outside the range,\\n /// the function retries until it gets a suitable index.\\n ///\\n /// @return index A random integer between `0` and `range - 1`, inclusive.\\n ///\\n /// @return newState The new state of the RNG.\\n /// When `getIndex()` is called one or more times,\\n /// care must be taken to always use the output `state`\\n /// of the most recent call as the input `state` of a subsequent call.\\n /// At the end of a transaction calling `RNG.getIndex()`,\\n /// the previous stored state must be overwritten with the latest output.\\n function getIndex(\\n uint256 range,\\n bytes32 state,\\n uint256 bits\\n ) internal view returns (uint256, bytes32) {\\n bool found = false;\\n uint256 index = 0;\\n bytes32 newState = state;\\n while (!found) {\\n index = truncate(bits, uint256(newState));\\n newState = keccak256(abi.encodePacked(newState, address(this)));\\n if (index < range) {\\n found = true;\\n }\\n }\\n return (index, newState);\\n }\\n\\n /// @notice Calculate how many bits are required\\n /// for an index in the range `[0 .. range-1]`.\\n ///\\n /// @param range The upper bound of the desired range, exclusive.\\n ///\\n /// @return uint The smallest number of bits\\n /// that can contain the number `range-1`.\\n function bitsRequired(uint256 range) internal pure returns (uint256) {\\n unchecked {\\n if (range == 1) {\\n return 0;\\n }\\n\\n uint256 bits = Constants.WEIGHT_WIDTH - 1;\\n\\n // Left shift by `bits`,\\n // so we have a 1 in the (bits + 1)th least significant bit\\n // and 0 in other bits.\\n // If this number is equal or greater than `range`,\\n // the range [0, range-1] fits in `bits` bits.\\n //\\n // Because we loop from high bits to low bits,\\n // we find the highest number of bits that doesn't fit the range,\\n // and return that number + 1.\\n while (1 << bits >= range) {\\n bits--;\\n }\\n\\n return bits + 1;\\n }\\n }\\n\\n /// @notice Truncate `input` to the `bits` least significant bits.\\n function truncate(uint256 bits, uint256 input)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n return input & ((1 << bits) - 1);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x67f87f589cd5123ffa32f883ea2f09b0e56258508bae82b8c655b3c27c71eb5e\"},\"@keep-network/sortition-pools/contracts/Rewards.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\n/// @title Rewards\\n/// @notice Rewards are allocated proportionally to operators\\n/// present in the pool at payout based on their weight in the pool.\\n///\\n/// To facilitate this, we use a global accumulator value\\n/// to track the total rewards one unit of weight would've earned\\n/// since the creation of the pool.\\n///\\n/// Whenever a reward is paid, the accumulator is increased\\n/// by the size of the reward divided by the total weight\\n/// of all eligible operators in the pool.\\n///\\n/// Each operator has an individual accumulator value,\\n/// set to equal the global accumulator when the operator joins the pool.\\n/// This accumulator reflects the amount of rewards\\n/// that have already been accounted for with that operator.\\n///\\n/// Whenever an operator's weight in the pool changes,\\n/// we can update the amount of rewards the operator has earned\\n/// by subtracting the operator's accumulator from the global accumulator.\\n/// This gives us the amount of rewards one unit of weight has earned\\n/// since the last time the operator's rewards have been updated.\\n/// Then we multiply that by the operator's previous (pre-change) weight\\n/// to determine how much rewards in total the operator has earned,\\n/// and add this to the operator's earned rewards.\\n/// Finally, we set the operator's accumulator to the global accumulator value.\\ncontract Rewards {\\n struct OperatorRewards {\\n // The state of the global accumulator\\n // when the operator's rewards were last updated\\n uint96 accumulated;\\n // The amount of rewards collected by the operator after the latest update.\\n // The amount the operator could withdraw may equal `available`\\n // or it may be greater, if more rewards have been paid in since then.\\n // To evaulate the most recent amount including rewards potentially paid\\n // since the last update, use `availableRewards` function.\\n uint96 available;\\n // If nonzero, the operator is ineligible for rewards\\n // and may only re-enable rewards after the specified timestamp.\\n // XXX: unsigned 32-bit integer unix seconds, will break around 2106\\n uint32 ineligibleUntil;\\n // Locally cached weight of the operator,\\n // used to reduce the cost of setting operators ineligible.\\n uint32 weight;\\n }\\n\\n // The global accumulator of how much rewards\\n // a hypothetical operator of weight 1 would have earned\\n // since the creation of the pool.\\n uint96 internal globalRewardAccumulator;\\n // If the amount of reward tokens paid in\\n // does not divide cleanly by pool weight,\\n // the difference is recorded as rounding dust\\n // and added to the next reward.\\n uint96 internal rewardRoundingDust;\\n\\n // The amount of rewards that would've been earned by ineligible operators\\n // had they not been ineligible.\\n uint96 public ineligibleEarnedRewards;\\n\\n // Ineligibility times are calculated from this offset,\\n // set at contract creation.\\n uint256 internal immutable ineligibleOffsetStart;\\n\\n mapping(uint32 => OperatorRewards) internal operatorRewards;\\n\\n constructor() {\\n // solhint-disable-next-line not-rely-on-time\\n ineligibleOffsetStart = block.timestamp;\\n }\\n\\n /// @notice Return whether the operator is eligible for rewards or not.\\n function isEligibleForRewards(uint32 operator) internal view returns (bool) {\\n return operatorRewards[operator].ineligibleUntil == 0;\\n }\\n\\n /// @notice Return the time the operator's reward eligibility can be restored.\\n function rewardsEligibilityRestorableAt(uint32 operator)\\n internal\\n view\\n returns (uint256)\\n {\\n uint32 until = operatorRewards[operator].ineligibleUntil;\\n require(until != 0, \\\"Operator already eligible\\\");\\n return (uint256(until) + ineligibleOffsetStart);\\n }\\n\\n /// @notice Return whether the operator is able to restore their eligibility\\n /// for rewards right away.\\n function canRestoreRewardEligibility(uint32 operator)\\n internal\\n view\\n returns (bool)\\n {\\n // solhint-disable-next-line not-rely-on-time\\n return rewardsEligibilityRestorableAt(operator) <= block.timestamp;\\n }\\n\\n /// @notice Internal function for updating the global state of rewards.\\n function addRewards(uint96 rewardAmount, uint32 currentPoolWeight) internal {\\n require(currentPoolWeight > 0, \\\"No recipients in pool\\\");\\n\\n uint96 totalAmount = rewardAmount + rewardRoundingDust;\\n uint96 perWeightReward = totalAmount / currentPoolWeight;\\n uint96 newRoundingDust = totalAmount % currentPoolWeight;\\n\\n globalRewardAccumulator += perWeightReward;\\n rewardRoundingDust = newRoundingDust;\\n }\\n\\n /// @notice Internal function for updating the operator's reward state.\\n function updateOperatorRewards(uint32 operator, uint32 newWeight) internal {\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n if (o.ineligibleUntil == 0) {\\n // If operator is not ineligible, update their earned rewards\\n o.available += accruedRewards;\\n } else {\\n // If ineligible, put the rewards into the ineligible pot\\n ineligibleEarnedRewards += accruedRewards;\\n }\\n // In any case, update their accumulator and weight\\n o.accumulated = acc;\\n o.weight = newWeight;\\n operatorRewards[operator] = o;\\n }\\n\\n /// @notice Set the amount of withdrawable tokens to zero\\n /// and return the previous withdrawable amount.\\n /// @dev Does not update the withdrawable amount,\\n /// but should usually be accompanied by an update.\\n function withdrawOperatorRewards(uint32 operator)\\n internal\\n returns (uint96 withdrawable)\\n {\\n OperatorRewards storage o = operatorRewards[operator];\\n withdrawable = o.available;\\n o.available = 0;\\n }\\n\\n /// @notice Set the amount of ineligible-earned tokens to zero\\n /// and return the previous amount.\\n function withdrawIneligibleRewards() internal returns (uint96 withdrawable) {\\n withdrawable = ineligibleEarnedRewards;\\n ineligibleEarnedRewards = 0;\\n }\\n\\n /// @notice Set the given operators as ineligible for rewards.\\n /// The operators can restore their eligibility at the given time.\\n function setIneligible(uint32[] memory operators, uint256 until) internal {\\n OperatorRewards memory o = OperatorRewards(0, 0, 0, 0);\\n uint96 globalAcc = globalRewardAccumulator;\\n uint96 accrued = 0;\\n // Record ineligibility as seconds after contract creation\\n uint32 _until = uint32(until - ineligibleOffsetStart);\\n\\n for (uint256 i = 0; i < operators.length; i++) {\\n uint32 operator = operators[i];\\n OperatorRewards storage r = operatorRewards[operator];\\n o.available = r.available;\\n o.accumulated = r.accumulated;\\n o.ineligibleUntil = r.ineligibleUntil;\\n o.weight = r.weight;\\n\\n if (o.ineligibleUntil != 0) {\\n // If operator is already ineligible,\\n // don't earn rewards or shorten its ineligibility\\n if (o.ineligibleUntil < _until) {\\n o.ineligibleUntil = _until;\\n }\\n } else {\\n // The operator becomes ineligible -> earn rewards\\n o.ineligibleUntil = _until;\\n accrued = (globalAcc - o.accumulated) * uint96(o.weight);\\n o.available += accrued;\\n }\\n o.accumulated = globalAcc;\\n\\n r.available = o.available;\\n r.accumulated = o.accumulated;\\n r.ineligibleUntil = o.ineligibleUntil;\\n r.weight = o.weight;\\n }\\n }\\n\\n /// @notice Restore the given operator's eligibility for rewards.\\n function restoreEligibility(uint32 operator) internal {\\n // solhint-disable-next-line not-rely-on-time\\n require(canRestoreRewardEligibility(operator), \\\"Operator still ineligible\\\");\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n ineligibleEarnedRewards += accruedRewards;\\n o.accumulated = acc;\\n o.ineligibleUntil = 0;\\n operatorRewards[operator] = o;\\n }\\n\\n /// @notice Returns the amount of rewards currently available for withdrawal\\n /// for the given operator.\\n function availableRewards(uint32 operator) internal view returns (uint96) {\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n if (o.ineligibleUntil == 0) {\\n // If operator is not ineligible, calculate newly accrued rewards and add\\n // them to the available ones, calculated during the last update.\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n return o.available + accruedRewards;\\n } else {\\n // If ineligible, return only the rewards calculated during the last\\n // update.\\n return o.available;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3a10abb408b44335a092387b2c7ee01db3b27997f1f2c888d9b7a2d92934c4e2\"},\"@keep-network/sortition-pools/contracts/SortitionPool.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"@thesis/solidity-contracts/contracts/token/IERC20WithPermit.sol\\\";\\nimport \\\"@thesis/solidity-contracts/contracts/token/IReceiveApproval.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\nimport \\\"./RNG.sol\\\";\\nimport \\\"./SortitionTree.sol\\\";\\nimport \\\"./Rewards.sol\\\";\\nimport \\\"./Chaosnet.sol\\\";\\n\\n/// @title Sortition Pool\\n/// @notice A logarithmic data structure used to store the pool of eligible\\n/// operators weighted by their stakes. It allows to select a group of operators\\n/// based on the provided pseudo-random seed.\\ncontract SortitionPool is\\n SortitionTree,\\n Rewards,\\n Ownable,\\n Chaosnet,\\n IReceiveApproval\\n{\\n using Branch for uint256;\\n using Leaf for uint256;\\n using Position for uint256;\\n\\n IERC20WithPermit public immutable rewardToken;\\n\\n uint256 public immutable poolWeightDivisor;\\n\\n bool public isLocked;\\n\\n event IneligibleForRewards(uint32[] ids, uint256 until);\\n\\n event RewardEligibilityRestored(address indexed operator, uint32 indexed id);\\n\\n /// @notice Reverts if called while pool is locked.\\n modifier onlyUnlocked() {\\n require(!isLocked, \\\"Sortition pool locked\\\");\\n _;\\n }\\n\\n /// @notice Reverts if called while pool is unlocked.\\n modifier onlyLocked() {\\n require(isLocked, \\\"Sortition pool unlocked\\\");\\n _;\\n }\\n\\n constructor(IERC20WithPermit _rewardToken, uint256 _poolWeightDivisor) {\\n rewardToken = _rewardToken;\\n poolWeightDivisor = _poolWeightDivisor;\\n }\\n\\n function receiveApproval(\\n address sender,\\n uint256 amount,\\n address token,\\n bytes calldata\\n ) external override {\\n require(token == address(rewardToken), \\\"Unsupported token\\\");\\n rewardToken.transferFrom(sender, address(this), amount);\\n Rewards.addRewards(uint96(amount), uint32(root.sumWeight()));\\n }\\n\\n /// @notice Withdraws all available rewards for the given operator to the\\n /// given beneficiary.\\n /// @dev Can be called only be the owner. Does not validate if the provided\\n /// beneficiary is associated with the provided operator - this needs to\\n /// be done by the owner calling this function.\\n /// @return The amount of rewards withdrawn in this call.\\n function withdrawRewards(address operator, address beneficiary)\\n public\\n onlyOwner\\n returns (uint96)\\n {\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(getPoolWeight(operator)));\\n uint96 earned = Rewards.withdrawOperatorRewards(id);\\n rewardToken.transfer(beneficiary, uint256(earned));\\n return earned;\\n }\\n\\n /// @notice Withdraws rewards not allocated to operators marked as ineligible\\n /// to the given recipient address.\\n /// @dev Can be called only by the owner.\\n function withdrawIneligible(address recipient) public onlyOwner {\\n uint96 earned = Rewards.withdrawIneligibleRewards();\\n rewardToken.transfer(recipient, uint256(earned));\\n }\\n\\n /// @notice Locks the sortition pool. In locked state, members cannot be\\n /// inserted and removed from the pool. Members statuses cannot\\n /// be updated as well.\\n /// @dev Can be called only by the contract owner.\\n function lock() public onlyOwner {\\n isLocked = true;\\n }\\n\\n /// @notice Unlocks the sortition pool. Removes all restrictions set by\\n /// the `lock` method.\\n /// @dev Can be called only by the contract owner.\\n function unlock() public onlyOwner {\\n isLocked = false;\\n }\\n\\n /// @notice Inserts an operator to the pool. Reverts if the operator is\\n /// already present. Reverts if the operator is not eligible because of their\\n /// authorized stake. Reverts if the chaosnet is active and the operator is\\n /// not a beta operator.\\n /// @dev Can be called only by the contract owner.\\n /// @param operator Address of the inserted operator.\\n /// @param authorizedStake Inserted operator's authorized stake for the application.\\n function insertOperator(address operator, uint256 authorizedStake)\\n public\\n onlyOwner\\n onlyUnlocked\\n {\\n uint256 weight = getWeight(authorizedStake);\\n require(weight > 0, \\\"Operator not eligible\\\");\\n\\n if (isChaosnetActive) {\\n require(isBetaOperator[operator], \\\"Not beta operator for chaosnet\\\");\\n }\\n\\n _insertOperator(operator, weight);\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(weight));\\n }\\n\\n /// @notice Update the operator's weight if present and eligible,\\n /// or remove from the pool if present and ineligible.\\n /// @dev Can be called only by the contract owner.\\n /// @param operator Address of the updated operator.\\n /// @param authorizedStake Operator's authorized stake for the application.\\n function updateOperatorStatus(address operator, uint256 authorizedStake)\\n public\\n onlyOwner\\n onlyUnlocked\\n {\\n uint256 weight = getWeight(authorizedStake);\\n\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(weight));\\n\\n if (weight == 0) {\\n _removeOperator(operator);\\n } else {\\n updateOperator(operator, weight);\\n }\\n }\\n\\n /// @notice Set the given operators as ineligible for rewards.\\n /// The operators can restore their eligibility at the given time.\\n function setRewardIneligibility(uint32[] calldata operators, uint256 until)\\n public\\n onlyOwner\\n {\\n Rewards.setIneligible(operators, until);\\n emit IneligibleForRewards(operators, until);\\n }\\n\\n /// @notice Restores reward eligibility for the operator.\\n function restoreRewardEligibility(address operator) public {\\n uint32 id = getOperatorID(operator);\\n Rewards.restoreEligibility(id);\\n emit RewardEligibilityRestored(operator, id);\\n }\\n\\n /// @notice Returns whether the operator is eligible for rewards or not.\\n function isEligibleForRewards(address operator) public view returns (bool) {\\n uint32 id = getOperatorID(operator);\\n return Rewards.isEligibleForRewards(id);\\n }\\n\\n /// @notice Returns the time the operator's reward eligibility can be restored.\\n function rewardsEligibilityRestorableAt(address operator)\\n public\\n view\\n returns (uint256)\\n {\\n uint32 id = getOperatorID(operator);\\n return Rewards.rewardsEligibilityRestorableAt(id);\\n }\\n\\n /// @notice Returns whether the operator is able to restore their eligibility\\n /// for rewards right away.\\n function canRestoreRewardEligibility(address operator)\\n public\\n view\\n returns (bool)\\n {\\n uint32 id = getOperatorID(operator);\\n return Rewards.canRestoreRewardEligibility(id);\\n }\\n\\n /// @notice Returns the amount of rewards withdrawable for the given operator.\\n function getAvailableRewards(address operator) public view returns (uint96) {\\n uint32 id = getOperatorID(operator);\\n return availableRewards(id);\\n }\\n\\n /// @notice Return whether the operator is present in the pool.\\n function isOperatorInPool(address operator) public view returns (bool) {\\n return getFlaggedLeafPosition(operator) != 0;\\n }\\n\\n /// @notice Return whether the operator's weight in the pool\\n /// matches their eligible weight.\\n function isOperatorUpToDate(address operator, uint256 authorizedStake)\\n public\\n view\\n returns (bool)\\n {\\n return getWeight(authorizedStake) == getPoolWeight(operator);\\n }\\n\\n /// @notice Return the weight of the operator in the pool,\\n /// which may or may not be out of date.\\n function getPoolWeight(address operator) public view returns (uint256) {\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n if (flaggedPosition == 0) {\\n return 0;\\n } else {\\n uint256 leafPosition = flaggedPosition.unsetFlag();\\n uint256 leafWeight = getLeafWeight(leafPosition);\\n return leafWeight;\\n }\\n }\\n\\n /// @notice Selects a new group of operators of the provided size based on\\n /// the provided pseudo-random seed. At least one operator has to be\\n /// registered in the pool, otherwise the function fails reverting the\\n /// transaction.\\n /// @param groupSize Size of the requested group\\n /// @param seed Pseudo-random number used to select operators to group\\n /// @return selected Members of the selected group\\n function selectGroup(uint256 groupSize, bytes32 seed)\\n public\\n view\\n onlyLocked\\n returns (uint32[] memory)\\n {\\n uint256 _root = root;\\n\\n bytes32 rngState = seed;\\n uint256 rngRange = _root.sumWeight();\\n require(rngRange > 0, \\\"Not enough operators in pool\\\");\\n uint256 currentIndex;\\n\\n uint256 bits = RNG.bitsRequired(rngRange);\\n\\n uint32[] memory selected = new uint32[](groupSize);\\n\\n for (uint256 i = 0; i < groupSize; i++) {\\n (currentIndex, rngState) = RNG.getIndex(rngRange, rngState, bits);\\n\\n uint256 leafPosition = pickWeightedLeaf(currentIndex, _root);\\n\\n uint256 leaf = leaves[leafPosition];\\n selected[i] = leaf.id();\\n }\\n return selected;\\n }\\n\\n function getWeight(uint256 authorization) internal view returns (uint256) {\\n return authorization / poolWeightDivisor;\\n }\\n}\\n\",\"keccak256\":\"0xab42e7c5b1828f42a73f699eb2dc96d4f793572a6323b8b1fbd7c5e0c065bda7\"},\"@keep-network/sortition-pools/contracts/SortitionTree.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Branch.sol\\\";\\nimport \\\"./Position.sol\\\";\\nimport \\\"./Leaf.sol\\\";\\nimport \\\"./Constants.sol\\\";\\n\\ncontract SortitionTree {\\n using Branch for uint256;\\n using Position for uint256;\\n using Leaf for uint256;\\n\\n // implicit tree\\n // root 8\\n // level2 64\\n // level3 512\\n // level4 4k\\n // level5 32k\\n // level6 256k\\n // level7 2M\\n uint256 internal root;\\n\\n // A 2-index mapping from layer => (index (0-index) => branch). For example,\\n // to access the 6th branch in the 2nd layer (right below the root node; the\\n // first branch layer), call branches[2][5]. Mappings are used in place of\\n // arrays for efficiency. The root is the first layer, the branches occupy\\n // layers 2 through 7, and layer 8 is for the leaves. Following this\\n // convention, the first index in `branches` is `2`, and the last index is\\n // `7`.\\n mapping(uint256 => mapping(uint256 => uint256)) internal branches;\\n\\n // A 0-index mapping from index => leaf, acting as an array. For example, to\\n // access the 42nd leaf, call leaves[41].\\n mapping(uint256 => uint256) internal leaves;\\n\\n // the flagged (see setFlag() and unsetFlag() in Position.sol) positions\\n // of all operators present in the pool\\n mapping(address => uint256) internal flaggedLeafPosition;\\n\\n // the leaf after the rightmost occupied leaf of each stack\\n uint256 internal rightmostLeaf;\\n\\n // the empty leaves in each stack\\n // between 0 and the rightmost occupied leaf\\n uint256[] internal emptyLeaves;\\n\\n // Each operator has an uint32 ID number\\n // which is allocated when they first join the pool\\n // and remains unchanged even if they leave and rejoin the pool.\\n mapping(address => uint32) internal operatorID;\\n\\n // The idAddress array records the address corresponding to each ID number.\\n // The ID number 0 is initialized with a zero address and is not used.\\n address[] internal idAddress;\\n\\n constructor() {\\n root = 0;\\n rightmostLeaf = 0;\\n idAddress.push();\\n }\\n\\n /// @notice Return the ID number of the given operator address. An ID number\\n /// of 0 means the operator has not been allocated an ID number yet.\\n /// @param operator Address of the operator.\\n /// @return the ID number of the given operator address\\n function getOperatorID(address operator) public view returns (uint32) {\\n return operatorID[operator];\\n }\\n\\n /// @notice Get the operator address corresponding to the given ID number. A\\n /// zero address means the ID number has not been allocated yet.\\n /// @param id ID of the operator\\n /// @return the address of the operator\\n function getIDOperator(uint32 id) public view returns (address) {\\n return idAddress.length > id ? idAddress[id] : address(0);\\n }\\n\\n /// @notice Gets the operator addresses corresponding to the given ID\\n /// numbers. A zero address means the ID number has not been allocated yet.\\n /// This function works just like getIDOperator except that it allows to fetch\\n /// operator addresses for multiple IDs in one call.\\n /// @param ids the array of the operator ids\\n /// @return an array of the associated operator addresses\\n function getIDOperators(uint32[] calldata ids)\\n public\\n view\\n returns (address[] memory)\\n {\\n uint256 idCount = idAddress.length;\\n\\n address[] memory operators = new address[](ids.length);\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint32 id = ids[i];\\n operators[i] = idCount > id ? idAddress[id] : address(0);\\n }\\n return operators;\\n }\\n\\n /// @notice Checks if operator is already registered in the pool.\\n /// @param operator the address of the operator\\n /// @return whether or not the operator is already registered in the pool\\n function isOperatorRegistered(address operator) public view returns (bool) {\\n return getFlaggedLeafPosition(operator) != 0;\\n }\\n\\n /// @notice Sum the number of operators in each trunk.\\n /// @return the number of operators in the pool\\n function operatorsInPool() public view returns (uint256) {\\n // Get the number of leaves that might be occupied;\\n // if `rightmostLeaf` equals `firstLeaf()` the tree must be empty,\\n // otherwise the difference between these numbers\\n // gives the number of leaves that may be occupied.\\n uint256 nPossiblyUsedLeaves = rightmostLeaf;\\n // Get the number of empty leaves\\n // not accounted for by the `rightmostLeaf`\\n uint256 nEmptyLeaves = emptyLeaves.length;\\n\\n return (nPossiblyUsedLeaves - nEmptyLeaves);\\n }\\n\\n /// @notice Convenience method to return the total weight of the pool\\n /// @return the total weight of the pool\\n function totalWeight() public view returns (uint256) {\\n return root.sumWeight();\\n }\\n\\n /// @notice Give the operator a new ID number.\\n /// Does not check if the operator already has an ID number.\\n /// @param operator the address of the operator\\n /// @return a new ID for that operator\\n function allocateOperatorID(address operator) internal returns (uint256) {\\n uint256 id = idAddress.length;\\n\\n require(id <= type(uint32).max, \\\"Pool capacity exceeded\\\");\\n\\n operatorID[operator] = uint32(id);\\n idAddress.push(operator);\\n return id;\\n }\\n\\n /// @notice Inserts an operator into the sortition pool\\n /// @param operator the address of an operator to insert\\n /// @param weight how much weight that operator has in the pool\\n function _insertOperator(address operator, uint256 weight) internal {\\n require(\\n !isOperatorRegistered(operator),\\n \\\"Operator is already registered in the pool\\\"\\n );\\n\\n // Fetch the operator's ID, and if they don't have one, allocate them one.\\n uint256 id = getOperatorID(operator);\\n if (id == 0) {\\n id = allocateOperatorID(operator);\\n }\\n\\n // Determine which leaf to insert them into\\n uint256 position = getEmptyLeafPosition();\\n // Record the block the operator was inserted in\\n uint256 theLeaf = Leaf.make(operator, block.number, id);\\n\\n // Update the leaf, and propagate the weight changes all the way up to the\\n // root.\\n root = setLeaf(position, theLeaf, weight, root);\\n\\n // Without position flags,\\n // the position 0x000000 would be treated as empty\\n flaggedLeafPosition[operator] = position.setFlag();\\n }\\n\\n /// @notice Remove an operator (and their weight) from the pool.\\n /// @param operator the address of the operator to remove\\n function _removeOperator(address operator) internal {\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n require(flaggedPosition != 0, \\\"Operator is not registered in the pool\\\");\\n uint256 unflaggedPosition = flaggedPosition.unsetFlag();\\n\\n // Update the leaf, and propagate the weight changes all the way up to the\\n // root.\\n root = removeLeaf(unflaggedPosition, root);\\n removeLeafPositionRecord(operator);\\n }\\n\\n /// @notice Update an operator's weight in the pool.\\n /// @param operator the address of the operator to update\\n /// @param weight the new weight\\n function updateOperator(address operator, uint256 weight) internal {\\n require(\\n isOperatorRegistered(operator),\\n \\\"Operator is not registered in the pool\\\"\\n );\\n\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n uint256 unflaggedPosition = flaggedPosition.unsetFlag();\\n root = updateLeaf(unflaggedPosition, weight, root);\\n }\\n\\n /// @notice Helper method to remove a leaf position record for an operator.\\n /// @param operator the address of the operator to remove the record for\\n function removeLeafPositionRecord(address operator) internal {\\n flaggedLeafPosition[operator] = 0;\\n }\\n\\n /// @notice Removes the data and weight from a particular leaf.\\n /// @param position the leaf index to remove\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function removeLeaf(uint256 position, uint256 _root)\\n internal\\n returns (uint256)\\n {\\n uint256 rightmostSubOne = rightmostLeaf - 1;\\n bool isRightmost = position == rightmostSubOne;\\n\\n // Clears out the data in the leaf node, and then propagates the weight\\n // changes all the way up to the root.\\n uint256 newRoot = setLeaf(position, 0, 0, _root);\\n\\n // Infer if need to fall back on emptyLeaves yet\\n if (isRightmost) {\\n rightmostLeaf = rightmostSubOne;\\n } else {\\n emptyLeaves.push(position);\\n }\\n return newRoot;\\n }\\n\\n /// @notice Updates the tree to give a particular leaf a new weight.\\n /// @param position the index of the leaf to update\\n /// @param weight the new weight\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function updateLeaf(\\n uint256 position,\\n uint256 weight,\\n uint256 _root\\n ) internal returns (uint256) {\\n if (getLeafWeight(position) != weight) {\\n return updateTree(position, weight, _root);\\n } else {\\n return _root;\\n }\\n }\\n\\n /// @notice Places a leaf into a particular position, with a given weight and\\n /// propagates that change.\\n /// @param position the index to place the leaf in\\n /// @param theLeaf the new leaf to place in the position\\n /// @param leafWeight the weight of the leaf\\n /// @param _root the root containing the new leaf\\n /// @return the updated root node\\n function setLeaf(\\n uint256 position,\\n uint256 theLeaf,\\n uint256 leafWeight,\\n uint256 _root\\n ) internal returns (uint256) {\\n // set leaf\\n leaves[position] = theLeaf;\\n\\n return (updateTree(position, leafWeight, _root));\\n }\\n\\n /// @notice Propagates a weight change at a position through the tree,\\n /// eventually returning the updated root.\\n /// @param position the index of leaf to update\\n /// @param weight the new weight of the leaf\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function updateTree(\\n uint256 position,\\n uint256 weight,\\n uint256 _root\\n ) internal returns (uint256) {\\n uint256 childSlot;\\n uint256 treeNode;\\n uint256 newNode;\\n uint256 nodeWeight = weight;\\n\\n uint256 parent = position;\\n // set levels 7 to 2\\n for (uint256 level = Constants.LEVELS; level >= 2; level--) {\\n childSlot = parent.slot();\\n parent = parent.parent();\\n treeNode = branches[level][parent];\\n newNode = treeNode.setSlot(childSlot, nodeWeight);\\n branches[level][parent] = newNode;\\n nodeWeight = newNode.sumWeight();\\n }\\n\\n // set level Root\\n childSlot = parent.slot();\\n return _root.setSlot(childSlot, nodeWeight);\\n }\\n\\n /// @notice Retrieves the next available empty leaf position. Tries to fill\\n /// left to right first, ignoring leaf removals, and then fills\\n /// most-recent-removals first.\\n /// @return the position of the empty leaf\\n function getEmptyLeafPosition() internal returns (uint256) {\\n uint256 rLeaf = rightmostLeaf;\\n bool spaceOnRight = (rLeaf + 1) < Constants.POOL_CAPACITY;\\n if (spaceOnRight) {\\n rightmostLeaf = rLeaf + 1;\\n return rLeaf;\\n } else {\\n uint256 emptyLeafCount = emptyLeaves.length;\\n require(emptyLeafCount > 0, \\\"Pool is full\\\");\\n uint256 emptyLeaf = emptyLeaves[emptyLeafCount - 1];\\n emptyLeaves.pop();\\n return emptyLeaf;\\n }\\n }\\n\\n /// @notice Gets the flagged leaf position for an operator.\\n /// @param operator the address of the operator\\n /// @return the leaf position of that operator\\n function getFlaggedLeafPosition(address operator)\\n internal\\n view\\n returns (uint256)\\n {\\n return flaggedLeafPosition[operator];\\n }\\n\\n /// @notice Gets the weight of a leaf at a particular position.\\n /// @param position the index of the leaf\\n /// @return the weight of the leaf at that position\\n function getLeafWeight(uint256 position) internal view returns (uint256) {\\n uint256 slot = position.slot();\\n uint256 parent = position.parent();\\n\\n // A leaf's weight information is stored a 32-bit slot in the branch layer\\n // directly above the leaf layer. To access it, we calculate that slot and\\n // parent position, and always know the hard-coded layer index.\\n uint256 node = branches[Constants.LEVELS][parent];\\n return node.getSlot(slot);\\n }\\n\\n /// @notice Picks a leaf given a random index.\\n /// @param index a number in `[0, _root.totalWeight())` used to decide\\n /// between leaves\\n /// @param _root the root of the tree\\n function pickWeightedLeaf(uint256 index, uint256 _root)\\n internal\\n view\\n returns (uint256 leafPosition)\\n {\\n uint256 currentIndex = index;\\n uint256 currentNode = _root;\\n uint256 currentPosition = 0;\\n uint256 currentSlot;\\n\\n require(index < currentNode.sumWeight(), \\\"Index exceeds weight\\\");\\n\\n // get root slot\\n (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex);\\n\\n // get slots from levels 2 to 7\\n for (uint256 level = 2; level <= Constants.LEVELS; level++) {\\n currentPosition = currentPosition.child(currentSlot);\\n currentNode = branches[level][currentPosition];\\n (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex);\\n }\\n\\n // get leaf position\\n leafPosition = currentPosition.child(currentSlot);\\n }\\n}\\n\",\"keccak256\":\"0x51daeca62ef52be78a1a9de4d2a1c5900c873165f59eda14d5965d7d7da90a03\"},\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n uint8 private constant _ADDRESS_LENGTH = 20;\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\\n */\\n function toHexString(address addr) internal pure returns (string memory) {\\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\\n }\\n}\\n\",\"keccak256\":\"0xaf159a8b1923ad2a26d516089bceca9bdeaeacd04be50983ea00ba63070f08a3\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.3) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n /// @solidity memory-safe-assembly\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0xdb7f5c28fc61cda0bd8ab60ce288e206b791643bcd3ba464a70cbec18895a2f5\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IApproveAndCall.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\n/// @notice An interface that should be implemented by tokens supporting\\n/// `approveAndCall`/`receiveApproval` pattern.\\ninterface IApproveAndCall {\\n /// @notice Executes `receiveApproval` function on spender as specified in\\n /// `IReceiveApproval` interface. Approves spender to withdraw from\\n /// the caller multiple times, up to the `amount`. If this\\n /// function is called again, it overwrites the current allowance\\n /// with `amount`. Reverts if the approval reverted or if\\n /// `receiveApproval` call on the spender reverted.\\n function approveAndCall(\\n address spender,\\n uint256 amount,\\n bytes memory extraData\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x393d18ef81a57dcc96fff4c340cc2945deaebb37b9796c322cf2bc96872c3df8\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IERC20WithPermit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\\\";\\n\\nimport \\\"./IApproveAndCall.sol\\\";\\n\\n/// @title IERC20WithPermit\\n/// @notice Burnable ERC20 token with EIP2612 permit functionality. User can\\n/// authorize a transfer of their token with a signature conforming\\n/// EIP712 standard instead of an on-chain transaction from their\\n/// address. Anyone can submit this signature on the user's behalf by\\n/// calling the permit function, as specified in EIP2612 standard,\\n/// paying gas fees, and possibly performing other actions in the same\\n/// transaction.\\ninterface IERC20WithPermit is IERC20, IERC20Metadata, IApproveAndCall {\\n /// @notice EIP2612 approval made with secp256k1 signature.\\n /// Users can authorize a transfer of their tokens with a signature\\n /// conforming EIP712 standard, rather than an on-chain transaction\\n /// from their address. Anyone can submit this signature on the\\n /// user's behalf by calling the permit function, paying gas fees,\\n /// and possibly performing other actions in the same transaction.\\n /// @dev The deadline argument can be set to `type(uint256).max to create\\n /// permits that effectively never expire.\\n function permit(\\n address owner,\\n address spender,\\n uint256 amount,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /// @notice Destroys `amount` tokens from the caller.\\n function burn(uint256 amount) external;\\n\\n /// @notice Destroys `amount` of tokens from `account`, deducting the amount\\n /// from caller's allowance.\\n function burnFrom(address account, uint256 amount) external;\\n\\n /// @notice Returns hash of EIP712 Domain struct with the token name as\\n /// a signing domain and token contract as a verifying contract.\\n /// Used to construct EIP2612 signature provided to `permit`\\n /// function.\\n /* solhint-disable-next-line func-name-mixedcase */\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n\\n /// @notice Returns the current nonce for EIP2612 permission for the\\n /// provided token owner for a replay protection. Used to construct\\n /// EIP2612 signature provided to `permit` function.\\n function nonce(address owner) external view returns (uint256);\\n\\n /// @notice Returns EIP2612 Permit message hash. Used to construct EIP2612\\n /// signature provided to `permit` function.\\n /* solhint-disable-next-line func-name-mixedcase */\\n function PERMIT_TYPEHASH() external pure returns (bytes32);\\n}\\n\",\"keccak256\":\"0xdac9a5086c19a7128b505a7be1ab0ac1aa314f6989cb88d2417e9d7383f89fa9\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IReceiveApproval.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\n/// @notice An interface that should be implemented by contracts supporting\\n/// `approveAndCall`/`receiveApproval` pattern.\\ninterface IReceiveApproval {\\n /// @notice Receives approval to spend tokens. Called as a result of\\n /// `approveAndCall` call on the token.\\n function receiveApproval(\\n address from,\\n uint256 amount,\\n address token,\\n bytes calldata extraData\\n ) external;\\n}\\n\",\"keccak256\":\"0x6a30d83ad230548b1e7839737affc8489a035314209de14b89dbef7fb0f66395\",\"license\":\"MIT\"},\"contracts/BeaconDkgValidator.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\nimport \\\"./libraries/BytesLib.sol\\\";\\nimport {BeaconDkg as DKG} from \\\"./libraries/BeaconDkg.sol\\\";\\n\\n/// @title DKG result validator\\n/// @notice DKGValidator allows performing a full validation of DKG result,\\n/// including checking the format of fields in the result, declared\\n/// selected group members, and signatures of operators supporting the\\n/// result. The operator submitting the result should perform the\\n/// validation using a free contract call before submitting the result\\n/// to ensure their result is valid and can not be challenged. All other\\n/// network operators should perform validation of the submitted result\\n/// using a free contract call and challenge the result if the\\n/// validation fails.\\ncontract BeaconDkgValidator {\\n using BytesLib for bytes;\\n using ECDSA for bytes32;\\n\\n /// @dev Size of a group in the threshold relay.\\n uint256 public constant groupSize = 64;\\n\\n /// @dev The minimum number of group members needed to interact according to\\n /// the protocol to produce a relay entry. The adversary can not learn\\n /// anything about the key as long as it does not break into\\n /// groupThreshold+1 of members.\\n uint256 public constant groupThreshold = 33;\\n\\n /// @dev The minimum number of active and properly behaving group members\\n /// during the DKG needed to accept the result. This number is higher\\n /// than `groupThreshold` to keep a safety margin for members becoming\\n /// inactive after DKG so that the group can still produce a relay\\n /// entry.\\n uint256 public constant activeThreshold = 58; // 90% of groupSize\\n\\n /// @dev Size in bytes of a single signature produced by operator supporting\\n /// DKG result.\\n uint256 public constant signatureByteSize = 65;\\n\\n SortitionPool public immutable sortitionPool;\\n\\n constructor(SortitionPool _sortitionPool) {\\n require(\\n address(_sortitionPool) != address(0),\\n \\\"Zero-address reference\\\"\\n );\\n\\n sortitionPool = _sortitionPool;\\n }\\n\\n /// @notice Performs a full validation of DKG result, including checking the\\n /// format of fields in the result, declared selected group members,\\n /// and signatures of operators supporting the result.\\n /// @param seed seed used to start the DKG and select group members\\n /// @param startBlock DKG start block\\n /// @return isValid true if the result is valid, false otherwise\\n /// @return errorMsg validation error message; empty for a valid result\\n function validate(\\n DKG.Result calldata result,\\n uint256 seed,\\n uint256 startBlock\\n ) external view returns (bool isValid, string memory errorMsg) {\\n (bool hasValidFields, string memory error) = validateFields(result);\\n if (!hasValidFields) {\\n return (false, error);\\n }\\n\\n if (!validateSignatures(result, startBlock)) {\\n return (false, \\\"Invalid signatures\\\");\\n }\\n\\n if (!validateGroupMembers(result, seed)) {\\n return (false, \\\"Invalid group members\\\");\\n }\\n\\n // At this point all group members and mishbehaved members were verified\\n if (!validateMembersHash(result)) {\\n return (false, \\\"Invalid members hash\\\");\\n }\\n\\n return (true, \\\"\\\");\\n }\\n\\n /// @notice Performs a static validation of DKG result fields: lengths,\\n /// ranges, and order of arrays.\\n /// @return isValid true if the result is valid, false otherwise\\n /// @return errorMsg validation error message; empty for a valid result\\n function validateFields(DKG.Result calldata result)\\n public\\n pure\\n returns (bool isValid, string memory errorMsg)\\n {\\n // Group public key needs to be 128 bytes long.\\n if (result.groupPubKey.length != 128) {\\n return (false, \\\"Malformed group public key\\\");\\n }\\n\\n // The number of misbehaved members can not exceed the threshold.\\n // Misbehaved member indices needs to be unique, between [1, groupSize],\\n // and sorted in ascending order.\\n uint8[] calldata misbehavedMembersIndices = result\\n .misbehavedMembersIndices;\\n if (groupSize - misbehavedMembersIndices.length < activeThreshold) {\\n return (false, \\\"Too many members misbehaving during DKG\\\");\\n }\\n if (misbehavedMembersIndices.length > 1) {\\n if (\\n misbehavedMembersIndices[0] < 1 ||\\n misbehavedMembersIndices[misbehavedMembersIndices.length - 1] >\\n groupSize\\n ) {\\n return (false, \\\"Corrupted misbehaved members indices\\\");\\n }\\n for (uint256 i = 1; i < misbehavedMembersIndices.length; i++) {\\n if (\\n misbehavedMembersIndices[i - 1] >=\\n misbehavedMembersIndices[i]\\n ) {\\n return (false, \\\"Corrupted misbehaved members indices\\\");\\n }\\n }\\n }\\n\\n // Each signature needs to have a correct length and signatures need to\\n // be provided.\\n uint256 signaturesCount = result.signatures.length / signatureByteSize;\\n if (result.signatures.length == 0) {\\n return (false, \\\"No signatures provided\\\");\\n }\\n if (result.signatures.length % signatureByteSize != 0) {\\n return (false, \\\"Malformed signatures array\\\");\\n }\\n\\n // We expect the same amount of signatures as the number of declared\\n // group member indices that signed the result.\\n uint256[] calldata signingMembersIndices = result.signingMembersIndices;\\n if (signaturesCount != signingMembersIndices.length) {\\n return (false, \\\"Unexpected signatures count\\\");\\n }\\n if (signaturesCount < groupThreshold) {\\n return (false, \\\"Too few signatures\\\");\\n }\\n if (signaturesCount > groupSize) {\\n return (false, \\\"Too many signatures\\\");\\n }\\n\\n // Signing member indices needs to be unique, between [1,groupSize],\\n // and sorted in ascending order.\\n if (\\n signingMembersIndices[0] < 1 ||\\n signingMembersIndices[signingMembersIndices.length - 1] > groupSize\\n ) {\\n return (false, \\\"Corrupted signing member indices\\\");\\n }\\n for (uint256 i = 1; i < signingMembersIndices.length; i++) {\\n if (signingMembersIndices[i - 1] >= signingMembersIndices[i]) {\\n return (false, \\\"Corrupted signing member indices\\\");\\n }\\n }\\n\\n return (true, \\\"\\\");\\n }\\n\\n /// @notice Performs validation of group members as declared in DKG\\n /// result against group members selected by the sortition pool.\\n /// @param seed seed used to start the DKG and select group members\\n /// @return true if group members matches; false otherwise\\n function validateGroupMembers(DKG.Result calldata result, uint256 seed)\\n public\\n view\\n returns (bool)\\n {\\n uint32[] calldata resultMembers = result.members;\\n uint32[] memory actualGroupMembers = sortitionPool.selectGroup(\\n groupSize,\\n bytes32(seed)\\n );\\n if (resultMembers.length != actualGroupMembers.length) {\\n return false;\\n }\\n for (uint256 i = 0; i < resultMembers.length; i++) {\\n if (resultMembers[i] != actualGroupMembers[i]) {\\n return false;\\n }\\n }\\n return true;\\n }\\n\\n /// @notice Performs validation of signatures supplied in DKG result.\\n /// Note that this function does not check if addresses which\\n /// supplied signatures supporting the result are the ones selected\\n /// to the group by sortition pool. This function should be used\\n /// together with `validateGroupMembers`.\\n /// @param startBlock DKG start block\\n /// @return true if group members matches; false otherwise\\n function validateSignatures(DKG.Result calldata result, uint256 startBlock)\\n public\\n view\\n returns (bool)\\n {\\n bytes32 hash = keccak256(\\n abi.encode(\\n block.chainid,\\n result.groupPubKey,\\n result.misbehavedMembersIndices,\\n startBlock\\n )\\n ).toEthSignedMessageHash();\\n\\n uint256[] calldata signingMembersIndices = result.signingMembersIndices;\\n uint32[] memory signingMemberIds = new uint32[](\\n signingMembersIndices.length\\n );\\n for (uint256 i = 0; i < signingMembersIndices.length; i++) {\\n signingMemberIds[i] = result.members[signingMembersIndices[i] - 1];\\n }\\n\\n address[] memory signingMemberAddresses = sortitionPool.getIDOperators(\\n signingMemberIds\\n );\\n\\n bytes memory current; // Current signature to be checked.\\n\\n uint256 signaturesCount = result.signatures.length / signatureByteSize;\\n for (uint256 i = 0; i < signaturesCount; i++) {\\n current = result.signatures.slice(\\n signatureByteSize * i,\\n signatureByteSize\\n );\\n address recoveredAddress = hash.recover(current);\\n\\n if (signingMemberAddresses[i] != recoveredAddress) {\\n return false;\\n }\\n }\\n\\n return true;\\n }\\n\\n /// @notice Performs validation of hashed group members that actively took\\n /// part in DKG.\\n /// @param result DKG result\\n /// @return true if result's group members hash matches with the one that is\\n /// challenged.\\n function validateMembersHash(DKG.Result calldata result)\\n public\\n pure\\n returns (bool)\\n {\\n if (result.misbehavedMembersIndices.length > 0) {\\n // members that generated a group signing key\\n uint32[] memory groupMembers = new uint32[](\\n result.members.length - result.misbehavedMembersIndices.length\\n );\\n uint256 k = 0; // misbehaved members counter\\n uint256 j = 0; // group members counter\\n for (uint256 i = 0; i < result.members.length; i++) {\\n // misbehaved member indices start from 1, so we need to -1 on misbehaved\\n if (i != result.misbehavedMembersIndices[k] - 1) {\\n groupMembers[j] = result.members[i];\\n j++;\\n } else if (k < result.misbehavedMembersIndices.length - 1) {\\n k++;\\n }\\n }\\n\\n return keccak256(abi.encode(groupMembers)) == result.membersHash;\\n }\\n\\n return keccak256(abi.encode(result.members)) == result.membersHash;\\n }\\n}\\n\",\"keccak256\":\"0xaacb5961dc3181238036f1e747b3d1935f356ca5ff27bd9c9c1c0c22dee6630c\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BeaconDkg.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\nimport \\\"./BytesLib.sol\\\";\\nimport {BeaconDkgValidator as DKGValidator} from \\\"../BeaconDkgValidator.sol\\\";\\n\\nlibrary BeaconDkg {\\n using BytesLib for bytes;\\n using ECDSA for bytes32;\\n\\n struct Parameters {\\n // Time in blocks during which a submitted result can be challenged.\\n uint256 resultChallengePeriodLength;\\n // Extra gas required to be left at the end of the challenge DKG result\\n // transaction.\\n uint256 resultChallengeExtraGas;\\n // Time in blocks during which a result is expected to be submitted.\\n uint256 resultSubmissionTimeout;\\n // Time in blocks during which only the result submitter is allowed to\\n // approve it. Once this period ends and the submitter have not approved\\n // the result, anyone can do it.\\n uint256 submitterPrecedencePeriodLength;\\n }\\n\\n struct Data {\\n // Address of the Sortition Pool contract.\\n SortitionPool sortitionPool;\\n // Address of the DKGValidator contract.\\n DKGValidator dkgValidator;\\n // DKG parameters. The parameters should persist between DKG executions.\\n // They should be updated with dedicated set functions only when DKG is not\\n // in progress.\\n Parameters parameters;\\n // Time in blocks at which DKG started.\\n uint256 startBlock;\\n // Seed used to start DKG.\\n uint256 seed;\\n // Time in blocks that should be added to result submission period calculation.\\n // It is used in case of a challenge to adjust DKG timeout calculation.\\n uint256 resultSubmissionStartBlockOffset;\\n // Hash of submitted DKG result.\\n bytes32 submittedResultHash;\\n // Block number from the moment of the DKG result submission.\\n uint256 submittedResultBlock;\\n }\\n\\n /// @notice DKG result.\\n struct Result {\\n // Claimed submitter candidate group member index.\\n // Must be in range [1, groupSize].\\n uint256 submitterMemberIndex;\\n // Generated candidate group public key\\n bytes groupPubKey;\\n // Array of misbehaved members indices (disqualified or inactive).\\n // Indices must be in range [1, groupSize], unique, and sorted in ascending\\n // order.\\n uint8[] misbehavedMembersIndices;\\n // Concatenation of signatures from members supporting the result.\\n // The message to be signed by each member is keccak256 hash of the\\n // calculated group public key, misbehaved members indices and DKG\\n // start block. The calculated hash should be prefixed with prefixed with\\n // `\\\\x19Ethereum signed message:\\\\n` before signing, so the message to\\n // sign is:\\n // `\\\\x19Ethereum signed message:\\\\n${keccak256(\\n // groupPubKey, misbehavedMembersIndices, dkgStartBlock\\n // )}`\\n bytes signatures;\\n // Indices of members corresponding to each signature. Indices must be\\n // be in range [1, groupSize], unique, and sorted in ascending order.\\n uint256[] signingMembersIndices;\\n // Identifiers of candidate group members as outputted by the group\\n // selection protocol.\\n uint32[] members;\\n // Keccak256 hash of group members identifiers that actively took part\\n // in DKG (excluding IA/DQ members).\\n bytes32 membersHash;\\n }\\n\\n /// @notice States for phases of group creation. The states doesn't include\\n /// timeouts which should be tracked and notified individually.\\n enum State {\\n // Group creation is not in progress. It is a state set after group creation\\n // completion either by timeout or by a result approval.\\n IDLE,\\n // Group creation is awaiting the seed and sortition pool is locked.\\n AWAITING_SEED,\\n // Off-chain DKG protocol execution is in progress. A result is being calculated\\n // by the clients in this state. It's not yet possible to submit the result.\\n KEY_GENERATION,\\n // After off-chain DKG protocol execution the contract awaits result submission.\\n // This is a state to which group creation returns in case of a result\\n // challenge notification.\\n AWAITING_RESULT,\\n // DKG result was submitted and awaits an approval or a challenge. If a result\\n // gets challenge the state returns to `AWAITING_RESULT`. If a result gets\\n // approval the state changes to `IDLE`.\\n CHALLENGE\\n }\\n\\n /// @dev Size of a group in the threshold relay.\\n uint256 public constant groupSize = 64;\\n\\n /// @notice Time in blocks after which DKG result is complete and ready to be\\n // published by clients.\\n uint256 public constant offchainDkgTime = 5 * (1 + 5) + 2 * (1 + 10) + 20;\\n\\n event DkgStarted(uint256 indexed seed);\\n\\n // To recreate the members that actively took part in dkg, the selected members\\n // array should be filtered out from misbehavedMembersIndices.\\n event DkgResultSubmitted(\\n bytes32 indexed resultHash,\\n uint256 indexed seed,\\n Result result\\n );\\n\\n event DkgTimedOut();\\n\\n event DkgResultApproved(\\n bytes32 indexed resultHash,\\n address indexed approver\\n );\\n\\n event DkgResultChallenged(\\n bytes32 indexed resultHash,\\n address indexed challenger,\\n string reason\\n );\\n\\n event DkgStateLocked();\\n\\n event DkgSeedTimedOut();\\n\\n /// @notice Initializes SortitionPool and DKGValidator addresses.\\n /// Can be performed only once.\\n /// @param _sortitionPool Sortition Pool reference\\n /// @param _dkgValidator DKGValidator reference\\n function init(\\n Data storage self,\\n SortitionPool _sortitionPool,\\n DKGValidator _dkgValidator\\n ) internal {\\n require(\\n address(self.sortitionPool) == address(0),\\n \\\"Sortition Pool address already set\\\"\\n );\\n\\n require(\\n address(self.dkgValidator) == address(0),\\n \\\"DKG Validator address already set\\\"\\n );\\n\\n self.sortitionPool = _sortitionPool;\\n self.dkgValidator = _dkgValidator;\\n }\\n\\n /// @notice Determines the current state of group creation. It doesn't take\\n /// timeouts into consideration. The timeouts should be tracked and\\n /// notified separately.\\n function currentState(Data storage self)\\n internal\\n view\\n returns (State state)\\n {\\n state = State.IDLE;\\n\\n if (self.sortitionPool.isLocked()) {\\n state = State.AWAITING_SEED;\\n\\n if (self.startBlock > 0) {\\n state = State.KEY_GENERATION;\\n\\n if (block.number > self.startBlock + offchainDkgTime) {\\n state = State.AWAITING_RESULT;\\n\\n if (self.submittedResultBlock > 0) {\\n state = State.CHALLENGE;\\n }\\n }\\n }\\n }\\n }\\n\\n /// @notice Locks the sortition pool and starts awaiting for the\\n /// group creation seed.\\n function lockState(Data storage self) internal {\\n require(currentState(self) == State.IDLE, \\\"Current state is not IDLE\\\");\\n\\n emit DkgStateLocked();\\n\\n self.sortitionPool.lock();\\n }\\n\\n function start(Data storage self, uint256 seed) internal {\\n require(\\n currentState(self) == State.AWAITING_SEED,\\n \\\"Current state is not AWAITING_SEED\\\"\\n );\\n\\n emit DkgStarted(seed);\\n\\n self.startBlock = block.number;\\n self.seed = seed;\\n }\\n\\n /// @notice Allows to submit a DKG result. The submitted result does not go\\n /// through a validation and before it gets accepted, it needs to\\n /// wait through the challenge period during which everyone has\\n /// a chance to challenge the result as invalid one. Submitter of\\n /// the result needs to be in the sortition pool and if the result\\n /// gets challenged, the submitter will get slashed.\\n function submitResult(Data storage self, Result calldata result) external {\\n require(\\n currentState(self) == State.AWAITING_RESULT,\\n \\\"Current state is not AWAITING_RESULT\\\"\\n );\\n require(!hasDkgTimedOut(self), \\\"DKG timeout already passed\\\");\\n\\n SortitionPool sortitionPool = self.sortitionPool;\\n\\n // Submitter must be an operator in the sortition pool.\\n // Declared submitter's member index in the DKG result needs to match\\n // the address calling this function.\\n require(\\n sortitionPool.isOperatorInPool(msg.sender),\\n \\\"Submitter not in the sortition pool\\\"\\n );\\n require(\\n sortitionPool.getIDOperator(\\n result.members[result.submitterMemberIndex - 1]\\n ) == msg.sender,\\n \\\"Unexpected submitter index\\\"\\n );\\n\\n self.submittedResultHash = keccak256(abi.encode(result));\\n self.submittedResultBlock = block.number;\\n\\n emit DkgResultSubmitted(self.submittedResultHash, self.seed, result);\\n }\\n\\n /// @notice Checks if DKG timed out. The DKG timeout period includes time required\\n /// for off-chain protocol execution and time for the result publication.\\n /// After this time a result cannot be submitted and DKG can be notified\\n /// about the timeout. DKG period is adjusted by result submission\\n /// offset that include blocks that were mined while invalid result\\n /// has been registered until it got challenged.\\n /// @return True if DKG timed out, false otherwise.\\n function hasDkgTimedOut(Data storage self) internal view returns (bool) {\\n return\\n currentState(self) == State.AWAITING_RESULT &&\\n block.number >\\n (self.startBlock +\\n offchainDkgTime +\\n self.resultSubmissionStartBlockOffset +\\n self.parameters.resultSubmissionTimeout);\\n }\\n\\n /// @notice Notifies about DKG timeout.\\n function notifyTimeout(Data storage self) internal {\\n require(hasDkgTimedOut(self), \\\"DKG has not timed out\\\");\\n\\n emit DkgTimedOut();\\n\\n complete(self);\\n }\\n\\n /// @notice Notifies about the seed was not delivered and restores the\\n /// initial DKG state (IDLE).\\n function notifySeedTimedOut(Data storage self) internal {\\n require(\\n currentState(self) == State.AWAITING_SEED,\\n \\\"Current state is not AWAITING_SEED\\\"\\n );\\n\\n emit DkgSeedTimedOut();\\n\\n complete(self);\\n }\\n\\n /// @notice Approves DKG result. Can be called when the challenge period for\\n /// the submitted result is finished. Considers the submitted result\\n /// as valid. For the first `submitterPrecedencePeriodLength`\\n /// blocks after the end of the challenge period can be called only\\n /// by the DKG result submitter. After that time, can be called by\\n /// anyone.\\n /// @dev Can be called after a challenge period for the submitted result.\\n /// @param result Result to approve. Must match the submitted result stored\\n /// during `submitResult`.\\n /// @return misbehavedMembers Identifiers of members who misbehaved during DKG.\\n function approveResult(Data storage self, Result calldata result)\\n external\\n returns (uint32[] memory misbehavedMembers)\\n {\\n require(\\n currentState(self) == State.CHALLENGE,\\n \\\"Current state is not CHALLENGE\\\"\\n );\\n\\n uint256 challengePeriodEnd = self.submittedResultBlock +\\n self.parameters.resultChallengePeriodLength;\\n\\n require(\\n block.number > challengePeriodEnd,\\n \\\"Challenge period has not passed yet\\\"\\n );\\n\\n require(\\n keccak256(abi.encode(result)) == self.submittedResultHash,\\n \\\"Result under approval is different than the submitted one\\\"\\n );\\n\\n // Extract submitter member address. Submitter member index is in\\n // range [1, groupSize] so we need to -1 when fetching identifier from members\\n // array.\\n address submitterMember = self.sortitionPool.getIDOperator(\\n result.members[result.submitterMemberIndex - 1]\\n );\\n\\n require(\\n msg.sender == submitterMember ||\\n block.number >\\n challengePeriodEnd +\\n self.parameters.submitterPrecedencePeriodLength,\\n \\\"Only the DKG result submitter can approve the result at this moment\\\"\\n );\\n\\n // Extract misbehaved members identifiers. Misbehaved members indices\\n // are in range [1, groupSize], so we need to -1 when fetching identifiers from\\n // members array.\\n misbehavedMembers = new uint32[](\\n result.misbehavedMembersIndices.length\\n );\\n for (uint256 i = 0; i < result.misbehavedMembersIndices.length; i++) {\\n misbehavedMembers[i] = result.members[\\n result.misbehavedMembersIndices[i] - 1\\n ];\\n }\\n\\n emit DkgResultApproved(self.submittedResultHash, msg.sender);\\n\\n return misbehavedMembers;\\n }\\n\\n /// @notice Challenges DKG result. If the submitted result is proved to be\\n /// invalid it reverts the DKG back to the result submission phase.\\n /// @dev Can be called during a challenge period for the submitted result.\\n /// @param result Result to challenge. Must match the submitted result\\n /// stored during `submitResult`.\\n /// @return maliciousResultHash Hash of the malicious result.\\n /// @return maliciousSubmitter Identifier of the malicious submitter.\\n function challengeResult(Data storage self, Result calldata result)\\n external\\n returns (bytes32 maliciousResultHash, uint32 maliciousSubmitter)\\n {\\n require(\\n currentState(self) == State.CHALLENGE,\\n \\\"Current state is not CHALLENGE\\\"\\n );\\n\\n require(\\n block.number <=\\n self.submittedResultBlock +\\n self.parameters.resultChallengePeriodLength,\\n \\\"Challenge period has already passed\\\"\\n );\\n\\n require(\\n keccak256(abi.encode(result)) == self.submittedResultHash,\\n \\\"Result under challenge is different than the submitted one\\\"\\n );\\n\\n // https://github.com/crytic/slither/issues/982\\n // slither-disable-next-line unused-return\\n try\\n self.dkgValidator.validate(result, self.seed, self.startBlock)\\n returns (\\n // slither-disable-next-line uninitialized-local,variable-scope\\n bool isValid,\\n // slither-disable-next-line uninitialized-local,variable-scope\\n string memory errorMsg\\n ) {\\n if (isValid) {\\n revert(\\\"unjustified challenge\\\");\\n }\\n\\n emit DkgResultChallenged(\\n self.submittedResultHash,\\n msg.sender,\\n errorMsg\\n );\\n } catch {\\n // if the validation reverted we consider the DKG result as invalid\\n emit DkgResultChallenged(\\n self.submittedResultHash,\\n msg.sender,\\n \\\"validation reverted\\\"\\n );\\n }\\n\\n // Consider result hash as malicious.\\n maliciousResultHash = self.submittedResultHash;\\n maliciousSubmitter = result.members[result.submitterMemberIndex - 1];\\n\\n // Adjust DKG result submission block start, so submission stage starts\\n // from the beginning.\\n self.resultSubmissionStartBlockOffset =\\n block.number -\\n self.startBlock -\\n offchainDkgTime;\\n\\n submittedResultCleanup(self);\\n\\n return (maliciousResultHash, maliciousSubmitter);\\n }\\n\\n /// @notice Due to EIP150, 1/64 of the gas is not forwarded to the call, and\\n /// will be kept to execute the remaining operations in the function\\n /// after the call inside the try-catch.\\n ///\\n /// To ensure there is no way for the caller to manipulate gas limit\\n /// in such a way that the call inside try-catch fails with out-of-gas\\n /// and the rest of the function is executed with the remaining\\n /// 1/64 of gas, we require an extra gas amount to be left at the\\n /// end of the call to the function challenging DKG result and\\n /// wrapping the call to BeaconDkgValidator and TokenStaking\\n /// contracts inside a try-catch.\\n function requireChallengeExtraGas(Data storage self) internal view {\\n require(\\n gasleft() >= self.parameters.resultChallengeExtraGas,\\n \\\"Not enough extra gas left\\\"\\n );\\n }\\n\\n /// @notice Updates DKG-related parameters\\n /// @param _resultChallengePeriodLength New value of the result challenge\\n /// period length. It is the number of blocks for which a DKG result\\n /// can be challenged.\\n /// @param _resultChallengeExtraGas New value of the result challenge extra\\n /// gas. It is the extra gas required to be left at the end of the\\n /// challenge DKG result transaction.\\n /// @param _resultSubmissionTimeout New value of the result submission\\n /// timeout in seconds. It is a timeout for a group to provide a DKG\\n /// result.\\n /// @param _submitterPrecedencePeriodLength New value of the submitter\\n /// precedence period length in blocks. It is the time during which\\n /// only the original DKG result submitter can approve it.\\n function setParameters(\\n Data storage self,\\n uint256 _resultChallengePeriodLength,\\n uint256 _resultChallengeExtraGas,\\n uint256 _resultSubmissionTimeout,\\n uint256 _submitterPrecedencePeriodLength\\n ) internal {\\n require(currentState(self) == State.IDLE, \\\"Current state is not IDLE\\\");\\n\\n require(\\n _resultChallengePeriodLength > 0,\\n \\\"Result challenge period length should be greater than zero\\\"\\n );\\n require(\\n _resultSubmissionTimeout > 0,\\n \\\"Result submission timeout should be greater than zero\\\"\\n );\\n require(\\n _submitterPrecedencePeriodLength < _resultSubmissionTimeout,\\n \\\"Submitter precedence period length should be less than the result submission timeout\\\"\\n );\\n\\n self\\n .parameters\\n .resultChallengePeriodLength = _resultChallengePeriodLength;\\n self.parameters.resultChallengeExtraGas = _resultChallengeExtraGas;\\n self.parameters.resultSubmissionTimeout = _resultSubmissionTimeout;\\n self\\n .parameters\\n .submitterPrecedencePeriodLength = _submitterPrecedencePeriodLength;\\n }\\n\\n /// @notice Completes DKG by cleaning up state.\\n /// @dev Should be called after DKG times out or a result is approved.\\n function complete(Data storage self) internal {\\n delete self.startBlock;\\n delete self.seed;\\n delete self.resultSubmissionStartBlockOffset;\\n submittedResultCleanup(self);\\n self.sortitionPool.unlock();\\n }\\n\\n /// @notice Cleans up submitted result state either after DKG completion\\n /// (as part of `complete` method) or after justified challenge.\\n function submittedResultCleanup(Data storage self) private {\\n delete self.submittedResultHash;\\n delete self.submittedResultBlock;\\n }\\n}\\n\",\"keccak256\":\"0x86bea35ab775ec969bc91208305f6f85aa9dd49bb74f8e57e7d453797e8ad98e\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BytesLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\n/*\\nVersion pulled from keep-core v1:\\nhttps://github.com/keep-network/keep-core/blob/f297202db00c027978ad8e7103a356503de5773c/solidity-v1/contracts/utils/BytesLib.sol\\n\\nTo compile it with solidity 0.8 `_preBytes_slot` was replaced with `_preBytes.slot`.\\n*/\\n\\n/*\\nhttps://github.com/GNSPS/solidity-bytes-utils/\\nThis is free and unencumbered software released into the public domain.\\nAnyone is free to copy, modify, publish, use, compile, sell, or\\ndistribute this software, either in source code form or as a compiled\\nbinary, for any purpose, commercial or non-commercial, and by any\\nmeans.\\nIn jurisdictions that recognize copyright laws, the author or authors\\nof this software dedicate any and all copyright interest in the\\nsoftware to the public domain. We make this dedication for the benefit\\nof the public at large and to the detriment of our heirs and\\nsuccessors. We intend this dedication to be an overt act of\\nrelinquishment in perpetuity of all present and future rights to this\\nsoftware under copyright law.\\nTHE SOFTWARE IS PROVIDED \\\"AS IS\\\", WITHOUT WARRANTY OF ANY KIND,\\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\\nIN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\\nOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\\nOTHER DEALINGS IN THE SOFTWARE.\\nFor more information, please refer to \\n*/\\n\\n/** @title BytesLib **/\\n/** @author https://github.com/GNSPS **/\\n\\nlibrary BytesLib {\\n function concatStorage(bytes storage _preBytes, bytes memory _postBytes)\\n internal\\n {\\n assembly {\\n // Read the first 32 bytes of _preBytes storage, which is the length\\n // of the array. (We don't need to use the offset into the slot\\n // because arrays use the entire slot.)\\n let fslot := sload(_preBytes.slot)\\n // Arrays of 31 bytes or less have an even value in their slot,\\n // while longer arrays have an odd value. The actual length is\\n // the slot divided by two for odd values, and the lowest order\\n // byte divided by two for even values.\\n // If the slot is even, bitwise and the slot with 255 and divide by\\n // two to get the length. If the slot is odd, bitwise and the slot\\n // with -1 and divide by two.\\n let slength := div(\\n and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)),\\n 2\\n )\\n let mlength := mload(_postBytes)\\n let newlength := add(slength, mlength)\\n // slength can contain both the length and contents of the array\\n // if length < 32 bytes so let's prepare for that\\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\\n switch add(lt(slength, 32), lt(newlength, 32))\\n case 2 {\\n // Since the new array still fits in the slot, we just need to\\n // update the contents of the slot.\\n // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length\\n sstore(\\n _preBytes.slot,\\n // all the modifications to the slot are inside this\\n // next block\\n add(\\n // we can just add to the slot contents because the\\n // bytes we want to change are the LSBs\\n fslot,\\n add(\\n mul(\\n div(\\n // load the bytes from memory\\n mload(add(_postBytes, 0x20)),\\n // zero all bytes to the right\\n exp(0x100, sub(32, mlength))\\n ),\\n // and now shift left the number of bytes to\\n // leave space for the length in the slot\\n exp(0x100, sub(32, newlength))\\n ),\\n // increase length by the double of the memory\\n // bytes length\\n mul(mlength, 2)\\n )\\n )\\n )\\n }\\n case 1 {\\n // The stored value fits in the slot, but the combined value\\n // will exceed it.\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\\n\\n // save new length\\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\\n\\n // The contents of the _postBytes array start 32 bytes into\\n // the structure. Our first read should obtain the `submod`\\n // bytes that can fit into the unused space in the last word\\n // of the stored array. To get this, we read 32 bytes starting\\n // from `submod`, so the data we read overlaps with the array\\n // contents by `submod` bytes. Masking the lowest-order\\n // `submod` bytes allows us to add that value directly to the\\n // stored value.\\n\\n let submod := sub(32, slength)\\n let mc := add(_postBytes, submod)\\n let end := add(_postBytes, mlength)\\n let mask := sub(exp(0x100, submod), 1)\\n\\n sstore(\\n sc,\\n add(\\n and(\\n fslot,\\n 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00\\n ),\\n and(mload(mc), mask)\\n )\\n )\\n\\n for {\\n mc := add(mc, 0x20)\\n sc := add(sc, 1)\\n } lt(mc, end) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n sstore(sc, mload(mc))\\n }\\n\\n mask := exp(0x100, sub(mc, end))\\n\\n sstore(sc, mul(div(mload(mc), mask), mask))\\n }\\n default {\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n // Start copying to the last used word of the stored array.\\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\\n\\n // save new length\\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\\n\\n // Copy over the first `submod` bytes of the new data as in\\n // case 1 above.\\n let slengthmod := mod(slength, 32)\\n let submod := sub(32, slengthmod)\\n let mc := add(_postBytes, submod)\\n let end := add(_postBytes, mlength)\\n let mask := sub(exp(0x100, submod), 1)\\n\\n sstore(sc, add(sload(sc), and(mload(mc), mask)))\\n\\n for {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } lt(mc, end) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n sstore(sc, mload(mc))\\n }\\n\\n mask := exp(0x100, sub(mc, end))\\n\\n sstore(sc, mul(div(mload(mc), mask), mask))\\n }\\n }\\n }\\n\\n function equalStorage(bytes storage _preBytes, bytes memory _postBytes)\\n internal\\n view\\n returns (bool)\\n {\\n bool success = true;\\n\\n assembly {\\n // we know _preBytes_offset is 0\\n let fslot := sload(_preBytes.slot)\\n // Decode the length of the stored array like in concatStorage().\\n let slength := div(\\n and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)),\\n 2\\n )\\n let mlength := mload(_postBytes)\\n\\n // if lengths don't match the arrays are not equal\\n switch eq(slength, mlength)\\n case 1 {\\n // slength can contain both the length and contents of the array\\n // if length < 32 bytes so let's prepare for that\\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\\n if iszero(iszero(slength)) {\\n switch lt(slength, 32)\\n case 1 {\\n // blank the last byte which is the length\\n fslot := mul(div(fslot, 0x100), 0x100)\\n\\n if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {\\n // unsuccess:\\n success := 0\\n }\\n }\\n default {\\n // cb is a circuit breaker in the for loop since there's\\n // no said feature for inline assembly loops\\n // cb = 1 - don't breaker\\n // cb = 0 - break\\n let cb := 1\\n\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n let sc := keccak256(0x0, 0x20)\\n\\n let mc := add(_postBytes, 0x20)\\n let end := add(mc, mlength)\\n\\n // the next line is the loop condition:\\n // while(uint(mc < end) + cb == 2)\\n for {\\n\\n } eq(add(lt(mc, end), cb), 2) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n if iszero(eq(sload(sc), mload(mc))) {\\n // unsuccess:\\n success := 0\\n cb := 0\\n }\\n }\\n }\\n }\\n }\\n default {\\n // unsuccess:\\n success := 0\\n }\\n }\\n\\n return success;\\n }\\n\\n function concat(bytes memory _preBytes, bytes memory _postBytes)\\n internal\\n pure\\n returns (bytes memory)\\n {\\n bytes memory tempBytes;\\n\\n assembly {\\n // Get a location of some free memory and store it in tempBytes as\\n // Solidity does for memory variables.\\n tempBytes := mload(0x40)\\n\\n // Store the length of the first bytes array at the beginning of\\n // the memory for tempBytes.\\n let length := mload(_preBytes)\\n mstore(tempBytes, length)\\n\\n // Maintain a memory counter for the current write location in the\\n // temp bytes array by adding the 32 bytes for the array length to\\n // the starting location.\\n let mc := add(tempBytes, 0x20)\\n // Stop copying when the memory counter reaches the length of the\\n // first bytes array.\\n let end := add(mc, length)\\n\\n for {\\n // Initialize a copy counter to the start of the _preBytes data,\\n // 32 bytes into its memory.\\n let cc := add(_preBytes, 0x20)\\n } lt(mc, end) {\\n // Increase both counters by 32 bytes each iteration.\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n // Write the _preBytes data into the tempBytes memory 32 bytes\\n // at a time.\\n mstore(mc, mload(cc))\\n }\\n\\n // Add the length of _postBytes to the current length of tempBytes\\n // and store it as the new length in the first 32 bytes of the\\n // tempBytes memory.\\n length := mload(_postBytes)\\n mstore(tempBytes, add(length, mload(tempBytes)))\\n\\n // Move the memory counter back from a multiple of 0x20 to the\\n // actual end of the _preBytes data.\\n mc := end\\n // Stop copying when the memory counter reaches the new combined\\n // length of the arrays.\\n end := add(mc, length)\\n\\n for {\\n let cc := add(_postBytes, 0x20)\\n } lt(mc, end) {\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n mstore(mc, mload(cc))\\n }\\n\\n // Update the free-memory pointer by padding our last write location\\n // to 32 bytes: add 31 bytes to the end of tempBytes to move to the\\n // next 32 byte block, then round down to the nearest multiple of\\n // 32. If the sum of the length of the two arrays is zero then add\\n // one before rounding down to leave a blank 32 bytes (the length block with 0).\\n mstore(\\n 0x40,\\n and(\\n add(add(end, iszero(add(length, mload(_preBytes)))), 31),\\n not(31) // Round down to the nearest 32 bytes.\\n )\\n )\\n }\\n\\n return tempBytes;\\n }\\n\\n function slice(\\n bytes memory _bytes,\\n uint256 _start,\\n uint256 _length\\n ) internal pure returns (bytes memory res) {\\n uint256 _end = _start + _length;\\n require(_end > _start && _bytes.length >= _end, \\\"Slice out of bounds\\\");\\n\\n assembly {\\n // Alloc bytes array with additional 32 bytes afterspace and assign it's size\\n res := mload(0x40)\\n mstore(0x40, add(add(res, 64), _length))\\n mstore(res, _length)\\n\\n // Compute distance between source and destination pointers\\n let diff := sub(res, add(_bytes, _start))\\n\\n for {\\n let src := add(add(_bytes, 32), _start)\\n let end := add(src, _length)\\n } lt(src, end) {\\n src := add(src, 32)\\n } {\\n mstore(add(src, diff), mload(src))\\n }\\n }\\n }\\n\\n function toAddress(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (address)\\n {\\n uint256 _totalLen = _start + 20;\\n require(\\n _totalLen > _start && _bytes.length >= _totalLen,\\n \\\"Address conversion out of bounds.\\\"\\n );\\n address tempAddress;\\n\\n assembly {\\n tempAddress := div(\\n mload(add(add(_bytes, 0x20), _start)),\\n 0x1000000000000000000000000\\n )\\n }\\n\\n return tempAddress;\\n }\\n\\n function toUint8(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (uint8)\\n {\\n require(\\n _bytes.length >= (_start + 1),\\n \\\"Uint8 conversion out of bounds.\\\"\\n );\\n uint8 tempUint;\\n\\n assembly {\\n tempUint := mload(add(add(_bytes, 0x1), _start))\\n }\\n\\n return tempUint;\\n }\\n\\n function toUint(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (uint256)\\n {\\n uint256 _totalLen = _start + 32;\\n require(\\n _totalLen > _start && _bytes.length >= _totalLen,\\n \\\"Uint conversion out of bounds.\\\"\\n );\\n uint256 tempUint;\\n\\n assembly {\\n tempUint := mload(add(add(_bytes, 0x20), _start))\\n }\\n\\n return tempUint;\\n }\\n\\n function equal(bytes memory _preBytes, bytes memory _postBytes)\\n internal\\n pure\\n returns (bool)\\n {\\n bool success = true;\\n\\n assembly {\\n let length := mload(_preBytes)\\n\\n // if lengths don't match the arrays are not equal\\n switch eq(length, mload(_postBytes))\\n case 1 {\\n // cb is a circuit breaker in the for loop since there's\\n // no said feature for inline assembly loops\\n // cb = 1 - don't breaker\\n // cb = 0 - break\\n let cb := 1\\n\\n let mc := add(_preBytes, 0x20)\\n let end := add(mc, length)\\n\\n for {\\n let cc := add(_postBytes, 0x20)\\n // the next line is the loop condition:\\n // while(uint(mc < end) + cb == 2)\\n } eq(add(lt(mc, end), cb), 2) {\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n // if any of these checks fails then arrays are not equal\\n if iszero(eq(mload(mc), mload(cc))) {\\n // unsuccess:\\n success := 0\\n cb := 0\\n }\\n }\\n }\\n default {\\n // unsuccess:\\n success := 0\\n }\\n }\\n\\n return success;\\n }\\n\\n function toBytes32(bytes memory _source)\\n internal\\n pure\\n returns (bytes32 result)\\n {\\n if (_source.length == 0) {\\n return 0x0;\\n }\\n\\n assembly {\\n result := mload(add(_source, 32))\\n }\\n }\\n\\n function keccak256Slice(\\n bytes memory _bytes,\\n uint256 _start,\\n uint256 _length\\n ) internal pure returns (bytes32 result) {\\n uint256 _end = _start + _length;\\n require(_end > _start && _bytes.length >= _end, \\\"Slice out of bounds\\\");\\n\\n assembly {\\n result := keccak256(add(add(_bytes, 32), _start), _length)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3b76e2fe36eb777440250dcf2ea7a689375e8af22f3cc33521095ff6954becdb\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "storageLayout": { + "storage": [], + "types": null + }, + "userdoc": { + "kind": "user", + "methods": { + "approveResult(BeaconDkg.Data storage,BeaconDkg.Result)": { + "notice": "Approves DKG result. Can be called when the challenge period for the submitted result is finished. Considers the submitted result as valid. For the first `submitterPrecedencePeriodLength` blocks after the end of the challenge period can be called only by the DKG result submitter. After that time, can be called by anyone." + }, + "challengeResult(BeaconDkg.Data storage,BeaconDkg.Result)": { + "notice": "Challenges DKG result. If the submitted result is proved to be invalid it reverts the DKG back to the result submission phase." + }, + "offchainDkgTime()": { + "notice": "Time in blocks after which DKG result is complete and ready to be" + }, + "submitResult(BeaconDkg.Data storage,BeaconDkg.Result)": { + "notice": "Allows to submit a DKG result. The submitted result does not go through a validation and before it gets accepted, it needs to wait through the challenge period during which everyone has a chance to challenge the result as invalid one. Submitter of the result needs to be in the sortition pool and if the result gets challenged, the submitter will get slashed." + } + }, + "version": 1 + } +} diff --git a/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/libraries/BeaconInactivity.sol/BeaconInactivity.json b/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/libraries/BeaconInactivity.sol/BeaconInactivity.json new file mode 100644 index 0000000000..620cbbd895 --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/libraries/BeaconInactivity.sol/BeaconInactivity.json @@ -0,0 +1,136 @@ +{ + "contractName": "BeaconInactivity", + "sourceName": "contracts/libraries/BeaconInactivity.sol", + "abi": [ + { + "inputs": [], + "name": "groupThreshold", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "signatureByteSize", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract SortitionPool", + "name": "sortitionPool", + "type": "SortitionPool" + }, + { + "components": [ + { + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "internalType": "uint256[]", + "name": "inactiveMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + } + ], + "internalType": "struct BeaconInactivity.Claim", + "name": "claim", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint32[]", + "name": "groupMembers", + "type": "uint32[]" + } + ], + "name": "verifyClaim", + "outputs": [ + { + "internalType": "uint32[]", + "name": "inactiveMembers", + "type": "uint32[]" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": "0x61109861003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe730000000000000000000000000000000000000000301460806040526004361061004b5760003560e01c80636dcc64f81461005057806389ef44b01461006b578063fc21976b14610073575b600080fd5b610058602181565b6040519081526020015b60405180910390f35b610058604181565b610086610081366004610baf565b610093565b6040516100629190610cb5565b60606100ab6100a56020880188610cff565b8461063f565b600060416100bc6040890189610d49565b6100c7929150610dbc565b90506100d66040880188610d49565b90506000036101255760405162461bcd60e51b8152602060048201526016602482015275139bc81cda59db985d1d5c995cc81c1c9bdd9a59195960521b60448201526064015b60405180910390fd5b60416101346040890189610d49565b61013f929150610dd0565b1561018c5760405162461bcd60e51b815260206004820152601a60248201527f4d616c666f726d6564207369676e617475726573206172726179000000000000604482015260640161011c565b6101996060880188610cff565b905081146101e95760405162461bcd60e51b815260206004820152601b60248201527f556e6578706563746564207369676e61747572657320636f756e740000000000604482015260640161011c565b602181101561022f5760405162461bcd60e51b8152602060048201526012602482015271546f6f20666577207369676e61747572657360701b604482015260640161011c565b828111156102755760405162461bcd60e51b8152602060048201526013602482015272546f6f206d616e79207369676e61747572657360681b604482015260640161011c565b61028b6102856060890189610cff565b8561063f565b60006103144687896102a060208d018d610cff565b6040516020016102b4959493929190610de4565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b90506000896001600160a01b031663f7f9a8fa87876040518363ffffffff1660e01b8152600401610346929190610e8c565b600060405180830381865afa158015610363573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261038b9190810190610ed5565b905060606000805b858110156104e05760006103aa60608e018e610cff565b838181106103ba576103ba610f87565b9050602002013590506104238260416103d39190610f9d565b60418f80604001906103e59190610d49565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509294939250506107579050565b9350600061043187866107fd565b90506001600160a01b03811686610449600185610fb4565b8151811061045957610459610f87565b60200260200101516001600160a01b0316146104ab5760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b604482015260640161011c565b831580156104c15750336001600160a01b038216145b156104cb57600193505b505080806104d890610fc7565b915050610393565b508061052e5760405162461bcd60e51b815260206004820152601b60248201527f53656e646572206d75737420626520636c61696d207369676e65720000000000604482015260640161011c565b61053b60208c018c610cff565b905067ffffffffffffffff81111561055557610555610b23565b60405190808252806020026020018201604052801561057e578160200160208202803683370190505b50955060005b61059160208d018d610cff565b905081101561062f5760006105a960208e018e610cff565b838181106105b9576105b9610f87565b90506020020135905089896001836105d19190610fb4565b8181106105e0576105e0610f87565b90506020020160208101906105f59190610fe0565b88838151811061060757610607610f87565b63ffffffff90921660209283029190910190910152508061062781610fc7565b915050610584565b5050505050509695505050505050565b811580159061064e5750808211155b61066a5760405162461bcd60e51b815260040161011c90611002565b60008383600081811061067f5761067f610f87565b905060200201351180156106b5575080838361069c600182610fb4565b8181106106ab576106ab610f87565b9050602002013511155b6106d15760405162461bcd60e51b815260040161011c90611002565b60005b6106df600184610fb4565b8110156107515783836106f3836001611039565b81811061070257610702610f87565b9050602002013584848381811061071b5761071b610f87565b905060200201351061073f5760405162461bcd60e51b815260040161011c90611002565b8061074981610fc7565b9150506106d4565b50505050565b606060006107658385611039565b90508381118015610777575080855110155b6107b95760405162461bcd60e51b8152602060048201526013602482015272536c696365206f7574206f6620626f756e647360681b604482015260640161011c565b604051915082604083010160405282825283850182038460208701018481015b808210156107f2578151838301526020820191506107d9565b505050509392505050565b600080600061080c8585610823565b9150915061081981610868565b5090505b92915050565b60008082516041036108595760208301516040840151606085015160001a61084d87828585610a21565b94509450505050610861565b506000905060025b9250929050565b600081600481111561087c5761087c61104c565b036108845750565b60018160048111156108985761089861104c565b036108e55760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161011c565b60028160048111156108f9576108f961104c565b036109465760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161011c565b600381600481111561095a5761095a61104c565b036109b25760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161011c565b60048160048111156109c6576109c661104c565b03610a1e5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b606482015260840161011c565b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115610a585750600090506003610b05565b8460ff16601b14158015610a7057508460ff16601c14155b15610a815750600090506004610b05565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015610ad5573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610afe57600060019250925050610b05565b9150600090505b94509492505050565b6001600160a01b0381168114610a1e57600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715610b6257610b62610b23565b604052919050565b60008083601f840112610b7c57600080fd5b50813567ffffffffffffffff811115610b9457600080fd5b6020830191508360208260051b850101111561086157600080fd5b60008060008060008060a08789031215610bc857600080fd5b8635610bd381610b0e565b955060208781013567ffffffffffffffff80821115610bf157600080fd5b908901906080828c031215610c0557600080fd5b90965060408901359080821115610c1b57600080fd5b818a0191508a601f830112610c2f57600080fd5b813581811115610c4157610c41610b23565b610c53601f8201601f19168501610b39565b8181528c85838601011115610c6757600080fd5b81858501868301376000918101909401529195506060890135945060808901359180831115610c9557600080fd5b5050610ca389828a01610b6a565b979a9699509497509295939492505050565b6020808252825182820181905260009190848201906040850190845b81811015610cf357835163ffffffff1683529284019291840191600101610cd1565b50909695505050505050565b6000808335601e19843603018112610d1657600080fd5b83018035915067ffffffffffffffff821115610d3157600080fd5b6020019150600581901b360382131561086157600080fd5b6000808335601e19843603018112610d6057600080fd5b83018035915067ffffffffffffffff821115610d7b57600080fd5b60200191503681900382131561086157600080fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082610dcb57610dcb610d90565b500490565b600082610ddf57610ddf610d90565b500690565b85815260006020868184015260806040840152855180608085015260005b81811015610e1e5787810183015185820160a001528201610e02565b50600060a08286010152601f19601f820116840191505060a08382030160608401528360a082015260018060fb1b03841115610e5957600080fd5b8360051b808660c08401370160c001979650505050505050565b803563ffffffff81168114610e8757600080fd5b919050565b60208082528181018390526000908460408401835b86811015610eca5763ffffffff610eb784610e73565b1682529183019190830190600101610ea1565b509695505050505050565b60006020808385031215610ee857600080fd5b825167ffffffffffffffff80821115610f0057600080fd5b818501915085601f830112610f1457600080fd5b815181811115610f2657610f26610b23565b8060051b9150610f37848301610b39565b8181529183018401918481019088841115610f5157600080fd5b938501935b83851015610f7b5784519250610f6b83610b0e565b8282529385019390850190610f56565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b808202811582820484141761081d5761081d610da6565b8181038181111561081d5761081d610da6565b600060018201610fd957610fd9610da6565b5060010190565b600060208284031215610ff257600080fd5b610ffb82610e73565b9392505050565b60208082526019908201527f436f72727570746564206d656d6265727320696e646963657300000000000000604082015260600190565b8082018082111561081d5761081d610da6565b634e487b7160e01b600052602160045260246000fdfea264697066735822122035df3a09b3a39447ac5429e9aa66850b441e978913349f8a4672594eb649d54b64736f6c63430008110033", + "deployedBytecode": "0x730000000000000000000000000000000000000000301460806040526004361061004b5760003560e01c80636dcc64f81461005057806389ef44b01461006b578063fc21976b14610073575b600080fd5b610058602181565b6040519081526020015b60405180910390f35b610058604181565b610086610081366004610baf565b610093565b6040516100629190610cb5565b60606100ab6100a56020880188610cff565b8461063f565b600060416100bc6040890189610d49565b6100c7929150610dbc565b90506100d66040880188610d49565b90506000036101255760405162461bcd60e51b8152602060048201526016602482015275139bc81cda59db985d1d5c995cc81c1c9bdd9a59195960521b60448201526064015b60405180910390fd5b60416101346040890189610d49565b61013f929150610dd0565b1561018c5760405162461bcd60e51b815260206004820152601a60248201527f4d616c666f726d6564207369676e617475726573206172726179000000000000604482015260640161011c565b6101996060880188610cff565b905081146101e95760405162461bcd60e51b815260206004820152601b60248201527f556e6578706563746564207369676e61747572657320636f756e740000000000604482015260640161011c565b602181101561022f5760405162461bcd60e51b8152602060048201526012602482015271546f6f20666577207369676e61747572657360701b604482015260640161011c565b828111156102755760405162461bcd60e51b8152602060048201526013602482015272546f6f206d616e79207369676e61747572657360681b604482015260640161011c565b61028b6102856060890189610cff565b8561063f565b60006103144687896102a060208d018d610cff565b6040516020016102b4959493929190610de4565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b90506000896001600160a01b031663f7f9a8fa87876040518363ffffffff1660e01b8152600401610346929190610e8c565b600060405180830381865afa158015610363573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261038b9190810190610ed5565b905060606000805b858110156104e05760006103aa60608e018e610cff565b838181106103ba576103ba610f87565b9050602002013590506104238260416103d39190610f9d565b60418f80604001906103e59190610d49565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509294939250506107579050565b9350600061043187866107fd565b90506001600160a01b03811686610449600185610fb4565b8151811061045957610459610f87565b60200260200101516001600160a01b0316146104ab5760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b604482015260640161011c565b831580156104c15750336001600160a01b038216145b156104cb57600193505b505080806104d890610fc7565b915050610393565b508061052e5760405162461bcd60e51b815260206004820152601b60248201527f53656e646572206d75737420626520636c61696d207369676e65720000000000604482015260640161011c565b61053b60208c018c610cff565b905067ffffffffffffffff81111561055557610555610b23565b60405190808252806020026020018201604052801561057e578160200160208202803683370190505b50955060005b61059160208d018d610cff565b905081101561062f5760006105a960208e018e610cff565b838181106105b9576105b9610f87565b90506020020135905089896001836105d19190610fb4565b8181106105e0576105e0610f87565b90506020020160208101906105f59190610fe0565b88838151811061060757610607610f87565b63ffffffff90921660209283029190910190910152508061062781610fc7565b915050610584565b5050505050509695505050505050565b811580159061064e5750808211155b61066a5760405162461bcd60e51b815260040161011c90611002565b60008383600081811061067f5761067f610f87565b905060200201351180156106b5575080838361069c600182610fb4565b8181106106ab576106ab610f87565b9050602002013511155b6106d15760405162461bcd60e51b815260040161011c90611002565b60005b6106df600184610fb4565b8110156107515783836106f3836001611039565b81811061070257610702610f87565b9050602002013584848381811061071b5761071b610f87565b905060200201351061073f5760405162461bcd60e51b815260040161011c90611002565b8061074981610fc7565b9150506106d4565b50505050565b606060006107658385611039565b90508381118015610777575080855110155b6107b95760405162461bcd60e51b8152602060048201526013602482015272536c696365206f7574206f6620626f756e647360681b604482015260640161011c565b604051915082604083010160405282825283850182038460208701018481015b808210156107f2578151838301526020820191506107d9565b505050509392505050565b600080600061080c8585610823565b9150915061081981610868565b5090505b92915050565b60008082516041036108595760208301516040840151606085015160001a61084d87828585610a21565b94509450505050610861565b506000905060025b9250929050565b600081600481111561087c5761087c61104c565b036108845750565b60018160048111156108985761089861104c565b036108e55760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161011c565b60028160048111156108f9576108f961104c565b036109465760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161011c565b600381600481111561095a5761095a61104c565b036109b25760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161011c565b60048160048111156109c6576109c661104c565b03610a1e5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b606482015260840161011c565b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115610a585750600090506003610b05565b8460ff16601b14158015610a7057508460ff16601c14155b15610a815750600090506004610b05565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015610ad5573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610afe57600060019250925050610b05565b9150600090505b94509492505050565b6001600160a01b0381168114610a1e57600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715610b6257610b62610b23565b604052919050565b60008083601f840112610b7c57600080fd5b50813567ffffffffffffffff811115610b9457600080fd5b6020830191508360208260051b850101111561086157600080fd5b60008060008060008060a08789031215610bc857600080fd5b8635610bd381610b0e565b955060208781013567ffffffffffffffff80821115610bf157600080fd5b908901906080828c031215610c0557600080fd5b90965060408901359080821115610c1b57600080fd5b818a0191508a601f830112610c2f57600080fd5b813581811115610c4157610c41610b23565b610c53601f8201601f19168501610b39565b8181528c85838601011115610c6757600080fd5b81858501868301376000918101909401529195506060890135945060808901359180831115610c9557600080fd5b5050610ca389828a01610b6a565b979a9699509497509295939492505050565b6020808252825182820181905260009190848201906040850190845b81811015610cf357835163ffffffff1683529284019291840191600101610cd1565b50909695505050505050565b6000808335601e19843603018112610d1657600080fd5b83018035915067ffffffffffffffff821115610d3157600080fd5b6020019150600581901b360382131561086157600080fd5b6000808335601e19843603018112610d6057600080fd5b83018035915067ffffffffffffffff821115610d7b57600080fd5b60200191503681900382131561086157600080fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082610dcb57610dcb610d90565b500490565b600082610ddf57610ddf610d90565b500690565b85815260006020868184015260806040840152855180608085015260005b81811015610e1e5787810183015185820160a001528201610e02565b50600060a08286010152601f19601f820116840191505060a08382030160608401528360a082015260018060fb1b03841115610e5957600080fd5b8360051b808660c08401370160c001979650505050505050565b803563ffffffff81168114610e8757600080fd5b919050565b60208082528181018390526000908460408401835b86811015610eca5763ffffffff610eb784610e73565b1682529183019190830190600101610ea1565b509695505050505050565b60006020808385031215610ee857600080fd5b825167ffffffffffffffff80821115610f0057600080fd5b818501915085601f830112610f1457600080fd5b815181811115610f2657610f26610b23565b8060051b9150610f37848301610b39565b8181529183018401918481019088841115610f5157600080fd5b938501935b83851015610f7b5784519250610f6b83610b0e565b8282529385019390850190610f56565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b808202811582820484141761081d5761081d610da6565b8181038181111561081d5761081d610da6565b600060018201610fd957610fd9610da6565b5060010190565b600060208284031215610ff257600080fd5b610ffb82610e73565b9392505050565b60208082526019908201527f436f72727570746564206d656d6265727320696e646963657300000000000000604082015260600190565b8082018082111561081d5761081d610da6565b634e487b7160e01b600052602160045260246000fdfea264697066735822122035df3a09b3a39447ac5429e9aa66850b441e978913349f8a4672594eb649d54b64736f6c63430008110033", + "linkReferences": {}, + "deployedLinkReferences": {}, + "devdoc": { + "kind": "dev", + "methods": { + "verifyClaim(SortitionPool,BeaconInactivity.Claim,bytes,uint256,uint32[])": { + "details": "Group members hash is validated upstream in RandomBeacon.notifyOperatorInactivity()", + "params": { + "claim": "Inactivity claim", + "groupMembers": "Identifiers of group members", + "groupPubKey": "Public key of the group raising the claim", + "nonce": "Current nonce for group used in the claim", + "sortitionPool": "Sortition pool reference" + }, + "returns": { + "inactiveMembers": "Identifiers of members who are inactive" + } + } + }, + "version": 1 + }, + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"groupThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"signatureByteSize\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract SortitionPool\",\"name\":\"sortitionPool\",\"type\":\"SortitionPool\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"groupId\",\"type\":\"uint64\"},{\"internalType\":\"uint256[]\",\"name\":\"inactiveMembersIndices\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"signatures\",\"type\":\"bytes\"},{\"internalType\":\"uint256[]\",\"name\":\"signingMembersIndices\",\"type\":\"uint256[]\"}],\"internalType\":\"struct BeaconInactivity.Claim\",\"name\":\"claim\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint32[]\",\"name\":\"groupMembers\",\"type\":\"uint32[]\"}],\"name\":\"verifyClaim\",\"outputs\":[{\"internalType\":\"uint32[]\",\"name\":\"inactiveMembers\",\"type\":\"uint32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"verifyClaim(SortitionPool,BeaconInactivity.Claim,bytes,uint256,uint32[])\":{\"details\":\"Group members hash is validated upstream in RandomBeacon.notifyOperatorInactivity()\",\"params\":{\"claim\":\"Inactivity claim\",\"groupMembers\":\"Identifiers of group members\",\"groupPubKey\":\"Public key of the group raising the claim\",\"nonce\":\"Current nonce for group used in the claim\",\"sortitionPool\":\"Sortition pool reference\"},\"returns\":{\"inactiveMembers\":\"Identifiers of members who are inactive\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"groupThreshold()\":{\"notice\":\"The minimum number of group members needed to interact according to the protocol to produce a valid inactivity claim.\"},\"signatureByteSize()\":{\"notice\":\"Size in bytes of a single signature produced by member supporting the inactivity claim.\"},\"verifyClaim(SortitionPool,BeaconInactivity.Claim,bytes,uint256,uint32[])\":{\"notice\":\"Verifies the inactivity claim according to the rules defined in `Claim` struct documentation. Reverts if verification fails.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/libraries/BeaconInactivity.sol\":\"BeaconInactivity\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@keep-network/sortition-pools/contracts/Branch.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\n/// @notice The implicit 8-ary trees of the sortition pool\\n/// rely on packing 8 \\\"slots\\\" of 32-bit values into each uint256.\\n/// The Branch library permits efficient calculations on these slots.\\nlibrary Branch {\\n /// @notice Calculate the right shift required\\n /// to make the 32 least significant bits of an uint256\\n /// be the bits of the `position`th slot\\n /// when treating the uint256 as a uint32[8].\\n ///\\n /// @dev Not used for efficiency reasons,\\n /// but left to illustrate the meaning of a common pattern.\\n /// I wish solidity had macros, even C macros.\\n function slotShift(uint256 position) internal pure returns (uint256) {\\n unchecked {\\n return position * Constants.SLOT_WIDTH;\\n }\\n }\\n\\n /// @notice Return the `position`th slot of the `node`,\\n /// treating `node` as a uint32[32].\\n function getSlot(uint256 node, uint256 position)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Doing a bitwise AND with `SLOT_MAX`\\n // clears all but the 32 least significant bits.\\n // Because of the right shift by `slotShift(position)` bits,\\n // those 32 bits contain the 32 bits in the `position`th slot of `node`.\\n return (node >> shiftBits) & Constants.SLOT_MAX;\\n }\\n }\\n\\n /// @notice Return `node` with the `position`th slot set to zero.\\n function clearSlot(uint256 node, uint256 position)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Shifting `SLOT_MAX` left by `slotShift(position)` bits\\n // gives us a number where all bits of the `position`th slot are set,\\n // and all other bits are unset.\\n //\\n // Using a bitwise NOT on this number,\\n // we get a uint256 where all bits are set\\n // except for those of the `position`th slot.\\n //\\n // Bitwise ANDing the original `node` with this number\\n // sets the bits of `position`th slot to zero,\\n // leaving all other bits unchanged.\\n return node & ~(Constants.SLOT_MAX << shiftBits);\\n }\\n }\\n\\n /// @notice Return `node` with the `position`th slot set to `weight`.\\n ///\\n /// @param weight The weight of of the node.\\n /// Safely truncated to a 32-bit number,\\n /// but this should never be called with an overflowing weight regardless.\\n function setSlot(\\n uint256 node,\\n uint256 position,\\n uint256 weight\\n ) internal pure returns (uint256) {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Clear the `position`th slot like in `clearSlot()`.\\n uint256 clearedNode = node & ~(Constants.SLOT_MAX << shiftBits);\\n // Bitwise AND `weight` with `SLOT_MAX`\\n // to clear all but the 32 least significant bits.\\n //\\n // Shift this left by `slotShift(position)` bits\\n // to obtain a uint256 with all bits unset\\n // except in the `position`th slot\\n // which contains the 32-bit value of `weight`.\\n uint256 shiftedWeight = (weight & Constants.SLOT_MAX) << shiftBits;\\n // When we bitwise OR these together,\\n // all other slots except the `position`th one come from the left argument,\\n // and the `position`th gets filled with `weight` from the right argument.\\n return clearedNode | shiftedWeight;\\n }\\n }\\n\\n /// @notice Calculate the summed weight of all slots in the `node`.\\n function sumWeight(uint256 node) internal pure returns (uint256 sum) {\\n unchecked {\\n sum = node & Constants.SLOT_MAX;\\n // Iterate through each slot\\n // by shifting `node` right in increments of 32 bits,\\n // and adding the 32 least significant bits to the `sum`.\\n uint256 newNode = node >> Constants.SLOT_WIDTH;\\n while (newNode > 0) {\\n sum += (newNode & Constants.SLOT_MAX);\\n newNode = newNode >> Constants.SLOT_WIDTH;\\n }\\n return sum;\\n }\\n }\\n\\n /// @notice Pick a slot in `node` that corresponds to `index`.\\n /// Treats the node like an array of virtual stakers,\\n /// the number of virtual stakers in each slot corresponding to its weight,\\n /// and picks which slot contains the `index`th virtual staker.\\n ///\\n /// @dev Requires that `index` be lower than `sumWeight(node)`.\\n /// However, this is not enforced for performance reasons.\\n /// If `index` exceeds the permitted range,\\n /// `pickWeightedSlot()` returns the rightmost slot\\n /// and an excessively high `newIndex`.\\n ///\\n /// @return slot The slot of `node` containing the `index`th virtual staker.\\n ///\\n /// @return newIndex The index of the `index`th virtual staker of `node`\\n /// within the returned slot.\\n function pickWeightedSlot(uint256 node, uint256 index)\\n internal\\n pure\\n returns (uint256 slot, uint256 newIndex)\\n {\\n unchecked {\\n newIndex = index;\\n uint256 newNode = node;\\n uint256 currentSlotWeight = newNode & Constants.SLOT_MAX;\\n while (newIndex >= currentSlotWeight) {\\n newIndex -= currentSlotWeight;\\n slot++;\\n newNode = newNode >> Constants.SLOT_WIDTH;\\n currentSlotWeight = newNode & Constants.SLOT_MAX;\\n }\\n return (slot, newIndex);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa7fb1c9c9789f30493e9a40e24a24f46875dc5e7630b4f67478167759f6d1882\"},\"@keep-network/sortition-pools/contracts/Chaosnet.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\n/// @title Chaosnet\\n/// @notice This is a beta staker program for stakers willing to go the extra\\n/// mile with monitoring, share their logs with the dev team, and allow to more\\n/// carefully monitor the bootstrapping network. As the network matures, the\\n/// beta program will be ended.\\ncontract Chaosnet {\\n /// @notice Indicates if the chaosnet is active. The chaosnet is active\\n /// after the contract deployment and can be ended with a call to\\n /// `deactivateChaosnet()`. Once deactivated chaosnet can not be activated\\n /// again.\\n bool public isChaosnetActive;\\n\\n /// @notice Indicates if the given operator is a beta operator for chaosnet.\\n mapping(address => bool) public isBetaOperator;\\n\\n /// @notice Address controlling chaosnet status and beta operator addresses.\\n address public chaosnetOwner;\\n\\n event BetaOperatorsAdded(address[] operators);\\n\\n event ChaosnetOwnerRoleTransferred(\\n address oldChaosnetOwner,\\n address newChaosnetOwner\\n );\\n\\n event ChaosnetDeactivated();\\n\\n constructor() {\\n _transferChaosnetOwner(msg.sender);\\n isChaosnetActive = true;\\n }\\n\\n modifier onlyChaosnetOwner() {\\n require(msg.sender == chaosnetOwner, \\\"Not the chaosnet owner\\\");\\n _;\\n }\\n\\n modifier onlyOnChaosnet() {\\n require(isChaosnetActive, \\\"Chaosnet is not active\\\");\\n _;\\n }\\n\\n /// @notice Adds beta operator to chaosnet. Can be called only by the\\n /// chaosnet owner when the chaosnet is active. Once the operator is added\\n /// as a beta operator, it can not be removed.\\n function addBetaOperators(address[] calldata operators)\\n public\\n onlyOnChaosnet\\n onlyChaosnetOwner\\n {\\n for (uint256 i = 0; i < operators.length; i++) {\\n isBetaOperator[operators[i]] = true;\\n }\\n\\n emit BetaOperatorsAdded(operators);\\n }\\n\\n /// @notice Deactivates the chaosnet. Can be called only by the chaosnet\\n /// owner. Once deactivated chaosnet can not be activated again.\\n function deactivateChaosnet() public onlyOnChaosnet onlyChaosnetOwner {\\n isChaosnetActive = false;\\n emit ChaosnetDeactivated();\\n }\\n\\n /// @notice Transfers the chaosnet owner role to another non-zero address.\\n function transferChaosnetOwnerRole(address newChaosnetOwner)\\n public\\n onlyChaosnetOwner\\n {\\n require(\\n newChaosnetOwner != address(0),\\n \\\"New chaosnet owner must not be zero address\\\"\\n );\\n _transferChaosnetOwner(newChaosnetOwner);\\n }\\n\\n function _transferChaosnetOwner(address newChaosnetOwner) internal {\\n address oldChaosnetOwner = chaosnetOwner;\\n chaosnetOwner = newChaosnetOwner;\\n emit ChaosnetOwnerRoleTransferred(oldChaosnetOwner, newChaosnetOwner);\\n }\\n}\\n\",\"keccak256\":\"0xeaf7bdd5626f88c329793a012621039692ce1b6e1f13013997ddb13d7e3032df\"},\"@keep-network/sortition-pools/contracts/Constants.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nlibrary Constants {\\n ////////////////////////////////////////////////////////////////////////////\\n // Parameters for configuration\\n\\n // How many bits a position uses per level of the tree;\\n // each branch of the tree contains 2**SLOT_BITS slots.\\n uint256 constant SLOT_BITS = 3;\\n uint256 constant LEVELS = 7;\\n ////////////////////////////////////////////////////////////////////////////\\n\\n ////////////////////////////////////////////////////////////////////////////\\n // Derived constants, do not touch\\n uint256 constant SLOT_COUNT = 2**SLOT_BITS;\\n uint256 constant SLOT_WIDTH = 256 / SLOT_COUNT;\\n uint256 constant LAST_SLOT = SLOT_COUNT - 1;\\n uint256 constant SLOT_MAX = (2**SLOT_WIDTH) - 1;\\n uint256 constant POOL_CAPACITY = SLOT_COUNT**LEVELS;\\n\\n uint256 constant ID_WIDTH = SLOT_WIDTH;\\n uint256 constant ID_MAX = SLOT_MAX;\\n\\n uint256 constant BLOCKHEIGHT_WIDTH = 96 - ID_WIDTH;\\n uint256 constant BLOCKHEIGHT_MAX = (2**BLOCKHEIGHT_WIDTH) - 1;\\n\\n uint256 constant SLOT_POINTER_MAX = (2**SLOT_BITS) - 1;\\n uint256 constant LEAF_FLAG = 1 << 255;\\n\\n uint256 constant WEIGHT_WIDTH = 256 / SLOT_COUNT;\\n ////////////////////////////////////////////////////////////////////////////\\n}\\n\",\"keccak256\":\"0xaef690ced707935745ff1482b7bb9bd9eb77bf6a39c717465e64cf12db8a7d39\"},\"@keep-network/sortition-pools/contracts/Leaf.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary Leaf {\\n function make(\\n address _operator,\\n uint256 _creationBlock,\\n uint256 _id\\n ) internal pure returns (uint256) {\\n assert(_creationBlock <= type(uint64).max);\\n assert(_id <= type(uint32).max);\\n // Converting a bytesX type into a larger type\\n // adds zero bytes on the right.\\n uint256 op = uint256(bytes32(bytes20(_operator)));\\n // Bitwise AND the id to erase\\n // all but the 32 least significant bits\\n uint256 uid = _id & Constants.ID_MAX;\\n // Erase all but the 64 least significant bits,\\n // then shift left by 32 bits to make room for the id\\n uint256 cb = (_creationBlock & Constants.BLOCKHEIGHT_MAX) <<\\n Constants.ID_WIDTH;\\n // Bitwise OR them all together to get\\n // [address operator || uint64 creationBlock || uint32 id]\\n return (op | cb | uid);\\n }\\n\\n function operator(uint256 leaf) internal pure returns (address) {\\n // Converting a bytesX type into a smaller type\\n // truncates it on the right.\\n return address(bytes20(bytes32(leaf)));\\n }\\n\\n /// @notice Return the block number the leaf was created in.\\n function creationBlock(uint256 leaf) internal pure returns (uint256) {\\n return ((leaf >> Constants.ID_WIDTH) & Constants.BLOCKHEIGHT_MAX);\\n }\\n\\n function id(uint256 leaf) internal pure returns (uint32) {\\n // Id is stored in the 32 least significant bits.\\n // Bitwise AND ensures that we only get the contents of those bits.\\n return uint32(leaf & Constants.ID_MAX);\\n }\\n}\\n\",\"keccak256\":\"0xbd107a1a43e48884885e5e966ffcbcd8fa5e89863715d717bb4006e9f89cdc2b\"},\"@keep-network/sortition-pools/contracts/Position.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary Position {\\n // Return the last 3 bits of a position number,\\n // corresponding to its slot in its parent\\n function slot(uint256 a) internal pure returns (uint256) {\\n return a & Constants.SLOT_POINTER_MAX;\\n }\\n\\n // Return the parent of a position number\\n function parent(uint256 a) internal pure returns (uint256) {\\n return a >> Constants.SLOT_BITS;\\n }\\n\\n // Return the location of the child of a at the given slot\\n function child(uint256 a, uint256 s) internal pure returns (uint256) {\\n return (a << Constants.SLOT_BITS) | (s & Constants.SLOT_POINTER_MAX); // slot(s)\\n }\\n\\n // Return the uint p as a flagged position uint:\\n // the least significant 21 bits contain the position\\n // and the 22nd bit is set as a flag\\n // to distinguish the position 0x000000 from an empty field.\\n function setFlag(uint256 p) internal pure returns (uint256) {\\n return p | Constants.LEAF_FLAG;\\n }\\n\\n // Turn a flagged position into an unflagged position\\n // by removing the flag at the 22nd least significant bit.\\n //\\n // We shouldn't _actually_ need this\\n // as all position-manipulating code should ignore non-position bits anyway\\n // but it's cheap to call so might as well do it.\\n function unsetFlag(uint256 p) internal pure returns (uint256) {\\n return p & (~Constants.LEAF_FLAG);\\n }\\n}\\n\",\"keccak256\":\"0xd3a927908080ac21353a92a6bce3d69e94a5c30f6b51f16b271b6cc679f110e2\"},\"@keep-network/sortition-pools/contracts/RNG.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Leaf.sol\\\";\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary RNG {\\n /// @notice Get an index in the range `[0 .. range-1]`\\n /// and the new state of the RNG,\\n /// using the provided `state` of the RNG.\\n ///\\n /// @param range The upper bound of the index, exclusive.\\n ///\\n /// @param state The previous state of the RNG.\\n /// The initial state needs to be obtained\\n /// from a trusted randomness oracle (the random beacon),\\n /// or from a chain of earlier calls to `RNG.getIndex()`\\n /// on an originally trusted seed.\\n ///\\n /// @dev Calculates the number of bits required for the desired range,\\n /// takes the least significant bits of `state`\\n /// and checks if the obtained index is within the desired range.\\n /// The original state is hashed with `keccak256` to get a new state.\\n /// If the index is outside the range,\\n /// the function retries until it gets a suitable index.\\n ///\\n /// @return index A random integer between `0` and `range - 1`, inclusive.\\n ///\\n /// @return newState The new state of the RNG.\\n /// When `getIndex()` is called one or more times,\\n /// care must be taken to always use the output `state`\\n /// of the most recent call as the input `state` of a subsequent call.\\n /// At the end of a transaction calling `RNG.getIndex()`,\\n /// the previous stored state must be overwritten with the latest output.\\n function getIndex(\\n uint256 range,\\n bytes32 state,\\n uint256 bits\\n ) internal view returns (uint256, bytes32) {\\n bool found = false;\\n uint256 index = 0;\\n bytes32 newState = state;\\n while (!found) {\\n index = truncate(bits, uint256(newState));\\n newState = keccak256(abi.encodePacked(newState, address(this)));\\n if (index < range) {\\n found = true;\\n }\\n }\\n return (index, newState);\\n }\\n\\n /// @notice Calculate how many bits are required\\n /// for an index in the range `[0 .. range-1]`.\\n ///\\n /// @param range The upper bound of the desired range, exclusive.\\n ///\\n /// @return uint The smallest number of bits\\n /// that can contain the number `range-1`.\\n function bitsRequired(uint256 range) internal pure returns (uint256) {\\n unchecked {\\n if (range == 1) {\\n return 0;\\n }\\n\\n uint256 bits = Constants.WEIGHT_WIDTH - 1;\\n\\n // Left shift by `bits`,\\n // so we have a 1 in the (bits + 1)th least significant bit\\n // and 0 in other bits.\\n // If this number is equal or greater than `range`,\\n // the range [0, range-1] fits in `bits` bits.\\n //\\n // Because we loop from high bits to low bits,\\n // we find the highest number of bits that doesn't fit the range,\\n // and return that number + 1.\\n while (1 << bits >= range) {\\n bits--;\\n }\\n\\n return bits + 1;\\n }\\n }\\n\\n /// @notice Truncate `input` to the `bits` least significant bits.\\n function truncate(uint256 bits, uint256 input)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n return input & ((1 << bits) - 1);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x67f87f589cd5123ffa32f883ea2f09b0e56258508bae82b8c655b3c27c71eb5e\"},\"@keep-network/sortition-pools/contracts/Rewards.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\n/// @title Rewards\\n/// @notice Rewards are allocated proportionally to operators\\n/// present in the pool at payout based on their weight in the pool.\\n///\\n/// To facilitate this, we use a global accumulator value\\n/// to track the total rewards one unit of weight would've earned\\n/// since the creation of the pool.\\n///\\n/// Whenever a reward is paid, the accumulator is increased\\n/// by the size of the reward divided by the total weight\\n/// of all eligible operators in the pool.\\n///\\n/// Each operator has an individual accumulator value,\\n/// set to equal the global accumulator when the operator joins the pool.\\n/// This accumulator reflects the amount of rewards\\n/// that have already been accounted for with that operator.\\n///\\n/// Whenever an operator's weight in the pool changes,\\n/// we can update the amount of rewards the operator has earned\\n/// by subtracting the operator's accumulator from the global accumulator.\\n/// This gives us the amount of rewards one unit of weight has earned\\n/// since the last time the operator's rewards have been updated.\\n/// Then we multiply that by the operator's previous (pre-change) weight\\n/// to determine how much rewards in total the operator has earned,\\n/// and add this to the operator's earned rewards.\\n/// Finally, we set the operator's accumulator to the global accumulator value.\\ncontract Rewards {\\n struct OperatorRewards {\\n // The state of the global accumulator\\n // when the operator's rewards were last updated\\n uint96 accumulated;\\n // The amount of rewards collected by the operator after the latest update.\\n // The amount the operator could withdraw may equal `available`\\n // or it may be greater, if more rewards have been paid in since then.\\n // To evaulate the most recent amount including rewards potentially paid\\n // since the last update, use `availableRewards` function.\\n uint96 available;\\n // If nonzero, the operator is ineligible for rewards\\n // and may only re-enable rewards after the specified timestamp.\\n // XXX: unsigned 32-bit integer unix seconds, will break around 2106\\n uint32 ineligibleUntil;\\n // Locally cached weight of the operator,\\n // used to reduce the cost of setting operators ineligible.\\n uint32 weight;\\n }\\n\\n // The global accumulator of how much rewards\\n // a hypothetical operator of weight 1 would have earned\\n // since the creation of the pool.\\n uint96 internal globalRewardAccumulator;\\n // If the amount of reward tokens paid in\\n // does not divide cleanly by pool weight,\\n // the difference is recorded as rounding dust\\n // and added to the next reward.\\n uint96 internal rewardRoundingDust;\\n\\n // The amount of rewards that would've been earned by ineligible operators\\n // had they not been ineligible.\\n uint96 public ineligibleEarnedRewards;\\n\\n // Ineligibility times are calculated from this offset,\\n // set at contract creation.\\n uint256 internal immutable ineligibleOffsetStart;\\n\\n mapping(uint32 => OperatorRewards) internal operatorRewards;\\n\\n constructor() {\\n // solhint-disable-next-line not-rely-on-time\\n ineligibleOffsetStart = block.timestamp;\\n }\\n\\n /// @notice Return whether the operator is eligible for rewards or not.\\n function isEligibleForRewards(uint32 operator) internal view returns (bool) {\\n return operatorRewards[operator].ineligibleUntil == 0;\\n }\\n\\n /// @notice Return the time the operator's reward eligibility can be restored.\\n function rewardsEligibilityRestorableAt(uint32 operator)\\n internal\\n view\\n returns (uint256)\\n {\\n uint32 until = operatorRewards[operator].ineligibleUntil;\\n require(until != 0, \\\"Operator already eligible\\\");\\n return (uint256(until) + ineligibleOffsetStart);\\n }\\n\\n /// @notice Return whether the operator is able to restore their eligibility\\n /// for rewards right away.\\n function canRestoreRewardEligibility(uint32 operator)\\n internal\\n view\\n returns (bool)\\n {\\n // solhint-disable-next-line not-rely-on-time\\n return rewardsEligibilityRestorableAt(operator) <= block.timestamp;\\n }\\n\\n /// @notice Internal function for updating the global state of rewards.\\n function addRewards(uint96 rewardAmount, uint32 currentPoolWeight) internal {\\n require(currentPoolWeight > 0, \\\"No recipients in pool\\\");\\n\\n uint96 totalAmount = rewardAmount + rewardRoundingDust;\\n uint96 perWeightReward = totalAmount / currentPoolWeight;\\n uint96 newRoundingDust = totalAmount % currentPoolWeight;\\n\\n globalRewardAccumulator += perWeightReward;\\n rewardRoundingDust = newRoundingDust;\\n }\\n\\n /// @notice Internal function for updating the operator's reward state.\\n function updateOperatorRewards(uint32 operator, uint32 newWeight) internal {\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n if (o.ineligibleUntil == 0) {\\n // If operator is not ineligible, update their earned rewards\\n o.available += accruedRewards;\\n } else {\\n // If ineligible, put the rewards into the ineligible pot\\n ineligibleEarnedRewards += accruedRewards;\\n }\\n // In any case, update their accumulator and weight\\n o.accumulated = acc;\\n o.weight = newWeight;\\n operatorRewards[operator] = o;\\n }\\n\\n /// @notice Set the amount of withdrawable tokens to zero\\n /// and return the previous withdrawable amount.\\n /// @dev Does not update the withdrawable amount,\\n /// but should usually be accompanied by an update.\\n function withdrawOperatorRewards(uint32 operator)\\n internal\\n returns (uint96 withdrawable)\\n {\\n OperatorRewards storage o = operatorRewards[operator];\\n withdrawable = o.available;\\n o.available = 0;\\n }\\n\\n /// @notice Set the amount of ineligible-earned tokens to zero\\n /// and return the previous amount.\\n function withdrawIneligibleRewards() internal returns (uint96 withdrawable) {\\n withdrawable = ineligibleEarnedRewards;\\n ineligibleEarnedRewards = 0;\\n }\\n\\n /// @notice Set the given operators as ineligible for rewards.\\n /// The operators can restore their eligibility at the given time.\\n function setIneligible(uint32[] memory operators, uint256 until) internal {\\n OperatorRewards memory o = OperatorRewards(0, 0, 0, 0);\\n uint96 globalAcc = globalRewardAccumulator;\\n uint96 accrued = 0;\\n // Record ineligibility as seconds after contract creation\\n uint32 _until = uint32(until - ineligibleOffsetStart);\\n\\n for (uint256 i = 0; i < operators.length; i++) {\\n uint32 operator = operators[i];\\n OperatorRewards storage r = operatorRewards[operator];\\n o.available = r.available;\\n o.accumulated = r.accumulated;\\n o.ineligibleUntil = r.ineligibleUntil;\\n o.weight = r.weight;\\n\\n if (o.ineligibleUntil != 0) {\\n // If operator is already ineligible,\\n // don't earn rewards or shorten its ineligibility\\n if (o.ineligibleUntil < _until) {\\n o.ineligibleUntil = _until;\\n }\\n } else {\\n // The operator becomes ineligible -> earn rewards\\n o.ineligibleUntil = _until;\\n accrued = (globalAcc - o.accumulated) * uint96(o.weight);\\n o.available += accrued;\\n }\\n o.accumulated = globalAcc;\\n\\n r.available = o.available;\\n r.accumulated = o.accumulated;\\n r.ineligibleUntil = o.ineligibleUntil;\\n r.weight = o.weight;\\n }\\n }\\n\\n /// @notice Restore the given operator's eligibility for rewards.\\n function restoreEligibility(uint32 operator) internal {\\n // solhint-disable-next-line not-rely-on-time\\n require(canRestoreRewardEligibility(operator), \\\"Operator still ineligible\\\");\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n ineligibleEarnedRewards += accruedRewards;\\n o.accumulated = acc;\\n o.ineligibleUntil = 0;\\n operatorRewards[operator] = o;\\n }\\n\\n /// @notice Returns the amount of rewards currently available for withdrawal\\n /// for the given operator.\\n function availableRewards(uint32 operator) internal view returns (uint96) {\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n if (o.ineligibleUntil == 0) {\\n // If operator is not ineligible, calculate newly accrued rewards and add\\n // them to the available ones, calculated during the last update.\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n return o.available + accruedRewards;\\n } else {\\n // If ineligible, return only the rewards calculated during the last\\n // update.\\n return o.available;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3a10abb408b44335a092387b2c7ee01db3b27997f1f2c888d9b7a2d92934c4e2\"},\"@keep-network/sortition-pools/contracts/SortitionPool.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"@thesis/solidity-contracts/contracts/token/IERC20WithPermit.sol\\\";\\nimport \\\"@thesis/solidity-contracts/contracts/token/IReceiveApproval.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\nimport \\\"./RNG.sol\\\";\\nimport \\\"./SortitionTree.sol\\\";\\nimport \\\"./Rewards.sol\\\";\\nimport \\\"./Chaosnet.sol\\\";\\n\\n/// @title Sortition Pool\\n/// @notice A logarithmic data structure used to store the pool of eligible\\n/// operators weighted by their stakes. It allows to select a group of operators\\n/// based on the provided pseudo-random seed.\\ncontract SortitionPool is\\n SortitionTree,\\n Rewards,\\n Ownable,\\n Chaosnet,\\n IReceiveApproval\\n{\\n using Branch for uint256;\\n using Leaf for uint256;\\n using Position for uint256;\\n\\n IERC20WithPermit public immutable rewardToken;\\n\\n uint256 public immutable poolWeightDivisor;\\n\\n bool public isLocked;\\n\\n event IneligibleForRewards(uint32[] ids, uint256 until);\\n\\n event RewardEligibilityRestored(address indexed operator, uint32 indexed id);\\n\\n /// @notice Reverts if called while pool is locked.\\n modifier onlyUnlocked() {\\n require(!isLocked, \\\"Sortition pool locked\\\");\\n _;\\n }\\n\\n /// @notice Reverts if called while pool is unlocked.\\n modifier onlyLocked() {\\n require(isLocked, \\\"Sortition pool unlocked\\\");\\n _;\\n }\\n\\n constructor(IERC20WithPermit _rewardToken, uint256 _poolWeightDivisor) {\\n rewardToken = _rewardToken;\\n poolWeightDivisor = _poolWeightDivisor;\\n }\\n\\n function receiveApproval(\\n address sender,\\n uint256 amount,\\n address token,\\n bytes calldata\\n ) external override {\\n require(token == address(rewardToken), \\\"Unsupported token\\\");\\n rewardToken.transferFrom(sender, address(this), amount);\\n Rewards.addRewards(uint96(amount), uint32(root.sumWeight()));\\n }\\n\\n /// @notice Withdraws all available rewards for the given operator to the\\n /// given beneficiary.\\n /// @dev Can be called only be the owner. Does not validate if the provided\\n /// beneficiary is associated with the provided operator - this needs to\\n /// be done by the owner calling this function.\\n /// @return The amount of rewards withdrawn in this call.\\n function withdrawRewards(address operator, address beneficiary)\\n public\\n onlyOwner\\n returns (uint96)\\n {\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(getPoolWeight(operator)));\\n uint96 earned = Rewards.withdrawOperatorRewards(id);\\n rewardToken.transfer(beneficiary, uint256(earned));\\n return earned;\\n }\\n\\n /// @notice Withdraws rewards not allocated to operators marked as ineligible\\n /// to the given recipient address.\\n /// @dev Can be called only by the owner.\\n function withdrawIneligible(address recipient) public onlyOwner {\\n uint96 earned = Rewards.withdrawIneligibleRewards();\\n rewardToken.transfer(recipient, uint256(earned));\\n }\\n\\n /// @notice Locks the sortition pool. In locked state, members cannot be\\n /// inserted and removed from the pool. Members statuses cannot\\n /// be updated as well.\\n /// @dev Can be called only by the contract owner.\\n function lock() public onlyOwner {\\n isLocked = true;\\n }\\n\\n /// @notice Unlocks the sortition pool. Removes all restrictions set by\\n /// the `lock` method.\\n /// @dev Can be called only by the contract owner.\\n function unlock() public onlyOwner {\\n isLocked = false;\\n }\\n\\n /// @notice Inserts an operator to the pool. Reverts if the operator is\\n /// already present. Reverts if the operator is not eligible because of their\\n /// authorized stake. Reverts if the chaosnet is active and the operator is\\n /// not a beta operator.\\n /// @dev Can be called only by the contract owner.\\n /// @param operator Address of the inserted operator.\\n /// @param authorizedStake Inserted operator's authorized stake for the application.\\n function insertOperator(address operator, uint256 authorizedStake)\\n public\\n onlyOwner\\n onlyUnlocked\\n {\\n uint256 weight = getWeight(authorizedStake);\\n require(weight > 0, \\\"Operator not eligible\\\");\\n\\n if (isChaosnetActive) {\\n require(isBetaOperator[operator], \\\"Not beta operator for chaosnet\\\");\\n }\\n\\n _insertOperator(operator, weight);\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(weight));\\n }\\n\\n /// @notice Update the operator's weight if present and eligible,\\n /// or remove from the pool if present and ineligible.\\n /// @dev Can be called only by the contract owner.\\n /// @param operator Address of the updated operator.\\n /// @param authorizedStake Operator's authorized stake for the application.\\n function updateOperatorStatus(address operator, uint256 authorizedStake)\\n public\\n onlyOwner\\n onlyUnlocked\\n {\\n uint256 weight = getWeight(authorizedStake);\\n\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(weight));\\n\\n if (weight == 0) {\\n _removeOperator(operator);\\n } else {\\n updateOperator(operator, weight);\\n }\\n }\\n\\n /// @notice Set the given operators as ineligible for rewards.\\n /// The operators can restore their eligibility at the given time.\\n function setRewardIneligibility(uint32[] calldata operators, uint256 until)\\n public\\n onlyOwner\\n {\\n Rewards.setIneligible(operators, until);\\n emit IneligibleForRewards(operators, until);\\n }\\n\\n /// @notice Restores reward eligibility for the operator.\\n function restoreRewardEligibility(address operator) public {\\n uint32 id = getOperatorID(operator);\\n Rewards.restoreEligibility(id);\\n emit RewardEligibilityRestored(operator, id);\\n }\\n\\n /// @notice Returns whether the operator is eligible for rewards or not.\\n function isEligibleForRewards(address operator) public view returns (bool) {\\n uint32 id = getOperatorID(operator);\\n return Rewards.isEligibleForRewards(id);\\n }\\n\\n /// @notice Returns the time the operator's reward eligibility can be restored.\\n function rewardsEligibilityRestorableAt(address operator)\\n public\\n view\\n returns (uint256)\\n {\\n uint32 id = getOperatorID(operator);\\n return Rewards.rewardsEligibilityRestorableAt(id);\\n }\\n\\n /// @notice Returns whether the operator is able to restore their eligibility\\n /// for rewards right away.\\n function canRestoreRewardEligibility(address operator)\\n public\\n view\\n returns (bool)\\n {\\n uint32 id = getOperatorID(operator);\\n return Rewards.canRestoreRewardEligibility(id);\\n }\\n\\n /// @notice Returns the amount of rewards withdrawable for the given operator.\\n function getAvailableRewards(address operator) public view returns (uint96) {\\n uint32 id = getOperatorID(operator);\\n return availableRewards(id);\\n }\\n\\n /// @notice Return whether the operator is present in the pool.\\n function isOperatorInPool(address operator) public view returns (bool) {\\n return getFlaggedLeafPosition(operator) != 0;\\n }\\n\\n /// @notice Return whether the operator's weight in the pool\\n /// matches their eligible weight.\\n function isOperatorUpToDate(address operator, uint256 authorizedStake)\\n public\\n view\\n returns (bool)\\n {\\n return getWeight(authorizedStake) == getPoolWeight(operator);\\n }\\n\\n /// @notice Return the weight of the operator in the pool,\\n /// which may or may not be out of date.\\n function getPoolWeight(address operator) public view returns (uint256) {\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n if (flaggedPosition == 0) {\\n return 0;\\n } else {\\n uint256 leafPosition = flaggedPosition.unsetFlag();\\n uint256 leafWeight = getLeafWeight(leafPosition);\\n return leafWeight;\\n }\\n }\\n\\n /// @notice Selects a new group of operators of the provided size based on\\n /// the provided pseudo-random seed. At least one operator has to be\\n /// registered in the pool, otherwise the function fails reverting the\\n /// transaction.\\n /// @param groupSize Size of the requested group\\n /// @param seed Pseudo-random number used to select operators to group\\n /// @return selected Members of the selected group\\n function selectGroup(uint256 groupSize, bytes32 seed)\\n public\\n view\\n onlyLocked\\n returns (uint32[] memory)\\n {\\n uint256 _root = root;\\n\\n bytes32 rngState = seed;\\n uint256 rngRange = _root.sumWeight();\\n require(rngRange > 0, \\\"Not enough operators in pool\\\");\\n uint256 currentIndex;\\n\\n uint256 bits = RNG.bitsRequired(rngRange);\\n\\n uint32[] memory selected = new uint32[](groupSize);\\n\\n for (uint256 i = 0; i < groupSize; i++) {\\n (currentIndex, rngState) = RNG.getIndex(rngRange, rngState, bits);\\n\\n uint256 leafPosition = pickWeightedLeaf(currentIndex, _root);\\n\\n uint256 leaf = leaves[leafPosition];\\n selected[i] = leaf.id();\\n }\\n return selected;\\n }\\n\\n function getWeight(uint256 authorization) internal view returns (uint256) {\\n return authorization / poolWeightDivisor;\\n }\\n}\\n\",\"keccak256\":\"0xab42e7c5b1828f42a73f699eb2dc96d4f793572a6323b8b1fbd7c5e0c065bda7\"},\"@keep-network/sortition-pools/contracts/SortitionTree.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Branch.sol\\\";\\nimport \\\"./Position.sol\\\";\\nimport \\\"./Leaf.sol\\\";\\nimport \\\"./Constants.sol\\\";\\n\\ncontract SortitionTree {\\n using Branch for uint256;\\n using Position for uint256;\\n using Leaf for uint256;\\n\\n // implicit tree\\n // root 8\\n // level2 64\\n // level3 512\\n // level4 4k\\n // level5 32k\\n // level6 256k\\n // level7 2M\\n uint256 internal root;\\n\\n // A 2-index mapping from layer => (index (0-index) => branch). For example,\\n // to access the 6th branch in the 2nd layer (right below the root node; the\\n // first branch layer), call branches[2][5]. Mappings are used in place of\\n // arrays for efficiency. The root is the first layer, the branches occupy\\n // layers 2 through 7, and layer 8 is for the leaves. Following this\\n // convention, the first index in `branches` is `2`, and the last index is\\n // `7`.\\n mapping(uint256 => mapping(uint256 => uint256)) internal branches;\\n\\n // A 0-index mapping from index => leaf, acting as an array. For example, to\\n // access the 42nd leaf, call leaves[41].\\n mapping(uint256 => uint256) internal leaves;\\n\\n // the flagged (see setFlag() and unsetFlag() in Position.sol) positions\\n // of all operators present in the pool\\n mapping(address => uint256) internal flaggedLeafPosition;\\n\\n // the leaf after the rightmost occupied leaf of each stack\\n uint256 internal rightmostLeaf;\\n\\n // the empty leaves in each stack\\n // between 0 and the rightmost occupied leaf\\n uint256[] internal emptyLeaves;\\n\\n // Each operator has an uint32 ID number\\n // which is allocated when they first join the pool\\n // and remains unchanged even if they leave and rejoin the pool.\\n mapping(address => uint32) internal operatorID;\\n\\n // The idAddress array records the address corresponding to each ID number.\\n // The ID number 0 is initialized with a zero address and is not used.\\n address[] internal idAddress;\\n\\n constructor() {\\n root = 0;\\n rightmostLeaf = 0;\\n idAddress.push();\\n }\\n\\n /// @notice Return the ID number of the given operator address. An ID number\\n /// of 0 means the operator has not been allocated an ID number yet.\\n /// @param operator Address of the operator.\\n /// @return the ID number of the given operator address\\n function getOperatorID(address operator) public view returns (uint32) {\\n return operatorID[operator];\\n }\\n\\n /// @notice Get the operator address corresponding to the given ID number. A\\n /// zero address means the ID number has not been allocated yet.\\n /// @param id ID of the operator\\n /// @return the address of the operator\\n function getIDOperator(uint32 id) public view returns (address) {\\n return idAddress.length > id ? idAddress[id] : address(0);\\n }\\n\\n /// @notice Gets the operator addresses corresponding to the given ID\\n /// numbers. A zero address means the ID number has not been allocated yet.\\n /// This function works just like getIDOperator except that it allows to fetch\\n /// operator addresses for multiple IDs in one call.\\n /// @param ids the array of the operator ids\\n /// @return an array of the associated operator addresses\\n function getIDOperators(uint32[] calldata ids)\\n public\\n view\\n returns (address[] memory)\\n {\\n uint256 idCount = idAddress.length;\\n\\n address[] memory operators = new address[](ids.length);\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint32 id = ids[i];\\n operators[i] = idCount > id ? idAddress[id] : address(0);\\n }\\n return operators;\\n }\\n\\n /// @notice Checks if operator is already registered in the pool.\\n /// @param operator the address of the operator\\n /// @return whether or not the operator is already registered in the pool\\n function isOperatorRegistered(address operator) public view returns (bool) {\\n return getFlaggedLeafPosition(operator) != 0;\\n }\\n\\n /// @notice Sum the number of operators in each trunk.\\n /// @return the number of operators in the pool\\n function operatorsInPool() public view returns (uint256) {\\n // Get the number of leaves that might be occupied;\\n // if `rightmostLeaf` equals `firstLeaf()` the tree must be empty,\\n // otherwise the difference between these numbers\\n // gives the number of leaves that may be occupied.\\n uint256 nPossiblyUsedLeaves = rightmostLeaf;\\n // Get the number of empty leaves\\n // not accounted for by the `rightmostLeaf`\\n uint256 nEmptyLeaves = emptyLeaves.length;\\n\\n return (nPossiblyUsedLeaves - nEmptyLeaves);\\n }\\n\\n /// @notice Convenience method to return the total weight of the pool\\n /// @return the total weight of the pool\\n function totalWeight() public view returns (uint256) {\\n return root.sumWeight();\\n }\\n\\n /// @notice Give the operator a new ID number.\\n /// Does not check if the operator already has an ID number.\\n /// @param operator the address of the operator\\n /// @return a new ID for that operator\\n function allocateOperatorID(address operator) internal returns (uint256) {\\n uint256 id = idAddress.length;\\n\\n require(id <= type(uint32).max, \\\"Pool capacity exceeded\\\");\\n\\n operatorID[operator] = uint32(id);\\n idAddress.push(operator);\\n return id;\\n }\\n\\n /// @notice Inserts an operator into the sortition pool\\n /// @param operator the address of an operator to insert\\n /// @param weight how much weight that operator has in the pool\\n function _insertOperator(address operator, uint256 weight) internal {\\n require(\\n !isOperatorRegistered(operator),\\n \\\"Operator is already registered in the pool\\\"\\n );\\n\\n // Fetch the operator's ID, and if they don't have one, allocate them one.\\n uint256 id = getOperatorID(operator);\\n if (id == 0) {\\n id = allocateOperatorID(operator);\\n }\\n\\n // Determine which leaf to insert them into\\n uint256 position = getEmptyLeafPosition();\\n // Record the block the operator was inserted in\\n uint256 theLeaf = Leaf.make(operator, block.number, id);\\n\\n // Update the leaf, and propagate the weight changes all the way up to the\\n // root.\\n root = setLeaf(position, theLeaf, weight, root);\\n\\n // Without position flags,\\n // the position 0x000000 would be treated as empty\\n flaggedLeafPosition[operator] = position.setFlag();\\n }\\n\\n /// @notice Remove an operator (and their weight) from the pool.\\n /// @param operator the address of the operator to remove\\n function _removeOperator(address operator) internal {\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n require(flaggedPosition != 0, \\\"Operator is not registered in the pool\\\");\\n uint256 unflaggedPosition = flaggedPosition.unsetFlag();\\n\\n // Update the leaf, and propagate the weight changes all the way up to the\\n // root.\\n root = removeLeaf(unflaggedPosition, root);\\n removeLeafPositionRecord(operator);\\n }\\n\\n /// @notice Update an operator's weight in the pool.\\n /// @param operator the address of the operator to update\\n /// @param weight the new weight\\n function updateOperator(address operator, uint256 weight) internal {\\n require(\\n isOperatorRegistered(operator),\\n \\\"Operator is not registered in the pool\\\"\\n );\\n\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n uint256 unflaggedPosition = flaggedPosition.unsetFlag();\\n root = updateLeaf(unflaggedPosition, weight, root);\\n }\\n\\n /// @notice Helper method to remove a leaf position record for an operator.\\n /// @param operator the address of the operator to remove the record for\\n function removeLeafPositionRecord(address operator) internal {\\n flaggedLeafPosition[operator] = 0;\\n }\\n\\n /// @notice Removes the data and weight from a particular leaf.\\n /// @param position the leaf index to remove\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function removeLeaf(uint256 position, uint256 _root)\\n internal\\n returns (uint256)\\n {\\n uint256 rightmostSubOne = rightmostLeaf - 1;\\n bool isRightmost = position == rightmostSubOne;\\n\\n // Clears out the data in the leaf node, and then propagates the weight\\n // changes all the way up to the root.\\n uint256 newRoot = setLeaf(position, 0, 0, _root);\\n\\n // Infer if need to fall back on emptyLeaves yet\\n if (isRightmost) {\\n rightmostLeaf = rightmostSubOne;\\n } else {\\n emptyLeaves.push(position);\\n }\\n return newRoot;\\n }\\n\\n /// @notice Updates the tree to give a particular leaf a new weight.\\n /// @param position the index of the leaf to update\\n /// @param weight the new weight\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function updateLeaf(\\n uint256 position,\\n uint256 weight,\\n uint256 _root\\n ) internal returns (uint256) {\\n if (getLeafWeight(position) != weight) {\\n return updateTree(position, weight, _root);\\n } else {\\n return _root;\\n }\\n }\\n\\n /// @notice Places a leaf into a particular position, with a given weight and\\n /// propagates that change.\\n /// @param position the index to place the leaf in\\n /// @param theLeaf the new leaf to place in the position\\n /// @param leafWeight the weight of the leaf\\n /// @param _root the root containing the new leaf\\n /// @return the updated root node\\n function setLeaf(\\n uint256 position,\\n uint256 theLeaf,\\n uint256 leafWeight,\\n uint256 _root\\n ) internal returns (uint256) {\\n // set leaf\\n leaves[position] = theLeaf;\\n\\n return (updateTree(position, leafWeight, _root));\\n }\\n\\n /// @notice Propagates a weight change at a position through the tree,\\n /// eventually returning the updated root.\\n /// @param position the index of leaf to update\\n /// @param weight the new weight of the leaf\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function updateTree(\\n uint256 position,\\n uint256 weight,\\n uint256 _root\\n ) internal returns (uint256) {\\n uint256 childSlot;\\n uint256 treeNode;\\n uint256 newNode;\\n uint256 nodeWeight = weight;\\n\\n uint256 parent = position;\\n // set levels 7 to 2\\n for (uint256 level = Constants.LEVELS; level >= 2; level--) {\\n childSlot = parent.slot();\\n parent = parent.parent();\\n treeNode = branches[level][parent];\\n newNode = treeNode.setSlot(childSlot, nodeWeight);\\n branches[level][parent] = newNode;\\n nodeWeight = newNode.sumWeight();\\n }\\n\\n // set level Root\\n childSlot = parent.slot();\\n return _root.setSlot(childSlot, nodeWeight);\\n }\\n\\n /// @notice Retrieves the next available empty leaf position. Tries to fill\\n /// left to right first, ignoring leaf removals, and then fills\\n /// most-recent-removals first.\\n /// @return the position of the empty leaf\\n function getEmptyLeafPosition() internal returns (uint256) {\\n uint256 rLeaf = rightmostLeaf;\\n bool spaceOnRight = (rLeaf + 1) < Constants.POOL_CAPACITY;\\n if (spaceOnRight) {\\n rightmostLeaf = rLeaf + 1;\\n return rLeaf;\\n } else {\\n uint256 emptyLeafCount = emptyLeaves.length;\\n require(emptyLeafCount > 0, \\\"Pool is full\\\");\\n uint256 emptyLeaf = emptyLeaves[emptyLeafCount - 1];\\n emptyLeaves.pop();\\n return emptyLeaf;\\n }\\n }\\n\\n /// @notice Gets the flagged leaf position for an operator.\\n /// @param operator the address of the operator\\n /// @return the leaf position of that operator\\n function getFlaggedLeafPosition(address operator)\\n internal\\n view\\n returns (uint256)\\n {\\n return flaggedLeafPosition[operator];\\n }\\n\\n /// @notice Gets the weight of a leaf at a particular position.\\n /// @param position the index of the leaf\\n /// @return the weight of the leaf at that position\\n function getLeafWeight(uint256 position) internal view returns (uint256) {\\n uint256 slot = position.slot();\\n uint256 parent = position.parent();\\n\\n // A leaf's weight information is stored a 32-bit slot in the branch layer\\n // directly above the leaf layer. To access it, we calculate that slot and\\n // parent position, and always know the hard-coded layer index.\\n uint256 node = branches[Constants.LEVELS][parent];\\n return node.getSlot(slot);\\n }\\n\\n /// @notice Picks a leaf given a random index.\\n /// @param index a number in `[0, _root.totalWeight())` used to decide\\n /// between leaves\\n /// @param _root the root of the tree\\n function pickWeightedLeaf(uint256 index, uint256 _root)\\n internal\\n view\\n returns (uint256 leafPosition)\\n {\\n uint256 currentIndex = index;\\n uint256 currentNode = _root;\\n uint256 currentPosition = 0;\\n uint256 currentSlot;\\n\\n require(index < currentNode.sumWeight(), \\\"Index exceeds weight\\\");\\n\\n // get root slot\\n (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex);\\n\\n // get slots from levels 2 to 7\\n for (uint256 level = 2; level <= Constants.LEVELS; level++) {\\n currentPosition = currentPosition.child(currentSlot);\\n currentNode = branches[level][currentPosition];\\n (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex);\\n }\\n\\n // get leaf position\\n leafPosition = currentPosition.child(currentSlot);\\n }\\n}\\n\",\"keccak256\":\"0x51daeca62ef52be78a1a9de4d2a1c5900c873165f59eda14d5965d7d7da90a03\"},\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n uint8 private constant _ADDRESS_LENGTH = 20;\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\\n */\\n function toHexString(address addr) internal pure returns (string memory) {\\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\\n }\\n}\\n\",\"keccak256\":\"0xaf159a8b1923ad2a26d516089bceca9bdeaeacd04be50983ea00ba63070f08a3\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.3) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n /// @solidity memory-safe-assembly\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0xdb7f5c28fc61cda0bd8ab60ce288e206b791643bcd3ba464a70cbec18895a2f5\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IApproveAndCall.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\n/// @notice An interface that should be implemented by tokens supporting\\n/// `approveAndCall`/`receiveApproval` pattern.\\ninterface IApproveAndCall {\\n /// @notice Executes `receiveApproval` function on spender as specified in\\n /// `IReceiveApproval` interface. Approves spender to withdraw from\\n /// the caller multiple times, up to the `amount`. If this\\n /// function is called again, it overwrites the current allowance\\n /// with `amount`. Reverts if the approval reverted or if\\n /// `receiveApproval` call on the spender reverted.\\n function approveAndCall(\\n address spender,\\n uint256 amount,\\n bytes memory extraData\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x393d18ef81a57dcc96fff4c340cc2945deaebb37b9796c322cf2bc96872c3df8\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IERC20WithPermit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\\\";\\n\\nimport \\\"./IApproveAndCall.sol\\\";\\n\\n/// @title IERC20WithPermit\\n/// @notice Burnable ERC20 token with EIP2612 permit functionality. User can\\n/// authorize a transfer of their token with a signature conforming\\n/// EIP712 standard instead of an on-chain transaction from their\\n/// address. Anyone can submit this signature on the user's behalf by\\n/// calling the permit function, as specified in EIP2612 standard,\\n/// paying gas fees, and possibly performing other actions in the same\\n/// transaction.\\ninterface IERC20WithPermit is IERC20, IERC20Metadata, IApproveAndCall {\\n /// @notice EIP2612 approval made with secp256k1 signature.\\n /// Users can authorize a transfer of their tokens with a signature\\n /// conforming EIP712 standard, rather than an on-chain transaction\\n /// from their address. Anyone can submit this signature on the\\n /// user's behalf by calling the permit function, paying gas fees,\\n /// and possibly performing other actions in the same transaction.\\n /// @dev The deadline argument can be set to `type(uint256).max to create\\n /// permits that effectively never expire.\\n function permit(\\n address owner,\\n address spender,\\n uint256 amount,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /// @notice Destroys `amount` tokens from the caller.\\n function burn(uint256 amount) external;\\n\\n /// @notice Destroys `amount` of tokens from `account`, deducting the amount\\n /// from caller's allowance.\\n function burnFrom(address account, uint256 amount) external;\\n\\n /// @notice Returns hash of EIP712 Domain struct with the token name as\\n /// a signing domain and token contract as a verifying contract.\\n /// Used to construct EIP2612 signature provided to `permit`\\n /// function.\\n /* solhint-disable-next-line func-name-mixedcase */\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n\\n /// @notice Returns the current nonce for EIP2612 permission for the\\n /// provided token owner for a replay protection. Used to construct\\n /// EIP2612 signature provided to `permit` function.\\n function nonce(address owner) external view returns (uint256);\\n\\n /// @notice Returns EIP2612 Permit message hash. Used to construct EIP2612\\n /// signature provided to `permit` function.\\n /* solhint-disable-next-line func-name-mixedcase */\\n function PERMIT_TYPEHASH() external pure returns (bytes32);\\n}\\n\",\"keccak256\":\"0xdac9a5086c19a7128b505a7be1ab0ac1aa314f6989cb88d2417e9d7383f89fa9\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IReceiveApproval.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\n/// @notice An interface that should be implemented by contracts supporting\\n/// `approveAndCall`/`receiveApproval` pattern.\\ninterface IReceiveApproval {\\n /// @notice Receives approval to spend tokens. Called as a result of\\n /// `approveAndCall` call on the token.\\n function receiveApproval(\\n address from,\\n uint256 amount,\\n address token,\\n bytes calldata extraData\\n ) external;\\n}\\n\",\"keccak256\":\"0x6a30d83ad230548b1e7839737affc8489a035314209de14b89dbef7fb0f66395\",\"license\":\"MIT\"},\"contracts/libraries/BeaconInactivity.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./BytesLib.sol\\\";\\nimport \\\"./Groups.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\n\\nlibrary BeaconInactivity {\\n using BytesLib for bytes;\\n using ECDSA for bytes32;\\n\\n struct Claim {\\n // ID of the group raising the inactivity claim.\\n uint64 groupId;\\n // Indices of members accused of being inactive. Indices must be in\\n // range [1, groupMembers.length], unique, and sorted in ascending order.\\n uint256[] inactiveMembersIndices;\\n // Concatenation of signatures from members supporting the claim.\\n // The message to be signed by each member is keccak256 hash of the\\n // concatenation of the chain ID, inactivity claim nonce for the given\\n // group, group public key, and inactive members indices. The calculated\\n // hash should be prefixed with `\\\\x19Ethereum signed message:\\\\n` before\\n // signing, so the message to sign is:\\n // `\\\\x19Ethereum signed message:\\\\n${keccak256(\\n // chainID | nonce | groupPubKey | inactiveMembersIndices\\n // )}`\\n bytes signatures;\\n // Indices of members corresponding to each signature. Indices must be\\n // in range [1, groupMembers.length], unique, and sorted in ascending\\n // order.\\n uint256[] signingMembersIndices;\\n }\\n\\n /// @notice The minimum number of group members needed to interact according\\n /// to the protocol to produce a valid inactivity claim.\\n uint256 public constant groupThreshold = 33;\\n\\n /// @notice Size in bytes of a single signature produced by member\\n /// supporting the inactivity claim.\\n uint256 public constant signatureByteSize = 65;\\n\\n /// @notice Verifies the inactivity claim according to the rules defined in\\n /// `Claim` struct documentation. Reverts if verification fails.\\n /// @dev Group members hash is validated upstream in\\n /// RandomBeacon.notifyOperatorInactivity()\\n /// @param sortitionPool Sortition pool reference\\n /// @param claim Inactivity claim\\n /// @param groupPubKey Public key of the group raising the claim\\n /// @param nonce Current nonce for group used in the claim\\n /// @param groupMembers Identifiers of group members\\n /// @return inactiveMembers Identifiers of members who are inactive\\n function verifyClaim(\\n SortitionPool sortitionPool,\\n Claim calldata claim,\\n bytes memory groupPubKey,\\n uint256 nonce,\\n uint32[] calldata groupMembers\\n ) external view returns (uint32[] memory inactiveMembers) {\\n // Validate inactive members indices. Maximum indices count is equal to\\n // the group size and is not limited deliberately to leave a theoretical\\n // possibility to accuse more members than `groupSize - groupThreshold`.\\n validateMembersIndices(\\n claim.inactiveMembersIndices,\\n groupMembers.length\\n );\\n\\n // Validate signatures array is properly formed and number of\\n // signatures and signers is correct.\\n uint256 signaturesCount = claim.signatures.length / signatureByteSize;\\n require(claim.signatures.length != 0, \\\"No signatures provided\\\");\\n require(\\n claim.signatures.length % signatureByteSize == 0,\\n \\\"Malformed signatures array\\\"\\n );\\n require(\\n signaturesCount == claim.signingMembersIndices.length,\\n \\\"Unexpected signatures count\\\"\\n );\\n require(signaturesCount >= groupThreshold, \\\"Too few signatures\\\");\\n require(signaturesCount <= groupMembers.length, \\\"Too many signatures\\\");\\n\\n // Validate signing members indices. Note that `signingMembersIndices`\\n // were already partially validated during `signatures` parameter\\n // validation.\\n validateMembersIndices(\\n claim.signingMembersIndices,\\n groupMembers.length\\n );\\n\\n // Usage of group public key and not group ID is important because it\\n // provides uniqueness of signed messages and prevent against reusing\\n // them in future in case some other application has a group with the\\n // same ID and subset of members.\\n bytes32 signedMessageHash = keccak256(\\n abi.encode(\\n block.chainid,\\n nonce,\\n groupPubKey,\\n claim.inactiveMembersIndices\\n )\\n ).toEthSignedMessageHash();\\n\\n address[] memory groupMembersAddresses = sortitionPool.getIDOperators(\\n groupMembers\\n );\\n\\n // Verify each signature.\\n bytes memory checkedSignature;\\n bool senderSignatureExists = false;\\n for (uint256 i = 0; i < signaturesCount; i++) {\\n uint256 memberIndex = claim.signingMembersIndices[i];\\n checkedSignature = claim.signatures.slice(\\n signatureByteSize * i,\\n signatureByteSize\\n );\\n address recoveredAddress = signedMessageHash.recover(\\n checkedSignature\\n );\\n\\n require(\\n groupMembersAddresses[memberIndex - 1] == recoveredAddress,\\n \\\"Invalid signature\\\"\\n );\\n\\n if (!senderSignatureExists && msg.sender == recoveredAddress) {\\n senderSignatureExists = true;\\n }\\n }\\n\\n require(senderSignatureExists, \\\"Sender must be claim signer\\\");\\n\\n inactiveMembers = new uint32[](claim.inactiveMembersIndices.length);\\n for (uint256 i = 0; i < claim.inactiveMembersIndices.length; i++) {\\n uint256 memberIndex = claim.inactiveMembersIndices[i];\\n inactiveMembers[i] = groupMembers[memberIndex - 1];\\n }\\n\\n return inactiveMembers;\\n }\\n\\n /// @notice Validates members indices array. Array is considered valid\\n /// if its size and each single index are in [1, groupSize] range,\\n /// indexes are unique, and sorted in an ascending order.\\n /// Reverts if validation fails.\\n /// @param indices Array to validate\\n /// @param groupSize Group size used as reference\\n function validateMembersIndices(\\n uint256[] calldata indices,\\n uint256 groupSize\\n ) internal pure {\\n require(\\n indices.length > 0 && indices.length <= groupSize,\\n \\\"Corrupted members indices\\\"\\n );\\n\\n // Check if first and last indices are in range [1, groupSize].\\n // This check combined with the loop below makes sure every single\\n // index is in the correct range.\\n require(\\n indices[0] > 0 && indices[indices.length - 1] <= groupSize,\\n \\\"Corrupted members indices\\\"\\n );\\n\\n for (uint256 i = 0; i < indices.length - 1; i++) {\\n // Check whether given index is smaller than the next one. This\\n // way we are sure indexes are ordered in the ascending order\\n // and there are no duplicates.\\n require(indices[i] < indices[i + 1], \\\"Corrupted members indices\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x8dffb20eb4ffd2e388080c5fbcb648e33480aca3dab4be2254cf30c5e72413bf\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BytesLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\n/*\\nVersion pulled from keep-core v1:\\nhttps://github.com/keep-network/keep-core/blob/f297202db00c027978ad8e7103a356503de5773c/solidity-v1/contracts/utils/BytesLib.sol\\n\\nTo compile it with solidity 0.8 `_preBytes_slot` was replaced with `_preBytes.slot`.\\n*/\\n\\n/*\\nhttps://github.com/GNSPS/solidity-bytes-utils/\\nThis is free and unencumbered software released into the public domain.\\nAnyone is free to copy, modify, publish, use, compile, sell, or\\ndistribute this software, either in source code form or as a compiled\\nbinary, for any purpose, commercial or non-commercial, and by any\\nmeans.\\nIn jurisdictions that recognize copyright laws, the author or authors\\nof this software dedicate any and all copyright interest in the\\nsoftware to the public domain. We make this dedication for the benefit\\nof the public at large and to the detriment of our heirs and\\nsuccessors. We intend this dedication to be an overt act of\\nrelinquishment in perpetuity of all present and future rights to this\\nsoftware under copyright law.\\nTHE SOFTWARE IS PROVIDED \\\"AS IS\\\", WITHOUT WARRANTY OF ANY KIND,\\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\\nIN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\\nOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\\nOTHER DEALINGS IN THE SOFTWARE.\\nFor more information, please refer to \\n*/\\n\\n/** @title BytesLib **/\\n/** @author https://github.com/GNSPS **/\\n\\nlibrary BytesLib {\\n function concatStorage(bytes storage _preBytes, bytes memory _postBytes)\\n internal\\n {\\n assembly {\\n // Read the first 32 bytes of _preBytes storage, which is the length\\n // of the array. (We don't need to use the offset into the slot\\n // because arrays use the entire slot.)\\n let fslot := sload(_preBytes.slot)\\n // Arrays of 31 bytes or less have an even value in their slot,\\n // while longer arrays have an odd value. The actual length is\\n // the slot divided by two for odd values, and the lowest order\\n // byte divided by two for even values.\\n // If the slot is even, bitwise and the slot with 255 and divide by\\n // two to get the length. If the slot is odd, bitwise and the slot\\n // with -1 and divide by two.\\n let slength := div(\\n and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)),\\n 2\\n )\\n let mlength := mload(_postBytes)\\n let newlength := add(slength, mlength)\\n // slength can contain both the length and contents of the array\\n // if length < 32 bytes so let's prepare for that\\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\\n switch add(lt(slength, 32), lt(newlength, 32))\\n case 2 {\\n // Since the new array still fits in the slot, we just need to\\n // update the contents of the slot.\\n // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length\\n sstore(\\n _preBytes.slot,\\n // all the modifications to the slot are inside this\\n // next block\\n add(\\n // we can just add to the slot contents because the\\n // bytes we want to change are the LSBs\\n fslot,\\n add(\\n mul(\\n div(\\n // load the bytes from memory\\n mload(add(_postBytes, 0x20)),\\n // zero all bytes to the right\\n exp(0x100, sub(32, mlength))\\n ),\\n // and now shift left the number of bytes to\\n // leave space for the length in the slot\\n exp(0x100, sub(32, newlength))\\n ),\\n // increase length by the double of the memory\\n // bytes length\\n mul(mlength, 2)\\n )\\n )\\n )\\n }\\n case 1 {\\n // The stored value fits in the slot, but the combined value\\n // will exceed it.\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\\n\\n // save new length\\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\\n\\n // The contents of the _postBytes array start 32 bytes into\\n // the structure. Our first read should obtain the `submod`\\n // bytes that can fit into the unused space in the last word\\n // of the stored array. To get this, we read 32 bytes starting\\n // from `submod`, so the data we read overlaps with the array\\n // contents by `submod` bytes. Masking the lowest-order\\n // `submod` bytes allows us to add that value directly to the\\n // stored value.\\n\\n let submod := sub(32, slength)\\n let mc := add(_postBytes, submod)\\n let end := add(_postBytes, mlength)\\n let mask := sub(exp(0x100, submod), 1)\\n\\n sstore(\\n sc,\\n add(\\n and(\\n fslot,\\n 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00\\n ),\\n and(mload(mc), mask)\\n )\\n )\\n\\n for {\\n mc := add(mc, 0x20)\\n sc := add(sc, 1)\\n } lt(mc, end) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n sstore(sc, mload(mc))\\n }\\n\\n mask := exp(0x100, sub(mc, end))\\n\\n sstore(sc, mul(div(mload(mc), mask), mask))\\n }\\n default {\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n // Start copying to the last used word of the stored array.\\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\\n\\n // save new length\\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\\n\\n // Copy over the first `submod` bytes of the new data as in\\n // case 1 above.\\n let slengthmod := mod(slength, 32)\\n let submod := sub(32, slengthmod)\\n let mc := add(_postBytes, submod)\\n let end := add(_postBytes, mlength)\\n let mask := sub(exp(0x100, submod), 1)\\n\\n sstore(sc, add(sload(sc), and(mload(mc), mask)))\\n\\n for {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } lt(mc, end) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n sstore(sc, mload(mc))\\n }\\n\\n mask := exp(0x100, sub(mc, end))\\n\\n sstore(sc, mul(div(mload(mc), mask), mask))\\n }\\n }\\n }\\n\\n function equalStorage(bytes storage _preBytes, bytes memory _postBytes)\\n internal\\n view\\n returns (bool)\\n {\\n bool success = true;\\n\\n assembly {\\n // we know _preBytes_offset is 0\\n let fslot := sload(_preBytes.slot)\\n // Decode the length of the stored array like in concatStorage().\\n let slength := div(\\n and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)),\\n 2\\n )\\n let mlength := mload(_postBytes)\\n\\n // if lengths don't match the arrays are not equal\\n switch eq(slength, mlength)\\n case 1 {\\n // slength can contain both the length and contents of the array\\n // if length < 32 bytes so let's prepare for that\\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\\n if iszero(iszero(slength)) {\\n switch lt(slength, 32)\\n case 1 {\\n // blank the last byte which is the length\\n fslot := mul(div(fslot, 0x100), 0x100)\\n\\n if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {\\n // unsuccess:\\n success := 0\\n }\\n }\\n default {\\n // cb is a circuit breaker in the for loop since there's\\n // no said feature for inline assembly loops\\n // cb = 1 - don't breaker\\n // cb = 0 - break\\n let cb := 1\\n\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n let sc := keccak256(0x0, 0x20)\\n\\n let mc := add(_postBytes, 0x20)\\n let end := add(mc, mlength)\\n\\n // the next line is the loop condition:\\n // while(uint(mc < end) + cb == 2)\\n for {\\n\\n } eq(add(lt(mc, end), cb), 2) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n if iszero(eq(sload(sc), mload(mc))) {\\n // unsuccess:\\n success := 0\\n cb := 0\\n }\\n }\\n }\\n }\\n }\\n default {\\n // unsuccess:\\n success := 0\\n }\\n }\\n\\n return success;\\n }\\n\\n function concat(bytes memory _preBytes, bytes memory _postBytes)\\n internal\\n pure\\n returns (bytes memory)\\n {\\n bytes memory tempBytes;\\n\\n assembly {\\n // Get a location of some free memory and store it in tempBytes as\\n // Solidity does for memory variables.\\n tempBytes := mload(0x40)\\n\\n // Store the length of the first bytes array at the beginning of\\n // the memory for tempBytes.\\n let length := mload(_preBytes)\\n mstore(tempBytes, length)\\n\\n // Maintain a memory counter for the current write location in the\\n // temp bytes array by adding the 32 bytes for the array length to\\n // the starting location.\\n let mc := add(tempBytes, 0x20)\\n // Stop copying when the memory counter reaches the length of the\\n // first bytes array.\\n let end := add(mc, length)\\n\\n for {\\n // Initialize a copy counter to the start of the _preBytes data,\\n // 32 bytes into its memory.\\n let cc := add(_preBytes, 0x20)\\n } lt(mc, end) {\\n // Increase both counters by 32 bytes each iteration.\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n // Write the _preBytes data into the tempBytes memory 32 bytes\\n // at a time.\\n mstore(mc, mload(cc))\\n }\\n\\n // Add the length of _postBytes to the current length of tempBytes\\n // and store it as the new length in the first 32 bytes of the\\n // tempBytes memory.\\n length := mload(_postBytes)\\n mstore(tempBytes, add(length, mload(tempBytes)))\\n\\n // Move the memory counter back from a multiple of 0x20 to the\\n // actual end of the _preBytes data.\\n mc := end\\n // Stop copying when the memory counter reaches the new combined\\n // length of the arrays.\\n end := add(mc, length)\\n\\n for {\\n let cc := add(_postBytes, 0x20)\\n } lt(mc, end) {\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n mstore(mc, mload(cc))\\n }\\n\\n // Update the free-memory pointer by padding our last write location\\n // to 32 bytes: add 31 bytes to the end of tempBytes to move to the\\n // next 32 byte block, then round down to the nearest multiple of\\n // 32. If the sum of the length of the two arrays is zero then add\\n // one before rounding down to leave a blank 32 bytes (the length block with 0).\\n mstore(\\n 0x40,\\n and(\\n add(add(end, iszero(add(length, mload(_preBytes)))), 31),\\n not(31) // Round down to the nearest 32 bytes.\\n )\\n )\\n }\\n\\n return tempBytes;\\n }\\n\\n function slice(\\n bytes memory _bytes,\\n uint256 _start,\\n uint256 _length\\n ) internal pure returns (bytes memory res) {\\n uint256 _end = _start + _length;\\n require(_end > _start && _bytes.length >= _end, \\\"Slice out of bounds\\\");\\n\\n assembly {\\n // Alloc bytes array with additional 32 bytes afterspace and assign it's size\\n res := mload(0x40)\\n mstore(0x40, add(add(res, 64), _length))\\n mstore(res, _length)\\n\\n // Compute distance between source and destination pointers\\n let diff := sub(res, add(_bytes, _start))\\n\\n for {\\n let src := add(add(_bytes, 32), _start)\\n let end := add(src, _length)\\n } lt(src, end) {\\n src := add(src, 32)\\n } {\\n mstore(add(src, diff), mload(src))\\n }\\n }\\n }\\n\\n function toAddress(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (address)\\n {\\n uint256 _totalLen = _start + 20;\\n require(\\n _totalLen > _start && _bytes.length >= _totalLen,\\n \\\"Address conversion out of bounds.\\\"\\n );\\n address tempAddress;\\n\\n assembly {\\n tempAddress := div(\\n mload(add(add(_bytes, 0x20), _start)),\\n 0x1000000000000000000000000\\n )\\n }\\n\\n return tempAddress;\\n }\\n\\n function toUint8(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (uint8)\\n {\\n require(\\n _bytes.length >= (_start + 1),\\n \\\"Uint8 conversion out of bounds.\\\"\\n );\\n uint8 tempUint;\\n\\n assembly {\\n tempUint := mload(add(add(_bytes, 0x1), _start))\\n }\\n\\n return tempUint;\\n }\\n\\n function toUint(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (uint256)\\n {\\n uint256 _totalLen = _start + 32;\\n require(\\n _totalLen > _start && _bytes.length >= _totalLen,\\n \\\"Uint conversion out of bounds.\\\"\\n );\\n uint256 tempUint;\\n\\n assembly {\\n tempUint := mload(add(add(_bytes, 0x20), _start))\\n }\\n\\n return tempUint;\\n }\\n\\n function equal(bytes memory _preBytes, bytes memory _postBytes)\\n internal\\n pure\\n returns (bool)\\n {\\n bool success = true;\\n\\n assembly {\\n let length := mload(_preBytes)\\n\\n // if lengths don't match the arrays are not equal\\n switch eq(length, mload(_postBytes))\\n case 1 {\\n // cb is a circuit breaker in the for loop since there's\\n // no said feature for inline assembly loops\\n // cb = 1 - don't breaker\\n // cb = 0 - break\\n let cb := 1\\n\\n let mc := add(_preBytes, 0x20)\\n let end := add(mc, length)\\n\\n for {\\n let cc := add(_postBytes, 0x20)\\n // the next line is the loop condition:\\n // while(uint(mc < end) + cb == 2)\\n } eq(add(lt(mc, end), cb), 2) {\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n // if any of these checks fails then arrays are not equal\\n if iszero(eq(mload(mc), mload(cc))) {\\n // unsuccess:\\n success := 0\\n cb := 0\\n }\\n }\\n }\\n default {\\n // unsuccess:\\n success := 0\\n }\\n }\\n\\n return success;\\n }\\n\\n function toBytes32(bytes memory _source)\\n internal\\n pure\\n returns (bytes32 result)\\n {\\n if (_source.length == 0) {\\n return 0x0;\\n }\\n\\n assembly {\\n result := mload(add(_source, 32))\\n }\\n }\\n\\n function keccak256Slice(\\n bytes memory _bytes,\\n uint256 _start,\\n uint256 _length\\n ) internal pure returns (bytes32 result) {\\n uint256 _end = _start + _length;\\n require(_end > _start && _bytes.length >= _end, \\\"Slice out of bounds\\\");\\n\\n assembly {\\n result := keccak256(add(add(_bytes, 32), _start), _length)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3b76e2fe36eb777440250dcf2ea7a689375e8af22f3cc33521095ff6954becdb\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/Groups.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\n/// @notice This library is used as a registry of created groups.\\n/// @dev This library should be used along with DKG library that ensures linear\\n/// groups creation (only one group creation happens at a time). A candidate\\n/// group has to be popped or activated before adding a new candidate group.\\nlibrary Groups {\\n struct Group {\\n bytes groupPubKey;\\n uint256 registrationBlockNumber;\\n // Keccak256 hash of group members identifiers array. Group members do not\\n // include operators selected by the sortition pool that misbehaved during DKG.\\n // See how `misbehavedMembersIndices` are used in `hashGroupMembers` function.\\n bytes32 membersHash;\\n // When selected group does not create a relay entry on-time it should\\n // be marked as terminated.\\n bool terminated;\\n }\\n\\n struct Data {\\n // Mapping of keccak256 hashes of group public keys to groups details.\\n mapping(bytes32 => Group) groupsData;\\n // Holds keccak256 hashes of group public keys in the order of registration.\\n bytes32[] groupsRegistry;\\n // Group ids that were active but failed creating a relay entry. When an\\n // active-terminated group qualifies to become 'expired', then it will\\n // be removed from this array.\\n uint64[] activeTerminatedGroups;\\n // Points to the first active group, it is also the expired groups counter.\\n uint64 expiredGroupOffset;\\n // Group lifetime in blocks. When a group reached its lifetime, it\\n // is no longer selected for new relay requests but may still be\\n // responsible for submitting relay entry if relay request assigned\\n // to that group is still pending.\\n uint256 groupLifetime;\\n }\\n\\n event GroupRegistered(uint64 indexed groupId, bytes indexed groupPubKey);\\n\\n /// @notice Performs preliminary validation of a new group public key.\\n /// The group public key must be unique and have 128 bytes in length.\\n /// If the validation fails, the function reverts. This function\\n /// must be called first for a public key of a group added with\\n /// `addGroup` function.\\n /// @param groupPubKey Candidate group public key\\n function validatePublicKey(Data storage self, bytes calldata groupPubKey)\\n internal\\n view\\n {\\n require(groupPubKey.length == 128, \\\"Invalid length of the public key\\\");\\n\\n bytes32 groupPubKeyHash = keccak256(groupPubKey);\\n\\n require(\\n self.groupsData[groupPubKeyHash].registrationBlockNumber == 0,\\n \\\"Group with this public key was already registered\\\"\\n );\\n }\\n\\n /// @notice Adds a new candidate group. The group is stored with group public\\n /// key and group members, but is not yet activated.\\n /// @dev The group members list is stored with all misbehaved members filtered out.\\n /// The code calling this function should ensure that the number of\\n /// candidate (not activated) groups is never more than one.\\n /// @param groupPubKey Generated candidate group public key\\n /// @param membersHash Keccak256 hash of members that actively took part in DKG.\\n function addGroup(\\n Data storage self,\\n bytes calldata groupPubKey,\\n bytes32 membersHash\\n ) internal {\\n bytes32 groupPubKeyHash = keccak256(groupPubKey);\\n\\n // We use group from storage that is assumed to be a struct set to the\\n // default values. We need to remember to overwrite fields in case a\\n // candidate group was already registered before and popped.\\n Group storage group = self.groupsData[groupPubKeyHash];\\n group.groupPubKey = groupPubKey;\\n group.membersHash = membersHash;\\n group.registrationBlockNumber = block.number;\\n\\n self.groupsRegistry.push(groupPubKeyHash);\\n\\n emit GroupRegistered(\\n uint64(self.groupsRegistry.length - 1),\\n groupPubKey\\n );\\n }\\n\\n /// @notice Goes through groups starting from the oldest one that is still\\n /// active and checks if it hasn't expired. If so, updates the information\\n /// about expired groups so that all expired groups are marked as such.\\n function expireOldGroups(Data storage self) internal {\\n // Move expiredGroupOffset as long as there are some groups that should\\n // be marked as expired. It is possible that expired group offset will\\n // move out of the groups array by one position. It means that all groups\\n // are expired (it points to the first active group) and that place in\\n // groups array - currently empty - will be possibly filled later by\\n // a new group.\\n while (\\n self.expiredGroupOffset < self.groupsRegistry.length &&\\n groupLifetimeOf(\\n self,\\n self.groupsRegistry[self.expiredGroupOffset]\\n ) <\\n block.number\\n ) {\\n self.expiredGroupOffset++;\\n }\\n\\n // Go through all activeTerminatedGroups and if some of the terminated\\n // groups are expired, remove them from activeTerminatedGroups collection\\n // and rearrange the array to preserve the original order.\\n // This is needed because we evaluate the shift of selected group index\\n // based on how many non-expired groups have been terminated. Hence it is\\n // important that a number of terminated groups matches the length of\\n // activeTerminatedGroups[].\\n uint256 i = 0;\\n while (i < self.activeTerminatedGroups.length) {\\n if (self.expiredGroupOffset > self.activeTerminatedGroups[i]) {\\n // When 'i'th group qualifies for expiration, we need to remove\\n // it from the activeTerminatedGroups array manually by rearranging\\n // the order starting from 'i'th group.\\n for (\\n uint256 j = i;\\n j < self.activeTerminatedGroups.length - 1;\\n j++\\n ) {\\n self.activeTerminatedGroups[j] = self\\n .activeTerminatedGroups[j + 1];\\n }\\n // Resizing the array length by 1. The last element was copied\\n // over in the loop above to an index \\\"second to last\\\". This is\\n // why we can safely remove it from here.\\n self.activeTerminatedGroups.pop();\\n } else {\\n i++;\\n }\\n }\\n }\\n\\n /// @notice Terminates group with the provided index. Reverts if the group\\n /// is already terminated.\\n /// @param groupId Index in the groupRegistry array.\\n function terminateGroup(Data storage self, uint64 groupId) internal {\\n require(\\n !isGroupTerminated(self, groupId),\\n \\\"Group has been already terminated\\\"\\n );\\n self.groupsData[self.groupsRegistry[groupId]].terminated = true;\\n // Expanding array for a new terminated group that is added below during\\n // sortition in ascending order.\\n self.activeTerminatedGroups.push();\\n\\n // Sorting activeTerminatedGroups by groupId in ascending order so a\\n // non-terminated group is properly selected.\\n uint256 i;\\n for (\\n i = self.activeTerminatedGroups.length - 1;\\n i > 0 && self.activeTerminatedGroups[i - 1] > groupId;\\n i--\\n ) {\\n self.activeTerminatedGroups[i] = self.activeTerminatedGroups[i - 1];\\n }\\n self.activeTerminatedGroups[i] = groupId;\\n }\\n\\n /// @notice Returns an index of a randomly selected active group. Terminated\\n /// and expired groups are not considered as active.\\n /// Before new group is selected, information about expired groups\\n /// is updated. At least one active group needs to be present for this\\n /// function to succeed.\\n /// @param seed Random number used as a group selection seed.\\n function selectGroup(Data storage self, uint256 seed)\\n internal\\n returns (uint64)\\n {\\n expireOldGroups(self);\\n\\n require(numberOfActiveGroups(self) > 0, \\\"No active groups\\\");\\n\\n uint64 selectedGroup = uint64(seed % numberOfActiveGroups(self));\\n uint64 result = shiftByTerminatedGroups(\\n self,\\n shiftByExpiredGroups(self, selectedGroup)\\n );\\n return result;\\n }\\n\\n /// @notice Setter for group lifetime.\\n /// @param lifetime Lifetime of a group in blocks.\\n function setGroupLifetime(Data storage self, uint256 lifetime) internal {\\n self.groupLifetime = lifetime;\\n }\\n\\n /// @notice Checks if group with the given index is terminated.\\n function isGroupTerminated(Data storage self, uint64 groupId)\\n internal\\n view\\n returns (bool)\\n {\\n return self.groupsData[self.groupsRegistry[groupId]].terminated;\\n }\\n\\n /// @notice Gets the cutoff time until which the given group is considered\\n /// to be active assuming it hasn't been terminated before.\\n function groupLifetimeOf(Data storage self, bytes32 groupPubKeyHash)\\n internal\\n view\\n returns (uint256)\\n {\\n return\\n self.groupsData[groupPubKeyHash].registrationBlockNumber +\\n self.groupLifetime;\\n }\\n\\n /// @notice Checks if group with the given index is active and non-terminated.\\n function isGroupActive(Data storage self, uint64 groupId)\\n internal\\n view\\n returns (bool)\\n {\\n return\\n groupLifetimeOf(self, self.groupsRegistry[groupId]) >=\\n block.number &&\\n !isGroupTerminated(self, groupId);\\n }\\n\\n function getGroup(Data storage self, uint64 groupId)\\n internal\\n view\\n returns (Group storage)\\n {\\n return self.groupsData[self.groupsRegistry[groupId]];\\n }\\n\\n function getGroup(Data storage self, bytes memory groupPubKey)\\n internal\\n view\\n returns (Group storage)\\n {\\n return self.groupsData[keccak256(groupPubKey)];\\n }\\n\\n /// @notice Gets the number of active groups. Expired and terminated\\n /// groups are not counted as active.\\n function numberOfActiveGroups(Data storage self)\\n internal\\n view\\n returns (uint64)\\n {\\n if (self.groupsRegistry.length == 0) {\\n return 0;\\n }\\n\\n uint256 activeGroups = self.groupsRegistry.length -\\n self.expiredGroupOffset -\\n self.activeTerminatedGroups.length;\\n\\n return uint64(activeGroups);\\n }\\n\\n /// @notice Evaluates the shift of a selected group index based on the number\\n /// of expired groups.\\n function shiftByExpiredGroups(Data storage self, uint64 selectedIndex)\\n internal\\n view\\n returns (uint64)\\n {\\n return self.expiredGroupOffset + selectedIndex;\\n }\\n\\n /// @notice Evaluates the shift of a selected group index based on the number\\n /// of non-expired but terminated groups.\\n function shiftByTerminatedGroups(Data storage self, uint64 selectedIndex)\\n internal\\n view\\n returns (uint64)\\n {\\n uint64 shiftedIndex = selectedIndex;\\n for (uint64 i = 0; i < self.activeTerminatedGroups.length; i++) {\\n if (self.activeTerminatedGroups[i] <= shiftedIndex) {\\n shiftedIndex++;\\n }\\n }\\n\\n return shiftedIndex;\\n }\\n}\\n\",\"keccak256\":\"0x27a3cee268e5afa5ee3a00089aa82faffff7c3882aa94919499de4ef55dcfb0c\",\"license\":\"GPL-3.0-only\"}},\"version\":1}", + "storageLayout": { + "storage": [], + "types": null + }, + "userdoc": { + "kind": "user", + "methods": { + "groupThreshold()": { + "notice": "The minimum number of group members needed to interact according to the protocol to produce a valid inactivity claim." + }, + "signatureByteSize()": { + "notice": "Size in bytes of a single signature produced by member supporting the inactivity claim." + }, + "verifyClaim(SortitionPool,BeaconInactivity.Claim,bytes,uint256,uint32[])": { + "notice": "Verifies the inactivity claim according to the rules defined in `Claim` struct documentation. Reverts if verification fails." + } + }, + "version": 1 + } +} diff --git a/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/test/RandomBeaconStub.sol/RandomBeaconStub.json b/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/test/RandomBeaconStub.sol/RandomBeaconStub.json new file mode 100644 index 0000000000..d4be86b034 --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/artifacts/contracts/test/RandomBeaconStub.sol/RandomBeaconStub.json @@ -0,0 +1,3535 @@ +{ + "contractName": "RandomBeaconStub", + "sourceName": "contracts/test/RandomBeaconStub.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "contract SortitionPool", + "name": "_sortitionPool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "_tToken", + "type": "address" + }, + { + "internalType": "contract IStaking", + "name": "_staking", + "type": "address" + }, + { + "internalType": "contract BeaconDkgValidator", + "name": "_dkgValidator", + "type": "address" + }, + { + "internalType": "contract ReimbursementPool", + "name": "_reimbursementPool", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "AuthorizationDecreaseApproved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "decreasingAt", + "type": "uint64" + } + ], + "name": "AuthorizationDecreaseRequested", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + } + ], + "name": "AuthorizationIncreased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint96", + "name": "minimumAuthorization", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "authorizationDecreaseDelay", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "authorizationDecreaseChangePeriod", + "type": "uint64" + } + ], + "name": "AuthorizationParametersUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "entry", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "entrySubmittedBlock", + "type": "uint256" + } + ], + "name": "CallbackFailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "slashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "maliciousSubmitter", + "type": "address" + } + ], + "name": "DkgMaliciousResultSlashed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "slashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "maliciousSubmitter", + "type": "address" + } + ], + "name": "DkgMaliciousResultSlashingFailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "approver", + "type": "address" + } + ], + "name": "DkgResultApproved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "indexed": false, + "internalType": "string", + "name": "reason", + "type": "string" + } + ], + "name": "DkgResultChallenged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "seed", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "indexed": false, + "internalType": "struct BeaconDkg.Result", + "name": "result", + "type": "tuple" + } + ], + "name": "DkgResultSubmitted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "DkgSeedTimedOut", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "seed", + "type": "uint256" + } + ], + "name": "DkgStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "DkgStateLocked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "DkgTimedOut", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultSubmissionGas", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultApprovalGasOffset", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "notifyOperatorInactivityGasOffset", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntrySubmissionGasOffset", + "type": "uint256" + } + ], + "name": "GasParametersUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldGovernance", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newGovernance", + "type": "address" + } + ], + "name": "GovernanceTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "groupCreationFrequency", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "groupLifetime", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultChallengePeriodLength", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultChallengeExtraGas", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultSubmissionTimeout", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "dkgResultSubmitterPrecedencePeriodLength", + "type": "uint256" + } + ], + "name": "GroupCreationParametersUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "indexed": true, + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + } + ], + "name": "GroupRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "notifier", + "type": "address" + } + ], + "name": "InactivityClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + } + ], + "name": "InvoluntaryAuthorizationDecreaseFailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "OperatorJoinedSortitionPool", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "OperatorRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "OperatorStatusUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newReimbursementPool", + "type": "address" + } + ], + "name": "ReimbursementPoolUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "slashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "groupMembers", + "type": "address[]" + } + ], + "name": "RelayEntryDelaySlashed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "slashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "groupMembers", + "type": "address[]" + } + ], + "name": "RelayEntryDelaySlashingFailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntrySoftTimeout", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntryHardTimeout", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "callbackGasLimit", + "type": "uint256" + } + ], + "name": "RelayEntryParametersUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "previousEntry", + "type": "bytes" + } + ], + "name": "RelayEntryRequested", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "submitter", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "entry", + "type": "bytes" + } + ], + "name": "RelayEntrySubmitted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "terminatedGroupId", + "type": "uint64" + } + ], + "name": "RelayEntryTimedOut", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "slashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "groupMembers", + "type": "address[]" + } + ], + "name": "RelayEntryTimeoutSlashed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "slashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "groupMembers", + "type": "address[]" + } + ], + "name": "RelayEntryTimeoutSlashingFailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isAuthorized", + "type": "bool" + } + ], + "name": "RequesterAuthorizationUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "sortitionPoolRewardsBanDuration", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntryTimeoutNotificationRewardMultiplier", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "unauthorizedSigningNotificationRewardMultiplier", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "dkgMaliciousResultNotificationRewardMultiplier", + "type": "uint256" + } + ], + "name": "RewardParametersUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "amount", + "type": "uint96" + } + ], + "name": "RewardsWithdrawn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "relayEntrySubmissionFailureSlashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "maliciousDkgResultSlashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "unauthorizedSigningSlashingAmount", + "type": "uint256" + } + ], + "name": "SlashingParametersUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "unauthorizedSigningSlashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "groupMembers", + "type": "address[]" + } + ], + "name": "UnauthorizedSigningSlashed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "unauthorizedSigningSlashingAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "groupMembers", + "type": "address[]" + } + ], + "name": "UnauthorizedSigningSlashingFailed", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "approveAuthorizationDecrease", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct BeaconDkg.Result", + "name": "dkgResult", + "type": "tuple" + } + ], + "name": "approveDkgResult", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + } + ], + "name": "authorizationDecreaseRequested", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + } + ], + "name": "authorizationIncreased", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "authorizationParameters", + "outputs": [ + { + "internalType": "uint96", + "name": "minimumAuthorization", + "type": "uint96" + }, + { + "internalType": "uint64", + "name": "authorizationDecreaseDelay", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "authorizationDecreaseChangePeriod", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "authorizedRequesters", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "availableRewards", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct BeaconDkg.Result", + "name": "dkgResult", + "type": "tuple" + } + ], + "name": "challengeDkgResult", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "dkgLockState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "eligibleStake", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gasParameters", + "outputs": [ + { + "internalType": "uint256", + "name": "dkgResultSubmissionGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultApprovalGasOffset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "notifyOperatorInactivityGasOffset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "relayEntrySubmissionGasOffset", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "genesis", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getCallbackContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getDkgData", + "outputs": [ + { + "components": [ + { + "internalType": "contract SortitionPool", + "name": "sortitionPool", + "type": "address" + }, + { + "internalType": "contract BeaconDkgValidator", + "name": "dkgValidator", + "type": "address" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "resultChallengePeriodLength", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "resultChallengeExtraGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "resultSubmissionTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "submitterPrecedencePeriodLength", + "type": "uint256" + } + ], + "internalType": "struct BeaconDkg.Parameters", + "name": "parameters", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "startBlock", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "seed", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "resultSubmissionStartBlockOffset", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "submittedResultHash", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "submittedResultBlock", + "type": "uint256" + } + ], + "internalType": "struct BeaconDkg.Data", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + } + ], + "name": "getGroup", + "outputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "registrationBlockNumber", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + }, + { + "internalType": "bool", + "name": "terminated", + "type": "bool" + } + ], + "internalType": "struct Groups.Group", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + } + ], + "name": "getGroup", + "outputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "registrationBlockNumber", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + }, + { + "internalType": "bool", + "name": "terminated", + "type": "bool" + } + ], + "internalType": "struct Groups.Group", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getGroupCreationState", + "outputs": [ + { + "internalType": "enum BeaconDkg.State", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getGroupsRegistry", + "outputs": [ + { + "internalType": "bytes32[]", + "name": "", + "type": "bytes32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "governance", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "groupCreationParameters", + "outputs": [ + { + "internalType": "uint256", + "name": "groupCreationFrequency", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "groupLifetime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultChallengePeriodLength", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultChallengeExtraGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultSubmissionTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgSubmitterPrecedencePeriodLength", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "hasDkgTimedOut", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "name": "inactivityClaimNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + }, + { + "internalType": "uint96", + "name": "fromAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "toAmount", + "type": "uint96" + } + ], + "name": "involuntaryAuthorizationDecrease", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isOperatorInPool", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isOperatorUpToDate", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isRelayRequestInProgress", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "joinSortitionPool", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "minimumAuthorization", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "notifyDkgTimeout", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "internalType": "uint256[]", + "name": "inactiveMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + } + ], + "internalType": "struct BeaconInactivity.Claim", + "name": "claim", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint32[]", + "name": "groupMembers", + "type": "uint32[]" + } + ], + "name": "notifyOperatorInactivity", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "operatorToStakingProvider", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "pendingAuthorizationDecrease", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "registerOperator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "reimbursementPool", + "outputs": [ + { + "internalType": "contract ReimbursementPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "relayEntryParameters", + "outputs": [ + { + "internalType": "uint256", + "name": "relayEntrySoftTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "relayEntryHardTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "callbackGasLimit", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "remainingAuthorizationDecreaseDelay", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32[]", + "name": "groupMembers", + "type": "uint32[]" + } + ], + "name": "reportRelayEntryTimeout", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "signedMsgSender", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + }, + { + "internalType": "uint32[]", + "name": "groupMembers", + "type": "uint32[]" + } + ], + "name": "reportUnauthorizedSigning", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IRandomBeaconConsumer", + "name": "callbackContract", + "type": "address" + } + ], + "name": "requestRelayEntry", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "rewardParameters", + "outputs": [ + { + "internalType": "uint256", + "name": "sortitionPoolRewardsBanDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "relayEntryTimeoutNotificationRewardMultiplier", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "unauthorizedSigningNotificationRewardMultiplier", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgMaliciousResultNotificationRewardMultiplier", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "groupMembersHash", + "type": "bytes32" + } + ], + "name": "roughlyAddGroup", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "groupId", + "type": "uint64" + } + ], + "name": "roughlyTerminateGroup", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "selectGroup", + "outputs": [ + { + "internalType": "uint32[]", + "name": "", + "type": "uint32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "bool", + "name": "isAuthorized", + "type": "bool" + } + ], + "name": "setRequesterAuthorization", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "slashingParameters", + "outputs": [ + { + "internalType": "uint96", + "name": "relayEntrySubmissionFailureSlashingAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "maliciousDkgResultSlashingAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "unauthorizedSigningSlashingAmount", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "sortitionPool", + "outputs": [ + { + "internalType": "contract SortitionPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "staking", + "outputs": [ + { + "internalType": "contract IStaking", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "stakingProviderToOperator", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "submitterMemberIndex", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "groupPubKey", + "type": "bytes" + }, + { + "internalType": "uint8[]", + "name": "misbehavedMembersIndices", + "type": "uint8[]" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + }, + { + "internalType": "uint256[]", + "name": "signingMembersIndices", + "type": "uint256[]" + }, + { + "internalType": "uint32[]", + "name": "members", + "type": "uint32[]" + }, + { + "internalType": "bytes32", + "name": "membersHash", + "type": "bytes32" + } + ], + "internalType": "struct BeaconDkg.Result", + "name": "dkgResult", + "type": "tuple" + } + ], + "name": "submitDkgResult", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "entry", + "type": "bytes" + }, + { + "internalType": "uint32[]", + "name": "groupMembers", + "type": "uint32[]" + } + ], + "name": "submitRelayEntry", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "entry", + "type": "bytes" + } + ], + "name": "submitRelayEntry", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "tToken", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newGovernance", + "type": "address" + } + ], + "name": "transferGovernance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "_minimumAuthorization", + "type": "uint96" + }, + { + "internalType": "uint64", + "name": "_authorizationDecreaseDelay", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "_authorizationDecreaseChangePeriod", + "type": "uint64" + } + ], + "name": "updateAuthorizationParameters", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dkgResultSubmissionGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultApprovalGasOffset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "notifyOperatorInactivityGasOffset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "relayEntrySubmissionGasOffset", + "type": "uint256" + } + ], + "name": "updateGasParameters", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "groupCreationFrequency", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "groupLifetime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultChallengePeriodLength", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultChallengeExtraGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgResultSubmissionTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgSubmitterPrecedencePeriodLength", + "type": "uint256" + } + ], + "name": "updateGroupCreationParameters", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "updateOperatorStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ReimbursementPool", + "name": "_reimbursementPool", + "type": "address" + } + ], + "name": "updateReimbursementPool", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "relayEntrySoftTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "relayEntryHardTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "callbackGasLimit", + "type": "uint256" + } + ], + "name": "updateRelayEntryParameters", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sortitionPoolRewardsBanDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "relayEntryTimeoutNotificationRewardMultiplier", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "unauthorizedSigningNotificationRewardMultiplier", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgMaliciousResultNotificationRewardMultiplier", + "type": "uint256" + } + ], + "name": "updateRewardParameters", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "relayEntrySubmissionFailureSlashingAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "maliciousDkgResultSlashingAmount", + "type": "uint96" + }, + { + "internalType": "uint96", + "name": "unauthorizedSigningSlashingAmount", + "type": "uint96" + } + ], + "name": "updateSlashingParameters", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + } + ], + "name": "withdrawIneligibleRewards", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingProvider", + "type": "address" + } + ], + "name": "withdrawRewards", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x60806040523480156200001157600080fd5b5060405162006d5038038062006d50833981016040819052620000349162000a58565b607180546001600160a01b038088166001600160a01b031992831681179093556072805482891690841617905560738054828816908416179055603280549185169190921617905585908590859085908590620000c75760405162461bcd60e51b8152602060048201526016602482015260008051602062006cf083398151915260448201526064015b60405180910390fd5b6001600160a01b0384166200010e5760405162461bcd60e51b8152602060048201526016602482015260008051602062006cf08339815191526044820152606401620000be565b6001600160a01b038316620001555760405162461bcd60e51b8152602060048201526016602482015260008051602062006cf08339815191526044820152606401620000be565b6001600160a01b0382166200019c5760405162461bcd60e51b8152602060048201526016602482015260008051602062006cf08339815191526044820152606401620000be565b6001600160a01b038116620001e35760405162461bcd60e51b8152602060048201526016602482015260008051602062006cf08339815191526044820152606401620000be565b62000200858360786200039b60201b62003221179092919060201c565b6200021760886200049460201b620033161760201c565b620002223362000539565b604051633d36f3fd60e21b815260746004820152690878678326eac90000006024820152623b538060448201819052606482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063f4dbcff49060840160006040518083038186803b1580156200028e57600080fd5b505af4158015620002a3573d6000803e3d6000fd5b5050606680546001600160c01b0319167415af1d78b58c40000000000015af1d78b58c40000017905550620002f1905060886815af1d78b58c4000006200059a602090811b620033aa17901c565b6064606a8190556069819055606855621275006067556200032a6078612d0061c35061050060146200063d602090811b6200343e17901c565b6200034b61050061168060886200085760201b62003636179092919060201c565b61fa006064556200036d60836203f480620008f5602090811b620036c117901c565b5050600260655550506203a052606b55505061a21c606c55505061d4e4606d555050612bf2606e5562000b41565b82546001600160a01b031615620004005760405162461bcd60e51b815260206004820152602260248201527f536f72746974696f6e20506f6f6c206164647265737320616c72656164792073604482015261195d60f21b6064820152608401620000be565b60018301546001600160a01b031615620004675760405162461bcd60e51b815260206004820152602160248201527f444b472056616c696461746f72206164647265737320616c72656164792073656044820152601d60fa1b6064820152608401620000be565b82546001600160a01b03199081166001600160a01b03938416178455600190930180549093169116179055565b6001810154158015620004a957506002810154155b620004f75760405162461bcd60e51b815260206004820152601e60248201527f5365656420656e74727920616c726561647920696e697469616c697a656400006044820152606401620000be565b6200052660405180606001604052806040815260200162006d1060409139620008fd60201b620036c91760201c565b8051600183015560200151600290910155565b600080546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce80910160405180910390a15050565b620005ba82546801000000000000000090046001600160401b0316151590565b15620006095760405162461bcd60e51b815260206004820152601960248201527f52656c6179207265717565737420696e2070726f6772657373000000000000006044820152606401620000be565b600390910180546001600160601b039092166801000000000000000002600160401b600160a01b0319909216919091179055565b60006200064a8662000983565b60048111156200065e576200065e62000ad8565b14620006ad5760405162461bcd60e51b815260206004820152601960248201527f43757272656e74207374617465206973206e6f742049444c45000000000000006044820152606401620000be565b60008411620007255760405162461bcd60e51b815260206004820152603a60248201527f526573756c74206368616c6c656e676520706572696f64206c656e677468207360448201527f686f756c642062652067726561746572207468616e207a65726f0000000000006064820152608401620000be565b600082116200079d5760405162461bcd60e51b815260206004820152603560248201527f526573756c74207375626d697373696f6e2074696d656f75742073686f756c6460448201527f2062652067726561746572207468616e207a65726f00000000000000000000006064820152608401620000be565b8181106200083a5760405162461bcd60e51b815260206004820152605460248201527f5375626d697474657220707265636564656e636520706572696f64206c656e6760448201527f74682073686f756c64206265206c657373207468616e2074686520726573756c60648201527f74207375626d697373696f6e2074696d656f7574000000000000000000000000608482015260a401620000be565b600285019390935560038401919091556004830155600590910155565b6200087783546801000000000000000090046001600160401b0316151590565b15620008c65760405162461bcd60e51b815260206004820152601960248201527f52656c6179207265717565737420696e2070726f6772657373000000000000006044820152606401620000be565b6003909201805463ffffffff938416640100000000026001600160401b03199091169390921692909217179055565b600490910155565b60408051808201909152600080825260208201528151604014620009645760405162461bcd60e51b815260206004820152601760248201527f496e76616c6964204731206279746573206c656e6774680000000000000000006044820152606401620000be565b5060208181015160409283015183518085019094529083529082015290565b805460408051632938b58d60e21b815290516000926001600160a01b03169163a4e2d6349160048083019260209291908290030181865afa158015620009cd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620009f3919062000aee565b1562000a3a575060068101546001901562000a3a57600290506048826006015462000a1f919062000b19565b43111562000a3a5750600a8101546003901562000a3a575060045b919050565b6001600160a01b038116811462000a5557600080fd5b50565b600080600080600060a0868803121562000a7157600080fd5b855162000a7e8162000a3f565b602087015190955062000a918162000a3f565b604087015190945062000aa48162000a3f565b606087015190935062000ab78162000a3f565b608087015190925062000aca8162000a3f565b809150509295509295909350565b634e487b7160e01b600052602160045260246000fd5b60006020828403121562000b0157600080fd5b8151801515811462000b1257600080fd5b9392505050565b8082018082111562000b3b57634e487b7160e01b600052601160045260246000fd5b92915050565b61619f8062000b516000396000f3fe608060405234801561001057600080fd5b50600436106103c55760003560e01c80637e33cba6116101ff578063c35d64ea1161011a578063e03e4535116100ad578063f5ee563f1161007c578063f5ee563f14610a0b578063f7186ce014610a39578063f854a27f14610a4c578063fd2a478814610a5f57600080fd5b8063e03e4535146109ca578063e686440f146109df578063ea3a5a8f146109f2578063f0820c92146109fa57600080fd5b8063ccfd3bbe116100e9578063ccfd3bbe14610970578063d38bfff414610983578063d855c63114610996578063ded56d451461099e57600080fd5b8063c35d64ea14610909578063c7c49c981461091c578063c9bacaad14610948578063cb8b37791461095b57600080fd5b8063a04e298011610192578063b53dacdf11610161578063b53dacdf146108bf578063b54a2374146108d2578063bf4ebe31146108e5578063c09975cd146108f657600080fd5b8063a04e298014610852578063a7f0b3de14610865578063b0d010d61461086d578063b142f85c1461088057600080fd5b80638f105e37116101ce5780638f105e37146107e7578063985e6487146108015780639a7d0935146108145780639c9de0281461082757600080fd5b80637e33cba614610785578063818680d4146107b057806388a59590146107c357806388ef69d0146107d457600080fd5b80634cf088d9116102ef57806368c349481161028257806377a5a7bd1161025157806377a5a7bd146106ef5780637b14729e146107025780637b35b4e61461075f5780637e0049fd1461077257600080fd5b806368c34948146106915780636a7f7a901461069957806374024ab7146106ac57806375e0ae5a146106dc57600080fd5b8063592b2abd116102be578063592b2abd146105bf5780635aa6e675146106585780635c5b38701461066b578063663032cd1461067e57600080fd5b80634cf088d914610541578063529023011461056c57806355b64bcc1461059957806357665912146105ac57600080fd5b8063319ac1011161036757806342d866931161033657806342d86693146104f55780634368ec0c146105085780634549cc4b1461051b5780634a07068e1461052e57600080fd5b8063319ac1011461047c578063339646ac1461049c5780633682a450146104af5780633ea478aa146104c257600080fd5b80631872ea94116103a35780631872ea94146103fa5780631c5b0762146104185780631d35fa631461042b578063313767661461046957600080fd5b80630519e991146103ca57806314a85474146103df578063167f0517146103f2575b600080fd5b6103dd6103d8366004614eac565b610a72565b005b6103dd6103ed366004614f0c565b610b2a565b6103dd610bfa565b610402610c7c565b60405161040f9190614f2c565b60405180910390f35b6103dd610426366004614f70565b610cd7565b608b5460665460408051600160401b9093046001600160601b0390811684528083166020850152600160601b9092049091169082015260600161040f565b6103dd610477366004614f8d565b610d64565b61048f61048a366004614fdc565b610fe2565b60405161040f919061503f565b6103dd6104aa366004615087565b6110d8565b6103dd6104bd366004614f70565b611165565b6104e56104d0366004614f70565b60706020526000908152604090205460ff1681565b604051901515815260200161040f565b6103dd610503366004614f70565b6111ac565b6103dd610516366004614f70565b611346565b61048f61052936600461516e565b611457565b6103dd61053c3660046151ed565b611492565b607354610554906001600160a01b031681565b6040516001600160a01b03909116815260200161040f565b606754606854606954606a545b60408051948552602085019390935291830152606082015260800161040f565b6103dd6105a736600461526f565b611800565b6103dd6105ba3660046152da565b611b99565b6105c7611ca2565b60405161040f919060006101608201905060018060a01b03808451168352806020850151166020840152506040830151805160408401526020810151606084015260408101516080840152606081015160a084015250606083015160c0830152608083015160e083015260a083015161010083015260c083015161012083015260e083015161014083015292915050565b600054610554906001600160a01b031681565b6103dd610679366004614f8d565b611d2d565b6103dd61068c366004614f70565b611ee8565b6104e5611f6d565b6103dd6106a7366004614f0c565b611f7e565b608b546064546040805163ffffffff8085168252640100000000909404909316602084015282015260600161040f565b6103dd6106ea366004614f70565b612006565b6103dd6106fd36600461530f565b612059565b6107306074546001600160601b038116916001600160401b03600160601b8304811692600160a01b90041690565b604080516001600160601b0390941684526001600160401b03928316602085015291169082015260600161040f565b6103dd61076d366004614f70565b6120f9565b6103dd610780366004614f8d565b612181565b610798610793366004614f70565b6121d4565b6040516001600160601b03909116815260200161040f565b6103dd6107be366004614fdc565b61226d565b606b54606c54606d54606e54610579565b6103dd6107e2366004615352565b61227b565b608854600160401b90046001600160401b031615156104e5565b6103dd61080f3660046153ab565b61228d565b6103dd6108223660046153e4565b612316565b61083a610835366004614f70565b61238f565b6040516001600160401b03909116815260200161040f565b6103dd610860366004615410565b612413565b6103dd61251a565b6103dd61087b366004615087565b6125dc565b606554608754607a54607b54607c54607d54604080519687526020870195909552938501929092526060840152608083015260a082015260c00161040f565b6103dd6108cd366004615450565b61265f565b607154610554906001600160a01b031681565b608c546001600160a01b0316610554565b603254610554906001600160a01b031681565b607254610554906001600160a01b031681565b61055461092a366004614f70565b6001600160a01b039081166000908152607560205260409020541690565b6103dd610956366004614f0c565b612b1c565b610963612ba4565b60405161040f91906154c7565b6103dd61097e3660046154ef565b612bb0565b6103dd610991366004614f70565b612e60565b6103dd612ef4565b6105546109ac366004614f70565b6001600160a01b039081166000908152607660205260409020541690565b6109d2612f7c565b60405161040f919061558e565b6104e56109ed366004614f70565b613000565b6103dd61309d565b6074546001600160601b0316610798565b610a2b610a19366004614fdc565b606f6020526000908152604090205481565b60405190815260200161040f565b6104e5610a47366004614f70565b6130a7565b610798610a5a366004614f70565b6130f2565b610798610a6d366004614f70565b6131d7565b6000546001600160a01b03163314610aa55760405162461bcd60e51b8152600401610a9c906155a1565b60405180910390fd5b610ab06088846133aa565b606680546001600160601b038481166001600160c01b03199092168217600160601b858316908102919091179093556040805191871682526020820192909252908101919091527f1eda09aaee2b21bbf5571b06eab42dd1b2c2b629a5d6336230ff8b0e1f538276906060015b60405180910390a1505050565b6073546001600160a01b03163314610b545760405162461bcd60e51b8152600401610a9c906155d8565b60735460715460405163117964a560e21b8152607460048201526001600160a01b039283166024820152908216604482015290841660648201526001600160601b038084166084830152821660a482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__906345e592949060c4015b60006040518083038186803b158015610bdd57600080fd5b505af4158015610bf1573d6000803e3d6000fd5b50505050505050565b60735460715460405163520c3d3160e01b8152607460048201526001600160a01b0392831660248201529116604482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063520c3d319060640160006040518083038186803b158015610c6257600080fd5b505af4158015610c76573d6000803e3d6000fd5b50505050565b60606083600101805480602002602001604051908101604052809291908181526020018280548015610ccd57602002820191906000526020600020905b815481526020019060010190808311610cb9575b5050505050905090565b60735460715460405163c6e1c83960e01b8152607460048201526001600160a01b0392831660248201529082166044820152908216606482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063c6e1c839906084015b60006040518083038186803b158015610d4957600080fd5b505af4158015610d5d573d6000803e3d6000fd5b5050505050565b6040516346bf00db60e01b8152600090819073__$852b9611da141be0769f808cc0e4dd5c7d$__906346bf00db90610da390607890879060040161574f565b6040805180830381865af4158015610dbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610de3919061586f565b606654607154604051638871ca5d60e01b815263ffffffff841660048201529395509193506001600160601b0316916000916001600160a01b031690638871ca5d90602401602060405180830381865afa158015610e45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e699190615894565b60408051600180825281830190925291925060009190602080830190803683375050506001600160a01b038381166000908152607660205260409020549192501681600081518110610ebd57610ebd6158b1565b6001600160a01b039283166020918202929092010152607354606a546040516383ddba8f60e01b815291909216916383ddba8f91610f0391879133908790600401615900565b600060405180830381600087803b158015610f1d57600080fd5b505af1925050508015610f2e575060015b610f8357604080516001600160601b03851681526001600160a01b038416602082015286917f14621289a12ab59e0737decc388bba91d929c723defb4682d5d19b9a12ecfecb910160405180910390a2610fd0565b604080516001600160601b03851681526001600160a01b038416602082015286917f88f76c659db78142f88e94db3ca791869495394c6c1b3d412ced9022dc97c9e3910160405180910390a25b610fda607861374d565b505050505050565b6040805160808101825260608082526000602083018190529282018390528101919091526110116083836137a1565b60405180608001604052908160008201805461102c90615940565b80601f016020809104026020016040519081016040528092919081815260200182805461105890615940565b80156110a55780601f1061107a576101008083540402835291602001916110a5565b820191906000526020600020905b81548152906001019060200180831161108857829003601f168201915b5050509183525050600182015460208201526002820154604082015260039091015460ff16151560609091015292915050565b6000546001600160a01b031633146111025760405162461bcd60e51b8152600401610a9c906155a1565b606784905560688390556069829055606a8190556040805185815260208101859052908101839052606081018290527fbe6727aab9b80431985c18deef80d48599397c63884c62e96959f82abd16f16d906080015b60405180910390a150505050565b604051634755926360e01b8152607460048201526001600160a01b038216602482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__90634755926390604401610d31565b6001600160a01b0381811660009081526075602052604090205416806112075760405162461bcd60e51b815260206004820152601060248201526f2ab735b737bbb71037b832b930ba37b960811b6044820152606401610a9c565b607354604051632de9480760e01b81526001600160a01b0384811660048301526000921690632de9480790602401606060405180830381865afa158015611252573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611276919061597a565b50607154604051637104c0e560e11b81526001600160a01b03868116600483015280841660248301529294506000935091169063e20981ca906044016020604051808303816000875af11580156112d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112f591906159bc565b6040516001600160601b03821681529091506001600160a01b038516907f38532b6dea69d7266fa923c7813d190be37625f2454ddfa3d93c45c79482e3fd906020015b60405180910390a250505050565b3360009081526070602052604090205460ff166113a55760405162461bcd60e51b815260206004820152601c60248201527f526571756573746572206d75737420626520617574686f72697a6564000000006044820152606401610a9c565b604080518082019091526089548152608a5460208201526000906113dc906113cc906137e8565b8051602090910120608390613822565b90506113e96088826138bf565b608c80546001600160a01b0319166001600160a01b03841617905560655460885461141d91906001600160401b03166159ef565b158015611444575060006114316078613a24565b6004811115611442576114426154b1565b145b15611453576114536078613ad7565b5050565b604080516080810182526060808252600060208084018290528385018290529183018190528451858301208152608390915291909120611011565b608854600160801b90046001600160401b031660006114b26083836137a1565b905083836040516020016114c7929190615a03565b604051602081830303815290604052805190602001208160020154146114ff5760405162461bcd60e51b8152600401610a9c90615a4e565b608b54607154604051637bfcd47d60e11b8152600160401b9092046001600160601b0316916000916001600160a01b03169063f7f9a8fa906115479089908990600401615a03565b600060405180830381865afa158015611564573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261158c9190810190615aa0565b9050600081516001600160401b038111156115a9576115a96150b9565b6040519080825280602002602001820160405280156115d2578160200160208202803683370190505b50905060005b82518110156116585761161c8382815181106115f6576115f66158b1565b60200260200101516001600160a01b039081166000908152607660205260409020541690565b82828151811061162e5761162e6158b1565b6001600160a01b03909216602092830291909101909101528061165081615b54565b9150506115d8565b506073546068546040516383ddba8f60e01b81526001600160a01b03909216916383ddba8f916116919187919033908790600401615900565b600060405180830381600087803b1580156116ab57600080fd5b505af19250505080156116bc575060015b61171457608854604051600160401b9091046001600160401b0316907f678dcbc52328cedef940fe45ab75280e81c09ec03fe55df62e67642aa18bc278906117079086908690615b6d565b60405180910390a2611764565b608854604051600160401b9091046001600160401b0316907f6e1369aebaf86903bf1f0ab69c3edd0cadbf0534635f699f57a74a3ce54d37189061175b9086908690615b6d565b60405180910390a25b61176f608386613baa565b6117796083613ddc565b60006117856083613ff7565b6001600160401b031611156117ca57604080518082019091526089548152608a5460208201526117b8906113cc906137e8565b94506117c560888661403f565b610bf1565b6117d46088614182565b60016117e06078613a24565b60048111156117f1576117f16154b1565b03610bf157610bf16078614237565b60005a6088549091506001600160401b03600160401b820481169160009161183391608391600160801b909104166137a1565b90508484604051602001611848929190615a03565b604051602081830303815290604052805190602001208160020154146118805760405162461bcd60e51b8152600401610a9c90615a4e565b600061188f60888989856142a2565b90506001600160601b03811615611a9d57607154604051637bfcd47d60e11b81526000916001600160a01b03169063f7f9a8fa906118d3908a908a90600401615a03565b600060405180830381865afa1580156118f0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119189190810190615aa0565b9050600081516001600160401b03811115611935576119356150b9565b60405190808252806020026020018201604052801561195e578160200160208202803683370190505b50905060005b82518110156119be576119828382815181106115f6576115f66158b1565b828281518110611994576119946158b1565b6001600160a01b0390921660209283029190910190910152806119b681615b54565b915050611964565b5060735460405163f07f91c560e01b81526001600160a01b039091169063f07f91c5906119f19086908590600401615b6d565b600060405180830381600087803b158015611a0b57600080fd5b505af1925050508015611a1c575060015b611a5f57847fd3f7d9c595537a55b26b224409f386868056764bc4d55bf8c3d86e20d047afc18484604051611a52929190615b6d565b60405180910390a2611a9a565b847f94af8e9c35b4ede2a77f659b202b1efe096bf99f0e6f5dd5905c800978a9a6478484604051611a91929190615b6d565b60405180910390a25b50505b6001611aa96078613a24565b6004811115611aba57611aba6154b1565b03611ae357611ae38888604051611ad2929190615b8f565b6040519081900390206078906142c7565b611b0b8888604051611af6929190615b8f565b604051908190039020606454608c9190614339565b603254606e546001600160a01b0390911690637ad226dc905a611b2e9088615b9f565b611b389190615bb2565b6040516001600160e01b031960e084901b1681526004810191909152336024820152604401600060405180830381600087803b158015611b7757600080fd5b505af1158015611b8b573d6000803e3d6000fd5b505050505050505050505050565b60005a608854909150600090611bc190608390600160801b90046001600160401b03166137a1565b9050611bd060888585846143e1565b6001611bdc6078613a24565b6004811115611bed57611bed6154b1565b03611c0557611c058484604051611ad2929190615b8f565b611c188484604051611af6929190615b8f565b603254606e546001600160a01b0390911690637ad226dc905a611c3b9086615b9f565b611c459190615bb2565b6040516001600160e01b031960e084901b1681526004810191909152336024820152604401600060405180830381600087803b158015611c8457600080fd5b505af1158015611c98573d6000803e3d6000fd5b5050505050505050565b611caa614dd0565b5060408051610100810182526078546001600160a01b03908116825260795416602080830191909152825160808082018552607a548252607b5492820192909252607c5481850152607d5460608083019190915293830152607e5492820192909252607f5482820152905460a082015260815460c082015260825460e082015290565b60005a60405163716ae95760e01b815290915060009073__$852b9611da141be0769f808cc0e4dd5c7d$__9063716ae95790611d7090607890879060040161574f565b600060405180830381865af4158015611d8d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611db59190810190615bc5565b805190915015611e33576071546067546001600160a01b039091169063942f6892908390611de39042615bb2565b6040518363ffffffff1660e01b8152600401611e00929190615c53565b600060405180830381600087803b158015611e1a57600080fd5b505af1158015611e2e573d6000803e3d6000fd5b505050505b611e51611e436020850185615c75565b6083919060c0870135614444565b611e5b607861450d565b603254606c546001600160a01b0390911690637ad226dc905a611e7e9086615b9f565b606b54611e8b9190615bb2565b611e959190615bb2565b6040516001600160e01b031960e084901b1681526004810191909152336024820152604401600060405180830381600087803b158015611ed457600080fd5b505af1158015610bf1573d6000803e3d6000fd5b6000546001600160a01b03163314611f125760405162461bcd60e51b8152600401610a9c906155a1565b607154604051632a59250560e21b81526001600160a01b0383811660048301529091169063a964941490602401600060405180830381600087803b158015611f5957600080fd5b505af1158015610d5d573d6000803e3d6000fd5b6000611f796078614571565b905090565b6073546001600160a01b03163314611fa85760405162461bcd60e51b8152600401610a9c906155d8565b604051636dc1282760e11b8152607460048201526001600160a01b03841660248201526001600160601b0380841660448301528216606482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063db82504e90608401610bc5565b6073546040516304a3b6b360e31b8152607460048201526001600160a01b039182166024820152908216604482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063251db59890606401610d31565b6000546001600160a01b031633146120835760405162461bcd60e51b8152600401610a9c906155a1565b6065869055608785905561209b60788585858561343e565b6040805187815260208101879052908101859052606081018490526080810183905260a081018290527f88243406f452bee756e4fff4cb19e6855a5d3b7bfab8814ea6838685e08da0939060c00160405180910390a1505050505050565b6000546001600160a01b031633146121235760405162461bcd60e51b8152600401610a9c906155a1565b6040516001600160a01b03821681527f0e2d2343d31b085b7c4e56d1c8a6ec79f7ab07460386f1c9a1756239fe2533ac9060200160405180910390a1603280546001600160a01b0319166001600160a01b0392909216919091179055565b61219a6121916020830183615c75565b608391906145ce565b6040516305149aaf60e51b815273__$852b9611da141be0769f808cc0e4dd5c7d$__9063a29355e090610d3190607890859060040161574f565b607354604051635c359a0f60e11b8152607460048201526001600160a01b039182166024820152908216604482015260009073__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063b86b341e906064015b602060405180830381865af4158015612243573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061226791906159bc565b92915050565b612278608382613baa565b50565b6122886083848484614444565b505050565b6000546001600160a01b031633146122b75760405162461bcd60e51b8152600401610a9c906155a1565b6001600160a01b038216600081815260706020908152604091829020805460ff191685151590811790915591519182527fb4d9db68405970190721d2b3726fc9f728c1413038755e60518dea67d5545556910160405180910390a25050565b6000546001600160a01b031633146123405760405162461bcd60e51b8152600401610a9c906155a1565b606481905561235160888484613636565b60408051848152602081018490529081018290527fea9006ae23cd9b51dbfbc9d747fc3b0bc77acba4fefba609c76f8e9a9513602e90606001610b1d565b604051624f4ac760e01b8152607460048201526001600160a01b038216602482015260009073__$1150d55cc8540ae1e6a8a840b6e83a829d$__90624f4ac790604401602060405180830381865af41580156123ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122679190615cbb565b6000546001600160a01b0316331461243d5760405162461bcd60e51b8152600401610a9c906155a1565b604051633d36f3fd60e21b8152607460048201526001600160601b03841660248201526001600160401b0380841660448301528216606482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063f4dbcff49060840160006040518083038186803b1580156124ae57600080fd5b505af41580156124c2573d6000803e3d6000fd5b5050604080516001600160601b03871681526001600160401b0380871660208301528516918101919091527f544b726e42801bb47073854eeedae851903f66fe32a5bd24e626e10b90027b5192506060019050610b1d565b6125246083613ff7565b6001600160401b0316156125715760405162461bcd60e51b81526020600482015260146024820152734e6f74206177616974696e672067656e6573697360601b6044820152606401610a9c565b61257b6078613ad7565b6125da7f4574c8c75d6e88acd28f7e467dac97b5c60c3838d9dad993900bdf402152228e436040516020016125ba929190918252602082015260400190565b60408051601f1981840301815291905280516020909101206078906142c7565b565b6000546001600160a01b031633146126065760405162461bcd60e51b8152600401610a9c906155a1565b606b849055606c839055606d829055606e8190556040805185815260208101859052908101839052606081018290527feffd28b20afc0bf9349e8d49d5346c7568689b661a6bcd71c26a939b57b0acd190608001611157565b600061266c6083856137a1565b60405180608001604052908160008201805461268790615940565b80601f01602080910402602001604051908101604052809291908181526020018280546126b390615940565b80156127005780601f106126d557610100808354040283529160200191612700565b820191906000526020600020905b8154815290600101906020018083116126e357829003601f168201915b5050505050815260200160018201548152602001600282015481526020016003820160009054906101000a900460ff1615151515815250509050828260405160200161274d929190615a03565b604051602081830303815290604052805190602001208160400151146127855760405162461bcd60e51b8152600401610a9c90615a4e565b8060600151156127d75760405162461bcd60e51b815260206004820152601a60248201527f47726f75702063616e6e6f74206265207465726d696e617465640000000000006044820152606401610a9c565b8051604080513360601b6bffffffffffffffffffffffff191660208201528151601481830301815260348201928390526339c6c5f160e21b90925273__$b5930e1c3596d61eae714f9835468f05d3$__9263e71b17c49261283c928a90603801615cd8565b602060405180830381865af4158015612859573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061287d9190615d11565b6128bd5760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b6044820152606401610a9c565b6128c8608385613baa565b607154604051637bfcd47d60e11b81526000916001600160a01b03169063f7f9a8fa906128fb9087908790600401615a03565b600060405180830381865afa158015612918573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526129409190810190615aa0565b9050600081516001600160401b0381111561295d5761295d6150b9565b604051908082528060200260200182016040528015612986578160200160208202803683370190505b50905060005b82518110156129e6576129aa8382815181106115f6576115f66158b1565b8282815181106129bc576129bc6158b1565b6001600160a01b0390921660209283029190910190910152806129de81615b54565b91505061298c565b506073546066546069546040516383ddba8f60e01b81526001600160a01b03909316926383ddba8f92612a3192600160601b9091046001600160601b03169133908790600401615900565b600060405180830381600087803b158015612a4b57600080fd5b505af1925050508015612a5c575060015b612abc576066546040516001600160401b038816917ffd4a5a45de3194b94e2a7954706ac9023b7c9935cf1a25242691da2a94d720d491612aaf91600160601b90046001600160601b0316908690615b6d565b60405180910390a2610bf1565b6066546040516001600160401b038816917fa311dcb2a3eb32651a722488f4f281b3f8e4ab05abcd8a37a5c7d663bba5a88591612b0b91600160601b90046001600160601b0316908690615b6d565b60405180910390a250505050505050565b6073546001600160a01b03163314612b465760405162461bcd60e51b8152600401610a9c906155d8565b604051633558d21760e21b8152607460048201526001600160a01b03841660248201526001600160601b0380841660448301528216606482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063d563485c90608401610bc5565b6000611f796078613a24565b60005a90506000612bc46020870187614fdc565b6001600160401b0381166000908152606f60205260409020549091508514612c1e5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c6964206e6f6e636560981b6044820152606401610a9c565b612c296083826146b7565b612c6b5760405162461bcd60e51b815260206004820152601360248201527247726f7570206973206e6f742061637469766560681b6044820152606401610a9c565b6000612c786083836137a1565b90508484604051602001612c8d929190615a03565b60405160208183030381529060405280519060200120816002015414612cc55760405162461bcd60e51b8152600401610a9c90615a4e565b60715460405163fc21976b60e01b815260009173__$1ba5315bb273adc70a9cc339490e63eb09$__9163fc21976b91612d16916001600160a01b03909116908c9087908d908d908d90600401615dab565b600060405180830381865af4158015612d33573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612d5b9190810190615bc5565b6001600160401b0384166000908152606f60205260408120805492935090612d8283615b54565b9091555050604080518881523360208201526001600160401b038516917f3ca10b33fda0a4adbc75ac1939659a06e8c332b8f6a2792bedbf8741e4268417910160405180910390a26071546067546001600160a01b039091169063942f6892908390612dee9042615bb2565b6040518363ffffffff1660e01b8152600401612e0b929190615c53565b600060405180830381600087803b158015612e2557600080fd5b505af1158015612e39573d6000803e3d6000fd5b5050603254606d546001600160a01b039091169250637ad226dc91505a611b2e9088615b9f565b6000546001600160a01b03163314612e8a5760405162461bcd60e51b8152600401610a9c906155a1565b6001600160a01b038116612eeb5760405162461bcd60e51b815260206004820152602260248201527f4e657720676f7665726e616e636520697320746865207a65726f206164647265604482015261737360f01b6064820152608401610a9c565b612278816146f7565b3360005a9050612f046078614758565b6032546001600160a01b0316637ad226dc5a612f209084615b9f565b6040516001600160e01b031960e084901b16815260048101919091526001600160a01b0385166024820152604401600060405180830381600087803b158015612f6857600080fd5b505af1158015610fda573d6000803e3d6000fd5b607154607f5460408051636c2530b960e01b81526060936001600160a01b031692636c2530b992612fbb92909190600401918252602082015260400190565b600060405180830381865afa158015612fd8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611f799190810190615bc5565b60735460715460405163148140a160e21b8152607460048201526001600160a01b0392831660248201529082166044820152908216606482015260009073__$1150d55cc8540ae1e6a8a840b6e83a829d$__90635205028490608401602060405180830381865af4158015613079573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122679190615d11565b6125da6078613ad7565b6071546040516307b8c36760e51b81526001600160a01b038381166004830152600092169063f7186ce090602401602060405180830381865afa158015613079573d6000803e3d6000fd5b600080613117836001600160a01b039081166000908152607560205260409020541690565b90506001600160a01b0381166131625760405162461bcd60e51b815260206004820152601060248201526f2ab735b737bbb71037b832b930ba37b960811b6044820152606401610a9c565b60715460405163439f18fd60e11b81526001600160a01b0383811660048301529091169063873e31fa90602401602060405180830381865afa1580156131ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131d091906159bc565b9392505050565b604051635fc3290960e11b8152607460048201526001600160a01b038216602482015260009073__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063bf86521290604401612226565b82546001600160a01b0316156132845760405162461bcd60e51b815260206004820152602260248201527f536f72746974696f6e20506f6f6c206164647265737320616c72656164792073604482015261195d60f21b6064820152608401610a9c565b60018301546001600160a01b0316156132e95760405162461bcd60e51b815260206004820152602160248201527f444b472056616c696461746f72206164647265737320616c72656164792073656044820152601d60fa1b6064820152608401610a9c565b82546001600160a01b03199081166001600160a01b03938416178455600190930180549093169116179055565b600181015415801561332a57506002810154155b6133765760405162461bcd60e51b815260206004820152601e60248201527f5365656420656e74727920616c726561647920696e697469616c697a656400006044820152606401610a9c565b61339760405180606001604052806040815260200161612a604091396136c9565b8051600183015560200151600290910155565b8154600160401b90046001600160401b0316156134055760405162461bcd60e51b815260206004820152601960248201527852656c6179207265717565737420696e2070726f677265737360381b6044820152606401610a9c565b600390910180546001600160601b03909216600160401b0273ffffffffffffffffffffffff000000000000000019909216919091179055565b600061344986613a24565b600481111561345a5761345a6154b1565b146134a35760405162461bcd60e51b815260206004820152601960248201527843757272656e74207374617465206973206e6f742049444c4560381b6044820152606401610a9c565b600084116135195760405162461bcd60e51b815260206004820152603a60248201527f526573756c74206368616c6c656e676520706572696f64206c656e677468207360448201527f686f756c642062652067726561746572207468616e207a65726f0000000000006064820152608401610a9c565b600082116135875760405162461bcd60e51b815260206004820152603560248201527f526573756c74207375626d697373696f6e2074696d656f75742073686f756c646044820152742062652067726561746572207468616e207a65726f60581b6064820152608401610a9c565b8181106136195760405162461bcd60e51b815260206004820152605460248201527f5375626d697474657220707265636564656e636520706572696f64206c656e6760448201527f74682073686f756c64206265206c657373207468616e2074686520726573756c6064820152731d081cdd589b5a5cdcda5bdb881d1a5b595bdd5d60621b608482015260a401610a9c565b600285019390935560038401919091556004830155600590910155565b8254600160401b90046001600160401b0316156136915760405162461bcd60e51b815260206004820152601960248201527852656c6179207265717565737420696e2070726f677265737360381b6044820152606401610a9c565b6003909201805463ffffffff9384166401000000000267ffffffffffffffff199091169390921692909217179055565b600490910155565b6040805180820190915260008082526020820152815160401461372e5760405162461bcd60e51b815260206004820152601760248201527f496e76616c6964204731206279746573206c656e6774680000000000000000006044820152606401610a9c565b5060208181015160409283015183518085019094529083529082015290565b60038101545a10156122785760405162461bcd60e51b815260206004820152601960248201527f4e6f7420656e6f75676820657874726120676173206c656674000000000000006044820152606401610a9c565b600082600001600084600101846001600160401b0316815481106137c7576137c76158b1565b90600052602060002001548152602001908152602001600020905092915050565b6040805181815260608181018352916000919060208201818036833750508451602095860151958301525060408101939093525090919050565b600061382d83613ddc565b600061383884613ff7565b6001600160401b0316116138815760405162461bcd60e51b815260206004820152601060248201526f4e6f206163746976652067726f75707360801b6044820152606401610a9c565b600061388c84613ff7565b61389f906001600160401b0316846159ef565b905060006138b6856138b187856147d7565b6147f3565b95945050505050565b8154600160401b90046001600160401b0316156139285760405162461bcd60e51b815260206004820152602160248201527f416e6f746865722072656c6179207265717565737420696e2070726f677265736044820152607360f81b6064820152608401610a9c565b815460009083908290613943906001600160401b0316615e8c565b82546101009290920a6001600160401b038181021990931682841691820217909355855477ffffffffffffffffffffffffffffffff00000000000000001916600160401b840267ffffffffffffffff60801b191617600160801b86841602176001600160c01b0316600160c01b43909316929092029190911785556040805180820190915260018601548152600286015460208201529092507fdf86f752d80d21879cbd208ba1d036c03f836b1d7f8f887b0b9e0b63f8a49f5d908490613a09906137e8565b604051613a17929190615eb2565b60405180910390a2505050565b805460408051632938b58d60e21b815290516000926001600160a01b03169163a4e2d6349160048083019260209291908290030181865afa158015613a6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a919190615d11565b15613ad25750600681015460019015613ad2576002905060488260060154613ab99190615bb2565b431115613ad25750600a81015460039015613ad2575060045b919050565b6000613ae282613a24565b6004811115613af357613af36154b1565b14613b3c5760405162461bcd60e51b815260206004820152601960248201527843757272656e74207374617465206973206e6f742049444c4560381b6044820152606401610a9c565b6040517f5c3ed2397d4d21298b2fb5027ac8e2d42e3c9c72bbb55ddb030e2a36a0cdff6b90600090a1805460408051637c1e845d60e11b815290516001600160a01b039092169163f83d08ba9160048082019260009290919082900301818387803b158015611f5957600080fd5b613bb48282614889565b15613c0b5760405162461bcd60e51b815260206004820152602160248201527f47726f757020686173206265656e20616c7265616479207465726d696e6174656044820152601960fa1b6064820152608401610a9c565b600182600001600084600101846001600160401b031681548110613c3157613c316158b1565b60009182526020808320919091015483528201929092526040018120600301805460ff1916921515929092179091556002830180546001908101808355918352613c7a91615b9f565b90505b600081118015613cda57506001600160401b03821660028401613ca1600184615b9f565b81548110613cb157613cb16158b1565b6000918252602090912060048204015460039091166008026101000a90046001600160401b0316115b15613d885760028301613cee600183615b9f565b81548110613cfe57613cfe6158b1565b90600052602060002090600491828204019190066008029054906101000a90046001600160401b0316836002018281548110613d3c57613d3c6158b1565b90600052602060002090600491828204019190066008026101000a8154816001600160401b0302191690836001600160401b031602179055508080613d8090615ed4565b915050613c7d565b81836002018281548110613d9e57613d9e6158b1565b90600052602060002090600491828204019190066008026101000a8154816001600160401b0302191690836001600160401b03160217905550505050565b600181015460038201546001600160401b0316108015613e36575060038101546001820180544392613e3492859290916001600160401b0316908110613e2457613e246158b1565b90600052602060002001546148d9565b105b15613e80576003810180546001600160401b0316906000613e5683615e8c565b91906101000a8154816001600160401b0302191690836001600160401b0316021790555050613ddc565b60005b600282015481101561145357816002018181548110613ea457613ea46158b1565b6000918252602090912060048204015460038481015492166008026101000a90046001600160401b0390811691161115613fe557805b6002830154613eeb90600190615b9f565b811015613f9b5760028301613f01826001615bb2565b81548110613f1157613f116158b1565b90600052602060002090600491828204019190066008029054906101000a90046001600160401b0316836002018281548110613f4f57613f4f6158b1565b90600052602060002090600491828204019190066008026101000a8154816001600160401b0302191690836001600160401b031602179055508080613f9390615b54565b915050613eda565b5081600201805480613faf57613faf615eeb565b60008281526020902060046000199092019182040180546001600160401b03600860038516026101000a02191690559055613e83565b80613fef81615b54565b915050613e83565b6001810154600090810361400d57506000919050565b60028201546003830154600184015460009291614035916001600160401b0390911690615b9f565b6131d09190615b9f565b614048826148fb565b6140945760405162461bcd60e51b815260206004820152601e60248201527f52656c6179207265717565737420646964206e6f742074696d65206f757400006044820152606401610a9c565b81546040516001600160401b03600160801b83048116808352600160401b90930416919082907fc28be0fa97c9083fa79881ba8950c1333fb45ec5100d2b893ec0f41544e78bef9060200160405180910390a283546fffffffffffffffffffffffffffffffff16600160801b6001600160401b03858116919091026001600160c01b031691909117600160c01b43831602178555604080518082019091526001860154815260028601546020820152908316907fdf86f752d80d21879cbd208ba1d036c03f836b1d7f8f887b0b9e0b63f8a49f5d908590614174906137e8565b604051611338929190615eb2565b61418b816148fb565b6141d75760405162461bcd60e51b815260206004820152601e60248201527f52656c6179207265717565737420646964206e6f742074696d65206f757400006044820152606401610a9c565b80546040516001600160401b03600160801b830481168252600160401b909204909116907fc28be0fa97c9083fa79881ba8950c1333fb45ec5100d2b893ec0f41544e78bef9060200160405180910390a280546001600160401b03169055565b600161424282613a24565b6004811115614253576142536154b1565b146142705760405162461bcd60e51b8152600401610a9c90615f01565b6040517f68c52f05452e81639fa06f379aee3178cddee4725521fff886f244c99e868b5090600090a16122788161450d565b6000806142ae8661496f565b90506142bc86868686614a04565b90505b949350505050565b60016142d283613a24565b60048111156142e3576142e36154b1565b146143005760405162461bcd60e51b8152600401610a9c90615f01565b60405181907fb2ad26c2940889d79df2ee9c758a8aefa00c5ca90eee119af0e5d795df3b98bb90600090a2436006830155600790910155565b82546001600160a01b031615612288578254604051631bfaf51960e21b8152600481018490524360248201526001600160a01b0390911690636febd464908390604401600060405180830381600088803b15801561439657600080fd5b5087f1935050505080156143a8575060015b61228857604080518381524360208201527f5e2af61e77ec91022b1cafe282abce475bb18e8cdd47083464caa06583fe39099101610b1d565b6143ea84614cf4565b43106144385760405162461bcd60e51b815260206004820152601f60248201527f52656c617920656e74727920736f66742074696d656f757420706173736564006044820152606401610a9c565b610c7684848484614a04565b60008383604051614456929190615b8f565b604080519182900390912060008181526020889052919091209091508061447e858783615f89565b50600281018390554360018083019190915586810180549182018155600090815260209020018290556040516144b79086908690615b8f565b6040519081900390206001878101546144d09190615b9f565b6001600160401b03167f4c0666db2c51896711b100d1f4f5d20a347c59e6e16ad8f365ed81ff97358b4e60405160405180910390a3505050505050565b600060068201819055600782018190556008820181905560098201819055600a820181905581546040805163a69df4b560e01b815290516001600160a01b039092169263a69df4b59260048084019382900301818387803b158015611f5957600080fd5b6000600361457e83613a24565b600481111561458f5761458f6154b1565b14801561226757506004820154600883015460068401546145b290604890615bb2565b6145bc9190615bb2565b6145c69190615bb2565b431192915050565b6080811461461e5760405162461bcd60e51b815260206004820181905260248201527f496e76616c6964206c656e677468206f6620746865207075626c6963206b65796044820152606401610a9c565b60008282604051614630929190615b8f565b604080519182900390912060008181526020879052919091206001015490915015610c765760405162461bcd60e51b815260206004820152603160248201527f47726f757020776974682074686973207075626c6963206b65792077617320616044820152701b1c9958591e481c9959da5cdd195c9959607a1b6064820152608401610a9c565b6000436146dc8485600101856001600160401b031681548110613e2457613e246158b1565b101580156131d057506146ef8383614889565b159392505050565b600080546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce80910160405180910390a15050565b61476181614571565b6147a55760405162461bcd60e51b81526020600482015260156024820152741112d1c81a185cc81b9bdd081d1a5b5959081bdd5d605a1b6044820152606401610a9c565b6040517f2852b3e178dd281713b041c3d90b4815bb55b7ec812931d1e8e8d8bb2ed72d3e90600090a16122788161450d565b60038201546000906131d09083906001600160401b0316616048565b600081815b60028501546001600160401b038216101561488157816001600160401b031685600201826001600160401b031681548110614835576148356158b1565b6000918252602090912060048204015460039091166008026101000a90046001600160401b03161161486f578161486b81615e8c565b9250505b8061487981615e8c565b9150506147f8565b509392505050565b600082600001600084600101846001600160401b0316815481106148af576148af6158b1565b6000918252602080832090910154835282019290925260400190206003015460ff16905092915050565b600482015460008281526020849052604081206001015490916131d091615bb2565b6003810154600090819061491f9063ffffffff64010000000082048116911661606f565b63ffffffff16905061494283546001600160401b03600160401b90910416151590565b80156131d057508254614966908290600160c01b90046001600160401b0316615bb2565b43119392505050565b60008061497b83614cf4565b9050804311156149fb5760006149918243615b9f565b6003850154909150640100000000900463ffffffff168111156149c357506003830154640100000000900463ffffffff165b6003840154640100000000810463ffffffff16906149f190600160401b90046001600160601b03168361608c565b6142bf91906160a3565b50600092915050565b8354600160401b90046001600160401b0316614a625760405162461bcd60e51b815260206004820152601c60248201527f4e6f2072656c6179207265717565737420696e2070726f6772657373000000006044820152606401610a9c565b614a6b846148fb565b15614ab85760405162461bcd60e51b815260206004820152601760248201527f52656c617920726571756573742074696d6564206f75740000000000000000006044820152606401610a9c565b73__$b5930e1c3596d61eae714f9835468f05d3$__63b6087a0f614b64838054614ae190615940565b80601f0160208091040260200160405190810160405280929190818152602001828054614b0d90615940565b8015614b5a5780601f10614b2f57610100808354040283529160200191614b5a565b820191906000526020600020905b815481529060010190602001808311614b3d57829003601f168201915b5050505050614d2f565b86600101614ba787878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506136c992505050565b6040518463ffffffff1660e01b8152600401614bc5939291906160b7565b602060405180830381865af4158015614be2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c069190615d11565b614c425760405162461bcd60e51b815260206004820152600d60248201526c496e76616c696420656e74727960981b6044820152606401610a9c565b8354604051600160401b9091046001600160401b0316907f087df9fd862e4448d02f8b58e33a18941769c795a8b83cfb95dfaf9c92ca897e90614c8a90339087908790616104565b60405180910390a2614cd183838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506136c992505050565b80516001860155602001516002850155505081546001600160401b031690915550565b60038101548154600091614d209163ffffffff90911690600160c01b90046001600160401b0316616048565b6001600160401b031692915050565b614d37614e53565b8151608014614d885760405162461bcd60e51b815260206004820152601760248201527f496e76616c6964204732206279746573206c656e6774680000000000000000006044820152606401610a9c565b50602081810151604080840151606080860151608096870151845197880185528785019586529187019290925292855281518083019092528152808301919091529082015290565b60405180610100016040528060006001600160a01b0316815260200160006001600160a01b03168152602001614e276040518060800160405280600081526020016000815260200160008152602001600081525090565b815260200160008152602001600081526020016000815260200160008019168152602001600081525090565b60408051608081018252600091810182815260608201929092529081908152602001614e92604051806040016040528060008152602001600081525090565b905290565b6001600160601b038116811461227857600080fd5b600080600060608486031215614ec157600080fd5b8335614ecc81614e97565b92506020840135614edc81614e97565b91506040840135614eec81614e97565b809150509250925092565b6001600160a01b038116811461227857600080fd5b600080600060608486031215614f2157600080fd5b8335614ecc81614ef7565b6020808252825182820181905260009190848201906040850190845b81811015614f6457835183529284019291840191600101614f48565b50909695505050505050565b600060208284031215614f8257600080fd5b81356131d081614ef7565b600060208284031215614f9f57600080fd5b81356001600160401b03811115614fb557600080fd5b820160e081850312156131d057600080fd5b6001600160401b038116811461227857600080fd5b600060208284031215614fee57600080fd5b81356131d081614fc7565b6000815180845260005b8181101561501f57602081850181015186830182015201615003565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600082516080602084015261505b60a0840182614ff9565b905060208401516040840152604084015160608401526060840151151560808401528091505092915050565b6000806000806080858703121561509d57600080fd5b5050823594602084013594506040840135936060013592509050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156150f7576150f76150b9565b604052919050565b600082601f83011261511057600080fd5b81356001600160401b03811115615129576151296150b9565b61513c601f8201601f19166020016150cf565b81815284602083860101111561515157600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561518057600080fd5b81356001600160401b0381111561519657600080fd5b6142bf848285016150ff565b60008083601f8401126151b457600080fd5b5081356001600160401b038111156151cb57600080fd5b6020830191508360208260051b85010111156151e657600080fd5b9250929050565b6000806020838503121561520057600080fd5b82356001600160401b0381111561521657600080fd5b615222858286016151a2565b90969095509350505050565b60008083601f84011261524057600080fd5b5081356001600160401b0381111561525757600080fd5b6020830191508360208285010111156151e657600080fd5b6000806000806040858703121561528557600080fd5b84356001600160401b038082111561529c57600080fd5b6152a88883890161522e565b909650945060208701359150808211156152c157600080fd5b506152ce878288016151a2565b95989497509550505050565b600080602083850312156152ed57600080fd5b82356001600160401b0381111561530357600080fd5b6152228582860161522e565b60008060008060008060c0878903121561532857600080fd5b505084359660208601359650604086013595606081013595506080810135945060a0013592509050565b60008060006040848603121561536757600080fd5b83356001600160401b0381111561537d57600080fd5b6153898682870161522e565b909790965060209590950135949350505050565b801515811461227857600080fd5b600080604083850312156153be57600080fd5b82356153c981614ef7565b915060208301356153d98161539d565b809150509250929050565b6000806000606084860312156153f957600080fd5b505081359360208301359350604090920135919050565b60008060006060848603121561542557600080fd5b833561543081614e97565b9250602084013561544081614fc7565b91506040840135614eec81614fc7565b6000806000806060858703121561546657600080fd5b84356001600160401b038082111561547d57600080fd5b615489888389016150ff565b95506020870135915061549b82614fc7565b909350604086013590808211156152c157600080fd5b634e487b7160e01b600052602160045260246000fd5b60208101600583106154e957634e487b7160e01b600052602160045260246000fd5b91905290565b6000806000806060858703121561550557600080fd5b84356001600160401b038082111561551c57600080fd5b908601906080828903121561553057600080fd5b90945060208601359350604086013590808211156152c157600080fd5b600081518084526020808501945080840160005b8381101561558357815163ffffffff1687529582019590820190600101615561565b509495945050505050565b6020815260006131d0602083018461554d565b6020808252601c908201527f43616c6c6572206973206e6f742074686520676f7665726e616e636500000000604082015260600190565b60208082526022908201527f43616c6c6572206973206e6f7420746865207374616b696e6720636f6e74726160408201526118dd60f21b606082015260800190565b6000808335601e1984360301811261563157600080fd5b83016020810192503590506001600160401b0381111561565057600080fd5b8036038213156151e657600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000808335601e1984360301811261569f57600080fd5b83016020810192503590506001600160401b038111156156be57600080fd5b8060051b36038213156151e657600080fd5b81835260006001600160fb1b038311156156e957600080fd5b8260051b80836020870137939093016020019392505050565b63ffffffff8116811461227857600080fd5b8183526000602080850194508260005b8581101561558357813561573781615702565b63ffffffff1687529582019590820190600101615724565b828152600060206040818401528335604084015261576f8185018561561a565b60e060608601526157856101208601828461565f565b9150506157956040860186615688565b603f19868403810160808801528184529192600092908501835b838110156157db57853560ff81168082146157c8578687fd5b83525094860194908601906001016157af565b506157e960608a018a61561a565b96509450818882030160a089015261580281878761565f565b9550506158126080890189615688565b94509250808786030160c088015261582b8585856156d0565b945061583a60a0890189615688565b94509250808786030160e08801525050615855838383615714565b9250505060c0840135610100840152809150509392505050565b6000806040838503121561588257600080fd5b8251915060208301516153d981615702565b6000602082840312156158a657600080fd5b81516131d081614ef7565b634e487b7160e01b600052603260045260246000fd5b600081518084526020808501945080840160005b838110156155835781516001600160a01b0316875295820195908201906001016158db565b6001600160601b038516815283602082015260018060a01b038316604082015260806060820152600061593660808301846158c7565b9695505050505050565b600181811c9082168061595457607f821691505b60208210810361597457634e487b7160e01b600052602260045260246000fd5b50919050565b60008060006060848603121561598f57600080fd5b835161599a81614ef7565b60208501519093506159ab81614ef7565b6040850151909250614eec81614ef7565b6000602082840312156159ce57600080fd5b81516131d081614e97565b634e487b7160e01b600052601260045260246000fd5b6000826159fe576159fe6159d9565b500690565b60208082528181018390526000908460408401835b86811015615a43578235615a2b81615702565b63ffffffff1682529183019190830190600101615a18565b509695505050505050565b602080825260159082015274496e76616c69642067726f7570206d656d6265727360581b604082015260600190565b60006001600160401b03821115615a9657615a966150b9565b5060051b60200190565b60006020808385031215615ab357600080fd5b82516001600160401b03811115615ac957600080fd5b8301601f81018513615ada57600080fd5b8051615aed615ae882615a7d565b6150cf565b81815260059190911b82018301908381019087831115615b0c57600080fd5b928401925b82841015615b33578351615b2481614ef7565b82529284019290840190615b11565b979650505050505050565b634e487b7160e01b600052601160045260246000fd5b600060018201615b6657615b66615b3e565b5060010190565b6001600160601b03831681526040602082015260006142bf60408301846158c7565b8183823760009101908152919050565b8181038181111561226757612267615b3e565b8082018082111561226757612267615b3e565b60006020808385031215615bd857600080fd5b82516001600160401b03811115615bee57600080fd5b8301601f81018513615bff57600080fd5b8051615c0d615ae882615a7d565b81815260059190911b82018301908381019087831115615c2c57600080fd5b928401925b82841015615b33578351615c4481615702565b82529284019290840190615c31565b604081526000615c66604083018561554d565b90508260208301529392505050565b6000808335601e19843603018112615c8c57600080fd5b8301803591506001600160401b03821115615ca657600080fd5b6020019150368190038213156151e657600080fd5b600060208284031215615ccd57600080fd5b81516131d081614fc7565b606081526000615ceb6060830186614ff9565b8281036020840152615cfd8186614ff9565b905082810360408401526159368185614ff9565b600060208284031215615d2357600080fd5b81516131d08161539d565b60008154615d3b81615940565b808552602060018381168015615d585760018114615d7257615da0565b60ff1985168884015283151560051b880183019550615da0565b866000528260002060005b85811015615d985781548a8201860152908301908401615d7d565b890184019650505b505050505092915050565b6001600160a01b038716815260a0602082015260008635615dcb81614fc7565b6001600160401b031660a0830152615de66020880188615688565b608060c0850152615dfc610120850182846156d0565b915050615e0c604089018961561a565b609f19808685030160e0870152615e2484838561565f565b9350615e3360608c018c615688565b93509150808685030161010087015250615e4e8383836156d0565b925050508281036040840152615e648188615d2e565b90508560608401528281036080840152615e7f818587615714565b9998505050505050505050565b60006001600160401b03808316818103615ea857615ea8615b3e565b6001019392505050565b6001600160401b03831681526040602082015260006142bf6040830184614ff9565b600081615ee357615ee3615b3e565b506000190190565b634e487b7160e01b600052603160045260246000fd5b60208082526022908201527f43757272656e74207374617465206973206e6f74204157414954494e475f5345604082015261115160f21b606082015260800190565b601f82111561228857600081815260208120601f850160051c81016020861015615f6a5750805b601f850160051c820191505b81811015610fda57828155600101615f76565b6001600160401b03831115615fa057615fa06150b9565b615fb483615fae8354615940565b83615f43565b6000601f841160018114615fe85760008515615fd05750838201355b600019600387901b1c1916600186901b178355610d5d565b600083815260209020601f19861690835b828110156160195786850135825560209485019460019092019101615ff9565b50868210156160365760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b6001600160401b0381811683821601908082111561606857616068615b3e565b5092915050565b63ffffffff81811683821601908082111561606857616068615b3e565b808202811582820484141761226757612267615b3e565b6000826160b2576160b26159d9565b500490565b835180518252602090810151818301528085015180516040840152810151606083015283546080830152600184015460a0830152825160c083015282015160e082015261010081016142bf565b6001600160a01b03841681526040602082018190526000906138b6908301848661565f56fe15c30f4b6cf6dbbcbdcc10fe22f54c8170aea44e198139b776d512d8f027319a1b9e8bfaf1383978231ce98e42bafc8129f473fc993cf60ce327f7d223460663a2646970667358221220623344856f46a889c9f07fc4a0c1f0526b7e079ca7ed61c3d73dde89a61c2e5264736f6c634300081100335a65726f2d61646472657373207265666572656e63650000000000000000000015c30f4b6cf6dbbcbdcc10fe22f54c8170aea44e198139b776d512d8f027319a1b9e8bfaf1383978231ce98e42bafc8129f473fc993cf60ce327f7d223460663", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106103c55760003560e01c80637e33cba6116101ff578063c35d64ea1161011a578063e03e4535116100ad578063f5ee563f1161007c578063f5ee563f14610a0b578063f7186ce014610a39578063f854a27f14610a4c578063fd2a478814610a5f57600080fd5b8063e03e4535146109ca578063e686440f146109df578063ea3a5a8f146109f2578063f0820c92146109fa57600080fd5b8063ccfd3bbe116100e9578063ccfd3bbe14610970578063d38bfff414610983578063d855c63114610996578063ded56d451461099e57600080fd5b8063c35d64ea14610909578063c7c49c981461091c578063c9bacaad14610948578063cb8b37791461095b57600080fd5b8063a04e298011610192578063b53dacdf11610161578063b53dacdf146108bf578063b54a2374146108d2578063bf4ebe31146108e5578063c09975cd146108f657600080fd5b8063a04e298014610852578063a7f0b3de14610865578063b0d010d61461086d578063b142f85c1461088057600080fd5b80638f105e37116101ce5780638f105e37146107e7578063985e6487146108015780639a7d0935146108145780639c9de0281461082757600080fd5b80637e33cba614610785578063818680d4146107b057806388a59590146107c357806388ef69d0146107d457600080fd5b80634cf088d9116102ef57806368c349481161028257806377a5a7bd1161025157806377a5a7bd146106ef5780637b14729e146107025780637b35b4e61461075f5780637e0049fd1461077257600080fd5b806368c34948146106915780636a7f7a901461069957806374024ab7146106ac57806375e0ae5a146106dc57600080fd5b8063592b2abd116102be578063592b2abd146105bf5780635aa6e675146106585780635c5b38701461066b578063663032cd1461067e57600080fd5b80634cf088d914610541578063529023011461056c57806355b64bcc1461059957806357665912146105ac57600080fd5b8063319ac1011161036757806342d866931161033657806342d86693146104f55780634368ec0c146105085780634549cc4b1461051b5780634a07068e1461052e57600080fd5b8063319ac1011461047c578063339646ac1461049c5780633682a450146104af5780633ea478aa146104c257600080fd5b80631872ea94116103a35780631872ea94146103fa5780631c5b0762146104185780631d35fa631461042b578063313767661461046957600080fd5b80630519e991146103ca57806314a85474146103df578063167f0517146103f2575b600080fd5b6103dd6103d8366004614eac565b610a72565b005b6103dd6103ed366004614f0c565b610b2a565b6103dd610bfa565b610402610c7c565b60405161040f9190614f2c565b60405180910390f35b6103dd610426366004614f70565b610cd7565b608b5460665460408051600160401b9093046001600160601b0390811684528083166020850152600160601b9092049091169082015260600161040f565b6103dd610477366004614f8d565b610d64565b61048f61048a366004614fdc565b610fe2565b60405161040f919061503f565b6103dd6104aa366004615087565b6110d8565b6103dd6104bd366004614f70565b611165565b6104e56104d0366004614f70565b60706020526000908152604090205460ff1681565b604051901515815260200161040f565b6103dd610503366004614f70565b6111ac565b6103dd610516366004614f70565b611346565b61048f61052936600461516e565b611457565b6103dd61053c3660046151ed565b611492565b607354610554906001600160a01b031681565b6040516001600160a01b03909116815260200161040f565b606754606854606954606a545b60408051948552602085019390935291830152606082015260800161040f565b6103dd6105a736600461526f565b611800565b6103dd6105ba3660046152da565b611b99565b6105c7611ca2565b60405161040f919060006101608201905060018060a01b03808451168352806020850151166020840152506040830151805160408401526020810151606084015260408101516080840152606081015160a084015250606083015160c0830152608083015160e083015260a083015161010083015260c083015161012083015260e083015161014083015292915050565b600054610554906001600160a01b031681565b6103dd610679366004614f8d565b611d2d565b6103dd61068c366004614f70565b611ee8565b6104e5611f6d565b6103dd6106a7366004614f0c565b611f7e565b608b546064546040805163ffffffff8085168252640100000000909404909316602084015282015260600161040f565b6103dd6106ea366004614f70565b612006565b6103dd6106fd36600461530f565b612059565b6107306074546001600160601b038116916001600160401b03600160601b8304811692600160a01b90041690565b604080516001600160601b0390941684526001600160401b03928316602085015291169082015260600161040f565b6103dd61076d366004614f70565b6120f9565b6103dd610780366004614f8d565b612181565b610798610793366004614f70565b6121d4565b6040516001600160601b03909116815260200161040f565b6103dd6107be366004614fdc565b61226d565b606b54606c54606d54606e54610579565b6103dd6107e2366004615352565b61227b565b608854600160401b90046001600160401b031615156104e5565b6103dd61080f3660046153ab565b61228d565b6103dd6108223660046153e4565b612316565b61083a610835366004614f70565b61238f565b6040516001600160401b03909116815260200161040f565b6103dd610860366004615410565b612413565b6103dd61251a565b6103dd61087b366004615087565b6125dc565b606554608754607a54607b54607c54607d54604080519687526020870195909552938501929092526060840152608083015260a082015260c00161040f565b6103dd6108cd366004615450565b61265f565b607154610554906001600160a01b031681565b608c546001600160a01b0316610554565b603254610554906001600160a01b031681565b607254610554906001600160a01b031681565b61055461092a366004614f70565b6001600160a01b039081166000908152607560205260409020541690565b6103dd610956366004614f0c565b612b1c565b610963612ba4565b60405161040f91906154c7565b6103dd61097e3660046154ef565b612bb0565b6103dd610991366004614f70565b612e60565b6103dd612ef4565b6105546109ac366004614f70565b6001600160a01b039081166000908152607660205260409020541690565b6109d2612f7c565b60405161040f919061558e565b6104e56109ed366004614f70565b613000565b6103dd61309d565b6074546001600160601b0316610798565b610a2b610a19366004614fdc565b606f6020526000908152604090205481565b60405190815260200161040f565b6104e5610a47366004614f70565b6130a7565b610798610a5a366004614f70565b6130f2565b610798610a6d366004614f70565b6131d7565b6000546001600160a01b03163314610aa55760405162461bcd60e51b8152600401610a9c906155a1565b60405180910390fd5b610ab06088846133aa565b606680546001600160601b038481166001600160c01b03199092168217600160601b858316908102919091179093556040805191871682526020820192909252908101919091527f1eda09aaee2b21bbf5571b06eab42dd1b2c2b629a5d6336230ff8b0e1f538276906060015b60405180910390a1505050565b6073546001600160a01b03163314610b545760405162461bcd60e51b8152600401610a9c906155d8565b60735460715460405163117964a560e21b8152607460048201526001600160a01b039283166024820152908216604482015290841660648201526001600160601b038084166084830152821660a482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__906345e592949060c4015b60006040518083038186803b158015610bdd57600080fd5b505af4158015610bf1573d6000803e3d6000fd5b50505050505050565b60735460715460405163520c3d3160e01b8152607460048201526001600160a01b0392831660248201529116604482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063520c3d319060640160006040518083038186803b158015610c6257600080fd5b505af4158015610c76573d6000803e3d6000fd5b50505050565b60606083600101805480602002602001604051908101604052809291908181526020018280548015610ccd57602002820191906000526020600020905b815481526020019060010190808311610cb9575b5050505050905090565b60735460715460405163c6e1c83960e01b8152607460048201526001600160a01b0392831660248201529082166044820152908216606482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063c6e1c839906084015b60006040518083038186803b158015610d4957600080fd5b505af4158015610d5d573d6000803e3d6000fd5b5050505050565b6040516346bf00db60e01b8152600090819073__$852b9611da141be0769f808cc0e4dd5c7d$__906346bf00db90610da390607890879060040161574f565b6040805180830381865af4158015610dbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610de3919061586f565b606654607154604051638871ca5d60e01b815263ffffffff841660048201529395509193506001600160601b0316916000916001600160a01b031690638871ca5d90602401602060405180830381865afa158015610e45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e699190615894565b60408051600180825281830190925291925060009190602080830190803683375050506001600160a01b038381166000908152607660205260409020549192501681600081518110610ebd57610ebd6158b1565b6001600160a01b039283166020918202929092010152607354606a546040516383ddba8f60e01b815291909216916383ddba8f91610f0391879133908790600401615900565b600060405180830381600087803b158015610f1d57600080fd5b505af1925050508015610f2e575060015b610f8357604080516001600160601b03851681526001600160a01b038416602082015286917f14621289a12ab59e0737decc388bba91d929c723defb4682d5d19b9a12ecfecb910160405180910390a2610fd0565b604080516001600160601b03851681526001600160a01b038416602082015286917f88f76c659db78142f88e94db3ca791869495394c6c1b3d412ced9022dc97c9e3910160405180910390a25b610fda607861374d565b505050505050565b6040805160808101825260608082526000602083018190529282018390528101919091526110116083836137a1565b60405180608001604052908160008201805461102c90615940565b80601f016020809104026020016040519081016040528092919081815260200182805461105890615940565b80156110a55780601f1061107a576101008083540402835291602001916110a5565b820191906000526020600020905b81548152906001019060200180831161108857829003601f168201915b5050509183525050600182015460208201526002820154604082015260039091015460ff16151560609091015292915050565b6000546001600160a01b031633146111025760405162461bcd60e51b8152600401610a9c906155a1565b606784905560688390556069829055606a8190556040805185815260208101859052908101839052606081018290527fbe6727aab9b80431985c18deef80d48599397c63884c62e96959f82abd16f16d906080015b60405180910390a150505050565b604051634755926360e01b8152607460048201526001600160a01b038216602482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__90634755926390604401610d31565b6001600160a01b0381811660009081526075602052604090205416806112075760405162461bcd60e51b815260206004820152601060248201526f2ab735b737bbb71037b832b930ba37b960811b6044820152606401610a9c565b607354604051632de9480760e01b81526001600160a01b0384811660048301526000921690632de9480790602401606060405180830381865afa158015611252573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611276919061597a565b50607154604051637104c0e560e11b81526001600160a01b03868116600483015280841660248301529294506000935091169063e20981ca906044016020604051808303816000875af11580156112d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112f591906159bc565b6040516001600160601b03821681529091506001600160a01b038516907f38532b6dea69d7266fa923c7813d190be37625f2454ddfa3d93c45c79482e3fd906020015b60405180910390a250505050565b3360009081526070602052604090205460ff166113a55760405162461bcd60e51b815260206004820152601c60248201527f526571756573746572206d75737420626520617574686f72697a6564000000006044820152606401610a9c565b604080518082019091526089548152608a5460208201526000906113dc906113cc906137e8565b8051602090910120608390613822565b90506113e96088826138bf565b608c80546001600160a01b0319166001600160a01b03841617905560655460885461141d91906001600160401b03166159ef565b158015611444575060006114316078613a24565b6004811115611442576114426154b1565b145b15611453576114536078613ad7565b5050565b604080516080810182526060808252600060208084018290528385018290529183018190528451858301208152608390915291909120611011565b608854600160801b90046001600160401b031660006114b26083836137a1565b905083836040516020016114c7929190615a03565b604051602081830303815290604052805190602001208160020154146114ff5760405162461bcd60e51b8152600401610a9c90615a4e565b608b54607154604051637bfcd47d60e11b8152600160401b9092046001600160601b0316916000916001600160a01b03169063f7f9a8fa906115479089908990600401615a03565b600060405180830381865afa158015611564573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261158c9190810190615aa0565b9050600081516001600160401b038111156115a9576115a96150b9565b6040519080825280602002602001820160405280156115d2578160200160208202803683370190505b50905060005b82518110156116585761161c8382815181106115f6576115f66158b1565b60200260200101516001600160a01b039081166000908152607660205260409020541690565b82828151811061162e5761162e6158b1565b6001600160a01b03909216602092830291909101909101528061165081615b54565b9150506115d8565b506073546068546040516383ddba8f60e01b81526001600160a01b03909216916383ddba8f916116919187919033908790600401615900565b600060405180830381600087803b1580156116ab57600080fd5b505af19250505080156116bc575060015b61171457608854604051600160401b9091046001600160401b0316907f678dcbc52328cedef940fe45ab75280e81c09ec03fe55df62e67642aa18bc278906117079086908690615b6d565b60405180910390a2611764565b608854604051600160401b9091046001600160401b0316907f6e1369aebaf86903bf1f0ab69c3edd0cadbf0534635f699f57a74a3ce54d37189061175b9086908690615b6d565b60405180910390a25b61176f608386613baa565b6117796083613ddc565b60006117856083613ff7565b6001600160401b031611156117ca57604080518082019091526089548152608a5460208201526117b8906113cc906137e8565b94506117c560888661403f565b610bf1565b6117d46088614182565b60016117e06078613a24565b60048111156117f1576117f16154b1565b03610bf157610bf16078614237565b60005a6088549091506001600160401b03600160401b820481169160009161183391608391600160801b909104166137a1565b90508484604051602001611848929190615a03565b604051602081830303815290604052805190602001208160020154146118805760405162461bcd60e51b8152600401610a9c90615a4e565b600061188f60888989856142a2565b90506001600160601b03811615611a9d57607154604051637bfcd47d60e11b81526000916001600160a01b03169063f7f9a8fa906118d3908a908a90600401615a03565b600060405180830381865afa1580156118f0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119189190810190615aa0565b9050600081516001600160401b03811115611935576119356150b9565b60405190808252806020026020018201604052801561195e578160200160208202803683370190505b50905060005b82518110156119be576119828382815181106115f6576115f66158b1565b828281518110611994576119946158b1565b6001600160a01b0390921660209283029190910190910152806119b681615b54565b915050611964565b5060735460405163f07f91c560e01b81526001600160a01b039091169063f07f91c5906119f19086908590600401615b6d565b600060405180830381600087803b158015611a0b57600080fd5b505af1925050508015611a1c575060015b611a5f57847fd3f7d9c595537a55b26b224409f386868056764bc4d55bf8c3d86e20d047afc18484604051611a52929190615b6d565b60405180910390a2611a9a565b847f94af8e9c35b4ede2a77f659b202b1efe096bf99f0e6f5dd5905c800978a9a6478484604051611a91929190615b6d565b60405180910390a25b50505b6001611aa96078613a24565b6004811115611aba57611aba6154b1565b03611ae357611ae38888604051611ad2929190615b8f565b6040519081900390206078906142c7565b611b0b8888604051611af6929190615b8f565b604051908190039020606454608c9190614339565b603254606e546001600160a01b0390911690637ad226dc905a611b2e9088615b9f565b611b389190615bb2565b6040516001600160e01b031960e084901b1681526004810191909152336024820152604401600060405180830381600087803b158015611b7757600080fd5b505af1158015611b8b573d6000803e3d6000fd5b505050505050505050505050565b60005a608854909150600090611bc190608390600160801b90046001600160401b03166137a1565b9050611bd060888585846143e1565b6001611bdc6078613a24565b6004811115611bed57611bed6154b1565b03611c0557611c058484604051611ad2929190615b8f565b611c188484604051611af6929190615b8f565b603254606e546001600160a01b0390911690637ad226dc905a611c3b9086615b9f565b611c459190615bb2565b6040516001600160e01b031960e084901b1681526004810191909152336024820152604401600060405180830381600087803b158015611c8457600080fd5b505af1158015611c98573d6000803e3d6000fd5b5050505050505050565b611caa614dd0565b5060408051610100810182526078546001600160a01b03908116825260795416602080830191909152825160808082018552607a548252607b5492820192909252607c5481850152607d5460608083019190915293830152607e5492820192909252607f5482820152905460a082015260815460c082015260825460e082015290565b60005a60405163716ae95760e01b815290915060009073__$852b9611da141be0769f808cc0e4dd5c7d$__9063716ae95790611d7090607890879060040161574f565b600060405180830381865af4158015611d8d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611db59190810190615bc5565b805190915015611e33576071546067546001600160a01b039091169063942f6892908390611de39042615bb2565b6040518363ffffffff1660e01b8152600401611e00929190615c53565b600060405180830381600087803b158015611e1a57600080fd5b505af1158015611e2e573d6000803e3d6000fd5b505050505b611e51611e436020850185615c75565b6083919060c0870135614444565b611e5b607861450d565b603254606c546001600160a01b0390911690637ad226dc905a611e7e9086615b9f565b606b54611e8b9190615bb2565b611e959190615bb2565b6040516001600160e01b031960e084901b1681526004810191909152336024820152604401600060405180830381600087803b158015611ed457600080fd5b505af1158015610bf1573d6000803e3d6000fd5b6000546001600160a01b03163314611f125760405162461bcd60e51b8152600401610a9c906155a1565b607154604051632a59250560e21b81526001600160a01b0383811660048301529091169063a964941490602401600060405180830381600087803b158015611f5957600080fd5b505af1158015610d5d573d6000803e3d6000fd5b6000611f796078614571565b905090565b6073546001600160a01b03163314611fa85760405162461bcd60e51b8152600401610a9c906155d8565b604051636dc1282760e11b8152607460048201526001600160a01b03841660248201526001600160601b0380841660448301528216606482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063db82504e90608401610bc5565b6073546040516304a3b6b360e31b8152607460048201526001600160a01b039182166024820152908216604482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063251db59890606401610d31565b6000546001600160a01b031633146120835760405162461bcd60e51b8152600401610a9c906155a1565b6065869055608785905561209b60788585858561343e565b6040805187815260208101879052908101859052606081018490526080810183905260a081018290527f88243406f452bee756e4fff4cb19e6855a5d3b7bfab8814ea6838685e08da0939060c00160405180910390a1505050505050565b6000546001600160a01b031633146121235760405162461bcd60e51b8152600401610a9c906155a1565b6040516001600160a01b03821681527f0e2d2343d31b085b7c4e56d1c8a6ec79f7ab07460386f1c9a1756239fe2533ac9060200160405180910390a1603280546001600160a01b0319166001600160a01b0392909216919091179055565b61219a6121916020830183615c75565b608391906145ce565b6040516305149aaf60e51b815273__$852b9611da141be0769f808cc0e4dd5c7d$__9063a29355e090610d3190607890859060040161574f565b607354604051635c359a0f60e11b8152607460048201526001600160a01b039182166024820152908216604482015260009073__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063b86b341e906064015b602060405180830381865af4158015612243573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061226791906159bc565b92915050565b612278608382613baa565b50565b6122886083848484614444565b505050565b6000546001600160a01b031633146122b75760405162461bcd60e51b8152600401610a9c906155a1565b6001600160a01b038216600081815260706020908152604091829020805460ff191685151590811790915591519182527fb4d9db68405970190721d2b3726fc9f728c1413038755e60518dea67d5545556910160405180910390a25050565b6000546001600160a01b031633146123405760405162461bcd60e51b8152600401610a9c906155a1565b606481905561235160888484613636565b60408051848152602081018490529081018290527fea9006ae23cd9b51dbfbc9d747fc3b0bc77acba4fefba609c76f8e9a9513602e90606001610b1d565b604051624f4ac760e01b8152607460048201526001600160a01b038216602482015260009073__$1150d55cc8540ae1e6a8a840b6e83a829d$__90624f4ac790604401602060405180830381865af41580156123ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122679190615cbb565b6000546001600160a01b0316331461243d5760405162461bcd60e51b8152600401610a9c906155a1565b604051633d36f3fd60e21b8152607460048201526001600160601b03841660248201526001600160401b0380841660448301528216606482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063f4dbcff49060840160006040518083038186803b1580156124ae57600080fd5b505af41580156124c2573d6000803e3d6000fd5b5050604080516001600160601b03871681526001600160401b0380871660208301528516918101919091527f544b726e42801bb47073854eeedae851903f66fe32a5bd24e626e10b90027b5192506060019050610b1d565b6125246083613ff7565b6001600160401b0316156125715760405162461bcd60e51b81526020600482015260146024820152734e6f74206177616974696e672067656e6573697360601b6044820152606401610a9c565b61257b6078613ad7565b6125da7f4574c8c75d6e88acd28f7e467dac97b5c60c3838d9dad993900bdf402152228e436040516020016125ba929190918252602082015260400190565b60408051601f1981840301815291905280516020909101206078906142c7565b565b6000546001600160a01b031633146126065760405162461bcd60e51b8152600401610a9c906155a1565b606b849055606c839055606d829055606e8190556040805185815260208101859052908101839052606081018290527feffd28b20afc0bf9349e8d49d5346c7568689b661a6bcd71c26a939b57b0acd190608001611157565b600061266c6083856137a1565b60405180608001604052908160008201805461268790615940565b80601f01602080910402602001604051908101604052809291908181526020018280546126b390615940565b80156127005780601f106126d557610100808354040283529160200191612700565b820191906000526020600020905b8154815290600101906020018083116126e357829003601f168201915b5050505050815260200160018201548152602001600282015481526020016003820160009054906101000a900460ff1615151515815250509050828260405160200161274d929190615a03565b604051602081830303815290604052805190602001208160400151146127855760405162461bcd60e51b8152600401610a9c90615a4e565b8060600151156127d75760405162461bcd60e51b815260206004820152601a60248201527f47726f75702063616e6e6f74206265207465726d696e617465640000000000006044820152606401610a9c565b8051604080513360601b6bffffffffffffffffffffffff191660208201528151601481830301815260348201928390526339c6c5f160e21b90925273__$b5930e1c3596d61eae714f9835468f05d3$__9263e71b17c49261283c928a90603801615cd8565b602060405180830381865af4158015612859573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061287d9190615d11565b6128bd5760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b6044820152606401610a9c565b6128c8608385613baa565b607154604051637bfcd47d60e11b81526000916001600160a01b03169063f7f9a8fa906128fb9087908790600401615a03565b600060405180830381865afa158015612918573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526129409190810190615aa0565b9050600081516001600160401b0381111561295d5761295d6150b9565b604051908082528060200260200182016040528015612986578160200160208202803683370190505b50905060005b82518110156129e6576129aa8382815181106115f6576115f66158b1565b8282815181106129bc576129bc6158b1565b6001600160a01b0390921660209283029190910190910152806129de81615b54565b91505061298c565b506073546066546069546040516383ddba8f60e01b81526001600160a01b03909316926383ddba8f92612a3192600160601b9091046001600160601b03169133908790600401615900565b600060405180830381600087803b158015612a4b57600080fd5b505af1925050508015612a5c575060015b612abc576066546040516001600160401b038816917ffd4a5a45de3194b94e2a7954706ac9023b7c9935cf1a25242691da2a94d720d491612aaf91600160601b90046001600160601b0316908690615b6d565b60405180910390a2610bf1565b6066546040516001600160401b038816917fa311dcb2a3eb32651a722488f4f281b3f8e4ab05abcd8a37a5c7d663bba5a88591612b0b91600160601b90046001600160601b0316908690615b6d565b60405180910390a250505050505050565b6073546001600160a01b03163314612b465760405162461bcd60e51b8152600401610a9c906155d8565b604051633558d21760e21b8152607460048201526001600160a01b03841660248201526001600160601b0380841660448301528216606482015273__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063d563485c90608401610bc5565b6000611f796078613a24565b60005a90506000612bc46020870187614fdc565b6001600160401b0381166000908152606f60205260409020549091508514612c1e5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c6964206e6f6e636560981b6044820152606401610a9c565b612c296083826146b7565b612c6b5760405162461bcd60e51b815260206004820152601360248201527247726f7570206973206e6f742061637469766560681b6044820152606401610a9c565b6000612c786083836137a1565b90508484604051602001612c8d929190615a03565b60405160208183030381529060405280519060200120816002015414612cc55760405162461bcd60e51b8152600401610a9c90615a4e565b60715460405163fc21976b60e01b815260009173__$1ba5315bb273adc70a9cc339490e63eb09$__9163fc21976b91612d16916001600160a01b03909116908c9087908d908d908d90600401615dab565b600060405180830381865af4158015612d33573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612d5b9190810190615bc5565b6001600160401b0384166000908152606f60205260408120805492935090612d8283615b54565b9091555050604080518881523360208201526001600160401b038516917f3ca10b33fda0a4adbc75ac1939659a06e8c332b8f6a2792bedbf8741e4268417910160405180910390a26071546067546001600160a01b039091169063942f6892908390612dee9042615bb2565b6040518363ffffffff1660e01b8152600401612e0b929190615c53565b600060405180830381600087803b158015612e2557600080fd5b505af1158015612e39573d6000803e3d6000fd5b5050603254606d546001600160a01b039091169250637ad226dc91505a611b2e9088615b9f565b6000546001600160a01b03163314612e8a5760405162461bcd60e51b8152600401610a9c906155a1565b6001600160a01b038116612eeb5760405162461bcd60e51b815260206004820152602260248201527f4e657720676f7665726e616e636520697320746865207a65726f206164647265604482015261737360f01b6064820152608401610a9c565b612278816146f7565b3360005a9050612f046078614758565b6032546001600160a01b0316637ad226dc5a612f209084615b9f565b6040516001600160e01b031960e084901b16815260048101919091526001600160a01b0385166024820152604401600060405180830381600087803b158015612f6857600080fd5b505af1158015610fda573d6000803e3d6000fd5b607154607f5460408051636c2530b960e01b81526060936001600160a01b031692636c2530b992612fbb92909190600401918252602082015260400190565b600060405180830381865afa158015612fd8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611f799190810190615bc5565b60735460715460405163148140a160e21b8152607460048201526001600160a01b0392831660248201529082166044820152908216606482015260009073__$1150d55cc8540ae1e6a8a840b6e83a829d$__90635205028490608401602060405180830381865af4158015613079573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122679190615d11565b6125da6078613ad7565b6071546040516307b8c36760e51b81526001600160a01b038381166004830152600092169063f7186ce090602401602060405180830381865afa158015613079573d6000803e3d6000fd5b600080613117836001600160a01b039081166000908152607560205260409020541690565b90506001600160a01b0381166131625760405162461bcd60e51b815260206004820152601060248201526f2ab735b737bbb71037b832b930ba37b960811b6044820152606401610a9c565b60715460405163439f18fd60e11b81526001600160a01b0383811660048301529091169063873e31fa90602401602060405180830381865afa1580156131ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131d091906159bc565b9392505050565b604051635fc3290960e11b8152607460048201526001600160a01b038216602482015260009073__$1150d55cc8540ae1e6a8a840b6e83a829d$__9063bf86521290604401612226565b82546001600160a01b0316156132845760405162461bcd60e51b815260206004820152602260248201527f536f72746974696f6e20506f6f6c206164647265737320616c72656164792073604482015261195d60f21b6064820152608401610a9c565b60018301546001600160a01b0316156132e95760405162461bcd60e51b815260206004820152602160248201527f444b472056616c696461746f72206164647265737320616c72656164792073656044820152601d60fa1b6064820152608401610a9c565b82546001600160a01b03199081166001600160a01b03938416178455600190930180549093169116179055565b600181015415801561332a57506002810154155b6133765760405162461bcd60e51b815260206004820152601e60248201527f5365656420656e74727920616c726561647920696e697469616c697a656400006044820152606401610a9c565b61339760405180606001604052806040815260200161612a604091396136c9565b8051600183015560200151600290910155565b8154600160401b90046001600160401b0316156134055760405162461bcd60e51b815260206004820152601960248201527852656c6179207265717565737420696e2070726f677265737360381b6044820152606401610a9c565b600390910180546001600160601b03909216600160401b0273ffffffffffffffffffffffff000000000000000019909216919091179055565b600061344986613a24565b600481111561345a5761345a6154b1565b146134a35760405162461bcd60e51b815260206004820152601960248201527843757272656e74207374617465206973206e6f742049444c4560381b6044820152606401610a9c565b600084116135195760405162461bcd60e51b815260206004820152603a60248201527f526573756c74206368616c6c656e676520706572696f64206c656e677468207360448201527f686f756c642062652067726561746572207468616e207a65726f0000000000006064820152608401610a9c565b600082116135875760405162461bcd60e51b815260206004820152603560248201527f526573756c74207375626d697373696f6e2074696d656f75742073686f756c646044820152742062652067726561746572207468616e207a65726f60581b6064820152608401610a9c565b8181106136195760405162461bcd60e51b815260206004820152605460248201527f5375626d697474657220707265636564656e636520706572696f64206c656e6760448201527f74682073686f756c64206265206c657373207468616e2074686520726573756c6064820152731d081cdd589b5a5cdcda5bdb881d1a5b595bdd5d60621b608482015260a401610a9c565b600285019390935560038401919091556004830155600590910155565b8254600160401b90046001600160401b0316156136915760405162461bcd60e51b815260206004820152601960248201527852656c6179207265717565737420696e2070726f677265737360381b6044820152606401610a9c565b6003909201805463ffffffff9384166401000000000267ffffffffffffffff199091169390921692909217179055565b600490910155565b6040805180820190915260008082526020820152815160401461372e5760405162461bcd60e51b815260206004820152601760248201527f496e76616c6964204731206279746573206c656e6774680000000000000000006044820152606401610a9c565b5060208181015160409283015183518085019094529083529082015290565b60038101545a10156122785760405162461bcd60e51b815260206004820152601960248201527f4e6f7420656e6f75676820657874726120676173206c656674000000000000006044820152606401610a9c565b600082600001600084600101846001600160401b0316815481106137c7576137c76158b1565b90600052602060002001548152602001908152602001600020905092915050565b6040805181815260608181018352916000919060208201818036833750508451602095860151958301525060408101939093525090919050565b600061382d83613ddc565b600061383884613ff7565b6001600160401b0316116138815760405162461bcd60e51b815260206004820152601060248201526f4e6f206163746976652067726f75707360801b6044820152606401610a9c565b600061388c84613ff7565b61389f906001600160401b0316846159ef565b905060006138b6856138b187856147d7565b6147f3565b95945050505050565b8154600160401b90046001600160401b0316156139285760405162461bcd60e51b815260206004820152602160248201527f416e6f746865722072656c6179207265717565737420696e2070726f677265736044820152607360f81b6064820152608401610a9c565b815460009083908290613943906001600160401b0316615e8c565b82546101009290920a6001600160401b038181021990931682841691820217909355855477ffffffffffffffffffffffffffffffff00000000000000001916600160401b840267ffffffffffffffff60801b191617600160801b86841602176001600160c01b0316600160c01b43909316929092029190911785556040805180820190915260018601548152600286015460208201529092507fdf86f752d80d21879cbd208ba1d036c03f836b1d7f8f887b0b9e0b63f8a49f5d908490613a09906137e8565b604051613a17929190615eb2565b60405180910390a2505050565b805460408051632938b58d60e21b815290516000926001600160a01b03169163a4e2d6349160048083019260209291908290030181865afa158015613a6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a919190615d11565b15613ad25750600681015460019015613ad2576002905060488260060154613ab99190615bb2565b431115613ad25750600a81015460039015613ad2575060045b919050565b6000613ae282613a24565b6004811115613af357613af36154b1565b14613b3c5760405162461bcd60e51b815260206004820152601960248201527843757272656e74207374617465206973206e6f742049444c4560381b6044820152606401610a9c565b6040517f5c3ed2397d4d21298b2fb5027ac8e2d42e3c9c72bbb55ddb030e2a36a0cdff6b90600090a1805460408051637c1e845d60e11b815290516001600160a01b039092169163f83d08ba9160048082019260009290919082900301818387803b158015611f5957600080fd5b613bb48282614889565b15613c0b5760405162461bcd60e51b815260206004820152602160248201527f47726f757020686173206265656e20616c7265616479207465726d696e6174656044820152601960fa1b6064820152608401610a9c565b600182600001600084600101846001600160401b031681548110613c3157613c316158b1565b60009182526020808320919091015483528201929092526040018120600301805460ff1916921515929092179091556002830180546001908101808355918352613c7a91615b9f565b90505b600081118015613cda57506001600160401b03821660028401613ca1600184615b9f565b81548110613cb157613cb16158b1565b6000918252602090912060048204015460039091166008026101000a90046001600160401b0316115b15613d885760028301613cee600183615b9f565b81548110613cfe57613cfe6158b1565b90600052602060002090600491828204019190066008029054906101000a90046001600160401b0316836002018281548110613d3c57613d3c6158b1565b90600052602060002090600491828204019190066008026101000a8154816001600160401b0302191690836001600160401b031602179055508080613d8090615ed4565b915050613c7d565b81836002018281548110613d9e57613d9e6158b1565b90600052602060002090600491828204019190066008026101000a8154816001600160401b0302191690836001600160401b03160217905550505050565b600181015460038201546001600160401b0316108015613e36575060038101546001820180544392613e3492859290916001600160401b0316908110613e2457613e246158b1565b90600052602060002001546148d9565b105b15613e80576003810180546001600160401b0316906000613e5683615e8c565b91906101000a8154816001600160401b0302191690836001600160401b0316021790555050613ddc565b60005b600282015481101561145357816002018181548110613ea457613ea46158b1565b6000918252602090912060048204015460038481015492166008026101000a90046001600160401b0390811691161115613fe557805b6002830154613eeb90600190615b9f565b811015613f9b5760028301613f01826001615bb2565b81548110613f1157613f116158b1565b90600052602060002090600491828204019190066008029054906101000a90046001600160401b0316836002018281548110613f4f57613f4f6158b1565b90600052602060002090600491828204019190066008026101000a8154816001600160401b0302191690836001600160401b031602179055508080613f9390615b54565b915050613eda565b5081600201805480613faf57613faf615eeb565b60008281526020902060046000199092019182040180546001600160401b03600860038516026101000a02191690559055613e83565b80613fef81615b54565b915050613e83565b6001810154600090810361400d57506000919050565b60028201546003830154600184015460009291614035916001600160401b0390911690615b9f565b6131d09190615b9f565b614048826148fb565b6140945760405162461bcd60e51b815260206004820152601e60248201527f52656c6179207265717565737420646964206e6f742074696d65206f757400006044820152606401610a9c565b81546040516001600160401b03600160801b83048116808352600160401b90930416919082907fc28be0fa97c9083fa79881ba8950c1333fb45ec5100d2b893ec0f41544e78bef9060200160405180910390a283546fffffffffffffffffffffffffffffffff16600160801b6001600160401b03858116919091026001600160c01b031691909117600160c01b43831602178555604080518082019091526001860154815260028601546020820152908316907fdf86f752d80d21879cbd208ba1d036c03f836b1d7f8f887b0b9e0b63f8a49f5d908590614174906137e8565b604051611338929190615eb2565b61418b816148fb565b6141d75760405162461bcd60e51b815260206004820152601e60248201527f52656c6179207265717565737420646964206e6f742074696d65206f757400006044820152606401610a9c565b80546040516001600160401b03600160801b830481168252600160401b909204909116907fc28be0fa97c9083fa79881ba8950c1333fb45ec5100d2b893ec0f41544e78bef9060200160405180910390a280546001600160401b03169055565b600161424282613a24565b6004811115614253576142536154b1565b146142705760405162461bcd60e51b8152600401610a9c90615f01565b6040517f68c52f05452e81639fa06f379aee3178cddee4725521fff886f244c99e868b5090600090a16122788161450d565b6000806142ae8661496f565b90506142bc86868686614a04565b90505b949350505050565b60016142d283613a24565b60048111156142e3576142e36154b1565b146143005760405162461bcd60e51b8152600401610a9c90615f01565b60405181907fb2ad26c2940889d79df2ee9c758a8aefa00c5ca90eee119af0e5d795df3b98bb90600090a2436006830155600790910155565b82546001600160a01b031615612288578254604051631bfaf51960e21b8152600481018490524360248201526001600160a01b0390911690636febd464908390604401600060405180830381600088803b15801561439657600080fd5b5087f1935050505080156143a8575060015b61228857604080518381524360208201527f5e2af61e77ec91022b1cafe282abce475bb18e8cdd47083464caa06583fe39099101610b1d565b6143ea84614cf4565b43106144385760405162461bcd60e51b815260206004820152601f60248201527f52656c617920656e74727920736f66742074696d656f757420706173736564006044820152606401610a9c565b610c7684848484614a04565b60008383604051614456929190615b8f565b604080519182900390912060008181526020889052919091209091508061447e858783615f89565b50600281018390554360018083019190915586810180549182018155600090815260209020018290556040516144b79086908690615b8f565b6040519081900390206001878101546144d09190615b9f565b6001600160401b03167f4c0666db2c51896711b100d1f4f5d20a347c59e6e16ad8f365ed81ff97358b4e60405160405180910390a3505050505050565b600060068201819055600782018190556008820181905560098201819055600a820181905581546040805163a69df4b560e01b815290516001600160a01b039092169263a69df4b59260048084019382900301818387803b158015611f5957600080fd5b6000600361457e83613a24565b600481111561458f5761458f6154b1565b14801561226757506004820154600883015460068401546145b290604890615bb2565b6145bc9190615bb2565b6145c69190615bb2565b431192915050565b6080811461461e5760405162461bcd60e51b815260206004820181905260248201527f496e76616c6964206c656e677468206f6620746865207075626c6963206b65796044820152606401610a9c565b60008282604051614630929190615b8f565b604080519182900390912060008181526020879052919091206001015490915015610c765760405162461bcd60e51b815260206004820152603160248201527f47726f757020776974682074686973207075626c6963206b65792077617320616044820152701b1c9958591e481c9959da5cdd195c9959607a1b6064820152608401610a9c565b6000436146dc8485600101856001600160401b031681548110613e2457613e246158b1565b101580156131d057506146ef8383614889565b159392505050565b600080546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce80910160405180910390a15050565b61476181614571565b6147a55760405162461bcd60e51b81526020600482015260156024820152741112d1c81a185cc81b9bdd081d1a5b5959081bdd5d605a1b6044820152606401610a9c565b6040517f2852b3e178dd281713b041c3d90b4815bb55b7ec812931d1e8e8d8bb2ed72d3e90600090a16122788161450d565b60038201546000906131d09083906001600160401b0316616048565b600081815b60028501546001600160401b038216101561488157816001600160401b031685600201826001600160401b031681548110614835576148356158b1565b6000918252602090912060048204015460039091166008026101000a90046001600160401b03161161486f578161486b81615e8c565b9250505b8061487981615e8c565b9150506147f8565b509392505050565b600082600001600084600101846001600160401b0316815481106148af576148af6158b1565b6000918252602080832090910154835282019290925260400190206003015460ff16905092915050565b600482015460008281526020849052604081206001015490916131d091615bb2565b6003810154600090819061491f9063ffffffff64010000000082048116911661606f565b63ffffffff16905061494283546001600160401b03600160401b90910416151590565b80156131d057508254614966908290600160c01b90046001600160401b0316615bb2565b43119392505050565b60008061497b83614cf4565b9050804311156149fb5760006149918243615b9f565b6003850154909150640100000000900463ffffffff168111156149c357506003830154640100000000900463ffffffff165b6003840154640100000000810463ffffffff16906149f190600160401b90046001600160601b03168361608c565b6142bf91906160a3565b50600092915050565b8354600160401b90046001600160401b0316614a625760405162461bcd60e51b815260206004820152601c60248201527f4e6f2072656c6179207265717565737420696e2070726f6772657373000000006044820152606401610a9c565b614a6b846148fb565b15614ab85760405162461bcd60e51b815260206004820152601760248201527f52656c617920726571756573742074696d6564206f75740000000000000000006044820152606401610a9c565b73__$b5930e1c3596d61eae714f9835468f05d3$__63b6087a0f614b64838054614ae190615940565b80601f0160208091040260200160405190810160405280929190818152602001828054614b0d90615940565b8015614b5a5780601f10614b2f57610100808354040283529160200191614b5a565b820191906000526020600020905b815481529060010190602001808311614b3d57829003601f168201915b5050505050614d2f565b86600101614ba787878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506136c992505050565b6040518463ffffffff1660e01b8152600401614bc5939291906160b7565b602060405180830381865af4158015614be2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c069190615d11565b614c425760405162461bcd60e51b815260206004820152600d60248201526c496e76616c696420656e74727960981b6044820152606401610a9c565b8354604051600160401b9091046001600160401b0316907f087df9fd862e4448d02f8b58e33a18941769c795a8b83cfb95dfaf9c92ca897e90614c8a90339087908790616104565b60405180910390a2614cd183838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506136c992505050565b80516001860155602001516002850155505081546001600160401b031690915550565b60038101548154600091614d209163ffffffff90911690600160c01b90046001600160401b0316616048565b6001600160401b031692915050565b614d37614e53565b8151608014614d885760405162461bcd60e51b815260206004820152601760248201527f496e76616c6964204732206279746573206c656e6774680000000000000000006044820152606401610a9c565b50602081810151604080840151606080860151608096870151845197880185528785019586529187019290925292855281518083019092528152808301919091529082015290565b60405180610100016040528060006001600160a01b0316815260200160006001600160a01b03168152602001614e276040518060800160405280600081526020016000815260200160008152602001600081525090565b815260200160008152602001600081526020016000815260200160008019168152602001600081525090565b60408051608081018252600091810182815260608201929092529081908152602001614e92604051806040016040528060008152602001600081525090565b905290565b6001600160601b038116811461227857600080fd5b600080600060608486031215614ec157600080fd5b8335614ecc81614e97565b92506020840135614edc81614e97565b91506040840135614eec81614e97565b809150509250925092565b6001600160a01b038116811461227857600080fd5b600080600060608486031215614f2157600080fd5b8335614ecc81614ef7565b6020808252825182820181905260009190848201906040850190845b81811015614f6457835183529284019291840191600101614f48565b50909695505050505050565b600060208284031215614f8257600080fd5b81356131d081614ef7565b600060208284031215614f9f57600080fd5b81356001600160401b03811115614fb557600080fd5b820160e081850312156131d057600080fd5b6001600160401b038116811461227857600080fd5b600060208284031215614fee57600080fd5b81356131d081614fc7565b6000815180845260005b8181101561501f57602081850181015186830182015201615003565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600082516080602084015261505b60a0840182614ff9565b905060208401516040840152604084015160608401526060840151151560808401528091505092915050565b6000806000806080858703121561509d57600080fd5b5050823594602084013594506040840135936060013592509050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156150f7576150f76150b9565b604052919050565b600082601f83011261511057600080fd5b81356001600160401b03811115615129576151296150b9565b61513c601f8201601f19166020016150cf565b81815284602083860101111561515157600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561518057600080fd5b81356001600160401b0381111561519657600080fd5b6142bf848285016150ff565b60008083601f8401126151b457600080fd5b5081356001600160401b038111156151cb57600080fd5b6020830191508360208260051b85010111156151e657600080fd5b9250929050565b6000806020838503121561520057600080fd5b82356001600160401b0381111561521657600080fd5b615222858286016151a2565b90969095509350505050565b60008083601f84011261524057600080fd5b5081356001600160401b0381111561525757600080fd5b6020830191508360208285010111156151e657600080fd5b6000806000806040858703121561528557600080fd5b84356001600160401b038082111561529c57600080fd5b6152a88883890161522e565b909650945060208701359150808211156152c157600080fd5b506152ce878288016151a2565b95989497509550505050565b600080602083850312156152ed57600080fd5b82356001600160401b0381111561530357600080fd5b6152228582860161522e565b60008060008060008060c0878903121561532857600080fd5b505084359660208601359650604086013595606081013595506080810135945060a0013592509050565b60008060006040848603121561536757600080fd5b83356001600160401b0381111561537d57600080fd5b6153898682870161522e565b909790965060209590950135949350505050565b801515811461227857600080fd5b600080604083850312156153be57600080fd5b82356153c981614ef7565b915060208301356153d98161539d565b809150509250929050565b6000806000606084860312156153f957600080fd5b505081359360208301359350604090920135919050565b60008060006060848603121561542557600080fd5b833561543081614e97565b9250602084013561544081614fc7565b91506040840135614eec81614fc7565b6000806000806060858703121561546657600080fd5b84356001600160401b038082111561547d57600080fd5b615489888389016150ff565b95506020870135915061549b82614fc7565b909350604086013590808211156152c157600080fd5b634e487b7160e01b600052602160045260246000fd5b60208101600583106154e957634e487b7160e01b600052602160045260246000fd5b91905290565b6000806000806060858703121561550557600080fd5b84356001600160401b038082111561551c57600080fd5b908601906080828903121561553057600080fd5b90945060208601359350604086013590808211156152c157600080fd5b600081518084526020808501945080840160005b8381101561558357815163ffffffff1687529582019590820190600101615561565b509495945050505050565b6020815260006131d0602083018461554d565b6020808252601c908201527f43616c6c6572206973206e6f742074686520676f7665726e616e636500000000604082015260600190565b60208082526022908201527f43616c6c6572206973206e6f7420746865207374616b696e6720636f6e74726160408201526118dd60f21b606082015260800190565b6000808335601e1984360301811261563157600080fd5b83016020810192503590506001600160401b0381111561565057600080fd5b8036038213156151e657600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000808335601e1984360301811261569f57600080fd5b83016020810192503590506001600160401b038111156156be57600080fd5b8060051b36038213156151e657600080fd5b81835260006001600160fb1b038311156156e957600080fd5b8260051b80836020870137939093016020019392505050565b63ffffffff8116811461227857600080fd5b8183526000602080850194508260005b8581101561558357813561573781615702565b63ffffffff1687529582019590820190600101615724565b828152600060206040818401528335604084015261576f8185018561561a565b60e060608601526157856101208601828461565f565b9150506157956040860186615688565b603f19868403810160808801528184529192600092908501835b838110156157db57853560ff81168082146157c8578687fd5b83525094860194908601906001016157af565b506157e960608a018a61561a565b96509450818882030160a089015261580281878761565f565b9550506158126080890189615688565b94509250808786030160c088015261582b8585856156d0565b945061583a60a0890189615688565b94509250808786030160e08801525050615855838383615714565b9250505060c0840135610100840152809150509392505050565b6000806040838503121561588257600080fd5b8251915060208301516153d981615702565b6000602082840312156158a657600080fd5b81516131d081614ef7565b634e487b7160e01b600052603260045260246000fd5b600081518084526020808501945080840160005b838110156155835781516001600160a01b0316875295820195908201906001016158db565b6001600160601b038516815283602082015260018060a01b038316604082015260806060820152600061593660808301846158c7565b9695505050505050565b600181811c9082168061595457607f821691505b60208210810361597457634e487b7160e01b600052602260045260246000fd5b50919050565b60008060006060848603121561598f57600080fd5b835161599a81614ef7565b60208501519093506159ab81614ef7565b6040850151909250614eec81614ef7565b6000602082840312156159ce57600080fd5b81516131d081614e97565b634e487b7160e01b600052601260045260246000fd5b6000826159fe576159fe6159d9565b500690565b60208082528181018390526000908460408401835b86811015615a43578235615a2b81615702565b63ffffffff1682529183019190830190600101615a18565b509695505050505050565b602080825260159082015274496e76616c69642067726f7570206d656d6265727360581b604082015260600190565b60006001600160401b03821115615a9657615a966150b9565b5060051b60200190565b60006020808385031215615ab357600080fd5b82516001600160401b03811115615ac957600080fd5b8301601f81018513615ada57600080fd5b8051615aed615ae882615a7d565b6150cf565b81815260059190911b82018301908381019087831115615b0c57600080fd5b928401925b82841015615b33578351615b2481614ef7565b82529284019290840190615b11565b979650505050505050565b634e487b7160e01b600052601160045260246000fd5b600060018201615b6657615b66615b3e565b5060010190565b6001600160601b03831681526040602082015260006142bf60408301846158c7565b8183823760009101908152919050565b8181038181111561226757612267615b3e565b8082018082111561226757612267615b3e565b60006020808385031215615bd857600080fd5b82516001600160401b03811115615bee57600080fd5b8301601f81018513615bff57600080fd5b8051615c0d615ae882615a7d565b81815260059190911b82018301908381019087831115615c2c57600080fd5b928401925b82841015615b33578351615c4481615702565b82529284019290840190615c31565b604081526000615c66604083018561554d565b90508260208301529392505050565b6000808335601e19843603018112615c8c57600080fd5b8301803591506001600160401b03821115615ca657600080fd5b6020019150368190038213156151e657600080fd5b600060208284031215615ccd57600080fd5b81516131d081614fc7565b606081526000615ceb6060830186614ff9565b8281036020840152615cfd8186614ff9565b905082810360408401526159368185614ff9565b600060208284031215615d2357600080fd5b81516131d08161539d565b60008154615d3b81615940565b808552602060018381168015615d585760018114615d7257615da0565b60ff1985168884015283151560051b880183019550615da0565b866000528260002060005b85811015615d985781548a8201860152908301908401615d7d565b890184019650505b505050505092915050565b6001600160a01b038716815260a0602082015260008635615dcb81614fc7565b6001600160401b031660a0830152615de66020880188615688565b608060c0850152615dfc610120850182846156d0565b915050615e0c604089018961561a565b609f19808685030160e0870152615e2484838561565f565b9350615e3360608c018c615688565b93509150808685030161010087015250615e4e8383836156d0565b925050508281036040840152615e648188615d2e565b90508560608401528281036080840152615e7f818587615714565b9998505050505050505050565b60006001600160401b03808316818103615ea857615ea8615b3e565b6001019392505050565b6001600160401b03831681526040602082015260006142bf6040830184614ff9565b600081615ee357615ee3615b3e565b506000190190565b634e487b7160e01b600052603160045260246000fd5b60208082526022908201527f43757272656e74207374617465206973206e6f74204157414954494e475f5345604082015261115160f21b606082015260800190565b601f82111561228857600081815260208120601f850160051c81016020861015615f6a5750805b601f850160051c820191505b81811015610fda57828155600101615f76565b6001600160401b03831115615fa057615fa06150b9565b615fb483615fae8354615940565b83615f43565b6000601f841160018114615fe85760008515615fd05750838201355b600019600387901b1c1916600186901b178355610d5d565b600083815260209020601f19861690835b828110156160195786850135825560209485019460019092019101615ff9565b50868210156160365760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b6001600160401b0381811683821601908082111561606857616068615b3e565b5092915050565b63ffffffff81811683821601908082111561606857616068615b3e565b808202811582820484141761226757612267615b3e565b6000826160b2576160b26159d9565b500490565b835180518252602090810151818301528085015180516040840152810151606083015283546080830152600184015460a0830152825160c083015282015160e082015261010081016142bf565b6001600160a01b03841681526040602082018190526000906138b6908301848661565f56fe15c30f4b6cf6dbbcbdcc10fe22f54c8170aea44e198139b776d512d8f027319a1b9e8bfaf1383978231ce98e42bafc8129f473fc993cf60ce327f7d223460663a2646970667358221220623344856f46a889c9f07fc4a0c1f0526b7e079ca7ed61c3d73dde89a61c2e5264736f6c63430008110033", + "linkReferences": { + "contracts/libraries/BLS.sol": { + "BLS": [ + { + "length": 20, + "start": 13157 + }, + { + "length": 20, + "start": 22027 + } + ] + }, + "contracts/libraries/BeaconAuthorization.sol": { + "BeaconAuthorization": [ + { + "length": 20, + "start": 600 + }, + { + "length": 20, + "start": 5880 + }, + { + "length": 20, + "start": 6014 + }, + { + "length": 20, + "start": 6244 + }, + { + "length": 20, + "start": 7387 + }, + { + "length": 20, + "start": 11061 + }, + { + "length": 20, + "start": 11144 + }, + { + "length": 20, + "start": 11609 + }, + { + "length": 20, + "start": 12039 + }, + { + "length": 20, + "start": 12234 + }, + { + "length": 20, + "start": 14035 + }, + { + "length": 20, + "start": 15248 + }, + { + "length": 20, + "start": 15696 + } + ] + }, + "contracts/libraries/BeaconDkg.sol": { + "BeaconDkg": [ + { + "length": 20, + "start": 6345 + }, + { + "length": 20, + "start": 10390 + }, + { + "length": 20, + "start": 11514 + } + ] + }, + "contracts/libraries/BeaconInactivity.sol": { + "BeaconInactivity": [ + { + "length": 20, + "start": 14379 + } + ] + } + }, + "deployedLinkReferences": { + "contracts/libraries/BLS.sol": { + "BLS": [ + { + "length": 20, + "start": 10260 + }, + { + "length": 20, + "start": 19130 + } + ] + }, + "contracts/libraries/BeaconAuthorization.sol": { + "BeaconAuthorization": [ + { + "length": 20, + "start": 2983 + }, + { + "length": 20, + "start": 3117 + }, + { + "length": 20, + "start": 3347 + }, + { + "length": 20, + "start": 4490 + }, + { + "length": 20, + "start": 8164 + }, + { + "length": 20, + "start": 8247 + }, + { + "length": 20, + "start": 8712 + }, + { + "length": 20, + "start": 9142 + }, + { + "length": 20, + "start": 9337 + }, + { + "length": 20, + "start": 11138 + }, + { + "length": 20, + "start": 12351 + }, + { + "length": 20, + "start": 12799 + } + ] + }, + "contracts/libraries/BeaconDkg.sol": { + "BeaconDkg": [ + { + "length": 20, + "start": 3448 + }, + { + "length": 20, + "start": 7493 + }, + { + "length": 20, + "start": 8617 + } + ] + }, + "contracts/libraries/BeaconInactivity.sol": { + "BeaconInactivity": [ + { + "length": 20, + "start": 11482 + } + ] + } + }, + "devdoc": { + "kind": "dev", + "methods": { + "approveDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))": { + "params": { + "dkgResult": "Result to approve. Must match the submitted result stored during `submitDkgResult`." + } + }, + "authorizationDecreaseRequested(address,uint96,uint96)": { + "details": "Can only be called by T staking contract." + }, + "authorizationIncreased(address,uint96,uint96)": { + "details": "Can only be called by T staking contract." + }, + "authorizationParameters()": { + "details": "The minimum authorization is also returned by `minimumAuthorization()` function, as a requirement of `IApplication` interface.", + "returns": { + "authorizationDecreaseChangePeriod": "Authorization decrease change period in seconds. It is the time, before authorization decrease delay end, during which the pending authorization decrease request can be overwritten. If set to 0, pending authorization decrease request can not be overwritten until the entire `authorizationDecreaseDelay` ends. If set to value equal `authorizationDecreaseDelay`, request can always be overwritten.", + "authorizationDecreaseDelay": "Delay in seconds that needs to pass between the time authorization decrease is requested and the time that request gets approved. Protects against free-riders earning rewards and not being active in the network.", + "minimumAuthorization": "The minimum authorization amount required so that operator can participate in the random beacon. This amount is required to execute slashing for providing a malicious DKG result or when a relay entry times out." + } + }, + "challengeDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))": { + "details": "Due to EIP-150 1/64 of the gas is not forwarded to the call, and will be kept to execute the remaining operations in the function after the call inside the try-catch. To eliminate a class of attacks related to the gas limit manipulation, this function requires an extra amount of gas to be left at the end of the execution.", + "params": { + "dkgResult": "Result to challenge. Must match the submitted result stored during `submitDkgResult`." + } + }, + "gasParameters()": { + "returns": { + "dkgResultApprovalGasOffset": "Gas that is meant to balance the DKG result approval's overall cost.", + "dkgResultSubmissionGas": "Calculated gas cost for submitting a DKG result. This will be refunded as part of the DKG approval process.", + "notifyOperatorInactivityGasOffset": "Gas that is meant to balance the operator inactivity notification cost.", + "relayEntrySubmissionGasOffset": "Gas that is meant to balance the relay entry submission cost." + } + }, + "groupCreationParameters()": { + "returns": { + "dkgResultChallengeExtraGas": "The extra gas required to be left at the end of the challenge DKG result transaction.", + "dkgResultChallengePeriodLength": "The number of blocks for which a DKG result can be challenged. Anyone can challenge DKG result for a certain number of blocks before the result is fully accepted and the group registered in the pool of active groups. If the challenge gets accepted, all operators who signed the malicious result get slashed for and the notifier gets rewarded.", + "dkgResultSubmissionTimeout": "Timeout in blocks for a group to submit the DKG result. All members are eligible to submit the DKG result. If `dkgResultSubmissionTimeout` passes without the DKG result submitted, DKG is considered as timed out and no DKG result for this group creation can be submitted anymore.", + "dkgSubmitterPrecedencePeriodLength": "Time during the DKG result approval stage when the submitter of the DKG result takes the precedence to approve the DKG result. After this time passes anyone can approve the DKG result.", + "groupCreationFrequency": "The frequency of a new group creation. Groups are created with a fixed frequency of relay requests.", + "groupLifetime": "Group lifetime in blocks. When a group reached its lifetime, it is no longer selected for new relay requests but may still be responsible for submitting relay entry if relay request assigned to that group is still pending." + } + }, + "hasDkgTimedOut()": { + "returns": { + "_0": "True if DKG timed out, false otherwise." + } + }, + "isRelayRequestInProgress()": { + "returns": { + "_0": "Flag indicating whether a relay entry request is currently in progress." + } + }, + "notifyOperatorInactivity((uint64,uint256[],bytes,uint256[]),uint256,uint32[])": { + "params": { + "claim": "Operator inactivity claim.", + "groupMembers": "Identifiers of group members.", + "nonce": "Current inactivity claim nonce for the given group. Must be the same as the stored one." + } + }, + "relayEntryParameters()": { + "returns": { + "callbackGasLimit": "Relay entry callback gas limit. This is the gas limit with which callback function provided in the relay request transaction is executed. The callback is executed with a new relay entry value in the same transaction the relay entry is submitted.", + "relayEntryHardTimeout": "Hard timeout in blocks for a group to submit the relay entry. After the soft timeout passes without relay entry submitted, all group members start getting slashed. The slashing amount increases linearly until the group submits the relay entry or until `relayEntryHardTimeout` is reached. When the hard timeout is reached, each group member will get slashed for `_relayEntrySubmissionFailureSlashingAmount`.", + "relayEntrySoftTimeout": "Soft timeout in blocks for a group to submit the relay entry. If the soft timeout is reached for submitting the relay entry, the slashing starts." + } + }, + "reportRelayEntryTimeout(uint32[])": { + "params": { + "groupMembers": "Identifiers of group members." + } + }, + "reportUnauthorizedSigning(bytes,uint64,uint32[])": { + "params": { + "groupId": "Group that is being reported for leaking a private key.", + "groupMembers": "Identifiers of group members.", + "signedMsgSender": "Signature of the sender's address as a message." + } + }, + "requestRelayEntry(address)": { + "params": { + "callbackContract": "Beacon consumer callback contract." + } + }, + "rewardParameters()": { + "returns": { + "dkgMaliciousResultNotificationRewardMultiplier": "Percentage of the staking contract malicious behavior notification reward which will be transferred to the notifier reporting about a malicious DKG result. Notifiers are rewarded from a notifiers treasury pool. For example, if notification reward is 1000 and the value of the multiplier is 5, the notifier will receive: 5% of 1000 = 50 per each operator affected.", + "relayEntryTimeoutNotificationRewardMultiplier": "Percentage of the staking contract malicious behavior notification reward which will be transferred to the notifier reporting about relay entry timeout. Notifiers are rewarded from a notifiers treasury pool. For example, if notification reward is 1000 and the value of the multiplier is 5, the notifier will receive: 5% of 1000 = 50 per each operator affected.", + "sortitionPoolRewardsBanDuration": "Duration of the sortition pool rewards ban imposed on operators who misbehaved during DKG by being inactive or disqualified and for operators that were identified by the rest of group members as inactive via `notifyOperatorInactivity`.", + "unauthorizedSigningNotificationRewardMultiplier": "Percentage of the staking contract malicious behavior notification reward which will be transferred to the notifier reporting about unauthorized signing. Notifiers are rewarded from a notifiers treasury pool. For example, if a notification reward is 1000 and the value of the multiplier is 5, the notifier will receive: 5% of 1000 = 50 per each operator affected." + } + }, + "selectGroup()": { + "returns": { + "_0": "IDs of selected group members." + } + }, + "setRequesterAuthorization(address,bool)": { + "details": "Can be called only by the contract guvnor, which should be the random beacon governance contract.", + "params": { + "isAuthorized": "True or false", + "requester": "Requester, can be a contract or EOA" + } + }, + "slashingParameters()": { + "returns": { + "maliciousDkgResultSlashingAmount": "Slashing amount for submitting a malicious DKG result. Every DKG result submitted can be challenged for the time of `dkg.ResultChallengePeriodLength`. If the DKG result submitted is challenged and proven to be malicious, the operator who submitted the malicious result is slashed for `maliciousDkgResultSlashingAmount`.", + "relayEntrySubmissionFailureSlashingAmount": "Slashing amount for not submitting relay entry. When relay entry hard timeout is reached without the relay entry submitted, each group member gets slashed for `relayEntrySubmissionFailureSlashingAmount`. If the relay entry gets submitted after the soft timeout, but before the hard timeout, each group member gets slashed proportionally to `relayEntrySubmissionFailureSlashingAmount` and the time passed since the soft deadline.", + "unauthorizedSigningSlashingAmount": "Slashing amount when an unauthorized signing has been proved, which means the private key leaked and all the group members should be punished." + } + }, + "submitDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))": { + "params": { + "dkgResult": "DKG result." + } + }, + "submitRelayEntry(bytes)": { + "params": { + "entry": "Group BLS signature over the previous entry." + } + }, + "submitRelayEntry(bytes,uint32[])": { + "params": { + "entry": "Group BLS signature over the previous entry.", + "groupMembers": "Identifiers of group members." + } + }, + "updateAuthorizationParameters(uint96,uint64,uint64)": { + "details": "Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.", + "params": { + "_authorizationDecreaseChangePeriod": "New authorization decrease change period in seconds", + "_authorizationDecreaseDelay": "New authorization decrease delay in seconds", + "_minimumAuthorization": "New minimum authorization amount" + } + }, + "updateGasParameters(uint256,uint256,uint256,uint256)": { + "details": "Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.", + "params": { + "dkgResultApprovalGasOffset": "New DKG result approval gas offset", + "dkgResultSubmissionGas": "New DKG result submission gas", + "notifyOperatorInactivityGasOffset": "New operator inactivity notification gas offset", + "relayEntrySubmissionGasOffset": "New relay entry submission gas offset" + } + }, + "updateGroupCreationParameters(uint256,uint256,uint256,uint256,uint256,uint256)": { + "details": "Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.", + "params": { + "dkgResultChallengeExtraGas": "New DKG result challenge extra gas", + "dkgResultChallengePeriodLength": "New DKG result challenge period length", + "dkgResultSubmissionTimeout": "New DKG result submission timeout", + "dkgSubmitterPrecedencePeriodLength": "New DKG result submitter precedence period length", + "groupCreationFrequency": "New group creation frequency", + "groupLifetime": "New group lifetime in blocks" + } + }, + "updateRelayEntryParameters(uint256,uint256,uint256)": { + "details": "Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.", + "params": { + "callbackGasLimit": "New callback gas limit", + "relayEntryHardTimeout": "New relay entry hard timeout", + "relayEntrySoftTimeout": "New relay entry submission soft timeout" + } + }, + "updateRewardParameters(uint256,uint256,uint256,uint256)": { + "details": "Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.", + "params": { + "dkgMaliciousResultNotificationRewardMultiplier": "New value of the DKG malicious result notification reward multiplier", + "relayEntryTimeoutNotificationRewardMultiplier": "New value of the relay entry timeout notification reward multiplier", + "sortitionPoolRewardsBanDuration": "New sortition pool rewards ban duration in seconds.", + "unauthorizedSigningNotificationRewardMultiplier": "New value of the unauthorized signing notification reward multiplier" + } + }, + "updateSlashingParameters(uint96,uint96,uint96)": { + "details": "Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.", + "params": { + "maliciousDkgResultSlashingAmount": "New malicious DKG result slashing amount", + "relayEntrySubmissionFailureSlashingAmount": "New relay entry submission failure amount", + "unauthorizedSigningSlashingAmount": "New unauthorized signing slashing amount" + } + }, + "withdrawIneligibleRewards(address)": { + "details": "Can be called only by the contract guvnor, which should be the random beacon governance contract.", + "params": { + "recipient": "Recipient of withdrawn rewards." + } + }, + "withdrawRewards(address)": { + "details": "Emits `RewardsWithdrawn` event." + } + }, + "version": 1 + }, + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract SortitionPool\",\"name\":\"_sortitionPool\",\"type\":\"address\"},{\"internalType\":\"contract IERC20\",\"name\":\"_tToken\",\"type\":\"address\"},{\"internalType\":\"contract IStaking\",\"name\":\"_staking\",\"type\":\"address\"},{\"internalType\":\"contract BeaconDkgValidator\",\"name\":\"_dkgValidator\",\"type\":\"address\"},{\"internalType\":\"contract ReimbursementPool\",\"name\":\"_reimbursementPool\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"}],\"name\":\"AuthorizationDecreaseApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"fromAmount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"toAmount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"decreasingAt\",\"type\":\"uint64\"}],\"name\":\"AuthorizationDecreaseRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"fromAmount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"toAmount\",\"type\":\"uint96\"}],\"name\":\"AuthorizationIncreased\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"minimumAuthorization\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"authorizationDecreaseDelay\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"authorizationDecreaseChangePeriod\",\"type\":\"uint64\"}],\"name\":\"AuthorizationParametersUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"entry\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"entrySubmittedBlock\",\"type\":\"uint256\"}],\"name\":\"CallbackFailed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"resultHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"slashingAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"maliciousSubmitter\",\"type\":\"address\"}],\"name\":\"DkgMaliciousResultSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"resultHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"slashingAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"maliciousSubmitter\",\"type\":\"address\"}],\"name\":\"DkgMaliciousResultSlashingFailed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"resultHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"approver\",\"type\":\"address\"}],\"name\":\"DkgResultApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"resultHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"reason\",\"type\":\"string\"}],\"name\":\"DkgResultChallenged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"resultHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"submitterMemberIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"},{\"internalType\":\"uint8[]\",\"name\":\"misbehavedMembersIndices\",\"type\":\"uint8[]\"},{\"internalType\":\"bytes\",\"name\":\"signatures\",\"type\":\"bytes\"},{\"internalType\":\"uint256[]\",\"name\":\"signingMembersIndices\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32[]\",\"name\":\"members\",\"type\":\"uint32[]\"},{\"internalType\":\"bytes32\",\"name\":\"membersHash\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"struct BeaconDkg.Result\",\"name\":\"result\",\"type\":\"tuple\"}],\"name\":\"DkgResultSubmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"DkgSeedTimedOut\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"}],\"name\":\"DkgStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"DkgStateLocked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"DkgTimedOut\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgResultSubmissionGas\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgResultApprovalGasOffset\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"notifyOperatorInactivityGasOffset\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"relayEntrySubmissionGasOffset\",\"type\":\"uint256\"}],\"name\":\"GasParametersUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldGovernance\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newGovernance\",\"type\":\"address\"}],\"name\":\"GovernanceTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"groupCreationFrequency\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"groupLifetime\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgResultChallengePeriodLength\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgResultChallengeExtraGas\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgResultSubmissionTimeout\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgResultSubmitterPrecedencePeriodLength\",\"type\":\"uint256\"}],\"name\":\"GroupCreationParametersUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"groupId\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"}],\"name\":\"GroupRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"groupId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"notifier\",\"type\":\"address\"}],\"name\":\"InactivityClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"fromAmount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"toAmount\",\"type\":\"uint96\"}],\"name\":\"InvoluntaryAuthorizationDecreaseFailed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"OperatorJoinedSortitionPool\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"OperatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"OperatorStatusUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newReimbursementPool\",\"type\":\"address\"}],\"name\":\"ReimbursementPoolUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"slashingAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"groupMembers\",\"type\":\"address[]\"}],\"name\":\"RelayEntryDelaySlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"slashingAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"groupMembers\",\"type\":\"address[]\"}],\"name\":\"RelayEntryDelaySlashingFailed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"relayEntrySoftTimeout\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"relayEntryHardTimeout\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"callbackGasLimit\",\"type\":\"uint256\"}],\"name\":\"RelayEntryParametersUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"groupId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"previousEntry\",\"type\":\"bytes\"}],\"name\":\"RelayEntryRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"entry\",\"type\":\"bytes\"}],\"name\":\"RelayEntrySubmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"terminatedGroupId\",\"type\":\"uint64\"}],\"name\":\"RelayEntryTimedOut\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"slashingAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"groupMembers\",\"type\":\"address[]\"}],\"name\":\"RelayEntryTimeoutSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"slashingAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"groupMembers\",\"type\":\"address[]\"}],\"name\":\"RelayEntryTimeoutSlashingFailed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isAuthorized\",\"type\":\"bool\"}],\"name\":\"RequesterAuthorizationUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"sortitionPoolRewardsBanDuration\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"relayEntryTimeoutNotificationRewardMultiplier\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"unauthorizedSigningNotificationRewardMultiplier\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dkgMaliciousResultNotificationRewardMultiplier\",\"type\":\"uint256\"}],\"name\":\"RewardParametersUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"RewardsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"relayEntrySubmissionFailureSlashingAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"maliciousDkgResultSlashingAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"unauthorizedSigningSlashingAmount\",\"type\":\"uint256\"}],\"name\":\"SlashingParametersUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"groupId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"unauthorizedSigningSlashingAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"groupMembers\",\"type\":\"address[]\"}],\"name\":\"UnauthorizedSigningSlashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"groupId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"unauthorizedSigningSlashingAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"groupMembers\",\"type\":\"address[]\"}],\"name\":\"UnauthorizedSigningSlashingFailed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"}],\"name\":\"approveAuthorizationDecrease\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"submitterMemberIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"},{\"internalType\":\"uint8[]\",\"name\":\"misbehavedMembersIndices\",\"type\":\"uint8[]\"},{\"internalType\":\"bytes\",\"name\":\"signatures\",\"type\":\"bytes\"},{\"internalType\":\"uint256[]\",\"name\":\"signingMembersIndices\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32[]\",\"name\":\"members\",\"type\":\"uint32[]\"},{\"internalType\":\"bytes32\",\"name\":\"membersHash\",\"type\":\"bytes32\"}],\"internalType\":\"struct BeaconDkg.Result\",\"name\":\"dkgResult\",\"type\":\"tuple\"}],\"name\":\"approveDkgResult\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"fromAmount\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"toAmount\",\"type\":\"uint96\"}],\"name\":\"authorizationDecreaseRequested\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"fromAmount\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"toAmount\",\"type\":\"uint96\"}],\"name\":\"authorizationIncreased\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"authorizationParameters\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"minimumAuthorization\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"authorizationDecreaseDelay\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"authorizationDecreaseChangePeriod\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"authorizedRequesters\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"}],\"name\":\"availableRewards\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"submitterMemberIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"},{\"internalType\":\"uint8[]\",\"name\":\"misbehavedMembersIndices\",\"type\":\"uint8[]\"},{\"internalType\":\"bytes\",\"name\":\"signatures\",\"type\":\"bytes\"},{\"internalType\":\"uint256[]\",\"name\":\"signingMembersIndices\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32[]\",\"name\":\"members\",\"type\":\"uint32[]\"},{\"internalType\":\"bytes32\",\"name\":\"membersHash\",\"type\":\"bytes32\"}],\"internalType\":\"struct BeaconDkg.Result\",\"name\":\"dkgResult\",\"type\":\"tuple\"}],\"name\":\"challengeDkgResult\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dkgLockState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"}],\"name\":\"eligibleStake\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gasParameters\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"dkgResultSubmissionGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgResultApprovalGasOffset\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"notifyOperatorInactivityGasOffset\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"relayEntrySubmissionGasOffset\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"genesis\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCallbackContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDkgData\",\"outputs\":[{\"components\":[{\"internalType\":\"contract SortitionPool\",\"name\":\"sortitionPool\",\"type\":\"address\"},{\"internalType\":\"contract BeaconDkgValidator\",\"name\":\"dkgValidator\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"resultChallengePeriodLength\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"resultChallengeExtraGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"resultSubmissionTimeout\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"submitterPrecedencePeriodLength\",\"type\":\"uint256\"}],\"internalType\":\"struct BeaconDkg.Parameters\",\"name\":\"parameters\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"startBlock\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"resultSubmissionStartBlockOffset\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"submittedResultHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"submittedResultBlock\",\"type\":\"uint256\"}],\"internalType\":\"struct BeaconDkg.Data\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"groupId\",\"type\":\"uint64\"}],\"name\":\"getGroup\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"registrationBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"membersHash\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"terminated\",\"type\":\"bool\"}],\"internalType\":\"struct Groups.Group\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"}],\"name\":\"getGroup\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"registrationBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"membersHash\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"terminated\",\"type\":\"bool\"}],\"internalType\":\"struct Groups.Group\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGroupCreationState\",\"outputs\":[{\"internalType\":\"enum BeaconDkg.State\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGroupsRegistry\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governance\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"groupCreationParameters\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"groupCreationFrequency\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"groupLifetime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgResultChallengePeriodLength\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgResultChallengeExtraGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgResultSubmissionTimeout\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgSubmitterPrecedencePeriodLength\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"hasDkgTimedOut\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"name\":\"inactivityClaimNonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"fromAmount\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"toAmount\",\"type\":\"uint96\"}],\"name\":\"involuntaryAuthorizationDecrease\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isOperatorInPool\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isOperatorUpToDate\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isRelayRequestInProgress\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"joinSortitionPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minimumAuthorization\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"notifyDkgTimeout\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"groupId\",\"type\":\"uint64\"},{\"internalType\":\"uint256[]\",\"name\":\"inactiveMembersIndices\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"signatures\",\"type\":\"bytes\"},{\"internalType\":\"uint256[]\",\"name\":\"signingMembersIndices\",\"type\":\"uint256[]\"}],\"internalType\":\"struct BeaconInactivity.Claim\",\"name\":\"claim\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint32[]\",\"name\":\"groupMembers\",\"type\":\"uint32[]\"}],\"name\":\"notifyOperatorInactivity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"operatorToStakingProvider\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"}],\"name\":\"pendingAuthorizationDecrease\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"registerOperator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reimbursementPool\",\"outputs\":[{\"internalType\":\"contract ReimbursementPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"relayEntryParameters\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"relayEntrySoftTimeout\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"relayEntryHardTimeout\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callbackGasLimit\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"}],\"name\":\"remainingAuthorizationDecreaseDelay\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32[]\",\"name\":\"groupMembers\",\"type\":\"uint32[]\"}],\"name\":\"reportRelayEntryTimeout\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"signedMsgSender\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"groupId\",\"type\":\"uint64\"},{\"internalType\":\"uint32[]\",\"name\":\"groupMembers\",\"type\":\"uint32[]\"}],\"name\":\"reportUnauthorizedSigning\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IRandomBeaconConsumer\",\"name\":\"callbackContract\",\"type\":\"address\"}],\"name\":\"requestRelayEntry\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardParameters\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"sortitionPoolRewardsBanDuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"relayEntryTimeoutNotificationRewardMultiplier\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unauthorizedSigningNotificationRewardMultiplier\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgMaliciousResultNotificationRewardMultiplier\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"groupMembersHash\",\"type\":\"bytes32\"}],\"name\":\"roughlyAddGroup\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"groupId\",\"type\":\"uint64\"}],\"name\":\"roughlyTerminateGroup\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"selectGroup\",\"outputs\":[{\"internalType\":\"uint32[]\",\"name\":\"\",\"type\":\"uint32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"isAuthorized\",\"type\":\"bool\"}],\"name\":\"setRequesterAuthorization\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"slashingParameters\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"relayEntrySubmissionFailureSlashingAmount\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"maliciousDkgResultSlashingAmount\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"unauthorizedSigningSlashingAmount\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sortitionPool\",\"outputs\":[{\"internalType\":\"contract SortitionPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"staking\",\"outputs\":[{\"internalType\":\"contract IStaking\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"}],\"name\":\"stakingProviderToOperator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"submitterMemberIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"},{\"internalType\":\"uint8[]\",\"name\":\"misbehavedMembersIndices\",\"type\":\"uint8[]\"},{\"internalType\":\"bytes\",\"name\":\"signatures\",\"type\":\"bytes\"},{\"internalType\":\"uint256[]\",\"name\":\"signingMembersIndices\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32[]\",\"name\":\"members\",\"type\":\"uint32[]\"},{\"internalType\":\"bytes32\",\"name\":\"membersHash\",\"type\":\"bytes32\"}],\"internalType\":\"struct BeaconDkg.Result\",\"name\":\"dkgResult\",\"type\":\"tuple\"}],\"name\":\"submitDkgResult\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"entry\",\"type\":\"bytes\"},{\"internalType\":\"uint32[]\",\"name\":\"groupMembers\",\"type\":\"uint32[]\"}],\"name\":\"submitRelayEntry\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"entry\",\"type\":\"bytes\"}],\"name\":\"submitRelayEntry\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"tToken\",\"outputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newGovernance\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"_minimumAuthorization\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"_authorizationDecreaseDelay\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"_authorizationDecreaseChangePeriod\",\"type\":\"uint64\"}],\"name\":\"updateAuthorizationParameters\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"dkgResultSubmissionGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgResultApprovalGasOffset\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"notifyOperatorInactivityGasOffset\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"relayEntrySubmissionGasOffset\",\"type\":\"uint256\"}],\"name\":\"updateGasParameters\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"groupCreationFrequency\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"groupLifetime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgResultChallengePeriodLength\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgResultChallengeExtraGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgResultSubmissionTimeout\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgSubmitterPrecedencePeriodLength\",\"type\":\"uint256\"}],\"name\":\"updateGroupCreationParameters\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"updateOperatorStatus\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract ReimbursementPool\",\"name\":\"_reimbursementPool\",\"type\":\"address\"}],\"name\":\"updateReimbursementPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"relayEntrySoftTimeout\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"relayEntryHardTimeout\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callbackGasLimit\",\"type\":\"uint256\"}],\"name\":\"updateRelayEntryParameters\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"sortitionPoolRewardsBanDuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"relayEntryTimeoutNotificationRewardMultiplier\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unauthorizedSigningNotificationRewardMultiplier\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgMaliciousResultNotificationRewardMultiplier\",\"type\":\"uint256\"}],\"name\":\"updateRewardParameters\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"relayEntrySubmissionFailureSlashingAmount\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"maliciousDkgResultSlashingAmount\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"unauthorizedSigningSlashingAmount\",\"type\":\"uint96\"}],\"name\":\"updateSlashingParameters\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"withdrawIneligibleRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakingProvider\",\"type\":\"address\"}],\"name\":\"withdrawRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"approveDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))\":{\"params\":{\"dkgResult\":\"Result to approve. Must match the submitted result stored during `submitDkgResult`.\"}},\"authorizationDecreaseRequested(address,uint96,uint96)\":{\"details\":\"Can only be called by T staking contract.\"},\"authorizationIncreased(address,uint96,uint96)\":{\"details\":\"Can only be called by T staking contract.\"},\"authorizationParameters()\":{\"details\":\"The minimum authorization is also returned by `minimumAuthorization()` function, as a requirement of `IApplication` interface.\",\"returns\":{\"authorizationDecreaseChangePeriod\":\"Authorization decrease change period in seconds. It is the time, before authorization decrease delay end, during which the pending authorization decrease request can be overwritten. If set to 0, pending authorization decrease request can not be overwritten until the entire `authorizationDecreaseDelay` ends. If set to value equal `authorizationDecreaseDelay`, request can always be overwritten.\",\"authorizationDecreaseDelay\":\"Delay in seconds that needs to pass between the time authorization decrease is requested and the time that request gets approved. Protects against free-riders earning rewards and not being active in the network.\",\"minimumAuthorization\":\"The minimum authorization amount required so that operator can participate in the random beacon. This amount is required to execute slashing for providing a malicious DKG result or when a relay entry times out.\"}},\"challengeDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))\":{\"details\":\"Due to EIP-150 1/64 of the gas is not forwarded to the call, and will be kept to execute the remaining operations in the function after the call inside the try-catch. To eliminate a class of attacks related to the gas limit manipulation, this function requires an extra amount of gas to be left at the end of the execution.\",\"params\":{\"dkgResult\":\"Result to challenge. Must match the submitted result stored during `submitDkgResult`.\"}},\"gasParameters()\":{\"returns\":{\"dkgResultApprovalGasOffset\":\"Gas that is meant to balance the DKG result approval's overall cost.\",\"dkgResultSubmissionGas\":\"Calculated gas cost for submitting a DKG result. This will be refunded as part of the DKG approval process.\",\"notifyOperatorInactivityGasOffset\":\"Gas that is meant to balance the operator inactivity notification cost.\",\"relayEntrySubmissionGasOffset\":\"Gas that is meant to balance the relay entry submission cost.\"}},\"groupCreationParameters()\":{\"returns\":{\"dkgResultChallengeExtraGas\":\"The extra gas required to be left at the end of the challenge DKG result transaction.\",\"dkgResultChallengePeriodLength\":\"The number of blocks for which a DKG result can be challenged. Anyone can challenge DKG result for a certain number of blocks before the result is fully accepted and the group registered in the pool of active groups. If the challenge gets accepted, all operators who signed the malicious result get slashed for and the notifier gets rewarded.\",\"dkgResultSubmissionTimeout\":\"Timeout in blocks for a group to submit the DKG result. All members are eligible to submit the DKG result. If `dkgResultSubmissionTimeout` passes without the DKG result submitted, DKG is considered as timed out and no DKG result for this group creation can be submitted anymore.\",\"dkgSubmitterPrecedencePeriodLength\":\"Time during the DKG result approval stage when the submitter of the DKG result takes the precedence to approve the DKG result. After this time passes anyone can approve the DKG result.\",\"groupCreationFrequency\":\"The frequency of a new group creation. Groups are created with a fixed frequency of relay requests.\",\"groupLifetime\":\"Group lifetime in blocks. When a group reached its lifetime, it is no longer selected for new relay requests but may still be responsible for submitting relay entry if relay request assigned to that group is still pending.\"}},\"hasDkgTimedOut()\":{\"returns\":{\"_0\":\"True if DKG timed out, false otherwise.\"}},\"isRelayRequestInProgress()\":{\"returns\":{\"_0\":\"Flag indicating whether a relay entry request is currently in progress.\"}},\"notifyOperatorInactivity((uint64,uint256[],bytes,uint256[]),uint256,uint32[])\":{\"params\":{\"claim\":\"Operator inactivity claim.\",\"groupMembers\":\"Identifiers of group members.\",\"nonce\":\"Current inactivity claim nonce for the given group. Must be the same as the stored one.\"}},\"relayEntryParameters()\":{\"returns\":{\"callbackGasLimit\":\"Relay entry callback gas limit. This is the gas limit with which callback function provided in the relay request transaction is executed. The callback is executed with a new relay entry value in the same transaction the relay entry is submitted.\",\"relayEntryHardTimeout\":\"Hard timeout in blocks for a group to submit the relay entry. After the soft timeout passes without relay entry submitted, all group members start getting slashed. The slashing amount increases linearly until the group submits the relay entry or until `relayEntryHardTimeout` is reached. When the hard timeout is reached, each group member will get slashed for `_relayEntrySubmissionFailureSlashingAmount`.\",\"relayEntrySoftTimeout\":\"Soft timeout in blocks for a group to submit the relay entry. If the soft timeout is reached for submitting the relay entry, the slashing starts.\"}},\"reportRelayEntryTimeout(uint32[])\":{\"params\":{\"groupMembers\":\"Identifiers of group members.\"}},\"reportUnauthorizedSigning(bytes,uint64,uint32[])\":{\"params\":{\"groupId\":\"Group that is being reported for leaking a private key.\",\"groupMembers\":\"Identifiers of group members.\",\"signedMsgSender\":\"Signature of the sender's address as a message.\"}},\"requestRelayEntry(address)\":{\"params\":{\"callbackContract\":\"Beacon consumer callback contract.\"}},\"rewardParameters()\":{\"returns\":{\"dkgMaliciousResultNotificationRewardMultiplier\":\"Percentage of the staking contract malicious behavior notification reward which will be transferred to the notifier reporting about a malicious DKG result. Notifiers are rewarded from a notifiers treasury pool. For example, if notification reward is 1000 and the value of the multiplier is 5, the notifier will receive: 5% of 1000 = 50 per each operator affected.\",\"relayEntryTimeoutNotificationRewardMultiplier\":\"Percentage of the staking contract malicious behavior notification reward which will be transferred to the notifier reporting about relay entry timeout. Notifiers are rewarded from a notifiers treasury pool. For example, if notification reward is 1000 and the value of the multiplier is 5, the notifier will receive: 5% of 1000 = 50 per each operator affected.\",\"sortitionPoolRewardsBanDuration\":\"Duration of the sortition pool rewards ban imposed on operators who misbehaved during DKG by being inactive or disqualified and for operators that were identified by the rest of group members as inactive via `notifyOperatorInactivity`.\",\"unauthorizedSigningNotificationRewardMultiplier\":\"Percentage of the staking contract malicious behavior notification reward which will be transferred to the notifier reporting about unauthorized signing. Notifiers are rewarded from a notifiers treasury pool. For example, if a notification reward is 1000 and the value of the multiplier is 5, the notifier will receive: 5% of 1000 = 50 per each operator affected.\"}},\"selectGroup()\":{\"returns\":{\"_0\":\"IDs of selected group members.\"}},\"setRequesterAuthorization(address,bool)\":{\"details\":\"Can be called only by the contract guvnor, which should be the random beacon governance contract.\",\"params\":{\"isAuthorized\":\"True or false\",\"requester\":\"Requester, can be a contract or EOA\"}},\"slashingParameters()\":{\"returns\":{\"maliciousDkgResultSlashingAmount\":\"Slashing amount for submitting a malicious DKG result. Every DKG result submitted can be challenged for the time of `dkg.ResultChallengePeriodLength`. If the DKG result submitted is challenged and proven to be malicious, the operator who submitted the malicious result is slashed for `maliciousDkgResultSlashingAmount`.\",\"relayEntrySubmissionFailureSlashingAmount\":\"Slashing amount for not submitting relay entry. When relay entry hard timeout is reached without the relay entry submitted, each group member gets slashed for `relayEntrySubmissionFailureSlashingAmount`. If the relay entry gets submitted after the soft timeout, but before the hard timeout, each group member gets slashed proportionally to `relayEntrySubmissionFailureSlashingAmount` and the time passed since the soft deadline.\",\"unauthorizedSigningSlashingAmount\":\"Slashing amount when an unauthorized signing has been proved, which means the private key leaked and all the group members should be punished.\"}},\"submitDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))\":{\"params\":{\"dkgResult\":\"DKG result.\"}},\"submitRelayEntry(bytes)\":{\"params\":{\"entry\":\"Group BLS signature over the previous entry.\"}},\"submitRelayEntry(bytes,uint32[])\":{\"params\":{\"entry\":\"Group BLS signature over the previous entry.\",\"groupMembers\":\"Identifiers of group members.\"}},\"updateAuthorizationParameters(uint96,uint64,uint64)\":{\"details\":\"Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.\",\"params\":{\"_authorizationDecreaseChangePeriod\":\"New authorization decrease change period in seconds\",\"_authorizationDecreaseDelay\":\"New authorization decrease delay in seconds\",\"_minimumAuthorization\":\"New minimum authorization amount\"}},\"updateGasParameters(uint256,uint256,uint256,uint256)\":{\"details\":\"Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.\",\"params\":{\"dkgResultApprovalGasOffset\":\"New DKG result approval gas offset\",\"dkgResultSubmissionGas\":\"New DKG result submission gas\",\"notifyOperatorInactivityGasOffset\":\"New operator inactivity notification gas offset\",\"relayEntrySubmissionGasOffset\":\"New relay entry submission gas offset\"}},\"updateGroupCreationParameters(uint256,uint256,uint256,uint256,uint256,uint256)\":{\"details\":\"Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.\",\"params\":{\"dkgResultChallengeExtraGas\":\"New DKG result challenge extra gas\",\"dkgResultChallengePeriodLength\":\"New DKG result challenge period length\",\"dkgResultSubmissionTimeout\":\"New DKG result submission timeout\",\"dkgSubmitterPrecedencePeriodLength\":\"New DKG result submitter precedence period length\",\"groupCreationFrequency\":\"New group creation frequency\",\"groupLifetime\":\"New group lifetime in blocks\"}},\"updateRelayEntryParameters(uint256,uint256,uint256)\":{\"details\":\"Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.\",\"params\":{\"callbackGasLimit\":\"New callback gas limit\",\"relayEntryHardTimeout\":\"New relay entry hard timeout\",\"relayEntrySoftTimeout\":\"New relay entry submission soft timeout\"}},\"updateRewardParameters(uint256,uint256,uint256,uint256)\":{\"details\":\"Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.\",\"params\":{\"dkgMaliciousResultNotificationRewardMultiplier\":\"New value of the DKG malicious result notification reward multiplier\",\"relayEntryTimeoutNotificationRewardMultiplier\":\"New value of the relay entry timeout notification reward multiplier\",\"sortitionPoolRewardsBanDuration\":\"New sortition pool rewards ban duration in seconds.\",\"unauthorizedSigningNotificationRewardMultiplier\":\"New value of the unauthorized signing notification reward multiplier\"}},\"updateSlashingParameters(uint96,uint96,uint96)\":{\"details\":\"Can be called only by the contract guvnor, which should be the random beacon governance contract. The caller is responsible for validating parameters.\",\"params\":{\"maliciousDkgResultSlashingAmount\":\"New malicious DKG result slashing amount\",\"relayEntrySubmissionFailureSlashingAmount\":\"New relay entry submission failure amount\",\"unauthorizedSigningSlashingAmount\":\"New unauthorized signing slashing amount\"}},\"withdrawIneligibleRewards(address)\":{\"details\":\"Can be called only by the contract guvnor, which should be the random beacon governance contract.\",\"params\":{\"recipient\":\"Recipient of withdrawn rewards.\"}},\"withdrawRewards(address)\":{\"details\":\"Emits `RewardsWithdrawn` event.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"approveAuthorizationDecrease(address)\":{\"notice\":\"Approves the previously registered authorization decrease request. Reverts if authorization decrease delay has not passed yet or if the authorization decrease was not requested for the given staking provider.\"},\"approveDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))\":{\"notice\":\"Approves DKG result. Can be called when the challenge period for the submitted result is finished. Considers the submitted result as valid, bans misbehaved group members from the sortition pool rewards, and completes the group creation by activating the candidate group. For the first `submitterPrecedencePeriodLength` blocks after the end of the challenge period can be called only by the DKG result submitter. After that time, can be called by anyone.\"},\"authorizationDecreaseRequested(address,uint96,uint96)\":{\"notice\":\"Used by T staking contract to inform the beacon that the authorization decrease for the given staking provider has been requested. Reverts if the amount after deauthorization would be non-zero and lower than the minimum authorization. Reverts if another authorization decrease request is pending for the staking provider and not enough time passed since the original request (see `authorizationDecreaseChangePeriod`). If the operator is not known (`registerOperator` was not called) it lets to `approveAuthorizationDecrease` immediately. If the operator is known (`registerOperator` was called), the operator needs to update state of the sortition pool with a call to `joinSortitionPool` or `updateOperatorStatus`. After the sortition pool state is in sync, authorization decrease delay starts. After authorization decrease delay passes, authorization decrease request needs to be approved with a call to `approveAuthorizationDecrease` function. If there is a pending authorization decrease request, it is overwritten, but only if enough time passed since the original request. Otherwise, the function reverts.\"},\"authorizationIncreased(address,uint96,uint96)\":{\"notice\":\"Used by T staking contract to inform the beacon that the authorized stake amount for the given staking provider increased. Reverts if the authorization amount is below the minimum. The function is not updating the sortition pool. Sortition pool state needs to be updated by the operator with a call to `joinSortitionPool` or `updateOperatorStatus`.\"},\"authorizationParameters()\":{\"notice\":\"Returns authorization-related parameters of the beacon.\"},\"authorizedRequesters(address)\":{\"notice\":\"Authorized addresses that can request a relay entry.\"},\"availableRewards(address)\":{\"notice\":\"Returns the amount of rewards available for withdrawal for the given staking provider. Reverts if staking provider has not registered the operator address.\"},\"challengeDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))\":{\"notice\":\"Challenges DKG result. If the submitted result is proved to be invalid it reverts the DKG back to the result submission phase. It removes a candidate group that was previously registered with the DKG result submission.\"},\"eligibleStake(address)\":{\"notice\":\"Returns the current value of the staking provider's eligible stake. Eligible stake is defined as the currently authorized stake minus the pending authorization decrease. Eligible stake is what is used for operator's weight in the sortition pool. If the authorized stake minus the pending authorization decrease is below the minimum authorization, eligible stake is 0.\"},\"gasParameters()\":{\"notice\":\"Returns gas-related parameters of the beacon.\"},\"genesis()\":{\"notice\":\"Triggers group selection if there are no active groups.\"},\"getGroupCreationState()\":{\"notice\":\"Check current group creation state.\"},\"groupCreationParameters()\":{\"notice\":\"Returns group-creation-related parameters of the beacon.\"},\"hasDkgTimedOut()\":{\"notice\":\"Checks if DKG timed out. The DKG timeout period includes time required for off-chain protocol execution and time for the result publication for all group members. After this time result cannot be submitted and DKG can be notified about the timeout.\"},\"inactivityClaimNonce(uint64)\":{\"notice\":\"Stores current operator inactivity claim nonce for given group. Each claim is made with an unique nonce which protects against claim replay.\"},\"involuntaryAuthorizationDecrease(address,uint96,uint96)\":{\"notice\":\"Used by T staking contract to inform the beacon the authorization has been decreased for the given staking provider involuntarily, as a result of slashing. If the operator is not known (`registerOperator` was not called) the function does nothing. The operator was never in a sortition pool so there is nothing to update. If the operator is known, sortition pool is unlocked, and the operator is in the sortition pool, the sortition pool state is updated. If the sortition pool is locked, update needs to be postponed. Every other staker is incentivized to call `updateOperatorStatus` for the problematic operator to increase their own rewards in the pool.\"},\"isOperatorInPool(address)\":{\"notice\":\"Returns true if the given operator is in the sortition pool. Otherwise, returns false.\"},\"isOperatorUpToDate(address)\":{\"notice\":\"Checks if the operator's authorized stake is in sync with operator's weight in the sortition pool. If the operator is not in the sortition pool and their authorized stake is non-zero, function returns false.\"},\"joinSortitionPool()\":{\"notice\":\"Lets the operator join the sortition pool. The operator address must be known - before calling this function, it has to be appointed by the staking provider by calling `registerOperator`. Also, the operator must have the minimum authorization required by the beacon. Function reverts if there is no minimum stake authorized or if the operator is not known. If there was an authorization decrease requested, it is activated by starting the authorization decrease delay.\"},\"minimumAuthorization()\":{\"notice\":\"The minimum authorization amount required so that operator can participate in the random beacon. This amount is required to execute slashing for providing a malicious DKG result or when a relay entry times out.\"},\"notifyDkgTimeout()\":{\"notice\":\"Notifies about DKG timeout.\"},\"notifyOperatorInactivity((uint64,uint256[],bytes,uint256[]),uint256,uint32[])\":{\"notice\":\"Notifies about operators who are inactive. Using this function, a majority of the group can decide about punishing specific group members who constantly fail doing their job. If the provided claim is proved to be valid and signed by sufficient number of group members, operators of members deemed as inactive are banned for sortition pool rewards for duration specified by `_sortitionPoolRewardsBanDuration` parameter. The sender of the claim must be one of the claim signers. This function can be called only for active and non-terminated groups.\"},\"operatorToStakingProvider(address)\":{\"notice\":\"Returns staking provider of the given operator.\"},\"pendingAuthorizationDecrease(address)\":{\"notice\":\"Returns the amount of stake that is pending authorization decrease for the given staking provider. If no authorization decrease has been requested, returns zero.\"},\"registerOperator(address)\":{\"notice\":\"Used by staking provider to set operator address that will operate a node. The given staking provider can set operator address only one time. The operator address can not be changed and must be unique. Reverts if the operator is already set for the staking provider or if the operator address is already in use. Reverts if there is a pending authorization decrease for the staking provider.\"},\"relayEntryParameters()\":{\"notice\":\"Returns relay-entry-related parameters of the beacon.\"},\"remainingAuthorizationDecreaseDelay(address)\":{\"notice\":\"Returns the remaining time in seconds that needs to pass before the requested authorization decrease can be approved. If the sortition pool state was not updated yet by the operator after requesting the authorization decrease, returns `type(uint64).max`.\"},\"reportRelayEntryTimeout(uint32[])\":{\"notice\":\"Reports a relay entry timeout.\"},\"reportUnauthorizedSigning(bytes,uint64,uint32[])\":{\"notice\":\"Reports unauthorized groups signing. Must provide a valid signature of the sender's address as a message. Successful signature verification means the private key has been leaked and all group members should be punished by slashing their tokens. Group has to be active or expired. Unauthorized signing cannot be reported for a terminated group. In case of reporting unauthorized signing for a terminated group, or when the signature is invalid, function reverts.\"},\"requestRelayEntry(address)\":{\"notice\":\"Creates a request to generate a new relay entry, which will include a random number (by signing the previous entry's random number). Requester must be previously authorized by the governance.\"},\"rewardParameters()\":{\"notice\":\"Returns reward-related parameters of the beacon.\"},\"selectGroup()\":{\"notice\":\"Selects a new group of operators. Can only be called when DKG is in progress and the pool is locked. At least one operator has to be registered in the pool, otherwise the function fails reverting the transaction.\"},\"setRequesterAuthorization(address,bool)\":{\"notice\":\"Set authorization for requesters that can request a relay entry.\"},\"slashingParameters()\":{\"notice\":\"Returns slashing-related parameters of the beacon.\"},\"stakingProviderToOperator(address)\":{\"notice\":\"Returns operator registered for the given staking provider.\"},\"submitDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))\":{\"notice\":\"`\\\\x19Ethereum signed message:\\\\n` before signing, so the message to sign is: `\\\\x19Ethereum signed message:\\\\n${keccak256(chainID,groupPubKey,misbehaved,startBlock)}`\"},\"submitRelayEntry(bytes)\":{\"notice\":\"Creates a new relay entry. Gas-optimized version that can be called only before the soft timeout. This should be the majority of cases.\"},\"submitRelayEntry(bytes,uint32[])\":{\"notice\":\"Creates a new relay entry.\"},\"transferGovernance(address)\":{\"notice\":\"Transfers governance of the contract to `newGovernance`.\"},\"updateAuthorizationParameters(uint96,uint64,uint64)\":{\"notice\":\"Updates the values of authorization parameters.\"},\"updateGasParameters(uint256,uint256,uint256,uint256)\":{\"notice\":\"Updates the values of gas parameters.\"},\"updateGroupCreationParameters(uint256,uint256,uint256,uint256,uint256,uint256)\":{\"notice\":\"Updates the values of group creation parameters.\"},\"updateOperatorStatus(address)\":{\"notice\":\"Updates status of the operator in the sortition pool. If there was an authorization decrease requested, it is activated by starting the authorization decrease delay. Function reverts if the operator is not known.\"},\"updateRelayEntryParameters(uint256,uint256,uint256)\":{\"notice\":\"Updates the values of relay entry parameters.\"},\"updateRewardParameters(uint256,uint256,uint256,uint256)\":{\"notice\":\"Updates the values of reward parameters.\"},\"updateSlashingParameters(uint96,uint96,uint96)\":{\"notice\":\"Updates the values of slashing parameters.\"},\"withdrawIneligibleRewards(address)\":{\"notice\":\"Withdraws rewards belonging to operators marked as ineligible for sortition pool rewards.\"},\"withdrawRewards(address)\":{\"notice\":\"Withdraws application rewards for the given staking provider. Rewards are withdrawn to the staking provider's beneficiary address set in the staking contract. Reverts if staking provider has not registered the operator address.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/test/RandomBeaconStub.sol\":\"RandomBeaconStub\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@keep-network/sortition-pools/contracts/Branch.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\n/// @notice The implicit 8-ary trees of the sortition pool\\n/// rely on packing 8 \\\"slots\\\" of 32-bit values into each uint256.\\n/// The Branch library permits efficient calculations on these slots.\\nlibrary Branch {\\n /// @notice Calculate the right shift required\\n /// to make the 32 least significant bits of an uint256\\n /// be the bits of the `position`th slot\\n /// when treating the uint256 as a uint32[8].\\n ///\\n /// @dev Not used for efficiency reasons,\\n /// but left to illustrate the meaning of a common pattern.\\n /// I wish solidity had macros, even C macros.\\n function slotShift(uint256 position) internal pure returns (uint256) {\\n unchecked {\\n return position * Constants.SLOT_WIDTH;\\n }\\n }\\n\\n /// @notice Return the `position`th slot of the `node`,\\n /// treating `node` as a uint32[32].\\n function getSlot(uint256 node, uint256 position)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Doing a bitwise AND with `SLOT_MAX`\\n // clears all but the 32 least significant bits.\\n // Because of the right shift by `slotShift(position)` bits,\\n // those 32 bits contain the 32 bits in the `position`th slot of `node`.\\n return (node >> shiftBits) & Constants.SLOT_MAX;\\n }\\n }\\n\\n /// @notice Return `node` with the `position`th slot set to zero.\\n function clearSlot(uint256 node, uint256 position)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Shifting `SLOT_MAX` left by `slotShift(position)` bits\\n // gives us a number where all bits of the `position`th slot are set,\\n // and all other bits are unset.\\n //\\n // Using a bitwise NOT on this number,\\n // we get a uint256 where all bits are set\\n // except for those of the `position`th slot.\\n //\\n // Bitwise ANDing the original `node` with this number\\n // sets the bits of `position`th slot to zero,\\n // leaving all other bits unchanged.\\n return node & ~(Constants.SLOT_MAX << shiftBits);\\n }\\n }\\n\\n /// @notice Return `node` with the `position`th slot set to `weight`.\\n ///\\n /// @param weight The weight of of the node.\\n /// Safely truncated to a 32-bit number,\\n /// but this should never be called with an overflowing weight regardless.\\n function setSlot(\\n uint256 node,\\n uint256 position,\\n uint256 weight\\n ) internal pure returns (uint256) {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Clear the `position`th slot like in `clearSlot()`.\\n uint256 clearedNode = node & ~(Constants.SLOT_MAX << shiftBits);\\n // Bitwise AND `weight` with `SLOT_MAX`\\n // to clear all but the 32 least significant bits.\\n //\\n // Shift this left by `slotShift(position)` bits\\n // to obtain a uint256 with all bits unset\\n // except in the `position`th slot\\n // which contains the 32-bit value of `weight`.\\n uint256 shiftedWeight = (weight & Constants.SLOT_MAX) << shiftBits;\\n // When we bitwise OR these together,\\n // all other slots except the `position`th one come from the left argument,\\n // and the `position`th gets filled with `weight` from the right argument.\\n return clearedNode | shiftedWeight;\\n }\\n }\\n\\n /// @notice Calculate the summed weight of all slots in the `node`.\\n function sumWeight(uint256 node) internal pure returns (uint256 sum) {\\n unchecked {\\n sum = node & Constants.SLOT_MAX;\\n // Iterate through each slot\\n // by shifting `node` right in increments of 32 bits,\\n // and adding the 32 least significant bits to the `sum`.\\n uint256 newNode = node >> Constants.SLOT_WIDTH;\\n while (newNode > 0) {\\n sum += (newNode & Constants.SLOT_MAX);\\n newNode = newNode >> Constants.SLOT_WIDTH;\\n }\\n return sum;\\n }\\n }\\n\\n /// @notice Pick a slot in `node` that corresponds to `index`.\\n /// Treats the node like an array of virtual stakers,\\n /// the number of virtual stakers in each slot corresponding to its weight,\\n /// and picks which slot contains the `index`th virtual staker.\\n ///\\n /// @dev Requires that `index` be lower than `sumWeight(node)`.\\n /// However, this is not enforced for performance reasons.\\n /// If `index` exceeds the permitted range,\\n /// `pickWeightedSlot()` returns the rightmost slot\\n /// and an excessively high `newIndex`.\\n ///\\n /// @return slot The slot of `node` containing the `index`th virtual staker.\\n ///\\n /// @return newIndex The index of the `index`th virtual staker of `node`\\n /// within the returned slot.\\n function pickWeightedSlot(uint256 node, uint256 index)\\n internal\\n pure\\n returns (uint256 slot, uint256 newIndex)\\n {\\n unchecked {\\n newIndex = index;\\n uint256 newNode = node;\\n uint256 currentSlotWeight = newNode & Constants.SLOT_MAX;\\n while (newIndex >= currentSlotWeight) {\\n newIndex -= currentSlotWeight;\\n slot++;\\n newNode = newNode >> Constants.SLOT_WIDTH;\\n currentSlotWeight = newNode & Constants.SLOT_MAX;\\n }\\n return (slot, newIndex);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa7fb1c9c9789f30493e9a40e24a24f46875dc5e7630b4f67478167759f6d1882\"},\"@keep-network/sortition-pools/contracts/Chaosnet.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\n/// @title Chaosnet\\n/// @notice This is a beta staker program for stakers willing to go the extra\\n/// mile with monitoring, share their logs with the dev team, and allow to more\\n/// carefully monitor the bootstrapping network. As the network matures, the\\n/// beta program will be ended.\\ncontract Chaosnet {\\n /// @notice Indicates if the chaosnet is active. The chaosnet is active\\n /// after the contract deployment and can be ended with a call to\\n /// `deactivateChaosnet()`. Once deactivated chaosnet can not be activated\\n /// again.\\n bool public isChaosnetActive;\\n\\n /// @notice Indicates if the given operator is a beta operator for chaosnet.\\n mapping(address => bool) public isBetaOperator;\\n\\n /// @notice Address controlling chaosnet status and beta operator addresses.\\n address public chaosnetOwner;\\n\\n event BetaOperatorsAdded(address[] operators);\\n\\n event ChaosnetOwnerRoleTransferred(\\n address oldChaosnetOwner,\\n address newChaosnetOwner\\n );\\n\\n event ChaosnetDeactivated();\\n\\n constructor() {\\n _transferChaosnetOwner(msg.sender);\\n isChaosnetActive = true;\\n }\\n\\n modifier onlyChaosnetOwner() {\\n require(msg.sender == chaosnetOwner, \\\"Not the chaosnet owner\\\");\\n _;\\n }\\n\\n modifier onlyOnChaosnet() {\\n require(isChaosnetActive, \\\"Chaosnet is not active\\\");\\n _;\\n }\\n\\n /// @notice Adds beta operator to chaosnet. Can be called only by the\\n /// chaosnet owner when the chaosnet is active. Once the operator is added\\n /// as a beta operator, it can not be removed.\\n function addBetaOperators(address[] calldata operators)\\n public\\n onlyOnChaosnet\\n onlyChaosnetOwner\\n {\\n for (uint256 i = 0; i < operators.length; i++) {\\n isBetaOperator[operators[i]] = true;\\n }\\n\\n emit BetaOperatorsAdded(operators);\\n }\\n\\n /// @notice Deactivates the chaosnet. Can be called only by the chaosnet\\n /// owner. Once deactivated chaosnet can not be activated again.\\n function deactivateChaosnet() public onlyOnChaosnet onlyChaosnetOwner {\\n isChaosnetActive = false;\\n emit ChaosnetDeactivated();\\n }\\n\\n /// @notice Transfers the chaosnet owner role to another non-zero address.\\n function transferChaosnetOwnerRole(address newChaosnetOwner)\\n public\\n onlyChaosnetOwner\\n {\\n require(\\n newChaosnetOwner != address(0),\\n \\\"New chaosnet owner must not be zero address\\\"\\n );\\n _transferChaosnetOwner(newChaosnetOwner);\\n }\\n\\n function _transferChaosnetOwner(address newChaosnetOwner) internal {\\n address oldChaosnetOwner = chaosnetOwner;\\n chaosnetOwner = newChaosnetOwner;\\n emit ChaosnetOwnerRoleTransferred(oldChaosnetOwner, newChaosnetOwner);\\n }\\n}\\n\",\"keccak256\":\"0xeaf7bdd5626f88c329793a012621039692ce1b6e1f13013997ddb13d7e3032df\"},\"@keep-network/sortition-pools/contracts/Constants.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nlibrary Constants {\\n ////////////////////////////////////////////////////////////////////////////\\n // Parameters for configuration\\n\\n // How many bits a position uses per level of the tree;\\n // each branch of the tree contains 2**SLOT_BITS slots.\\n uint256 constant SLOT_BITS = 3;\\n uint256 constant LEVELS = 7;\\n ////////////////////////////////////////////////////////////////////////////\\n\\n ////////////////////////////////////////////////////////////////////////////\\n // Derived constants, do not touch\\n uint256 constant SLOT_COUNT = 2**SLOT_BITS;\\n uint256 constant SLOT_WIDTH = 256 / SLOT_COUNT;\\n uint256 constant LAST_SLOT = SLOT_COUNT - 1;\\n uint256 constant SLOT_MAX = (2**SLOT_WIDTH) - 1;\\n uint256 constant POOL_CAPACITY = SLOT_COUNT**LEVELS;\\n\\n uint256 constant ID_WIDTH = SLOT_WIDTH;\\n uint256 constant ID_MAX = SLOT_MAX;\\n\\n uint256 constant BLOCKHEIGHT_WIDTH = 96 - ID_WIDTH;\\n uint256 constant BLOCKHEIGHT_MAX = (2**BLOCKHEIGHT_WIDTH) - 1;\\n\\n uint256 constant SLOT_POINTER_MAX = (2**SLOT_BITS) - 1;\\n uint256 constant LEAF_FLAG = 1 << 255;\\n\\n uint256 constant WEIGHT_WIDTH = 256 / SLOT_COUNT;\\n ////////////////////////////////////////////////////////////////////////////\\n}\\n\",\"keccak256\":\"0xaef690ced707935745ff1482b7bb9bd9eb77bf6a39c717465e64cf12db8a7d39\"},\"@keep-network/sortition-pools/contracts/Leaf.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary Leaf {\\n function make(\\n address _operator,\\n uint256 _creationBlock,\\n uint256 _id\\n ) internal pure returns (uint256) {\\n assert(_creationBlock <= type(uint64).max);\\n assert(_id <= type(uint32).max);\\n // Converting a bytesX type into a larger type\\n // adds zero bytes on the right.\\n uint256 op = uint256(bytes32(bytes20(_operator)));\\n // Bitwise AND the id to erase\\n // all but the 32 least significant bits\\n uint256 uid = _id & Constants.ID_MAX;\\n // Erase all but the 64 least significant bits,\\n // then shift left by 32 bits to make room for the id\\n uint256 cb = (_creationBlock & Constants.BLOCKHEIGHT_MAX) <<\\n Constants.ID_WIDTH;\\n // Bitwise OR them all together to get\\n // [address operator || uint64 creationBlock || uint32 id]\\n return (op | cb | uid);\\n }\\n\\n function operator(uint256 leaf) internal pure returns (address) {\\n // Converting a bytesX type into a smaller type\\n // truncates it on the right.\\n return address(bytes20(bytes32(leaf)));\\n }\\n\\n /// @notice Return the block number the leaf was created in.\\n function creationBlock(uint256 leaf) internal pure returns (uint256) {\\n return ((leaf >> Constants.ID_WIDTH) & Constants.BLOCKHEIGHT_MAX);\\n }\\n\\n function id(uint256 leaf) internal pure returns (uint32) {\\n // Id is stored in the 32 least significant bits.\\n // Bitwise AND ensures that we only get the contents of those bits.\\n return uint32(leaf & Constants.ID_MAX);\\n }\\n}\\n\",\"keccak256\":\"0xbd107a1a43e48884885e5e966ffcbcd8fa5e89863715d717bb4006e9f89cdc2b\"},\"@keep-network/sortition-pools/contracts/Position.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary Position {\\n // Return the last 3 bits of a position number,\\n // corresponding to its slot in its parent\\n function slot(uint256 a) internal pure returns (uint256) {\\n return a & Constants.SLOT_POINTER_MAX;\\n }\\n\\n // Return the parent of a position number\\n function parent(uint256 a) internal pure returns (uint256) {\\n return a >> Constants.SLOT_BITS;\\n }\\n\\n // Return the location of the child of a at the given slot\\n function child(uint256 a, uint256 s) internal pure returns (uint256) {\\n return (a << Constants.SLOT_BITS) | (s & Constants.SLOT_POINTER_MAX); // slot(s)\\n }\\n\\n // Return the uint p as a flagged position uint:\\n // the least significant 21 bits contain the position\\n // and the 22nd bit is set as a flag\\n // to distinguish the position 0x000000 from an empty field.\\n function setFlag(uint256 p) internal pure returns (uint256) {\\n return p | Constants.LEAF_FLAG;\\n }\\n\\n // Turn a flagged position into an unflagged position\\n // by removing the flag at the 22nd least significant bit.\\n //\\n // We shouldn't _actually_ need this\\n // as all position-manipulating code should ignore non-position bits anyway\\n // but it's cheap to call so might as well do it.\\n function unsetFlag(uint256 p) internal pure returns (uint256) {\\n return p & (~Constants.LEAF_FLAG);\\n }\\n}\\n\",\"keccak256\":\"0xd3a927908080ac21353a92a6bce3d69e94a5c30f6b51f16b271b6cc679f110e2\"},\"@keep-network/sortition-pools/contracts/RNG.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Leaf.sol\\\";\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary RNG {\\n /// @notice Get an index in the range `[0 .. range-1]`\\n /// and the new state of the RNG,\\n /// using the provided `state` of the RNG.\\n ///\\n /// @param range The upper bound of the index, exclusive.\\n ///\\n /// @param state The previous state of the RNG.\\n /// The initial state needs to be obtained\\n /// from a trusted randomness oracle (the random beacon),\\n /// or from a chain of earlier calls to `RNG.getIndex()`\\n /// on an originally trusted seed.\\n ///\\n /// @dev Calculates the number of bits required for the desired range,\\n /// takes the least significant bits of `state`\\n /// and checks if the obtained index is within the desired range.\\n /// The original state is hashed with `keccak256` to get a new state.\\n /// If the index is outside the range,\\n /// the function retries until it gets a suitable index.\\n ///\\n /// @return index A random integer between `0` and `range - 1`, inclusive.\\n ///\\n /// @return newState The new state of the RNG.\\n /// When `getIndex()` is called one or more times,\\n /// care must be taken to always use the output `state`\\n /// of the most recent call as the input `state` of a subsequent call.\\n /// At the end of a transaction calling `RNG.getIndex()`,\\n /// the previous stored state must be overwritten with the latest output.\\n function getIndex(\\n uint256 range,\\n bytes32 state,\\n uint256 bits\\n ) internal view returns (uint256, bytes32) {\\n bool found = false;\\n uint256 index = 0;\\n bytes32 newState = state;\\n while (!found) {\\n index = truncate(bits, uint256(newState));\\n newState = keccak256(abi.encodePacked(newState, address(this)));\\n if (index < range) {\\n found = true;\\n }\\n }\\n return (index, newState);\\n }\\n\\n /// @notice Calculate how many bits are required\\n /// for an index in the range `[0 .. range-1]`.\\n ///\\n /// @param range The upper bound of the desired range, exclusive.\\n ///\\n /// @return uint The smallest number of bits\\n /// that can contain the number `range-1`.\\n function bitsRequired(uint256 range) internal pure returns (uint256) {\\n unchecked {\\n if (range == 1) {\\n return 0;\\n }\\n\\n uint256 bits = Constants.WEIGHT_WIDTH - 1;\\n\\n // Left shift by `bits`,\\n // so we have a 1 in the (bits + 1)th least significant bit\\n // and 0 in other bits.\\n // If this number is equal or greater than `range`,\\n // the range [0, range-1] fits in `bits` bits.\\n //\\n // Because we loop from high bits to low bits,\\n // we find the highest number of bits that doesn't fit the range,\\n // and return that number + 1.\\n while (1 << bits >= range) {\\n bits--;\\n }\\n\\n return bits + 1;\\n }\\n }\\n\\n /// @notice Truncate `input` to the `bits` least significant bits.\\n function truncate(uint256 bits, uint256 input)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n return input & ((1 << bits) - 1);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x67f87f589cd5123ffa32f883ea2f09b0e56258508bae82b8c655b3c27c71eb5e\"},\"@keep-network/sortition-pools/contracts/Rewards.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\n/// @title Rewards\\n/// @notice Rewards are allocated proportionally to operators\\n/// present in the pool at payout based on their weight in the pool.\\n///\\n/// To facilitate this, we use a global accumulator value\\n/// to track the total rewards one unit of weight would've earned\\n/// since the creation of the pool.\\n///\\n/// Whenever a reward is paid, the accumulator is increased\\n/// by the size of the reward divided by the total weight\\n/// of all eligible operators in the pool.\\n///\\n/// Each operator has an individual accumulator value,\\n/// set to equal the global accumulator when the operator joins the pool.\\n/// This accumulator reflects the amount of rewards\\n/// that have already been accounted for with that operator.\\n///\\n/// Whenever an operator's weight in the pool changes,\\n/// we can update the amount of rewards the operator has earned\\n/// by subtracting the operator's accumulator from the global accumulator.\\n/// This gives us the amount of rewards one unit of weight has earned\\n/// since the last time the operator's rewards have been updated.\\n/// Then we multiply that by the operator's previous (pre-change) weight\\n/// to determine how much rewards in total the operator has earned,\\n/// and add this to the operator's earned rewards.\\n/// Finally, we set the operator's accumulator to the global accumulator value.\\ncontract Rewards {\\n struct OperatorRewards {\\n // The state of the global accumulator\\n // when the operator's rewards were last updated\\n uint96 accumulated;\\n // The amount of rewards collected by the operator after the latest update.\\n // The amount the operator could withdraw may equal `available`\\n // or it may be greater, if more rewards have been paid in since then.\\n // To evaulate the most recent amount including rewards potentially paid\\n // since the last update, use `availableRewards` function.\\n uint96 available;\\n // If nonzero, the operator is ineligible for rewards\\n // and may only re-enable rewards after the specified timestamp.\\n // XXX: unsigned 32-bit integer unix seconds, will break around 2106\\n uint32 ineligibleUntil;\\n // Locally cached weight of the operator,\\n // used to reduce the cost of setting operators ineligible.\\n uint32 weight;\\n }\\n\\n // The global accumulator of how much rewards\\n // a hypothetical operator of weight 1 would have earned\\n // since the creation of the pool.\\n uint96 internal globalRewardAccumulator;\\n // If the amount of reward tokens paid in\\n // does not divide cleanly by pool weight,\\n // the difference is recorded as rounding dust\\n // and added to the next reward.\\n uint96 internal rewardRoundingDust;\\n\\n // The amount of rewards that would've been earned by ineligible operators\\n // had they not been ineligible.\\n uint96 public ineligibleEarnedRewards;\\n\\n // Ineligibility times are calculated from this offset,\\n // set at contract creation.\\n uint256 internal immutable ineligibleOffsetStart;\\n\\n mapping(uint32 => OperatorRewards) internal operatorRewards;\\n\\n constructor() {\\n // solhint-disable-next-line not-rely-on-time\\n ineligibleOffsetStart = block.timestamp;\\n }\\n\\n /// @notice Return whether the operator is eligible for rewards or not.\\n function isEligibleForRewards(uint32 operator) internal view returns (bool) {\\n return operatorRewards[operator].ineligibleUntil == 0;\\n }\\n\\n /// @notice Return the time the operator's reward eligibility can be restored.\\n function rewardsEligibilityRestorableAt(uint32 operator)\\n internal\\n view\\n returns (uint256)\\n {\\n uint32 until = operatorRewards[operator].ineligibleUntil;\\n require(until != 0, \\\"Operator already eligible\\\");\\n return (uint256(until) + ineligibleOffsetStart);\\n }\\n\\n /// @notice Return whether the operator is able to restore their eligibility\\n /// for rewards right away.\\n function canRestoreRewardEligibility(uint32 operator)\\n internal\\n view\\n returns (bool)\\n {\\n // solhint-disable-next-line not-rely-on-time\\n return rewardsEligibilityRestorableAt(operator) <= block.timestamp;\\n }\\n\\n /// @notice Internal function for updating the global state of rewards.\\n function addRewards(uint96 rewardAmount, uint32 currentPoolWeight) internal {\\n require(currentPoolWeight > 0, \\\"No recipients in pool\\\");\\n\\n uint96 totalAmount = rewardAmount + rewardRoundingDust;\\n uint96 perWeightReward = totalAmount / currentPoolWeight;\\n uint96 newRoundingDust = totalAmount % currentPoolWeight;\\n\\n globalRewardAccumulator += perWeightReward;\\n rewardRoundingDust = newRoundingDust;\\n }\\n\\n /// @notice Internal function for updating the operator's reward state.\\n function updateOperatorRewards(uint32 operator, uint32 newWeight) internal {\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n if (o.ineligibleUntil == 0) {\\n // If operator is not ineligible, update their earned rewards\\n o.available += accruedRewards;\\n } else {\\n // If ineligible, put the rewards into the ineligible pot\\n ineligibleEarnedRewards += accruedRewards;\\n }\\n // In any case, update their accumulator and weight\\n o.accumulated = acc;\\n o.weight = newWeight;\\n operatorRewards[operator] = o;\\n }\\n\\n /// @notice Set the amount of withdrawable tokens to zero\\n /// and return the previous withdrawable amount.\\n /// @dev Does not update the withdrawable amount,\\n /// but should usually be accompanied by an update.\\n function withdrawOperatorRewards(uint32 operator)\\n internal\\n returns (uint96 withdrawable)\\n {\\n OperatorRewards storage o = operatorRewards[operator];\\n withdrawable = o.available;\\n o.available = 0;\\n }\\n\\n /// @notice Set the amount of ineligible-earned tokens to zero\\n /// and return the previous amount.\\n function withdrawIneligibleRewards() internal returns (uint96 withdrawable) {\\n withdrawable = ineligibleEarnedRewards;\\n ineligibleEarnedRewards = 0;\\n }\\n\\n /// @notice Set the given operators as ineligible for rewards.\\n /// The operators can restore their eligibility at the given time.\\n function setIneligible(uint32[] memory operators, uint256 until) internal {\\n OperatorRewards memory o = OperatorRewards(0, 0, 0, 0);\\n uint96 globalAcc = globalRewardAccumulator;\\n uint96 accrued = 0;\\n // Record ineligibility as seconds after contract creation\\n uint32 _until = uint32(until - ineligibleOffsetStart);\\n\\n for (uint256 i = 0; i < operators.length; i++) {\\n uint32 operator = operators[i];\\n OperatorRewards storage r = operatorRewards[operator];\\n o.available = r.available;\\n o.accumulated = r.accumulated;\\n o.ineligibleUntil = r.ineligibleUntil;\\n o.weight = r.weight;\\n\\n if (o.ineligibleUntil != 0) {\\n // If operator is already ineligible,\\n // don't earn rewards or shorten its ineligibility\\n if (o.ineligibleUntil < _until) {\\n o.ineligibleUntil = _until;\\n }\\n } else {\\n // The operator becomes ineligible -> earn rewards\\n o.ineligibleUntil = _until;\\n accrued = (globalAcc - o.accumulated) * uint96(o.weight);\\n o.available += accrued;\\n }\\n o.accumulated = globalAcc;\\n\\n r.available = o.available;\\n r.accumulated = o.accumulated;\\n r.ineligibleUntil = o.ineligibleUntil;\\n r.weight = o.weight;\\n }\\n }\\n\\n /// @notice Restore the given operator's eligibility for rewards.\\n function restoreEligibility(uint32 operator) internal {\\n // solhint-disable-next-line not-rely-on-time\\n require(canRestoreRewardEligibility(operator), \\\"Operator still ineligible\\\");\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n ineligibleEarnedRewards += accruedRewards;\\n o.accumulated = acc;\\n o.ineligibleUntil = 0;\\n operatorRewards[operator] = o;\\n }\\n\\n /// @notice Returns the amount of rewards currently available for withdrawal\\n /// for the given operator.\\n function availableRewards(uint32 operator) internal view returns (uint96) {\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n if (o.ineligibleUntil == 0) {\\n // If operator is not ineligible, calculate newly accrued rewards and add\\n // them to the available ones, calculated during the last update.\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n return o.available + accruedRewards;\\n } else {\\n // If ineligible, return only the rewards calculated during the last\\n // update.\\n return o.available;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3a10abb408b44335a092387b2c7ee01db3b27997f1f2c888d9b7a2d92934c4e2\"},\"@keep-network/sortition-pools/contracts/SortitionPool.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"@thesis/solidity-contracts/contracts/token/IERC20WithPermit.sol\\\";\\nimport \\\"@thesis/solidity-contracts/contracts/token/IReceiveApproval.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\nimport \\\"./RNG.sol\\\";\\nimport \\\"./SortitionTree.sol\\\";\\nimport \\\"./Rewards.sol\\\";\\nimport \\\"./Chaosnet.sol\\\";\\n\\n/// @title Sortition Pool\\n/// @notice A logarithmic data structure used to store the pool of eligible\\n/// operators weighted by their stakes. It allows to select a group of operators\\n/// based on the provided pseudo-random seed.\\ncontract SortitionPool is\\n SortitionTree,\\n Rewards,\\n Ownable,\\n Chaosnet,\\n IReceiveApproval\\n{\\n using Branch for uint256;\\n using Leaf for uint256;\\n using Position for uint256;\\n\\n IERC20WithPermit public immutable rewardToken;\\n\\n uint256 public immutable poolWeightDivisor;\\n\\n bool public isLocked;\\n\\n event IneligibleForRewards(uint32[] ids, uint256 until);\\n\\n event RewardEligibilityRestored(address indexed operator, uint32 indexed id);\\n\\n /// @notice Reverts if called while pool is locked.\\n modifier onlyUnlocked() {\\n require(!isLocked, \\\"Sortition pool locked\\\");\\n _;\\n }\\n\\n /// @notice Reverts if called while pool is unlocked.\\n modifier onlyLocked() {\\n require(isLocked, \\\"Sortition pool unlocked\\\");\\n _;\\n }\\n\\n constructor(IERC20WithPermit _rewardToken, uint256 _poolWeightDivisor) {\\n rewardToken = _rewardToken;\\n poolWeightDivisor = _poolWeightDivisor;\\n }\\n\\n function receiveApproval(\\n address sender,\\n uint256 amount,\\n address token,\\n bytes calldata\\n ) external override {\\n require(token == address(rewardToken), \\\"Unsupported token\\\");\\n rewardToken.transferFrom(sender, address(this), amount);\\n Rewards.addRewards(uint96(amount), uint32(root.sumWeight()));\\n }\\n\\n /// @notice Withdraws all available rewards for the given operator to the\\n /// given beneficiary.\\n /// @dev Can be called only be the owner. Does not validate if the provided\\n /// beneficiary is associated with the provided operator - this needs to\\n /// be done by the owner calling this function.\\n /// @return The amount of rewards withdrawn in this call.\\n function withdrawRewards(address operator, address beneficiary)\\n public\\n onlyOwner\\n returns (uint96)\\n {\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(getPoolWeight(operator)));\\n uint96 earned = Rewards.withdrawOperatorRewards(id);\\n rewardToken.transfer(beneficiary, uint256(earned));\\n return earned;\\n }\\n\\n /// @notice Withdraws rewards not allocated to operators marked as ineligible\\n /// to the given recipient address.\\n /// @dev Can be called only by the owner.\\n function withdrawIneligible(address recipient) public onlyOwner {\\n uint96 earned = Rewards.withdrawIneligibleRewards();\\n rewardToken.transfer(recipient, uint256(earned));\\n }\\n\\n /// @notice Locks the sortition pool. In locked state, members cannot be\\n /// inserted and removed from the pool. Members statuses cannot\\n /// be updated as well.\\n /// @dev Can be called only by the contract owner.\\n function lock() public onlyOwner {\\n isLocked = true;\\n }\\n\\n /// @notice Unlocks the sortition pool. Removes all restrictions set by\\n /// the `lock` method.\\n /// @dev Can be called only by the contract owner.\\n function unlock() public onlyOwner {\\n isLocked = false;\\n }\\n\\n /// @notice Inserts an operator to the pool. Reverts if the operator is\\n /// already present. Reverts if the operator is not eligible because of their\\n /// authorized stake. Reverts if the chaosnet is active and the operator is\\n /// not a beta operator.\\n /// @dev Can be called only by the contract owner.\\n /// @param operator Address of the inserted operator.\\n /// @param authorizedStake Inserted operator's authorized stake for the application.\\n function insertOperator(address operator, uint256 authorizedStake)\\n public\\n onlyOwner\\n onlyUnlocked\\n {\\n uint256 weight = getWeight(authorizedStake);\\n require(weight > 0, \\\"Operator not eligible\\\");\\n\\n if (isChaosnetActive) {\\n require(isBetaOperator[operator], \\\"Not beta operator for chaosnet\\\");\\n }\\n\\n _insertOperator(operator, weight);\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(weight));\\n }\\n\\n /// @notice Update the operator's weight if present and eligible,\\n /// or remove from the pool if present and ineligible.\\n /// @dev Can be called only by the contract owner.\\n /// @param operator Address of the updated operator.\\n /// @param authorizedStake Operator's authorized stake for the application.\\n function updateOperatorStatus(address operator, uint256 authorizedStake)\\n public\\n onlyOwner\\n onlyUnlocked\\n {\\n uint256 weight = getWeight(authorizedStake);\\n\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(weight));\\n\\n if (weight == 0) {\\n _removeOperator(operator);\\n } else {\\n updateOperator(operator, weight);\\n }\\n }\\n\\n /// @notice Set the given operators as ineligible for rewards.\\n /// The operators can restore their eligibility at the given time.\\n function setRewardIneligibility(uint32[] calldata operators, uint256 until)\\n public\\n onlyOwner\\n {\\n Rewards.setIneligible(operators, until);\\n emit IneligibleForRewards(operators, until);\\n }\\n\\n /// @notice Restores reward eligibility for the operator.\\n function restoreRewardEligibility(address operator) public {\\n uint32 id = getOperatorID(operator);\\n Rewards.restoreEligibility(id);\\n emit RewardEligibilityRestored(operator, id);\\n }\\n\\n /// @notice Returns whether the operator is eligible for rewards or not.\\n function isEligibleForRewards(address operator) public view returns (bool) {\\n uint32 id = getOperatorID(operator);\\n return Rewards.isEligibleForRewards(id);\\n }\\n\\n /// @notice Returns the time the operator's reward eligibility can be restored.\\n function rewardsEligibilityRestorableAt(address operator)\\n public\\n view\\n returns (uint256)\\n {\\n uint32 id = getOperatorID(operator);\\n return Rewards.rewardsEligibilityRestorableAt(id);\\n }\\n\\n /// @notice Returns whether the operator is able to restore their eligibility\\n /// for rewards right away.\\n function canRestoreRewardEligibility(address operator)\\n public\\n view\\n returns (bool)\\n {\\n uint32 id = getOperatorID(operator);\\n return Rewards.canRestoreRewardEligibility(id);\\n }\\n\\n /// @notice Returns the amount of rewards withdrawable for the given operator.\\n function getAvailableRewards(address operator) public view returns (uint96) {\\n uint32 id = getOperatorID(operator);\\n return availableRewards(id);\\n }\\n\\n /// @notice Return whether the operator is present in the pool.\\n function isOperatorInPool(address operator) public view returns (bool) {\\n return getFlaggedLeafPosition(operator) != 0;\\n }\\n\\n /// @notice Return whether the operator's weight in the pool\\n /// matches their eligible weight.\\n function isOperatorUpToDate(address operator, uint256 authorizedStake)\\n public\\n view\\n returns (bool)\\n {\\n return getWeight(authorizedStake) == getPoolWeight(operator);\\n }\\n\\n /// @notice Return the weight of the operator in the pool,\\n /// which may or may not be out of date.\\n function getPoolWeight(address operator) public view returns (uint256) {\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n if (flaggedPosition == 0) {\\n return 0;\\n } else {\\n uint256 leafPosition = flaggedPosition.unsetFlag();\\n uint256 leafWeight = getLeafWeight(leafPosition);\\n return leafWeight;\\n }\\n }\\n\\n /// @notice Selects a new group of operators of the provided size based on\\n /// the provided pseudo-random seed. At least one operator has to be\\n /// registered in the pool, otherwise the function fails reverting the\\n /// transaction.\\n /// @param groupSize Size of the requested group\\n /// @param seed Pseudo-random number used to select operators to group\\n /// @return selected Members of the selected group\\n function selectGroup(uint256 groupSize, bytes32 seed)\\n public\\n view\\n onlyLocked\\n returns (uint32[] memory)\\n {\\n uint256 _root = root;\\n\\n bytes32 rngState = seed;\\n uint256 rngRange = _root.sumWeight();\\n require(rngRange > 0, \\\"Not enough operators in pool\\\");\\n uint256 currentIndex;\\n\\n uint256 bits = RNG.bitsRequired(rngRange);\\n\\n uint32[] memory selected = new uint32[](groupSize);\\n\\n for (uint256 i = 0; i < groupSize; i++) {\\n (currentIndex, rngState) = RNG.getIndex(rngRange, rngState, bits);\\n\\n uint256 leafPosition = pickWeightedLeaf(currentIndex, _root);\\n\\n uint256 leaf = leaves[leafPosition];\\n selected[i] = leaf.id();\\n }\\n return selected;\\n }\\n\\n function getWeight(uint256 authorization) internal view returns (uint256) {\\n return authorization / poolWeightDivisor;\\n }\\n}\\n\",\"keccak256\":\"0xab42e7c5b1828f42a73f699eb2dc96d4f793572a6323b8b1fbd7c5e0c065bda7\"},\"@keep-network/sortition-pools/contracts/SortitionTree.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Branch.sol\\\";\\nimport \\\"./Position.sol\\\";\\nimport \\\"./Leaf.sol\\\";\\nimport \\\"./Constants.sol\\\";\\n\\ncontract SortitionTree {\\n using Branch for uint256;\\n using Position for uint256;\\n using Leaf for uint256;\\n\\n // implicit tree\\n // root 8\\n // level2 64\\n // level3 512\\n // level4 4k\\n // level5 32k\\n // level6 256k\\n // level7 2M\\n uint256 internal root;\\n\\n // A 2-index mapping from layer => (index (0-index) => branch). For example,\\n // to access the 6th branch in the 2nd layer (right below the root node; the\\n // first branch layer), call branches[2][5]. Mappings are used in place of\\n // arrays for efficiency. The root is the first layer, the branches occupy\\n // layers 2 through 7, and layer 8 is for the leaves. Following this\\n // convention, the first index in `branches` is `2`, and the last index is\\n // `7`.\\n mapping(uint256 => mapping(uint256 => uint256)) internal branches;\\n\\n // A 0-index mapping from index => leaf, acting as an array. For example, to\\n // access the 42nd leaf, call leaves[41].\\n mapping(uint256 => uint256) internal leaves;\\n\\n // the flagged (see setFlag() and unsetFlag() in Position.sol) positions\\n // of all operators present in the pool\\n mapping(address => uint256) internal flaggedLeafPosition;\\n\\n // the leaf after the rightmost occupied leaf of each stack\\n uint256 internal rightmostLeaf;\\n\\n // the empty leaves in each stack\\n // between 0 and the rightmost occupied leaf\\n uint256[] internal emptyLeaves;\\n\\n // Each operator has an uint32 ID number\\n // which is allocated when they first join the pool\\n // and remains unchanged even if they leave and rejoin the pool.\\n mapping(address => uint32) internal operatorID;\\n\\n // The idAddress array records the address corresponding to each ID number.\\n // The ID number 0 is initialized with a zero address and is not used.\\n address[] internal idAddress;\\n\\n constructor() {\\n root = 0;\\n rightmostLeaf = 0;\\n idAddress.push();\\n }\\n\\n /// @notice Return the ID number of the given operator address. An ID number\\n /// of 0 means the operator has not been allocated an ID number yet.\\n /// @param operator Address of the operator.\\n /// @return the ID number of the given operator address\\n function getOperatorID(address operator) public view returns (uint32) {\\n return operatorID[operator];\\n }\\n\\n /// @notice Get the operator address corresponding to the given ID number. A\\n /// zero address means the ID number has not been allocated yet.\\n /// @param id ID of the operator\\n /// @return the address of the operator\\n function getIDOperator(uint32 id) public view returns (address) {\\n return idAddress.length > id ? idAddress[id] : address(0);\\n }\\n\\n /// @notice Gets the operator addresses corresponding to the given ID\\n /// numbers. A zero address means the ID number has not been allocated yet.\\n /// This function works just like getIDOperator except that it allows to fetch\\n /// operator addresses for multiple IDs in one call.\\n /// @param ids the array of the operator ids\\n /// @return an array of the associated operator addresses\\n function getIDOperators(uint32[] calldata ids)\\n public\\n view\\n returns (address[] memory)\\n {\\n uint256 idCount = idAddress.length;\\n\\n address[] memory operators = new address[](ids.length);\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint32 id = ids[i];\\n operators[i] = idCount > id ? idAddress[id] : address(0);\\n }\\n return operators;\\n }\\n\\n /// @notice Checks if operator is already registered in the pool.\\n /// @param operator the address of the operator\\n /// @return whether or not the operator is already registered in the pool\\n function isOperatorRegistered(address operator) public view returns (bool) {\\n return getFlaggedLeafPosition(operator) != 0;\\n }\\n\\n /// @notice Sum the number of operators in each trunk.\\n /// @return the number of operators in the pool\\n function operatorsInPool() public view returns (uint256) {\\n // Get the number of leaves that might be occupied;\\n // if `rightmostLeaf` equals `firstLeaf()` the tree must be empty,\\n // otherwise the difference between these numbers\\n // gives the number of leaves that may be occupied.\\n uint256 nPossiblyUsedLeaves = rightmostLeaf;\\n // Get the number of empty leaves\\n // not accounted for by the `rightmostLeaf`\\n uint256 nEmptyLeaves = emptyLeaves.length;\\n\\n return (nPossiblyUsedLeaves - nEmptyLeaves);\\n }\\n\\n /// @notice Convenience method to return the total weight of the pool\\n /// @return the total weight of the pool\\n function totalWeight() public view returns (uint256) {\\n return root.sumWeight();\\n }\\n\\n /// @notice Give the operator a new ID number.\\n /// Does not check if the operator already has an ID number.\\n /// @param operator the address of the operator\\n /// @return a new ID for that operator\\n function allocateOperatorID(address operator) internal returns (uint256) {\\n uint256 id = idAddress.length;\\n\\n require(id <= type(uint32).max, \\\"Pool capacity exceeded\\\");\\n\\n operatorID[operator] = uint32(id);\\n idAddress.push(operator);\\n return id;\\n }\\n\\n /// @notice Inserts an operator into the sortition pool\\n /// @param operator the address of an operator to insert\\n /// @param weight how much weight that operator has in the pool\\n function _insertOperator(address operator, uint256 weight) internal {\\n require(\\n !isOperatorRegistered(operator),\\n \\\"Operator is already registered in the pool\\\"\\n );\\n\\n // Fetch the operator's ID, and if they don't have one, allocate them one.\\n uint256 id = getOperatorID(operator);\\n if (id == 0) {\\n id = allocateOperatorID(operator);\\n }\\n\\n // Determine which leaf to insert them into\\n uint256 position = getEmptyLeafPosition();\\n // Record the block the operator was inserted in\\n uint256 theLeaf = Leaf.make(operator, block.number, id);\\n\\n // Update the leaf, and propagate the weight changes all the way up to the\\n // root.\\n root = setLeaf(position, theLeaf, weight, root);\\n\\n // Without position flags,\\n // the position 0x000000 would be treated as empty\\n flaggedLeafPosition[operator] = position.setFlag();\\n }\\n\\n /// @notice Remove an operator (and their weight) from the pool.\\n /// @param operator the address of the operator to remove\\n function _removeOperator(address operator) internal {\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n require(flaggedPosition != 0, \\\"Operator is not registered in the pool\\\");\\n uint256 unflaggedPosition = flaggedPosition.unsetFlag();\\n\\n // Update the leaf, and propagate the weight changes all the way up to the\\n // root.\\n root = removeLeaf(unflaggedPosition, root);\\n removeLeafPositionRecord(operator);\\n }\\n\\n /// @notice Update an operator's weight in the pool.\\n /// @param operator the address of the operator to update\\n /// @param weight the new weight\\n function updateOperator(address operator, uint256 weight) internal {\\n require(\\n isOperatorRegistered(operator),\\n \\\"Operator is not registered in the pool\\\"\\n );\\n\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n uint256 unflaggedPosition = flaggedPosition.unsetFlag();\\n root = updateLeaf(unflaggedPosition, weight, root);\\n }\\n\\n /// @notice Helper method to remove a leaf position record for an operator.\\n /// @param operator the address of the operator to remove the record for\\n function removeLeafPositionRecord(address operator) internal {\\n flaggedLeafPosition[operator] = 0;\\n }\\n\\n /// @notice Removes the data and weight from a particular leaf.\\n /// @param position the leaf index to remove\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function removeLeaf(uint256 position, uint256 _root)\\n internal\\n returns (uint256)\\n {\\n uint256 rightmostSubOne = rightmostLeaf - 1;\\n bool isRightmost = position == rightmostSubOne;\\n\\n // Clears out the data in the leaf node, and then propagates the weight\\n // changes all the way up to the root.\\n uint256 newRoot = setLeaf(position, 0, 0, _root);\\n\\n // Infer if need to fall back on emptyLeaves yet\\n if (isRightmost) {\\n rightmostLeaf = rightmostSubOne;\\n } else {\\n emptyLeaves.push(position);\\n }\\n return newRoot;\\n }\\n\\n /// @notice Updates the tree to give a particular leaf a new weight.\\n /// @param position the index of the leaf to update\\n /// @param weight the new weight\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function updateLeaf(\\n uint256 position,\\n uint256 weight,\\n uint256 _root\\n ) internal returns (uint256) {\\n if (getLeafWeight(position) != weight) {\\n return updateTree(position, weight, _root);\\n } else {\\n return _root;\\n }\\n }\\n\\n /// @notice Places a leaf into a particular position, with a given weight and\\n /// propagates that change.\\n /// @param position the index to place the leaf in\\n /// @param theLeaf the new leaf to place in the position\\n /// @param leafWeight the weight of the leaf\\n /// @param _root the root containing the new leaf\\n /// @return the updated root node\\n function setLeaf(\\n uint256 position,\\n uint256 theLeaf,\\n uint256 leafWeight,\\n uint256 _root\\n ) internal returns (uint256) {\\n // set leaf\\n leaves[position] = theLeaf;\\n\\n return (updateTree(position, leafWeight, _root));\\n }\\n\\n /// @notice Propagates a weight change at a position through the tree,\\n /// eventually returning the updated root.\\n /// @param position the index of leaf to update\\n /// @param weight the new weight of the leaf\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function updateTree(\\n uint256 position,\\n uint256 weight,\\n uint256 _root\\n ) internal returns (uint256) {\\n uint256 childSlot;\\n uint256 treeNode;\\n uint256 newNode;\\n uint256 nodeWeight = weight;\\n\\n uint256 parent = position;\\n // set levels 7 to 2\\n for (uint256 level = Constants.LEVELS; level >= 2; level--) {\\n childSlot = parent.slot();\\n parent = parent.parent();\\n treeNode = branches[level][parent];\\n newNode = treeNode.setSlot(childSlot, nodeWeight);\\n branches[level][parent] = newNode;\\n nodeWeight = newNode.sumWeight();\\n }\\n\\n // set level Root\\n childSlot = parent.slot();\\n return _root.setSlot(childSlot, nodeWeight);\\n }\\n\\n /// @notice Retrieves the next available empty leaf position. Tries to fill\\n /// left to right first, ignoring leaf removals, and then fills\\n /// most-recent-removals first.\\n /// @return the position of the empty leaf\\n function getEmptyLeafPosition() internal returns (uint256) {\\n uint256 rLeaf = rightmostLeaf;\\n bool spaceOnRight = (rLeaf + 1) < Constants.POOL_CAPACITY;\\n if (spaceOnRight) {\\n rightmostLeaf = rLeaf + 1;\\n return rLeaf;\\n } else {\\n uint256 emptyLeafCount = emptyLeaves.length;\\n require(emptyLeafCount > 0, \\\"Pool is full\\\");\\n uint256 emptyLeaf = emptyLeaves[emptyLeafCount - 1];\\n emptyLeaves.pop();\\n return emptyLeaf;\\n }\\n }\\n\\n /// @notice Gets the flagged leaf position for an operator.\\n /// @param operator the address of the operator\\n /// @return the leaf position of that operator\\n function getFlaggedLeafPosition(address operator)\\n internal\\n view\\n returns (uint256)\\n {\\n return flaggedLeafPosition[operator];\\n }\\n\\n /// @notice Gets the weight of a leaf at a particular position.\\n /// @param position the index of the leaf\\n /// @return the weight of the leaf at that position\\n function getLeafWeight(uint256 position) internal view returns (uint256) {\\n uint256 slot = position.slot();\\n uint256 parent = position.parent();\\n\\n // A leaf's weight information is stored a 32-bit slot in the branch layer\\n // directly above the leaf layer. To access it, we calculate that slot and\\n // parent position, and always know the hard-coded layer index.\\n uint256 node = branches[Constants.LEVELS][parent];\\n return node.getSlot(slot);\\n }\\n\\n /// @notice Picks a leaf given a random index.\\n /// @param index a number in `[0, _root.totalWeight())` used to decide\\n /// between leaves\\n /// @param _root the root of the tree\\n function pickWeightedLeaf(uint256 index, uint256 _root)\\n internal\\n view\\n returns (uint256 leafPosition)\\n {\\n uint256 currentIndex = index;\\n uint256 currentNode = _root;\\n uint256 currentPosition = 0;\\n uint256 currentSlot;\\n\\n require(index < currentNode.sumWeight(), \\\"Index exceeds weight\\\");\\n\\n // get root slot\\n (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex);\\n\\n // get slots from levels 2 to 7\\n for (uint256 level = 2; level <= Constants.LEVELS; level++) {\\n currentPosition = currentPosition.child(currentSlot);\\n currentNode = branches[level][currentPosition];\\n (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex);\\n }\\n\\n // get leaf position\\n leafPosition = currentPosition.child(currentSlot);\\n }\\n}\\n\",\"keccak256\":\"0x51daeca62ef52be78a1a9de4d2a1c5900c873165f59eda14d5965d7d7da90a03\"},\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/security/ReentrancyGuard.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Contract module that helps prevent reentrant calls to a function.\\n *\\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\\n * available, which can be applied to functions to make sure there are no nested\\n * (reentrant) calls to them.\\n *\\n * Note that because there is a single `nonReentrant` guard, functions marked as\\n * `nonReentrant` may not call one another. This can be worked around by making\\n * those functions `private`, and then adding `external` `nonReentrant` entry\\n * points to them.\\n *\\n * TIP: If you would like to learn more about reentrancy and alternative ways\\n * to protect against it, check out our blog post\\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\\n */\\nabstract contract ReentrancyGuard {\\n // Booleans are more expensive than uint256 or any type that takes up a full\\n // word because each write operation emits an extra SLOAD to first read the\\n // slot's contents, replace the bits taken up by the boolean, and then write\\n // back. This is the compiler's defense against contract upgrades and\\n // pointer aliasing, and it cannot be disabled.\\n\\n // The values being non-zero value makes deployment a bit more expensive,\\n // but in exchange the refund on every call to nonReentrant will be lower in\\n // amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to\\n // increase the likelihood of the full refund coming into effect.\\n uint256 private constant _NOT_ENTERED = 1;\\n uint256 private constant _ENTERED = 2;\\n\\n uint256 private _status;\\n\\n constructor() {\\n _status = _NOT_ENTERED;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and making it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_status != _ENTERED, \\\"ReentrancyGuard: reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n _status = _ENTERED;\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _status = _NOT_ENTERED;\\n }\\n}\\n\",\"keccak256\":\"0x0e9621f60b2faabe65549f7ed0f24e8853a45c1b7990d47e8160e523683f3935\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n uint8 private constant _ADDRESS_LENGTH = 20;\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\\n */\\n function toHexString(address addr) internal pure returns (string memory) {\\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\\n }\\n}\\n\",\"keccak256\":\"0xaf159a8b1923ad2a26d516089bceca9bdeaeacd04be50983ea00ba63070f08a3\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.3) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n /// @solidity memory-safe-assembly\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0xdb7f5c28fc61cda0bd8ab60ce288e206b791643bcd3ba464a70cbec18895a2f5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\n /**\\n * @dev Returns the largest of two numbers.\\n */\\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a >= b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the smallest of two numbers.\\n */\\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a < b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the average of two numbers. The result is rounded towards\\n * zero.\\n */\\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b) / 2 can overflow.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1);\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. It the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`.\\n // We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`.\\n // This gives `2**k < a <= 2**(k+1)` \\u2192 `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`.\\n // Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a\\n // good first aproximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1;\\n uint256 x = a;\\n if (x >> 128 > 0) {\\n x >>= 128;\\n result <<= 64;\\n }\\n if (x >> 64 > 0) {\\n x >>= 64;\\n result <<= 32;\\n }\\n if (x >> 32 > 0) {\\n x >>= 32;\\n result <<= 16;\\n }\\n if (x >> 16 > 0) {\\n x >>= 16;\\n result <<= 8;\\n }\\n if (x >> 8 > 0) {\\n x >>= 8;\\n result <<= 4;\\n }\\n if (x >> 4 > 0) {\\n x >>= 4;\\n result <<= 2;\\n }\\n if (x >> 2 > 0) {\\n result <<= 1;\\n }\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n uint256 result = sqrt(a);\\n if (rounding == Rounding.Up && result * result < a) {\\n result += 1;\\n }\\n return result;\\n }\\n}\\n\",\"keccak256\":\"0xd15c3e400531f00203839159b2b8e7209c5158b35618f570c695b7e47f12e9f0\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IApproveAndCall.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\n/// @notice An interface that should be implemented by tokens supporting\\n/// `approveAndCall`/`receiveApproval` pattern.\\ninterface IApproveAndCall {\\n /// @notice Executes `receiveApproval` function on spender as specified in\\n /// `IReceiveApproval` interface. Approves spender to withdraw from\\n /// the caller multiple times, up to the `amount`. If this\\n /// function is called again, it overwrites the current allowance\\n /// with `amount`. Reverts if the approval reverted or if\\n /// `receiveApproval` call on the spender reverted.\\n function approveAndCall(\\n address spender,\\n uint256 amount,\\n bytes memory extraData\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x393d18ef81a57dcc96fff4c340cc2945deaebb37b9796c322cf2bc96872c3df8\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IERC20WithPermit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\\\";\\n\\nimport \\\"./IApproveAndCall.sol\\\";\\n\\n/// @title IERC20WithPermit\\n/// @notice Burnable ERC20 token with EIP2612 permit functionality. User can\\n/// authorize a transfer of their token with a signature conforming\\n/// EIP712 standard instead of an on-chain transaction from their\\n/// address. Anyone can submit this signature on the user's behalf by\\n/// calling the permit function, as specified in EIP2612 standard,\\n/// paying gas fees, and possibly performing other actions in the same\\n/// transaction.\\ninterface IERC20WithPermit is IERC20, IERC20Metadata, IApproveAndCall {\\n /// @notice EIP2612 approval made with secp256k1 signature.\\n /// Users can authorize a transfer of their tokens with a signature\\n /// conforming EIP712 standard, rather than an on-chain transaction\\n /// from their address. Anyone can submit this signature on the\\n /// user's behalf by calling the permit function, paying gas fees,\\n /// and possibly performing other actions in the same transaction.\\n /// @dev The deadline argument can be set to `type(uint256).max to create\\n /// permits that effectively never expire.\\n function permit(\\n address owner,\\n address spender,\\n uint256 amount,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /// @notice Destroys `amount` tokens from the caller.\\n function burn(uint256 amount) external;\\n\\n /// @notice Destroys `amount` of tokens from `account`, deducting the amount\\n /// from caller's allowance.\\n function burnFrom(address account, uint256 amount) external;\\n\\n /// @notice Returns hash of EIP712 Domain struct with the token name as\\n /// a signing domain and token contract as a verifying contract.\\n /// Used to construct EIP2612 signature provided to `permit`\\n /// function.\\n /* solhint-disable-next-line func-name-mixedcase */\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n\\n /// @notice Returns the current nonce for EIP2612 permission for the\\n /// provided token owner for a replay protection. Used to construct\\n /// EIP2612 signature provided to `permit` function.\\n function nonce(address owner) external view returns (uint256);\\n\\n /// @notice Returns EIP2612 Permit message hash. Used to construct EIP2612\\n /// signature provided to `permit` function.\\n /* solhint-disable-next-line func-name-mixedcase */\\n function PERMIT_TYPEHASH() external pure returns (bytes32);\\n}\\n\",\"keccak256\":\"0xdac9a5086c19a7128b505a7be1ab0ac1aa314f6989cb88d2417e9d7383f89fa9\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IReceiveApproval.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\n/// @notice An interface that should be implemented by contracts supporting\\n/// `approveAndCall`/`receiveApproval` pattern.\\ninterface IReceiveApproval {\\n /// @notice Receives approval to spend tokens. Called as a result of\\n /// `approveAndCall` call on the token.\\n function receiveApproval(\\n address from,\\n uint256 amount,\\n address token,\\n bytes calldata extraData\\n ) external;\\n}\\n\",\"keccak256\":\"0x6a30d83ad230548b1e7839737affc8489a035314209de14b89dbef7fb0f66395\",\"license\":\"MIT\"},\"@threshold-network/solidity-contracts/contracts/staking/IApplication.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-or-later\\n\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n\\npragma solidity ^0.8.9;\\n\\n/// @title Application interface for Threshold Network applications\\n/// @notice Generic interface for an application. Application is an external\\n/// smart contract or a set of smart contracts utilizing functionalities\\n/// offered by Threshold Network. Applications authorized for the given\\n/// staking provider are eligible to slash the stake delegated to that\\n/// staking provider.\\ninterface IApplication {\\n /// @dev Event emitted by `withdrawRewards` function.\\n event RewardsWithdrawn(address indexed stakingProvider, uint96 amount);\\n\\n /// @notice Withdraws application rewards for the given staking provider.\\n /// Rewards are withdrawn to the staking provider's beneficiary\\n /// address set in the staking contract.\\n /// @dev Emits `RewardsWithdrawn` event.\\n function withdrawRewards(address stakingProvider) external;\\n\\n /// @notice Used by T staking contract to inform the application that the\\n /// authorized amount for the given staking provider increased.\\n /// The application may do any necessary housekeeping. The\\n /// application must revert the transaction in case the\\n /// authorization is below the minimum required.\\n function authorizationIncreased(\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external;\\n\\n /// @notice Used by T staking contract to inform the application that the\\n /// authorization decrease for the given staking provider has been\\n /// requested. The application should mark the authorization as\\n /// pending decrease and respond to the staking contract with\\n /// `approveAuthorizationDecrease` at its discretion. It may\\n /// happen right away but it also may happen several months later.\\n /// If there is already a pending authorization decrease request\\n /// for the application, and the application does not agree for\\n /// overwriting it, the function should revert.\\n function authorizationDecreaseRequested(\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external;\\n\\n /// @notice Used by T staking contract to inform the application the\\n /// authorization has been decreased for the given staking provider\\n /// involuntarily, as a result of slashing. Lets the application to\\n /// do any housekeeping neccessary. Called with 250k gas limit and\\n /// does not revert the transaction if\\n /// `involuntaryAuthorizationDecrease` call failed.\\n function involuntaryAuthorizationDecrease(\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external;\\n\\n /// @notice Returns the amount of application rewards available for\\n /// withdrawal for the given staking provider.\\n function availableRewards(address stakingProvider)\\n external\\n view\\n returns (uint96);\\n\\n /// @notice The minimum authorization amount required for the staking\\n /// provider so that they can participate in the application.\\n function minimumAuthorization() external view returns (uint96);\\n}\\n\",\"keccak256\":\"0x43d707dccc548bf48ad316d9652450cb297203234d251132cdc6b97508eb44c5\",\"license\":\"GPL-3.0-or-later\"},\"@threshold-network/solidity-contracts/contracts/staking/IStaking.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-or-later\\n\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n// \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c \\u2590\\u2588\\u2588\\u2588\\u2588\\u258c\\n\\npragma solidity ^0.8.9;\\n\\n/// @title Interface of Threshold Network staking contract\\n/// @notice The staking contract enables T owners to have their wallets offline\\n/// and their stake managed by staking providers on their behalf.\\n/// The staking contract does not define operator role. The operator\\n/// responsible for running off-chain client software is appointed by\\n/// the staking provider in the particular application utilizing the\\n/// staking contract. All off-chain client software should be able\\n/// to run without exposing operator's or staking provider\\u2019s private\\n/// key and should not require any owner\\u2019s keys at all. The stake\\n/// delegation optimizes the network throughput without compromising the\\n/// security of the owners\\u2019 stake.\\ninterface IStaking {\\n enum StakeType {\\n NU,\\n KEEP,\\n T\\n }\\n\\n //\\n //\\n // Delegating a stake\\n //\\n //\\n\\n /// @notice Creates a delegation with `msg.sender` owner with the given\\n /// staking provider, beneficiary, and authorizer. Transfers the\\n /// given amount of T to the staking contract.\\n /// @dev The owner of the delegation needs to have the amount approved to\\n /// transfer to the staking contract.\\n function stake(\\n address stakingProvider,\\n address payable beneficiary,\\n address authorizer,\\n uint96 amount\\n ) external;\\n\\n /// @notice Allows the Governance to set the minimum required stake amount.\\n /// This amount is required to protect against griefing the staking\\n /// contract and individual applications are allowed to require\\n /// higher minimum stakes if necessary.\\n function setMinimumStakeAmount(uint96 amount) external;\\n\\n //\\n //\\n // Authorizing an application\\n //\\n //\\n\\n /// @notice Allows the Governance to approve the particular application\\n /// before individual stake authorizers are able to authorize it.\\n function approveApplication(address application) external;\\n\\n /// @notice Increases the authorization of the given staking provider for\\n /// the given application by the given amount. Can only be called by\\n /// the authorizer for that staking provider.\\n /// @dev Calls `authorizationIncreased(address stakingProvider, uint256 amount)`\\n /// on the given application to notify the application about\\n /// authorization change. See `IApplication`.\\n function increaseAuthorization(\\n address stakingProvider,\\n address application,\\n uint96 amount\\n ) external;\\n\\n /// @notice Requests decrease of the authorization for the given staking\\n /// provider on the given application by the provided amount.\\n /// It may not change the authorized amount immediatelly. When\\n /// it happens depends on the application. Can only be called by the\\n /// given staking provider\\u2019s authorizer. Overwrites pending\\n /// authorization decrease for the given staking provider and\\n /// application if the application agrees for that. If the\\n /// application does not agree for overwriting, the function\\n /// reverts.\\n /// @dev Calls `authorizationDecreaseRequested(address stakingProvider, uint256 amount)`\\n /// on the given application. See `IApplication`.\\n function requestAuthorizationDecrease(\\n address stakingProvider,\\n address application,\\n uint96 amount\\n ) external;\\n\\n /// @notice Requests decrease of all authorizations for the given staking\\n /// provider on all applications by all authorized amount.\\n /// It may not change the authorized amount immediatelly. When\\n /// it happens depends on the application. Can only be called by the\\n /// given staking provider\\u2019s authorizer. Overwrites pending\\n /// authorization decrease for the given staking provider and\\n /// application.\\n /// @dev Calls `authorizationDecreaseRequested(address stakingProvider, uint256 amount)`\\n /// for each authorized application. See `IApplication`.\\n function requestAuthorizationDecrease(address stakingProvider) external;\\n\\n /// @notice Called by the application at its discretion to approve the\\n /// previously requested authorization decrease request. Can only be\\n /// called by the application that was previously requested to\\n /// decrease the authorization for that staking provider.\\n /// Returns resulting authorized amount for the application.\\n function approveAuthorizationDecrease(address stakingProvider)\\n external\\n returns (uint96);\\n\\n /// @notice Decreases the authorization for the given `stakingProvider` on\\n /// the given disabled `application`, for all authorized amount.\\n /// Can be called by anyone.\\n function forceDecreaseAuthorization(\\n address stakingProvider,\\n address application\\n ) external;\\n\\n /// @notice Pauses the given application\\u2019s eligibility to slash stakes.\\n /// Besides that stakers can't change authorization to the application.\\n /// Can be called only by the Panic Button of the particular\\n /// application. The paused application can not slash stakes until\\n /// it is approved again by the Governance using `approveApplication`\\n /// function. Should be used only in case of an emergency.\\n function pauseApplication(address application) external;\\n\\n /// @notice Disables the given application. The disabled application can't\\n /// slash stakers. Also stakers can't increase authorization to that\\n /// application but can decrease without waiting by calling\\n /// `requestAuthorizationDecrease` at any moment. Can be called only\\n /// by the governance. The disabled application can't be approved\\n /// again. Should be used only in case of an emergency.\\n function disableApplication(address application) external;\\n\\n /// @notice Sets the Panic Button role for the given application to the\\n /// provided address. Can only be called by the Governance. If the\\n /// Panic Button for the given application should be disabled, the\\n /// role address should be set to 0x0 address.\\n function setPanicButton(address application, address panicButton) external;\\n\\n /// @notice Sets the maximum number of applications one staking provider can\\n /// have authorized. Used to protect against DoSing slashing queue.\\n /// Can only be called by the Governance.\\n function setAuthorizationCeiling(uint256 ceiling) external;\\n\\n //\\n //\\n // Stake top-up\\n //\\n //\\n\\n /// @notice Increases the amount of the stake for the given staking provider.\\n /// If `autoIncrease` flag is true then the amount will be added for\\n /// all authorized applications.\\n /// @dev The sender of this transaction needs to have the amount approved to\\n /// transfer to the staking contract.\\n function topUp(address stakingProvider, uint96 amount) external;\\n\\n /// @notice Toggle `autoIncrease` flag. If true then the complete amount\\n /// in top-up will be added to already authorized applications.\\n function toggleAutoAuthorizationIncrease(address stakingProvider) external;\\n\\n //\\n //\\n // Undelegating a stake (unstaking)\\n //\\n //\\n\\n /// @notice Reduces the liquid T stake amount by the provided amount and\\n /// withdraws T to the owner. Reverts if there is at least one\\n /// authorization higher than the sum of the legacy stake and\\n /// remaining liquid T stake or if the unstake amount is higher than\\n /// the liquid T stake amount. Can be called only by the delegation\\n /// owner or the staking provider.\\n function unstakeT(address stakingProvider, uint96 amount) external;\\n\\n /// @notice Sets the legacy KEEP staking contract active stake amount cached\\n /// in T staking contract to 0. Reverts if the amount of liquid T\\n /// staked in T staking contract is lower than the highest\\n /// application authorization. This function allows to unstake from\\n /// KEEP staking contract and still being able to operate in T\\n /// network and earning rewards based on the liquid T staked. Can be\\n /// called only by the delegation owner or the staking provider.\\n function unstakeKeep(address stakingProvider) external;\\n\\n /// @notice Sets to 0 the amount of T that is cached from the legacy\\n /// NU staking contract. Reverts if there is at least one\\n /// authorization higher than the sum of remaining legacy NU stake\\n /// and native T stake for that staking provider or if the unstaked\\n /// amount is higher than the cached legacy stake amount. If succeeded,\\n /// the legacy NU stake can be partially or fully undelegated on\\n /// the legacy NU staking contract. This function allows to unstake\\n /// from NU staking contract while still being able to operate in\\n /// T network and earning rewards based on the native T staked.\\n /// Can be called only by the stake owner or the staking provider.\\n function unstakeNu(address stakingProvider) external;\\n\\n /// @notice Sets cached legacy stake amount to 0, sets the liquid T stake\\n /// amount to 0 and withdraws all liquid T from the stake to the\\n /// owner. Reverts if there is at least one non-zero authorization.\\n /// Can be called only by the delegation owner or the staking\\n /// provider.\\n function unstakeAll(address stakingProvider) external;\\n\\n //\\n //\\n // Keeping information in sync\\n //\\n //\\n\\n /// @notice Sets reward in T tokens for notification of misbehaviour\\n /// of one staking provider. Can only be called by the governance.\\n function setNotificationReward(uint96 reward) external;\\n\\n /// @notice Transfer some amount of T tokens as reward for notifications\\n /// of misbehaviour\\n function pushNotificationReward(uint96 reward) external;\\n\\n /// @notice Withdraw some amount of T tokens from notifiers treasury.\\n /// Can only be called by the governance.\\n function withdrawNotificationReward(address recipient, uint96 amount)\\n external;\\n\\n /// @notice Adds staking providers to the slashing queue along with the\\n /// amount that should be slashed from each one of them. Can only be\\n /// called by application authorized for all staking providers in\\n /// the array.\\n function slash(uint96 amount, address[] memory stakingProviders) external;\\n\\n /// @notice Adds staking providers to the slashing queue along with the\\n /// amount. The notifier will receive reward per each staking\\n /// provider from notifiers treasury. Can only be called by\\n /// application authorized for all staking providers in the array.\\n function seize(\\n uint96 amount,\\n uint256 rewardMultipier,\\n address notifier,\\n address[] memory stakingProviders\\n ) external;\\n\\n /// @notice Takes the given number of queued slashing operations and\\n /// processes them. Receives 5% of the slashed amount.\\n /// Executes `involuntaryAllocationDecrease` function on each\\n /// affected application.\\n function processSlashing(uint256 count) external;\\n\\n //\\n //\\n // Auxiliary functions\\n //\\n //\\n\\n /// @notice Returns the authorized stake amount of the staking provider for\\n /// the application.\\n function authorizedStake(address stakingProvider, address application)\\n external\\n view\\n returns (uint96);\\n\\n /// @notice Returns staked amount of T, Keep and Nu for the specified\\n /// staking provider.\\n /// @dev All values are in T denomination\\n function stakes(address stakingProvider)\\n external\\n view\\n returns (\\n uint96 tStake,\\n uint96 keepInTStake,\\n uint96 nuInTStake\\n );\\n\\n /// @notice Returns start staking timestamp.\\n /// @dev This value is set at most once.\\n function getStartStakingTimestamp(address stakingProvider)\\n external\\n view\\n returns (uint256);\\n\\n /// @notice Returns auto-increase flag.\\n function getAutoIncreaseFlag(address stakingProvider)\\n external\\n view\\n returns (bool);\\n\\n /// @notice Returns staked amount of NU for the specified staking provider.\\n function stakedNu(address stakingProvider) external view returns (uint256);\\n\\n /// @notice Gets the stake owner, the beneficiary and the authorizer\\n /// for the specified staking provider address.\\n /// @return owner Stake owner address.\\n /// @return beneficiary Beneficiary address.\\n /// @return authorizer Authorizer address.\\n function rolesOf(address stakingProvider)\\n external\\n view\\n returns (\\n address owner,\\n address payable beneficiary,\\n address authorizer\\n );\\n\\n /// @notice Returns length of application array\\n function getApplicationsLength() external view returns (uint256);\\n\\n /// @notice Returns length of slashing queue\\n function getSlashingQueueLength() external view returns (uint256);\\n\\n /// @notice Returns minimum possible stake for T, KEEP or NU in T\\n /// denomination.\\n /// @dev For example, suppose the given staking provider has 10 T, 20 T worth\\n /// of KEEP, and 30 T worth of NU all staked, and the maximum\\n /// application authorization is 40 T, then `getMinStaked` for\\n /// that staking provider returns:\\n /// * 0 T if KEEP stake type specified i.e.\\n /// min = 40 T max - (10 T) = 30 T\\n /// * 10 T if NU stake type specified i.e.\\n /// min = 40 T max - (10 T) = 30 T\\n /// * 0 T if T stake type specified i.e.\\n /// min = 40 T max = 40 T\\n /// In other words, the minimum stake amount for the specified\\n /// stake type is the minimum amount of stake of the given type\\n /// needed to satisfy the maximum application authorization given\\n /// the staked amounts of the T stake types for that staking provider.\\n function getMinStaked(address stakingProvider, StakeType stakeTypes)\\n external\\n view\\n returns (uint96);\\n\\n /// @notice Returns available amount to authorize for the specified application\\n function getAvailableToAuthorize(\\n address stakingProvider,\\n address application\\n ) external view returns (uint96);\\n}\\n\",\"keccak256\":\"0xc8fbea45ba10de0383d6e7b2dd0f3931971e1b702e4a308ff8325bb23fdff81c\",\"license\":\"GPL-3.0-or-later\"},\"contracts/BeaconDkgValidator.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\nimport \\\"./libraries/BytesLib.sol\\\";\\nimport {BeaconDkg as DKG} from \\\"./libraries/BeaconDkg.sol\\\";\\n\\n/// @title DKG result validator\\n/// @notice DKGValidator allows performing a full validation of DKG result,\\n/// including checking the format of fields in the result, declared\\n/// selected group members, and signatures of operators supporting the\\n/// result. The operator submitting the result should perform the\\n/// validation using a free contract call before submitting the result\\n/// to ensure their result is valid and can not be challenged. All other\\n/// network operators should perform validation of the submitted result\\n/// using a free contract call and challenge the result if the\\n/// validation fails.\\ncontract BeaconDkgValidator {\\n using BytesLib for bytes;\\n using ECDSA for bytes32;\\n\\n /// @dev Size of a group in the threshold relay.\\n uint256 public constant groupSize = 64;\\n\\n /// @dev The minimum number of group members needed to interact according to\\n /// the protocol to produce a relay entry. The adversary can not learn\\n /// anything about the key as long as it does not break into\\n /// groupThreshold+1 of members.\\n uint256 public constant groupThreshold = 33;\\n\\n /// @dev The minimum number of active and properly behaving group members\\n /// during the DKG needed to accept the result. This number is higher\\n /// than `groupThreshold` to keep a safety margin for members becoming\\n /// inactive after DKG so that the group can still produce a relay\\n /// entry.\\n uint256 public constant activeThreshold = 58; // 90% of groupSize\\n\\n /// @dev Size in bytes of a single signature produced by operator supporting\\n /// DKG result.\\n uint256 public constant signatureByteSize = 65;\\n\\n SortitionPool public immutable sortitionPool;\\n\\n constructor(SortitionPool _sortitionPool) {\\n require(\\n address(_sortitionPool) != address(0),\\n \\\"Zero-address reference\\\"\\n );\\n\\n sortitionPool = _sortitionPool;\\n }\\n\\n /// @notice Performs a full validation of DKG result, including checking the\\n /// format of fields in the result, declared selected group members,\\n /// and signatures of operators supporting the result.\\n /// @param seed seed used to start the DKG and select group members\\n /// @param startBlock DKG start block\\n /// @return isValid true if the result is valid, false otherwise\\n /// @return errorMsg validation error message; empty for a valid result\\n function validate(\\n DKG.Result calldata result,\\n uint256 seed,\\n uint256 startBlock\\n ) external view returns (bool isValid, string memory errorMsg) {\\n (bool hasValidFields, string memory error) = validateFields(result);\\n if (!hasValidFields) {\\n return (false, error);\\n }\\n\\n if (!validateSignatures(result, startBlock)) {\\n return (false, \\\"Invalid signatures\\\");\\n }\\n\\n if (!validateGroupMembers(result, seed)) {\\n return (false, \\\"Invalid group members\\\");\\n }\\n\\n // At this point all group members and mishbehaved members were verified\\n if (!validateMembersHash(result)) {\\n return (false, \\\"Invalid members hash\\\");\\n }\\n\\n return (true, \\\"\\\");\\n }\\n\\n /// @notice Performs a static validation of DKG result fields: lengths,\\n /// ranges, and order of arrays.\\n /// @return isValid true if the result is valid, false otherwise\\n /// @return errorMsg validation error message; empty for a valid result\\n function validateFields(DKG.Result calldata result)\\n public\\n pure\\n returns (bool isValid, string memory errorMsg)\\n {\\n // Group public key needs to be 128 bytes long.\\n if (result.groupPubKey.length != 128) {\\n return (false, \\\"Malformed group public key\\\");\\n }\\n\\n // The number of misbehaved members can not exceed the threshold.\\n // Misbehaved member indices needs to be unique, between [1, groupSize],\\n // and sorted in ascending order.\\n uint8[] calldata misbehavedMembersIndices = result\\n .misbehavedMembersIndices;\\n if (groupSize - misbehavedMembersIndices.length < activeThreshold) {\\n return (false, \\\"Too many members misbehaving during DKG\\\");\\n }\\n if (misbehavedMembersIndices.length > 1) {\\n if (\\n misbehavedMembersIndices[0] < 1 ||\\n misbehavedMembersIndices[misbehavedMembersIndices.length - 1] >\\n groupSize\\n ) {\\n return (false, \\\"Corrupted misbehaved members indices\\\");\\n }\\n for (uint256 i = 1; i < misbehavedMembersIndices.length; i++) {\\n if (\\n misbehavedMembersIndices[i - 1] >=\\n misbehavedMembersIndices[i]\\n ) {\\n return (false, \\\"Corrupted misbehaved members indices\\\");\\n }\\n }\\n }\\n\\n // Each signature needs to have a correct length and signatures need to\\n // be provided.\\n uint256 signaturesCount = result.signatures.length / signatureByteSize;\\n if (result.signatures.length == 0) {\\n return (false, \\\"No signatures provided\\\");\\n }\\n if (result.signatures.length % signatureByteSize != 0) {\\n return (false, \\\"Malformed signatures array\\\");\\n }\\n\\n // We expect the same amount of signatures as the number of declared\\n // group member indices that signed the result.\\n uint256[] calldata signingMembersIndices = result.signingMembersIndices;\\n if (signaturesCount != signingMembersIndices.length) {\\n return (false, \\\"Unexpected signatures count\\\");\\n }\\n if (signaturesCount < groupThreshold) {\\n return (false, \\\"Too few signatures\\\");\\n }\\n if (signaturesCount > groupSize) {\\n return (false, \\\"Too many signatures\\\");\\n }\\n\\n // Signing member indices needs to be unique, between [1,groupSize],\\n // and sorted in ascending order.\\n if (\\n signingMembersIndices[0] < 1 ||\\n signingMembersIndices[signingMembersIndices.length - 1] > groupSize\\n ) {\\n return (false, \\\"Corrupted signing member indices\\\");\\n }\\n for (uint256 i = 1; i < signingMembersIndices.length; i++) {\\n if (signingMembersIndices[i - 1] >= signingMembersIndices[i]) {\\n return (false, \\\"Corrupted signing member indices\\\");\\n }\\n }\\n\\n return (true, \\\"\\\");\\n }\\n\\n /// @notice Performs validation of group members as declared in DKG\\n /// result against group members selected by the sortition pool.\\n /// @param seed seed used to start the DKG and select group members\\n /// @return true if group members matches; false otherwise\\n function validateGroupMembers(DKG.Result calldata result, uint256 seed)\\n public\\n view\\n returns (bool)\\n {\\n uint32[] calldata resultMembers = result.members;\\n uint32[] memory actualGroupMembers = sortitionPool.selectGroup(\\n groupSize,\\n bytes32(seed)\\n );\\n if (resultMembers.length != actualGroupMembers.length) {\\n return false;\\n }\\n for (uint256 i = 0; i < resultMembers.length; i++) {\\n if (resultMembers[i] != actualGroupMembers[i]) {\\n return false;\\n }\\n }\\n return true;\\n }\\n\\n /// @notice Performs validation of signatures supplied in DKG result.\\n /// Note that this function does not check if addresses which\\n /// supplied signatures supporting the result are the ones selected\\n /// to the group by sortition pool. This function should be used\\n /// together with `validateGroupMembers`.\\n /// @param startBlock DKG start block\\n /// @return true if group members matches; false otherwise\\n function validateSignatures(DKG.Result calldata result, uint256 startBlock)\\n public\\n view\\n returns (bool)\\n {\\n bytes32 hash = keccak256(\\n abi.encode(\\n block.chainid,\\n result.groupPubKey,\\n result.misbehavedMembersIndices,\\n startBlock\\n )\\n ).toEthSignedMessageHash();\\n\\n uint256[] calldata signingMembersIndices = result.signingMembersIndices;\\n uint32[] memory signingMemberIds = new uint32[](\\n signingMembersIndices.length\\n );\\n for (uint256 i = 0; i < signingMembersIndices.length; i++) {\\n signingMemberIds[i] = result.members[signingMembersIndices[i] - 1];\\n }\\n\\n address[] memory signingMemberAddresses = sortitionPool.getIDOperators(\\n signingMemberIds\\n );\\n\\n bytes memory current; // Current signature to be checked.\\n\\n uint256 signaturesCount = result.signatures.length / signatureByteSize;\\n for (uint256 i = 0; i < signaturesCount; i++) {\\n current = result.signatures.slice(\\n signatureByteSize * i,\\n signatureByteSize\\n );\\n address recoveredAddress = hash.recover(current);\\n\\n if (signingMemberAddresses[i] != recoveredAddress) {\\n return false;\\n }\\n }\\n\\n return true;\\n }\\n\\n /// @notice Performs validation of hashed group members that actively took\\n /// part in DKG.\\n /// @param result DKG result\\n /// @return true if result's group members hash matches with the one that is\\n /// challenged.\\n function validateMembersHash(DKG.Result calldata result)\\n public\\n pure\\n returns (bool)\\n {\\n if (result.misbehavedMembersIndices.length > 0) {\\n // members that generated a group signing key\\n uint32[] memory groupMembers = new uint32[](\\n result.members.length - result.misbehavedMembersIndices.length\\n );\\n uint256 k = 0; // misbehaved members counter\\n uint256 j = 0; // group members counter\\n for (uint256 i = 0; i < result.members.length; i++) {\\n // misbehaved member indices start from 1, so we need to -1 on misbehaved\\n if (i != result.misbehavedMembersIndices[k] - 1) {\\n groupMembers[j] = result.members[i];\\n j++;\\n } else if (k < result.misbehavedMembersIndices.length - 1) {\\n k++;\\n }\\n }\\n\\n return keccak256(abi.encode(groupMembers)) == result.membersHash;\\n }\\n\\n return keccak256(abi.encode(result.members)) == result.membersHash;\\n }\\n}\\n\",\"keccak256\":\"0xaacb5961dc3181238036f1e747b3d1935f356ca5ff27bd9c9c1c0c22dee6630c\",\"license\":\"GPL-3.0-only\"},\"contracts/Governable.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\n/// @notice Governable contract.\\n/// @dev A constructor is not defined, which makes the contract compatible with\\n/// upgradable proxies. This requires calling explicitly `_transferGovernance`\\n/// function in a child contract.\\nabstract contract Governable {\\n // Governance of the contract\\n // The variable should be initialized by the implementing contract.\\n // slither-disable-next-line uninitialized-state\\n address public governance;\\n\\n // Reserved storage space in case we need to add more variables,\\n // since there are upgradeable contracts that inherit from this one.\\n // See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\\n // slither-disable-next-line unused-state\\n uint256[49] private __gap;\\n\\n event GovernanceTransferred(address oldGovernance, address newGovernance);\\n\\n modifier onlyGovernance() virtual {\\n require(governance == msg.sender, \\\"Caller is not the governance\\\");\\n _;\\n }\\n\\n /// @notice Transfers governance of the contract to `newGovernance`.\\n function transferGovernance(address newGovernance)\\n external\\n virtual\\n onlyGovernance\\n {\\n require(\\n newGovernance != address(0),\\n \\\"New governance is the zero address\\\"\\n );\\n _transferGovernance(newGovernance);\\n }\\n\\n function _transferGovernance(address newGovernance) internal virtual {\\n address oldGovernance = governance;\\n governance = newGovernance;\\n emit GovernanceTransferred(oldGovernance, newGovernance);\\n }\\n}\\n\",\"keccak256\":\"0xcc6a0fe8fdf05a805d2874dc7dd76dede1eb16e3ab77f2d0069dbb92272ab0a3\",\"license\":\"GPL-3.0-only\"},\"contracts/RandomBeacon.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./api/IRandomBeacon.sol\\\";\\nimport \\\"./libraries/Groups.sol\\\";\\nimport \\\"./libraries/Relay.sol\\\";\\nimport \\\"./libraries/Groups.sol\\\";\\nimport \\\"./libraries/Callback.sol\\\";\\nimport \\\"./Reimbursable.sol\\\";\\nimport \\\"./Governable.sol\\\";\\nimport {BeaconInactivity as Inactivity} from \\\"./libraries/BeaconInactivity.sol\\\";\\nimport {BeaconAuthorization as Authorization} from \\\"./libraries/BeaconAuthorization.sol\\\";\\nimport {BeaconDkg as DKG} from \\\"./libraries/BeaconDkg.sol\\\";\\nimport {BeaconDkgValidator as DKGValidator} from \\\"./BeaconDkgValidator.sol\\\";\\n\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\nimport \\\"@threshold-network/solidity-contracts/contracts/staking/IApplication.sol\\\";\\nimport \\\"@threshold-network/solidity-contracts/contracts/staking/IStaking.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/Math.sol\\\";\\n\\n/// @title Keep Random Beacon\\n/// @notice Keep Random Beacon contract. It lets to request a new\\n/// relay entry and validates the new relay entry provided by the\\n/// network. This contract is in charge of all other Random Beacon\\n/// activities such as group lifecycle or slashing.\\n/// @dev Should be owned by the governance contract controlling Random Beacon\\n/// parameters.\\ncontract RandomBeacon is IRandomBeacon, IApplication, Governable, Reimbursable {\\n using SafeERC20 for IERC20;\\n using Authorization for Authorization.Data;\\n using DKG for DKG.Data;\\n using Groups for Groups.Data;\\n using Relay for Relay.Data;\\n using Callback for Callback.Data;\\n\\n // Constant parameters\\n\\n /// @notice Seed value used for the genesis group selection.\\n /// https://www.wolframalpha.com/input/?i=pi+to+78+digits\\n uint256 internal constant genesisSeed =\\n 31415926535897932384626433832795028841971693993751058209749445923078164062862;\\n\\n // Governable parameters\\n\\n /// @notice Relay entry callback gas limit. This is the gas limit with which\\n /// callback function provided in the relay request transaction is\\n /// executed. The callback is executed with a new relay entry value\\n /// in the same transaction the relay entry is submitted.\\n uint256 internal _callbackGasLimit;\\n\\n /// @notice The frequency of new group creation. Groups are created with\\n /// a fixed frequency of relay requests.\\n uint256 internal _groupCreationFrequency;\\n\\n /// @notice Slashing amount for submitting a malicious DKG result. Every\\n /// DKG result submitted can be challenged for the time of\\n /// `dkg.ResultChallengePeriodLength`. If the DKG result submitted\\n /// is challenged and proven to be malicious, the operator who\\n /// submitted the malicious result is slashed for\\n /// `_maliciousDkgResultSlashingAmount`.\\n uint96 internal _maliciousDkgResultSlashingAmount;\\n\\n /// @notice Slashing amount when an unauthorized signing has been proved,\\n /// which means the private key leaked and all the group members\\n /// should be punished.\\n uint96 internal _unauthorizedSigningSlashingAmount;\\n\\n /// @notice Duration of the sortition pool rewards ban imposed on operators\\n /// who misbehaved during DKG by being inactive or disqualified and\\n /// for operators that were identified by the rest of group members\\n /// as inactive via `notifyOperatorInactivity`.\\n uint256 internal _sortitionPoolRewardsBanDuration;\\n\\n /// @notice Percentage of the staking contract malicious behavior\\n /// notification reward which will be transferred to the notifier\\n /// reporting about relay entry timeout. Notifiers are rewarded\\n /// from a notifiers treasury pool. For example, if\\n /// notification reward is 1000 and the value of the multiplier is\\n /// 5, the notifier will receive: 5% of 1000 = 50 per each\\n /// operator affected.\\n uint256 internal _relayEntryTimeoutNotificationRewardMultiplier;\\n\\n /// @notice Percentage of the staking contract malicious behavior\\n /// notification reward which will be transferred to the notifier\\n /// reporting about unauthorized signing. Notifiers are rewarded\\n /// from a notifiers treasury pool. For example, if a\\n /// notification reward is 1000 and the value of the multiplier is\\n /// 5, the notifier will receive: 5% of 1000 = 50 per each\\n /// operator affected.\\n uint256 internal _unauthorizedSigningNotificationRewardMultiplier;\\n\\n /// @notice Percentage of the staking contract malicious behavior\\n /// notification reward which will be transferred to the notifier\\n /// reporting about a malicious DKG result. Notifiers are rewarded\\n /// from a notifiers treasury pool. For example, if\\n /// notification reward is 1000 and the value of the multiplier is\\n /// 5, the notifier will receive: 5% of 1000 = 50 per each\\n /// operator affected.\\n uint256 internal _dkgMaliciousResultNotificationRewardMultiplier;\\n\\n /// @notice Calculated gas cost for submitting a DKG result. This will\\n /// be refunded as part of the DKG approval process. It is in the\\n /// submitter's interest to not skip his priority turn on the approval,\\n /// otherwise the refund of the DKG submission will be refunded to\\n /// another group member that will call the DKG approve function.\\n uint256 internal _dkgResultSubmissionGas;\\n\\n /// @notice Gas that is meant to balance the DKG result approval's overall\\n /// cost. Can be updated by the governance based on the current\\n /// market conditions.\\n uint256 internal _dkgResultApprovalGasOffset;\\n\\n /// @notice Gas that is meant to balance the operator inactivity notification\\n /// cost. Can be updated by the governance based on the current\\n /// market conditions.\\n uint256 internal _notifyOperatorInactivityGasOffset;\\n\\n /// @notice Gas that is meant to balance the relay entry submission cost.\\n /// Can be updated by the governance based on the current market\\n /// conditions.\\n uint256 internal _relayEntrySubmissionGasOffset;\\n\\n // Other parameters\\n\\n /// @notice Stores current operator inactivity claim nonce for given group.\\n /// Each claim is made with an unique nonce which protects\\n /// against claim replay.\\n mapping(uint64 => uint256) public inactivityClaimNonce; // groupId -> nonce\\n\\n /// @notice Authorized addresses that can request a relay entry.\\n mapping(address => bool) public authorizedRequesters;\\n\\n // External dependencies\\n\\n SortitionPool public sortitionPool;\\n IERC20 public tToken;\\n IStaking public staking;\\n\\n // Libraries data storages\\n\\n Authorization.Data internal authorization;\\n DKG.Data internal dkg;\\n Groups.Data internal groups;\\n Relay.Data internal relay;\\n Callback.Data internal callback;\\n\\n // Events\\n\\n event AuthorizationParametersUpdated(\\n uint96 minimumAuthorization,\\n uint64 authorizationDecreaseDelay,\\n uint64 authorizationDecreaseChangePeriod\\n );\\n\\n event RelayEntryParametersUpdated(\\n uint256 relayEntrySoftTimeout,\\n uint256 relayEntryHardTimeout,\\n uint256 callbackGasLimit\\n );\\n\\n event GroupCreationParametersUpdated(\\n uint256 groupCreationFrequency,\\n uint256 groupLifetime,\\n uint256 dkgResultChallengePeriodLength,\\n uint256 dkgResultChallengeExtraGas,\\n uint256 dkgResultSubmissionTimeout,\\n uint256 dkgResultSubmitterPrecedencePeriodLength\\n );\\n\\n event RewardParametersUpdated(\\n uint256 sortitionPoolRewardsBanDuration,\\n uint256 relayEntryTimeoutNotificationRewardMultiplier,\\n uint256 unauthorizedSigningNotificationRewardMultiplier,\\n uint256 dkgMaliciousResultNotificationRewardMultiplier\\n );\\n\\n event SlashingParametersUpdated(\\n uint256 relayEntrySubmissionFailureSlashingAmount,\\n uint256 maliciousDkgResultSlashingAmount,\\n uint256 unauthorizedSigningSlashingAmount\\n );\\n\\n event GasParametersUpdated(\\n uint256 dkgResultSubmissionGas,\\n uint256 dkgResultApprovalGasOffset,\\n uint256 notifyOperatorInactivityGasOffset,\\n uint256 relayEntrySubmissionGasOffset\\n );\\n\\n event RequesterAuthorizationUpdated(\\n address indexed requester,\\n bool isAuthorized\\n );\\n\\n event DkgStarted(uint256 indexed seed);\\n\\n event DkgResultSubmitted(\\n bytes32 indexed resultHash,\\n uint256 indexed seed,\\n DKG.Result result\\n );\\n\\n event DkgTimedOut();\\n\\n event DkgResultApproved(\\n bytes32 indexed resultHash,\\n address indexed approver\\n );\\n\\n event DkgResultChallenged(\\n bytes32 indexed resultHash,\\n address indexed challenger,\\n string reason\\n );\\n\\n event DkgMaliciousResultSlashed(\\n bytes32 indexed resultHash,\\n uint256 slashingAmount,\\n address maliciousSubmitter\\n );\\n\\n event DkgMaliciousResultSlashingFailed(\\n bytes32 indexed resultHash,\\n uint256 slashingAmount,\\n address maliciousSubmitter\\n );\\n\\n event DkgStateLocked();\\n\\n event DkgSeedTimedOut();\\n\\n event GroupRegistered(uint64 indexed groupId, bytes indexed groupPubKey);\\n\\n event RelayEntryRequested(\\n uint256 indexed requestId,\\n uint64 groupId,\\n bytes previousEntry\\n );\\n\\n event RelayEntrySubmitted(\\n uint256 indexed requestId,\\n address submitter,\\n bytes entry\\n );\\n\\n event RelayEntryTimedOut(\\n uint256 indexed requestId,\\n uint64 terminatedGroupId\\n );\\n\\n event RelayEntryDelaySlashed(\\n uint256 indexed requestId,\\n uint256 slashingAmount,\\n address[] groupMembers\\n );\\n\\n event RelayEntryDelaySlashingFailed(\\n uint256 indexed requestId,\\n uint256 slashingAmount,\\n address[] groupMembers\\n );\\n\\n event RelayEntryTimeoutSlashed(\\n uint256 indexed requestId,\\n uint256 slashingAmount,\\n address[] groupMembers\\n );\\n\\n event RelayEntryTimeoutSlashingFailed(\\n uint256 indexed requestId,\\n uint256 slashingAmount,\\n address[] groupMembers\\n );\\n\\n event UnauthorizedSigningSlashed(\\n uint64 indexed groupId,\\n uint256 unauthorizedSigningSlashingAmount,\\n address[] groupMembers\\n );\\n\\n event UnauthorizedSigningSlashingFailed(\\n uint64 indexed groupId,\\n uint256 unauthorizedSigningSlashingAmount,\\n address[] groupMembers\\n );\\n\\n event CallbackFailed(uint256 entry, uint256 entrySubmittedBlock);\\n\\n event InactivityClaimed(\\n uint64 indexed groupId,\\n uint256 nonce,\\n address notifier\\n );\\n\\n event OperatorRegistered(\\n address indexed stakingProvider,\\n address indexed operator\\n );\\n\\n event AuthorizationIncreased(\\n address indexed stakingProvider,\\n address indexed operator,\\n uint96 fromAmount,\\n uint96 toAmount\\n );\\n\\n event AuthorizationDecreaseRequested(\\n address indexed stakingProvider,\\n address indexed operator,\\n uint96 fromAmount,\\n uint96 toAmount,\\n uint64 decreasingAt\\n );\\n\\n event AuthorizationDecreaseApproved(address indexed stakingProvider);\\n\\n event InvoluntaryAuthorizationDecreaseFailed(\\n address indexed stakingProvider,\\n address indexed operator,\\n uint96 fromAmount,\\n uint96 toAmount\\n );\\n\\n event OperatorJoinedSortitionPool(\\n address indexed stakingProvider,\\n address indexed operator\\n );\\n\\n event OperatorStatusUpdated(\\n address indexed stakingProvider,\\n address indexed operator\\n );\\n\\n /// @dev Assigns initial values to parameters to make the beacon work\\n /// safely. These parameters are just proposed defaults and they might\\n /// be updated with `update*` functions after the contract deployment\\n /// and before transferring the ownership to the governance contract.\\n constructor(\\n SortitionPool _sortitionPool,\\n IERC20 _tToken,\\n IStaking _staking,\\n DKGValidator _dkgValidator,\\n ReimbursementPool _reimbursementPool\\n ) {\\n sortitionPool = _sortitionPool;\\n tToken = _tToken;\\n staking = _staking;\\n reimbursementPool = _reimbursementPool;\\n\\n require(\\n address(_sortitionPool) != address(0),\\n \\\"Zero-address reference\\\"\\n );\\n require(address(_tToken) != address(0), \\\"Zero-address reference\\\");\\n require(address(_staking) != address(0), \\\"Zero-address reference\\\");\\n require(address(_dkgValidator) != address(0), \\\"Zero-address reference\\\");\\n require(\\n address(_reimbursementPool) != address(0),\\n \\\"Zero-address reference\\\"\\n );\\n\\n dkg.init(_sortitionPool, _dkgValidator);\\n relay.initSeedEntry();\\n\\n _transferGovernance(msg.sender);\\n\\n //\\n // All parameters set in the constructor are initial ones, used at the\\n // moment contracts were deployed for the first time. Parameters are\\n // governable and values assigned in the constructor do not need to\\n // reflect the current ones.\\n //\\n\\n // Minimum authorization is 40k T.\\n //\\n // Authorization decrease delay is 45 days.\\n //\\n // Authorization decrease change period is 45 days. It means pending\\n // authorization decrease can be overwritten all the time.\\n authorization.setParameters(40_000e18, 3_888_000, 3_888_000);\\n\\n // Malicious DKG result slashing amount is set initially to 1% of the\\n // minimum authorization (400 T). This values needs to be increased\\n // significantly once the system is fully launched.\\n //\\n // Unauthorized signing slashing amount is set initially to 1% of the\\n // minimum authorization (400 T). This values needs to be increased\\n // significantly once the system is fully launched.\\n //\\n // Slashing amount for not providing relay entry on time is set\\n // initially to 1% of the minimum authorization (400 T). This values\\n // needs to be increased significantly once the system is fully launched.\\n //\\n // Inactive operators are set as ineligible for rewards for 2 weeks.\\n _maliciousDkgResultSlashingAmount = 400e18;\\n _unauthorizedSigningSlashingAmount = 400e18;\\n relay.setRelayEntrySubmissionFailureSlashingAmount(400e18);\\n\\n // Notifier of a malicious DKG result receives 100% of the notifier\\n // reward from the staking contract.\\n //\\n // Notifier of unauthorized signing receives 100% of the notifier\\n // reward from the staking contract.\\n //\\n // Notifier of relay entry timeout receives 100% of the notifier\\n // reward from the staking contract.\\n _dkgMaliciousResultNotificationRewardMultiplier = 100;\\n _unauthorizedSigningNotificationRewardMultiplier = 100;\\n _relayEntryTimeoutNotificationRewardMultiplier = 100;\\n\\n // Inactive operators are set as ineligible for rewards for 2 weeks.\\n _sortitionPoolRewardsBanDuration = 2 weeks;\\n\\n // DKG result challenge period length is set to 48h, assuming\\n // 15s block time.\\n //\\n // The extra gas required for DKG result challenge is 50k units.\\n //\\n // DKG result submission timeout, gives each member 20 blocks to submit\\n // the result. Assuming 15s block time, it is ~8h to submit the result\\n // in the pessimistic case.\\n //\\n // The original DKG result submitter has 20 blocks to approve it before\\n // anyone else can do that.\\n //\\n // With these parameters, the happy path takes no more than 56 hours.\\n // In practice, it should take about 48 hours (just the challenge time).\\n dkg.setParameters(11_520, 50_000, 1_280, 20);\\n\\n // Relay entry soft timeout gives each of 64 members 20 blocks to submit\\n // the result.\\n //\\n // Relay entry hard timeout is set to ~48h assuming 15s block time.\\n relay.setTimeouts(1_280, 5_760);\\n\\n // Callback gas limit is set to 56k units of gas. As of April 2022, it\\n // is enough to store new entry and block number on-chain.\\n // If the cost of EVM opcodes change over time, these parameters will\\n // have to be updated.\\n _callbackGasLimit = 64_000;\\n\\n // Group lifetime is set to 45 days assuming 15s block time.\\n //\\n // New group is created every 2 relay requests.\\n //\\n // This way, even if ECDSA WalletRegistry is the only consumer of the\\n // beacon initially, and relay request is executed every week, we should\\n // have 2 active groups in the system all the time.\\n groups.setGroupLifetime(259_200);\\n _groupCreationFrequency = 2;\\n\\n // Gas parameters were adjusted based on Ethereum state in April 2022.\\n // If the cost of EVM opcodes change over time, these parameters will\\n // have to be updated.\\n _dkgResultSubmissionGas = 237_650;\\n _dkgResultApprovalGasOffset = 41_500;\\n _notifyOperatorInactivityGasOffset = 54_500;\\n _relayEntrySubmissionGasOffset = 11_250;\\n }\\n\\n modifier onlyStakingContract() {\\n require(\\n msg.sender == address(staking),\\n \\\"Caller is not the staking contract\\\"\\n );\\n _;\\n }\\n\\n modifier onlyReimbursableAdmin() override {\\n require(governance == msg.sender, \\\"Caller is not the governance\\\");\\n _;\\n }\\n\\n /// @notice Updates the values of authorization parameters.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract. The caller is responsible for\\n /// validating parameters.\\n /// @param _minimumAuthorization New minimum authorization amount\\n /// @param _authorizationDecreaseDelay New authorization decrease delay in\\n /// seconds\\n /// @param _authorizationDecreaseChangePeriod New authorization decrease\\n /// change period in seconds\\n function updateAuthorizationParameters(\\n uint96 _minimumAuthorization,\\n uint64 _authorizationDecreaseDelay,\\n uint64 _authorizationDecreaseChangePeriod\\n ) external onlyGovernance {\\n authorization.setParameters(\\n _minimumAuthorization,\\n _authorizationDecreaseDelay,\\n _authorizationDecreaseChangePeriod\\n );\\n\\n emit AuthorizationParametersUpdated(\\n _minimumAuthorization,\\n _authorizationDecreaseDelay,\\n _authorizationDecreaseChangePeriod\\n );\\n }\\n\\n /// @notice Updates the values of relay entry parameters.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract. The caller is responsible for\\n /// validating parameters.\\n /// @param relayEntrySoftTimeout New relay entry submission soft timeout\\n /// @param relayEntryHardTimeout New relay entry hard timeout\\n /// @param callbackGasLimit New callback gas limit\\n function updateRelayEntryParameters(\\n uint256 relayEntrySoftTimeout,\\n uint256 relayEntryHardTimeout,\\n uint256 callbackGasLimit\\n ) external onlyGovernance {\\n _callbackGasLimit = callbackGasLimit;\\n relay.setTimeouts(relayEntrySoftTimeout, relayEntryHardTimeout);\\n\\n emit RelayEntryParametersUpdated(\\n relayEntrySoftTimeout,\\n relayEntryHardTimeout,\\n callbackGasLimit\\n );\\n }\\n\\n /// @notice Updates the values of group creation parameters.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract. The caller is responsible for\\n /// validating parameters.\\n /// @param groupCreationFrequency New group creation frequency\\n /// @param groupLifetime New group lifetime in blocks\\n /// @param dkgResultChallengePeriodLength New DKG result challenge period\\n /// length\\n /// @param dkgResultChallengeExtraGas New DKG result challenge extra gas\\n /// @param dkgResultSubmissionTimeout New DKG result submission timeout\\n /// @param dkgSubmitterPrecedencePeriodLength New DKG result submitter\\n /// precedence period length\\n function updateGroupCreationParameters(\\n uint256 groupCreationFrequency,\\n uint256 groupLifetime,\\n uint256 dkgResultChallengePeriodLength,\\n uint256 dkgResultChallengeExtraGas,\\n uint256 dkgResultSubmissionTimeout,\\n uint256 dkgSubmitterPrecedencePeriodLength\\n ) external onlyGovernance {\\n _groupCreationFrequency = groupCreationFrequency;\\n groups.setGroupLifetime(groupLifetime);\\n dkg.setParameters(\\n dkgResultChallengePeriodLength,\\n dkgResultChallengeExtraGas,\\n dkgResultSubmissionTimeout,\\n dkgSubmitterPrecedencePeriodLength\\n );\\n\\n emit GroupCreationParametersUpdated(\\n groupCreationFrequency,\\n groupLifetime,\\n dkgResultChallengePeriodLength,\\n dkgResultChallengeExtraGas,\\n dkgResultSubmissionTimeout,\\n dkgSubmitterPrecedencePeriodLength\\n );\\n }\\n\\n /// @notice Updates the values of reward parameters.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract. The caller is responsible for\\n /// validating parameters.\\n /// @param sortitionPoolRewardsBanDuration New sortition pool rewards\\n /// ban duration in seconds.\\n /// @param relayEntryTimeoutNotificationRewardMultiplier New value of the\\n /// relay entry timeout notification reward multiplier\\n /// @param unauthorizedSigningNotificationRewardMultiplier New value of the\\n /// unauthorized signing notification reward multiplier\\n /// @param dkgMaliciousResultNotificationRewardMultiplier New value of the\\n /// DKG malicious result notification reward multiplier\\n function updateRewardParameters(\\n uint256 sortitionPoolRewardsBanDuration,\\n uint256 relayEntryTimeoutNotificationRewardMultiplier,\\n uint256 unauthorizedSigningNotificationRewardMultiplier,\\n uint256 dkgMaliciousResultNotificationRewardMultiplier\\n ) external onlyGovernance {\\n _sortitionPoolRewardsBanDuration = sortitionPoolRewardsBanDuration;\\n _relayEntryTimeoutNotificationRewardMultiplier = relayEntryTimeoutNotificationRewardMultiplier;\\n _unauthorizedSigningNotificationRewardMultiplier = unauthorizedSigningNotificationRewardMultiplier;\\n _dkgMaliciousResultNotificationRewardMultiplier = dkgMaliciousResultNotificationRewardMultiplier;\\n emit RewardParametersUpdated(\\n sortitionPoolRewardsBanDuration,\\n relayEntryTimeoutNotificationRewardMultiplier,\\n unauthorizedSigningNotificationRewardMultiplier,\\n dkgMaliciousResultNotificationRewardMultiplier\\n );\\n }\\n\\n /// @notice Updates the values of slashing parameters.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract. The caller is responsible for\\n /// validating parameters.\\n /// @param relayEntrySubmissionFailureSlashingAmount New relay entry\\n /// submission failure amount\\n /// @param maliciousDkgResultSlashingAmount New malicious DKG result\\n /// slashing amount\\n /// @param unauthorizedSigningSlashingAmount New unauthorized signing\\n /// slashing amount\\n function updateSlashingParameters(\\n uint96 relayEntrySubmissionFailureSlashingAmount,\\n uint96 maliciousDkgResultSlashingAmount,\\n uint96 unauthorizedSigningSlashingAmount\\n ) external onlyGovernance {\\n relay.setRelayEntrySubmissionFailureSlashingAmount(\\n relayEntrySubmissionFailureSlashingAmount\\n );\\n _maliciousDkgResultSlashingAmount = maliciousDkgResultSlashingAmount;\\n _unauthorizedSigningSlashingAmount = unauthorizedSigningSlashingAmount;\\n emit SlashingParametersUpdated(\\n relayEntrySubmissionFailureSlashingAmount,\\n maliciousDkgResultSlashingAmount,\\n unauthorizedSigningSlashingAmount\\n );\\n }\\n\\n /// @notice Updates the values of gas parameters.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract. The caller is responsible for\\n /// validating parameters.\\n /// @param dkgResultSubmissionGas New DKG result submission gas\\n /// @param dkgResultApprovalGasOffset New DKG result approval gas offset\\n /// @param notifyOperatorInactivityGasOffset New operator inactivity\\n /// notification gas offset\\n /// @param relayEntrySubmissionGasOffset New relay entry submission gas\\n /// offset\\n function updateGasParameters(\\n uint256 dkgResultSubmissionGas,\\n uint256 dkgResultApprovalGasOffset,\\n uint256 notifyOperatorInactivityGasOffset,\\n uint256 relayEntrySubmissionGasOffset\\n ) external onlyGovernance {\\n _dkgResultSubmissionGas = dkgResultSubmissionGas;\\n _dkgResultApprovalGasOffset = dkgResultApprovalGasOffset;\\n _notifyOperatorInactivityGasOffset = notifyOperatorInactivityGasOffset;\\n _relayEntrySubmissionGasOffset = relayEntrySubmissionGasOffset;\\n\\n emit GasParametersUpdated(\\n dkgResultSubmissionGas,\\n dkgResultApprovalGasOffset,\\n notifyOperatorInactivityGasOffset,\\n relayEntrySubmissionGasOffset\\n );\\n }\\n\\n /// @notice Set authorization for requesters that can request a relay\\n /// entry.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract.\\n /// @param requester Requester, can be a contract or EOA\\n /// @param isAuthorized True or false\\n function setRequesterAuthorization(address requester, bool isAuthorized)\\n external\\n onlyGovernance\\n {\\n authorizedRequesters[requester] = isAuthorized;\\n\\n emit RequesterAuthorizationUpdated(requester, isAuthorized);\\n }\\n\\n /// @notice Withdraws application rewards for the given staking provider.\\n /// Rewards are withdrawn to the staking provider's beneficiary\\n /// address set in the staking contract. Reverts if staking provider\\n /// has not registered the operator address.\\n /// @dev Emits `RewardsWithdrawn` event.\\n function withdrawRewards(address stakingProvider) external {\\n address operator = stakingProviderToOperator(stakingProvider);\\n require(operator != address(0), \\\"Unknown operator\\\");\\n (, address beneficiary, ) = staking.rolesOf(stakingProvider);\\n uint96 amount = sortitionPool.withdrawRewards(operator, beneficiary);\\n // slither-disable-next-line reentrancy-events\\n emit RewardsWithdrawn(stakingProvider, amount);\\n }\\n\\n /// @notice Withdraws rewards belonging to operators marked as ineligible\\n /// for sortition pool rewards.\\n /// @dev Can be called only by the contract guvnor, which should be the\\n /// random beacon governance contract.\\n /// @param recipient Recipient of withdrawn rewards.\\n function withdrawIneligibleRewards(address recipient)\\n external\\n onlyGovernance\\n {\\n sortitionPool.withdrawIneligible(recipient);\\n }\\n\\n /// @notice Used by staking provider to set operator address that will\\n /// operate a node. The given staking provider can set operator\\n /// address only one time. The operator address can not be changed\\n /// and must be unique. Reverts if the operator is already set for\\n /// the staking provider or if the operator address is already in\\n /// use. Reverts if there is a pending authorization decrease for\\n /// the staking provider.\\n function registerOperator(address operator) external {\\n authorization.registerOperator(operator);\\n }\\n\\n /// @notice Lets the operator join the sortition pool. The operator address\\n /// must be known - before calling this function, it has to be\\n /// appointed by the staking provider by calling `registerOperator`.\\n /// Also, the operator must have the minimum authorization required\\n /// by the beacon. Function reverts if there is no minimum stake\\n /// authorized or if the operator is not known. If there was an\\n /// authorization decrease requested, it is activated by starting\\n /// the authorization decrease delay.\\n function joinSortitionPool() external {\\n authorization.joinSortitionPool(staking, sortitionPool);\\n }\\n\\n /// @notice Updates status of the operator in the sortition pool. If there\\n /// was an authorization decrease requested, it is activated by\\n /// starting the authorization decrease delay.\\n /// Function reverts if the operator is not known.\\n function updateOperatorStatus(address operator) external {\\n authorization.updateOperatorStatus(staking, sortitionPool, operator);\\n }\\n\\n /// @notice Used by T staking contract to inform the beacon that the\\n /// authorized stake amount for the given staking provider increased.\\n ///\\n /// Reverts if the authorization amount is below the minimum.\\n ///\\n /// The function is not updating the sortition pool. Sortition pool\\n /// state needs to be updated by the operator with a call to\\n /// `joinSortitionPool` or `updateOperatorStatus`.\\n ///\\n /// @dev Can only be called by T staking contract.\\n function authorizationIncreased(\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external onlyStakingContract {\\n authorization.authorizationIncreased(\\n stakingProvider,\\n fromAmount,\\n toAmount\\n );\\n }\\n\\n /// @notice Used by T staking contract to inform the beacon that the\\n /// authorization decrease for the given staking provider has been\\n /// requested.\\n ///\\n /// Reverts if the amount after deauthorization would be non-zero\\n /// and lower than the minimum authorization.\\n ///\\n /// Reverts if another authorization decrease request is pending for\\n /// the staking provider and not enough time passed since the\\n /// original request (see `authorizationDecreaseChangePeriod`).\\n ///\\n /// If the operator is not known (`registerOperator` was not called)\\n /// it lets to `approveAuthorizationDecrease` immediately. If the\\n /// operator is known (`registerOperator` was called), the operator\\n /// needs to update state of the sortition pool with a call to\\n /// `joinSortitionPool` or `updateOperatorStatus`. After the\\n /// sortition pool state is in sync, authorization decrease delay\\n /// starts.\\n ///\\n /// After authorization decrease delay passes, authorization\\n /// decrease request needs to be approved with a call to\\n /// `approveAuthorizationDecrease` function.\\n ///\\n /// If there is a pending authorization decrease request, it is\\n /// overwritten, but only if enough time passed since the original\\n /// request. Otherwise, the function reverts.\\n ///\\n /// @dev Can only be called by T staking contract.\\n function authorizationDecreaseRequested(\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external onlyStakingContract {\\n authorization.authorizationDecreaseRequested(\\n stakingProvider,\\n fromAmount,\\n toAmount\\n );\\n }\\n\\n /// @notice Approves the previously registered authorization decrease\\n /// request. Reverts if authorization decrease delay has not passed\\n /// yet or if the authorization decrease was not requested for the\\n /// given staking provider.\\n function approveAuthorizationDecrease(address stakingProvider) external {\\n authorization.approveAuthorizationDecrease(staking, stakingProvider);\\n }\\n\\n /// @notice Used by T staking contract to inform the beacon the\\n /// authorization has been decreased for the given staking provider\\n /// involuntarily, as a result of slashing.\\n ///\\n /// If the operator is not known (`registerOperator` was not called)\\n /// the function does nothing. The operator was never in a sortition\\n /// pool so there is nothing to update.\\n ///\\n /// If the operator is known, sortition pool is unlocked, and the\\n /// operator is in the sortition pool, the sortition pool state is\\n /// updated. If the sortition pool is locked, update needs to be\\n /// postponed. Every other staker is incentivized to call\\n /// `updateOperatorStatus` for the problematic operator to increase\\n /// their own rewards in the pool.\\n function involuntaryAuthorizationDecrease(\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external onlyStakingContract {\\n authorization.involuntaryAuthorizationDecrease(\\n staking,\\n sortitionPool,\\n stakingProvider,\\n fromAmount,\\n toAmount\\n );\\n }\\n\\n /// @notice Triggers group selection if there are no active groups.\\n function genesis() external {\\n require(groups.numberOfActiveGroups() == 0, \\\"Not awaiting genesis\\\");\\n\\n dkg.lockState();\\n dkg.start(\\n uint256(keccak256(abi.encodePacked(genesisSeed, block.number)))\\n );\\n }\\n\\n /// @notice Submits result of DKG protocol. It is on-chain part of phase 14 of\\n /// the protocol. The DKG result consists of result submitting member\\n /// index, calculated group public key, bytes array of misbehaved\\n /// members, concatenation of signatures from group members,\\n /// indices of members corresponding to each signature and\\n /// the list of group members.\\n /// When the result is verified successfully it gets registered and\\n /// waits for an approval. A result can be challenged to verify the\\n /// members list corresponds to the expected set of members determined\\n /// by the sortition pool.\\n /// A candidate group is registered based on the submitted DKG result\\n /// details.\\n /// @dev The message to be signed by each member is keccak256 hash of the\\n /// chain ID, calculated group public key, misbehaved members as bytes\\n /// and DKG start block. The calculated hash should be prefixed with\\n // prefixed with\\n /// `\\\\x19Ethereum signed message:\\\\n` before signing, so the message to\\n /// sign is:\\n /// `\\\\x19Ethereum signed message:\\\\n${keccak256(chainID,groupPubKey,misbehaved,startBlock)}`\\n /// @param dkgResult DKG result.\\n function submitDkgResult(DKG.Result calldata dkgResult) external {\\n groups.validatePublicKey(dkgResult.groupPubKey);\\n dkg.submitResult(dkgResult);\\n }\\n\\n /// @notice Notifies about DKG timeout.\\n function notifyDkgTimeout() external refundable(msg.sender) {\\n dkg.notifyTimeout();\\n }\\n\\n /// @notice Approves DKG result. Can be called when the challenge period for\\n /// the submitted result is finished. Considers the submitted result\\n /// as valid, bans misbehaved group members from the sortition pool\\n /// rewards, and completes the group creation by activating the\\n /// candidate group. For the first `submitterPrecedencePeriodLength`\\n /// blocks after the end of the challenge period can be called only\\n /// by the DKG result submitter. After that time, can be called by\\n /// anyone.\\n /// @param dkgResult Result to approve. Must match the submitted result\\n /// stored during `submitDkgResult`.\\n function approveDkgResult(DKG.Result calldata dkgResult) external {\\n uint256 gasStart = gasleft();\\n\\n uint32[] memory misbehavedMembers = dkg.approveResult(dkgResult);\\n\\n if (misbehavedMembers.length > 0) {\\n sortitionPool.setRewardIneligibility(\\n misbehavedMembers,\\n // solhint-disable-next-line not-rely-on-time\\n block.timestamp + _sortitionPoolRewardsBanDuration\\n );\\n }\\n\\n groups.addGroup(dkgResult.groupPubKey, dkgResult.membersHash);\\n dkg.complete();\\n\\n // Refund msg.sender's ETH for DKG result submission and result approval\\n reimbursementPool.refund(\\n _dkgResultSubmissionGas +\\n (gasStart - gasleft()) +\\n _dkgResultApprovalGasOffset,\\n msg.sender\\n );\\n }\\n\\n /// @notice Challenges DKG result. If the submitted result is proved to be\\n /// invalid it reverts the DKG back to the result submission phase.\\n /// It removes a candidate group that was previously registered with\\n /// the DKG result submission.\\n /// @param dkgResult Result to challenge. Must match the submitted result\\n /// stored during `submitDkgResult`.\\n /// @dev Due to EIP-150 1/64 of the gas is not forwarded to the call, and\\n /// will be kept to execute the remaining operations in the function\\n /// after the call inside the try-catch. To eliminate a class of\\n /// attacks related to the gas limit manipulation, this function\\n /// requires an extra amount of gas to be left at the end of the\\n /// execution.\\n function challengeDkgResult(DKG.Result calldata dkgResult) external {\\n (bytes32 maliciousResultHash, uint32 maliciousSubmitter) = dkg\\n .challengeResult(dkgResult);\\n\\n uint96 slashingAmount = _maliciousDkgResultSlashingAmount;\\n address maliciousSubmitterAddresses = sortitionPool.getIDOperator(\\n maliciousSubmitter\\n );\\n\\n address[] memory stakingProviderWrapper = new address[](1);\\n stakingProviderWrapper[0] = operatorToStakingProvider(\\n maliciousSubmitterAddresses\\n );\\n try\\n staking.seize(\\n slashingAmount,\\n _dkgMaliciousResultNotificationRewardMultiplier,\\n msg.sender,\\n stakingProviderWrapper\\n )\\n {\\n // slither-disable-next-line reentrancy-events\\n emit DkgMaliciousResultSlashed(\\n maliciousResultHash,\\n slashingAmount,\\n maliciousSubmitterAddresses\\n );\\n } catch {\\n // Should never happen but we want to ensure a non-critical path\\n // failure from an external contract does not stop the challenge\\n // to complete.\\n emit DkgMaliciousResultSlashingFailed(\\n maliciousResultHash,\\n slashingAmount,\\n maliciousSubmitterAddresses\\n );\\n }\\n\\n // Due to EIP-150, 1/64 of the gas is not forwarded to the call, and\\n // will be kept to execute the remaining operations in the function\\n // after the call inside the try-catch.\\n //\\n // To ensure there is no way for the caller to manipulate gas limit in\\n // such a way that the call inside try-catch fails with out-of-gas and\\n // the rest of the function is executed with the remaining 1/64 of gas,\\n // we require an extra gas amount to be left at the end of the call to\\n // `challengeDkgResult`.\\n dkg.requireChallengeExtraGas();\\n }\\n\\n /// @notice Check current group creation state.\\n function getGroupCreationState() external view returns (DKG.State) {\\n return dkg.currentState();\\n }\\n\\n /// @notice Checks if DKG timed out. The DKG timeout period includes time required\\n /// for off-chain protocol execution and time for the result publication\\n /// for all group members. After this time result cannot be submitted\\n /// and DKG can be notified about the timeout.\\n /// @return True if DKG timed out, false otherwise.\\n function hasDkgTimedOut() external view returns (bool) {\\n return dkg.hasDkgTimedOut();\\n }\\n\\n function getGroupsRegistry() external view returns (bytes32[] memory) {\\n return groups.groupsRegistry;\\n }\\n\\n function getGroup(uint64 groupId)\\n external\\n view\\n returns (Groups.Group memory)\\n {\\n return groups.getGroup(groupId);\\n }\\n\\n function getGroup(bytes memory groupPubKey)\\n external\\n view\\n returns (Groups.Group memory)\\n {\\n return groups.getGroup(groupPubKey);\\n }\\n\\n /// @notice Creates a request to generate a new relay entry, which will\\n /// include a random number (by signing the previous entry's\\n /// random number). Requester must be previously authorized by the\\n /// governance.\\n /// @param callbackContract Beacon consumer callback contract.\\n function requestRelayEntry(IRandomBeaconConsumer callbackContract)\\n external\\n {\\n require(\\n authorizedRequesters[msg.sender],\\n \\\"Requester must be authorized\\\"\\n );\\n\\n uint64 groupId = groups.selectGroup(\\n uint256(keccak256(AltBn128.g1Marshal(relay.previousEntry)))\\n );\\n\\n relay.requestEntry(groupId);\\n\\n callback.setCallbackContract(callbackContract);\\n\\n // If the current request should trigger group creation we need to lock\\n // DKG state (lock sortition pool) to prevent operators from changing\\n // its state before relay entry is known. That entry will be used as a\\n // group selection seed.\\n if (\\n relay.requestCount % _groupCreationFrequency == 0 &&\\n dkg.currentState() == DKG.State.IDLE\\n ) {\\n dkg.lockState();\\n }\\n }\\n\\n /// @notice Creates a new relay entry. Gas-optimized version that can be\\n /// called only before the soft timeout. This should be the majority\\n /// of cases.\\n /// @param entry Group BLS signature over the previous entry.\\n function submitRelayEntry(bytes calldata entry) external {\\n uint256 gasStart = gasleft();\\n\\n Groups.Group storage group = groups.getGroup(\\n relay.currentRequestGroupID\\n );\\n\\n relay.submitEntryBeforeSoftTimeout(entry, group.groupPubKey);\\n\\n // If DKG is awaiting a seed, that means the we should start the actual\\n // group creation process.\\n if (dkg.currentState() == DKG.State.AWAITING_SEED) {\\n dkg.start(uint256(keccak256(entry)));\\n }\\n\\n callback.executeCallback(uint256(keccak256(entry)), _callbackGasLimit);\\n\\n reimbursementPool.refund(\\n (gasStart - gasleft()) + _relayEntrySubmissionGasOffset,\\n msg.sender\\n );\\n }\\n\\n /// @notice Creates a new relay entry.\\n /// @param entry Group BLS signature over the previous entry.\\n /// @param groupMembers Identifiers of group members.\\n function submitRelayEntry(\\n bytes calldata entry,\\n uint32[] calldata groupMembers\\n ) external {\\n uint256 gasStart = gasleft();\\n uint256 currentRequestId = relay.currentRequestID;\\n\\n Groups.Group storage group = groups.getGroup(\\n relay.currentRequestGroupID\\n );\\n\\n require(\\n group.membersHash == keccak256(abi.encode(groupMembers)),\\n \\\"Invalid group members\\\"\\n );\\n\\n uint96 slashingAmount = relay.submitEntry(entry, group.groupPubKey);\\n\\n if (slashingAmount > 0) {\\n address[] memory groupMembersAddresses = sortitionPool\\n .getIDOperators(groupMembers);\\n\\n address[] memory stakingProvidersAddresses = new address[](\\n groupMembersAddresses.length\\n );\\n for (uint256 i = 0; i < groupMembersAddresses.length; i++) {\\n stakingProvidersAddresses[i] = operatorToStakingProvider(\\n groupMembersAddresses[i]\\n );\\n }\\n\\n try staking.slash(slashingAmount, stakingProvidersAddresses) {\\n // slither-disable-next-line reentrancy-events\\n emit RelayEntryDelaySlashed(\\n currentRequestId,\\n slashingAmount,\\n groupMembersAddresses\\n );\\n } catch {\\n // Should never happen but we want to ensure a non-critical path\\n // failure from an external contract does not stop group members\\n // from submitting a valid relay entry.\\n emit RelayEntryDelaySlashingFailed(\\n currentRequestId,\\n slashingAmount,\\n groupMembersAddresses\\n );\\n }\\n }\\n\\n // If DKG is awaiting a seed, that means the we should start the actual\\n // group creation process.\\n if (dkg.currentState() == DKG.State.AWAITING_SEED) {\\n dkg.start(uint256(keccak256(entry)));\\n }\\n\\n callback.executeCallback(uint256(keccak256(entry)), _callbackGasLimit);\\n reimbursementPool.refund(\\n (gasStart - gasleft()) + _relayEntrySubmissionGasOffset,\\n msg.sender\\n );\\n }\\n\\n /// @notice Reports a relay entry timeout.\\n /// @param groupMembers Identifiers of group members.\\n function reportRelayEntryTimeout(uint32[] calldata groupMembers) external {\\n uint64 groupId = relay.currentRequestGroupID;\\n Groups.Group storage group = groups.getGroup(groupId);\\n\\n require(\\n group.membersHash == keccak256(abi.encode(groupMembers)),\\n \\\"Invalid group members\\\"\\n );\\n\\n uint96 slashingAmount = relay.relayEntrySubmissionFailureSlashingAmount;\\n address[] memory groupMembersAddresses = sortitionPool.getIDOperators(\\n groupMembers\\n );\\n\\n address[] memory stakingProvidersAddresses = new address[](\\n groupMembersAddresses.length\\n );\\n for (uint256 i = 0; i < groupMembersAddresses.length; i++) {\\n stakingProvidersAddresses[i] = operatorToStakingProvider(\\n groupMembersAddresses[i]\\n );\\n }\\n\\n try\\n staking.seize(\\n slashingAmount,\\n _relayEntryTimeoutNotificationRewardMultiplier,\\n msg.sender,\\n stakingProvidersAddresses\\n )\\n {\\n // slither-disable-next-line reentrancy-events\\n emit RelayEntryTimeoutSlashed(\\n relay.currentRequestID,\\n slashingAmount,\\n groupMembersAddresses\\n );\\n } catch {\\n // Should never happen but we want to ensure a non-critical path\\n // failure from an external contract does not stop the challenge\\n // to complete.\\n emit RelayEntryTimeoutSlashingFailed(\\n relay.currentRequestID,\\n slashingAmount,\\n groupMembersAddresses\\n );\\n }\\n\\n groups.terminateGroup(groupId);\\n groups.expireOldGroups();\\n\\n if (groups.numberOfActiveGroups() > 0) {\\n groupId = groups.selectGroup(\\n uint256(keccak256(AltBn128.g1Marshal(relay.previousEntry)))\\n );\\n relay.retryOnEntryTimeout(groupId);\\n } else {\\n relay.cleanupOnEntryTimeout();\\n\\n // If DKG is awaiting a seed, we should notify about its timeout to\\n // avoid blocking the future group creation.\\n if (dkg.currentState() == DKG.State.AWAITING_SEED) {\\n dkg.notifySeedTimedOut();\\n }\\n }\\n }\\n\\n /// @notice Reports unauthorized groups signing. Must provide a valid signature\\n /// of the sender's address as a message. Successful signature\\n /// verification means the private key has been leaked and all group\\n /// members should be punished by slashing their tokens. Group has\\n /// to be active or expired. Unauthorized signing cannot be reported\\n /// for a terminated group. In case of reporting unauthorized\\n /// signing for a terminated group, or when the signature is invalid,\\n /// function reverts.\\n /// @param signedMsgSender Signature of the sender's address as a message.\\n /// @param groupId Group that is being reported for leaking a private key.\\n /// @param groupMembers Identifiers of group members.\\n function reportUnauthorizedSigning(\\n bytes memory signedMsgSender,\\n uint64 groupId,\\n uint32[] calldata groupMembers\\n ) external {\\n Groups.Group memory group = groups.getGroup(groupId);\\n\\n require(\\n group.membersHash == keccak256(abi.encode(groupMembers)),\\n \\\"Invalid group members\\\"\\n );\\n\\n require(!group.terminated, \\\"Group cannot be terminated\\\");\\n\\n require(\\n BLS.verifyBytes(\\n group.groupPubKey,\\n abi.encodePacked(msg.sender),\\n signedMsgSender\\n ),\\n \\\"Invalid signature\\\"\\n );\\n\\n groups.terminateGroup(groupId);\\n\\n address[] memory groupMembersAddresses = sortitionPool.getIDOperators(\\n groupMembers\\n );\\n\\n address[] memory stakingProvidersAddresses = new address[](\\n groupMembersAddresses.length\\n );\\n for (uint256 i = 0; i < groupMembersAddresses.length; i++) {\\n stakingProvidersAddresses[i] = operatorToStakingProvider(\\n groupMembersAddresses[i]\\n );\\n }\\n\\n try\\n staking.seize(\\n _unauthorizedSigningSlashingAmount,\\n _unauthorizedSigningNotificationRewardMultiplier,\\n msg.sender,\\n stakingProvidersAddresses\\n )\\n {\\n // slither-disable-next-line reentrancy-events\\n emit UnauthorizedSigningSlashed(\\n groupId,\\n _unauthorizedSigningSlashingAmount,\\n groupMembersAddresses\\n );\\n } catch {\\n // Should never happen but we want to ensure a non-critical path\\n // failure from an external contract does not stop the challenge\\n // to complete.\\n emit UnauthorizedSigningSlashingFailed(\\n groupId,\\n _unauthorizedSigningSlashingAmount,\\n groupMembersAddresses\\n );\\n }\\n }\\n\\n /// @notice Notifies about operators who are inactive. Using this function,\\n /// a majority of the group can decide about punishing specific\\n /// group members who constantly fail doing their job. If the provided\\n /// claim is proved to be valid and signed by sufficient number\\n /// of group members, operators of members deemed as inactive are\\n /// banned for sortition pool rewards for duration specified by\\n /// `_sortitionPoolRewardsBanDuration` parameter. The sender of\\n /// the claim must be one of the claim signers. This function can be\\n /// called only for active and non-terminated groups.\\n /// @param claim Operator inactivity claim.\\n /// @param nonce Current inactivity claim nonce for the given group. Must\\n /// be the same as the stored one.\\n /// @param groupMembers Identifiers of group members.\\n function notifyOperatorInactivity(\\n Inactivity.Claim calldata claim,\\n uint256 nonce,\\n uint32[] calldata groupMembers\\n ) external {\\n uint256 gasStart = gasleft();\\n uint64 groupId = claim.groupId;\\n\\n require(nonce == inactivityClaimNonce[groupId], \\\"Invalid nonce\\\");\\n\\n require(groups.isGroupActive(groupId), \\\"Group is not active\\\");\\n\\n Groups.Group storage group = groups.getGroup(groupId);\\n\\n require(\\n group.membersHash == keccak256(abi.encode(groupMembers)),\\n \\\"Invalid group members\\\"\\n );\\n\\n uint32[] memory ineligibleOperators = Inactivity.verifyClaim(\\n sortitionPool,\\n claim,\\n group.groupPubKey,\\n nonce,\\n groupMembers\\n );\\n\\n inactivityClaimNonce[groupId]++;\\n\\n emit InactivityClaimed(groupId, nonce, msg.sender);\\n\\n sortitionPool.setRewardIneligibility(\\n ineligibleOperators,\\n // solhint-disable-next-line not-rely-on-time\\n block.timestamp + _sortitionPoolRewardsBanDuration\\n );\\n\\n reimbursementPool.refund(\\n (gasStart - gasleft()) + _notifyOperatorInactivityGasOffset,\\n msg.sender\\n );\\n }\\n\\n /// @notice The minimum authorization amount required so that operator can\\n /// participate in the random beacon. This amount is required to\\n /// execute slashing for providing a malicious DKG result or when\\n /// a relay entry times out.\\n function minimumAuthorization() external view returns (uint96) {\\n return authorization.parameters.minimumAuthorization;\\n }\\n\\n /// @return Flag indicating whether a relay entry request is currently\\n /// in progress.\\n function isRelayRequestInProgress() external view returns (bool) {\\n return relay.isRequestInProgress();\\n }\\n\\n /// @notice Returns the current value of the staking provider's eligible\\n /// stake. Eligible stake is defined as the currently authorized\\n /// stake minus the pending authorization decrease. Eligible stake\\n /// is what is used for operator's weight in the sortition pool.\\n /// If the authorized stake minus the pending authorization decrease\\n /// is below the minimum authorization, eligible stake is 0.\\n function eligibleStake(address stakingProvider)\\n external\\n view\\n returns (uint96)\\n {\\n return authorization.eligibleStake(staking, stakingProvider);\\n }\\n\\n /// @notice Returns the amount of rewards available for withdrawal for the\\n /// given staking provider. Reverts if staking provider has not\\n /// registered the operator address.\\n function availableRewards(address stakingProvider)\\n external\\n view\\n returns (uint96)\\n {\\n address operator = stakingProviderToOperator(stakingProvider);\\n require(operator != address(0), \\\"Unknown operator\\\");\\n return sortitionPool.getAvailableRewards(operator);\\n }\\n\\n /// @notice Returns the amount of stake that is pending authorization\\n /// decrease for the given staking provider. If no authorization\\n /// decrease has been requested, returns zero.\\n function pendingAuthorizationDecrease(address stakingProvider)\\n external\\n view\\n returns (uint96)\\n {\\n return authorization.pendingAuthorizationDecrease(stakingProvider);\\n }\\n\\n /// @notice Returns the remaining time in seconds that needs to pass before\\n /// the requested authorization decrease can be approved.\\n /// If the sortition pool state was not updated yet by the operator\\n /// after requesting the authorization decrease, returns\\n /// `type(uint64).max`.\\n function remainingAuthorizationDecreaseDelay(address stakingProvider)\\n external\\n view\\n returns (uint64)\\n {\\n return\\n authorization.remainingAuthorizationDecreaseDelay(stakingProvider);\\n }\\n\\n /// @notice Returns operator registered for the given staking provider.\\n function stakingProviderToOperator(address stakingProvider)\\n public\\n view\\n returns (address)\\n {\\n return authorization.stakingProviderToOperator[stakingProvider];\\n }\\n\\n /// @notice Returns staking provider of the given operator.\\n function operatorToStakingProvider(address operator)\\n public\\n view\\n returns (address)\\n {\\n return authorization.operatorToStakingProvider[operator];\\n }\\n\\n /// @notice Checks if the operator's authorized stake is in sync with\\n /// operator's weight in the sortition pool.\\n /// If the operator is not in the sortition pool and their\\n /// authorized stake is non-zero, function returns false.\\n function isOperatorUpToDate(address operator) external view returns (bool) {\\n return\\n authorization.isOperatorUpToDate(staking, sortitionPool, operator);\\n }\\n\\n /// @notice Returns true if the given operator is in the sortition pool.\\n /// Otherwise, returns false.\\n function isOperatorInPool(address operator) external view returns (bool) {\\n return sortitionPool.isOperatorInPool(operator);\\n }\\n\\n /// @notice Selects a new group of operators. Can only be called when DKG\\n /// is in progress and the pool is locked.\\n /// At least one operator has to be registered in the pool,\\n /// otherwise the function fails reverting the transaction.\\n /// @return IDs of selected group members.\\n function selectGroup() external view returns (uint32[] memory) {\\n return sortitionPool.selectGroup(DKG.groupSize, bytes32(dkg.seed));\\n }\\n\\n /// @notice Returns authorization-related parameters of the beacon.\\n /// @dev The minimum authorization is also returned by `minimumAuthorization()`\\n /// function, as a requirement of `IApplication` interface.\\n /// @return minimumAuthorization The minimum authorization amount required\\n /// so that operator can participate in the random beacon. This\\n /// amount is required to execute slashing for providing a malicious\\n /// DKG result or when a relay entry times out.\\n /// @return authorizationDecreaseDelay Delay in seconds that needs to pass\\n /// between the time authorization decrease is requested and the\\n /// time that request gets approved. Protects against free-riders\\n /// earning rewards and not being active in the network.\\n /// @return authorizationDecreaseChangePeriod Authorization decrease change\\n /// period in seconds. It is the time, before authorization decrease\\n /// delay end, during which the pending authorization decrease\\n /// request can be overwritten.\\n /// If set to 0, pending authorization decrease request can not be\\n /// overwritten until the entire `authorizationDecreaseDelay` ends.\\n /// If set to value equal `authorizationDecreaseDelay`, request can\\n /// always be overwritten.\\n function authorizationParameters()\\n external\\n view\\n returns (\\n uint96 minimumAuthorization,\\n uint64 authorizationDecreaseDelay,\\n uint64 authorizationDecreaseChangePeriod\\n )\\n {\\n return (\\n authorization.parameters.minimumAuthorization,\\n authorization.parameters.authorizationDecreaseDelay,\\n authorization.parameters.authorizationDecreaseChangePeriod\\n );\\n }\\n\\n /// @notice Returns relay-entry-related parameters of the beacon.\\n /// @return relayEntrySoftTimeout Soft timeout in blocks for a group to\\n /// submit the relay entry. If the soft timeout is reached for\\n /// submitting the relay entry, the slashing starts.\\n /// @return relayEntryHardTimeout Hard timeout in blocks for a group to\\n /// submit the relay entry. After the soft timeout passes without\\n /// relay entry submitted, all group members start getting slashed.\\n /// The slashing amount increases linearly until the group submits\\n /// the relay entry or until `relayEntryHardTimeout` is reached.\\n /// When the hard timeout is reached, each group member will get\\n /// slashed for `_relayEntrySubmissionFailureSlashingAmount`.\\n /// @return callbackGasLimit Relay entry callback gas limit. This is the gas\\n /// limit with which callback function provided in the relay request\\n /// transaction is executed. The callback is executed with a new\\n /// relay entry value in the same transaction the relay entry is\\n /// submitted.\\n function relayEntryParameters()\\n external\\n view\\n returns (\\n uint256 relayEntrySoftTimeout,\\n uint256 relayEntryHardTimeout,\\n uint256 callbackGasLimit\\n )\\n {\\n return (\\n relay.relayEntrySoftTimeout,\\n relay.relayEntryHardTimeout,\\n _callbackGasLimit\\n );\\n }\\n\\n /// @notice Returns group-creation-related parameters of the beacon.\\n /// @return groupCreationFrequency The frequency of a new group creation.\\n /// Groups are created with a fixed frequency of relay requests.\\n /// @return groupLifetime Group lifetime in blocks. When a group reached its\\n /// lifetime, it is no longer selected for new relay requests but\\n /// may still be responsible for submitting relay entry if relay\\n /// request assigned to that group is still pending.\\n /// @return dkgResultChallengePeriodLength The number of blocks for which\\n /// a DKG result can be challenged. Anyone can challenge DKG result\\n /// for a certain number of blocks before the result is fully\\n /// accepted and the group registered in the pool of active groups.\\n /// If the challenge gets accepted, all operators who signed the\\n /// malicious result get slashed for and the notifier gets rewarded.\\n /// @return dkgResultChallengeExtraGas The extra gas required to be left at\\n /// the end of the challenge DKG result transaction.\\n /// @return dkgResultSubmissionTimeout Timeout in blocks for a group to\\n /// submit the DKG result. All members are eligible to submit the\\n /// DKG result. If `dkgResultSubmissionTimeout` passes without the\\n /// DKG result submitted, DKG is considered as timed out and no DKG\\n /// result for this group creation can be submitted anymore.\\n /// @return dkgSubmitterPrecedencePeriodLength Time during the DKG result\\n /// approval stage when the submitter of the DKG result takes the\\n /// precedence to approve the DKG result. After this time passes\\n /// anyone can approve the DKG result.\\n function groupCreationParameters()\\n external\\n view\\n returns (\\n uint256 groupCreationFrequency,\\n uint256 groupLifetime,\\n uint256 dkgResultChallengePeriodLength,\\n uint256 dkgResultChallengeExtraGas,\\n uint256 dkgResultSubmissionTimeout,\\n uint256 dkgSubmitterPrecedencePeriodLength\\n )\\n {\\n return (\\n _groupCreationFrequency,\\n groups.groupLifetime,\\n dkg.parameters.resultChallengePeriodLength,\\n dkg.parameters.resultChallengeExtraGas,\\n dkg.parameters.resultSubmissionTimeout,\\n dkg.parameters.submitterPrecedencePeriodLength\\n );\\n }\\n\\n /// @notice Returns reward-related parameters of the beacon.\\n /// @return sortitionPoolRewardsBanDuration Duration of the sortition pool\\n /// rewards ban imposed on operators who misbehaved during DKG by\\n /// being inactive or disqualified and for operators that were\\n /// identified by the rest of group members as inactive via\\n /// `notifyOperatorInactivity`.\\n /// @return relayEntryTimeoutNotificationRewardMultiplier Percentage of the\\n /// staking contract malicious behavior notification reward which\\n /// will be transferred to the notifier reporting about relay entry\\n /// timeout. Notifiers are rewarded from a notifiers treasury pool.\\n /// For example, if notification reward is 1000 and the value of the\\n /// multiplier is 5, the notifier will receive: 5% of 1000 = 50 per\\n /// each operator affected.\\n /// @return unauthorizedSigningNotificationRewardMultiplier Percentage of the\\n /// staking contract malicious behavior notification reward which\\n /// will be transferred to the notifier reporting about unauthorized\\n /// signing. Notifiers are rewarded from a notifiers treasury pool.\\n /// For example, if a notification reward is 1000 and the value of\\n /// the multiplier is 5, the notifier will receive: 5% of 1000 = 50\\n /// per each operator affected.\\n /// @return dkgMaliciousResultNotificationRewardMultiplier Percentage of the\\n /// staking contract malicious behavior notification reward which\\n /// will be transferred to the notifier reporting about a malicious\\n /// DKG result. Notifiers are rewarded from a notifiers treasury\\n /// pool. For example, if notification reward is 1000 and the value\\n /// of the multiplier is 5, the notifier will receive:\\n /// 5% of 1000 = 50 per each operator affected.\\n function rewardParameters()\\n external\\n view\\n returns (\\n uint256 sortitionPoolRewardsBanDuration,\\n uint256 relayEntryTimeoutNotificationRewardMultiplier,\\n uint256 unauthorizedSigningNotificationRewardMultiplier,\\n uint256 dkgMaliciousResultNotificationRewardMultiplier\\n )\\n {\\n return (\\n _sortitionPoolRewardsBanDuration,\\n _relayEntryTimeoutNotificationRewardMultiplier,\\n _unauthorizedSigningNotificationRewardMultiplier,\\n _dkgMaliciousResultNotificationRewardMultiplier\\n );\\n }\\n\\n /// @notice Returns slashing-related parameters of the beacon.\\n /// @return relayEntrySubmissionFailureSlashingAmount Slashing amount for\\n /// not submitting relay entry. When relay entry hard timeout is\\n /// reached without the relay entry submitted, each group member\\n /// gets slashed for `relayEntrySubmissionFailureSlashingAmount`.\\n /// If the relay entry gets submitted after the soft timeout, but\\n /// before the hard timeout, each group member gets slashed\\n /// proportionally to `relayEntrySubmissionFailureSlashingAmount`\\n /// and the time passed since the soft deadline.\\n /// @return maliciousDkgResultSlashingAmount Slashing amount for submitting\\n /// a malicious DKG result. Every DKG result submitted can be\\n /// challenged for the time of `dkg.ResultChallengePeriodLength`.\\n /// If the DKG result submitted is challenged and proven to be\\n /// malicious, the operator who submitted the malicious result is\\n /// slashed for `maliciousDkgResultSlashingAmount`.\\n /// @return unauthorizedSigningSlashingAmount Slashing amount when an\\n /// unauthorized signing has been proved, which means the private\\n /// key leaked and all the group members should be punished.\\n function slashingParameters()\\n external\\n view\\n returns (\\n uint96 relayEntrySubmissionFailureSlashingAmount,\\n uint96 maliciousDkgResultSlashingAmount,\\n uint96 unauthorizedSigningSlashingAmount\\n )\\n {\\n return (\\n relay.relayEntrySubmissionFailureSlashingAmount,\\n _maliciousDkgResultSlashingAmount,\\n _unauthorizedSigningSlashingAmount\\n );\\n }\\n\\n /// @notice Returns gas-related parameters of the beacon.\\n /// @return dkgResultSubmissionGas Calculated gas cost for submitting a DKG\\n /// result. This will be refunded as part of the DKG approval\\n /// process.\\n /// @return dkgResultApprovalGasOffset Gas that is meant to balance the DKG\\n /// result approval's overall cost.\\n /// @return notifyOperatorInactivityGasOffset Gas that is meant to balance\\n /// the operator inactivity notification cost.\\n /// @return relayEntrySubmissionGasOffset Gas that is meant to balance the\\n /// relay entry submission cost.\\n function gasParameters()\\n external\\n view\\n returns (\\n uint256 dkgResultSubmissionGas,\\n uint256 dkgResultApprovalGasOffset,\\n uint256 notifyOperatorInactivityGasOffset,\\n uint256 relayEntrySubmissionGasOffset\\n )\\n {\\n return (\\n _dkgResultSubmissionGas,\\n _dkgResultApprovalGasOffset,\\n _notifyOperatorInactivityGasOffset,\\n _relayEntrySubmissionGasOffset\\n );\\n }\\n}\\n\",\"keccak256\":\"0x50e6572ce7e51404a9918bf80d13004c4f4fd2a41fbc898f8aac84fa71423917\",\"license\":\"GPL-3.0-only\"},\"contracts/Reimbursable.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./ReimbursementPool.sol\\\";\\n\\nabstract contract Reimbursable {\\n // The variable should be initialized by the implementing contract.\\n // slither-disable-next-line uninitialized-state\\n ReimbursementPool public reimbursementPool;\\n\\n // Reserved storage space in case we need to add more variables,\\n // since there are upgradeable contracts that inherit from this one.\\n // See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\\n // slither-disable-next-line unused-state\\n uint256[49] private __gap;\\n\\n event ReimbursementPoolUpdated(address newReimbursementPool);\\n\\n modifier refundable(address receiver) {\\n uint256 gasStart = gasleft();\\n _;\\n reimbursementPool.refund(gasStart - gasleft(), receiver);\\n }\\n\\n modifier onlyReimbursableAdmin() virtual {\\n _;\\n }\\n\\n function updateReimbursementPool(ReimbursementPool _reimbursementPool)\\n external\\n onlyReimbursableAdmin\\n {\\n emit ReimbursementPoolUpdated(address(_reimbursementPool));\\n\\n reimbursementPool = _reimbursementPool;\\n }\\n}\\n\",\"keccak256\":\"0x6b01344c1ec13aaab1dc432d3afabe08d6dd0d1a9248be8b36a0747ac22e5d9f\",\"license\":\"GPL-3.0-only\"},\"contracts/ReimbursementPool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/security/ReentrancyGuard.sol\\\";\\n\\ncontract ReimbursementPool is Ownable, ReentrancyGuard {\\n /// @notice Authorized contracts that can interact with the reimbursment pool.\\n /// Authorization can be granted and removed by the owner.\\n mapping(address => bool) public isAuthorized;\\n\\n /// @notice Static gas includes:\\n /// - cost of the refund function\\n /// - base transaction cost\\n uint256 public staticGas;\\n\\n /// @notice Max gas price used to reimburse a transaction submitter. Protects\\n /// against malicious operator-miners.\\n uint256 public maxGasPrice;\\n\\n event StaticGasUpdated(uint256 newStaticGas);\\n\\n event MaxGasPriceUpdated(uint256 newMaxGasPrice);\\n\\n event SendingEtherFailed(uint256 refundAmount, address receiver);\\n\\n event AuthorizedContract(address thirdPartyContract);\\n\\n event UnauthorizedContract(address thirdPartyContract);\\n\\n event FundsWithdrawn(uint256 withdrawnAmount, address receiver);\\n\\n constructor(uint256 _staticGas, uint256 _maxGasPrice) {\\n staticGas = _staticGas;\\n maxGasPrice = _maxGasPrice;\\n }\\n\\n /// @notice Receive ETH\\n receive() external payable {}\\n\\n /// @notice Refunds ETH to a spender for executing specific transactions.\\n /// @dev Ignoring the result of sending ETH to a receiver is made on purpose.\\n /// For EOA receiving ETH should always work. If a receiver is a smart\\n /// contract, then we do not want to fail a transaction, because in some\\n /// cases the refund is done at the very end of multiple calls where all\\n /// the previous calls were already paid off. It is a receiver's smart\\n /// contract resposibility to make sure it can receive ETH.\\n /// @dev Only authorized contracts are allowed calling this function.\\n /// @param gasSpent Gas spent on a transaction that needs to be reimbursed.\\n /// @param receiver Address where the reimbursment is sent.\\n function refund(uint256 gasSpent, address receiver) external nonReentrant {\\n require(\\n isAuthorized[msg.sender],\\n \\\"Contract is not authorized for a refund\\\"\\n );\\n require(receiver != address(0), \\\"Receiver's address cannot be zero\\\");\\n\\n uint256 gasPrice = tx.gasprice < maxGasPrice\\n ? tx.gasprice\\n : maxGasPrice;\\n\\n uint256 refundAmount = (gasSpent + staticGas) * gasPrice;\\n\\n /* solhint-disable avoid-low-level-calls */\\n // slither-disable-next-line low-level-calls,unchecked-lowlevel\\n (bool sent, ) = receiver.call{value: refundAmount}(\\\"\\\");\\n /* solhint-enable avoid-low-level-calls */\\n if (!sent) {\\n // slither-disable-next-line reentrancy-events\\n emit SendingEtherFailed(refundAmount, receiver);\\n }\\n }\\n\\n /// @notice Authorize a contract that can interact with this reimbursment pool.\\n /// Can be authorized by the owner only.\\n /// @param _contract Authorized contract.\\n function authorize(address _contract) external onlyOwner {\\n isAuthorized[_contract] = true;\\n\\n emit AuthorizedContract(_contract);\\n }\\n\\n /// @notice Unauthorize a contract that was previously authorized to interact\\n /// with this reimbursment pool. Can be unauthorized by the\\n /// owner only.\\n /// @param _contract Authorized contract.\\n function unauthorize(address _contract) external onlyOwner {\\n delete isAuthorized[_contract];\\n\\n emit UnauthorizedContract(_contract);\\n }\\n\\n /// @notice Setting a static gas cost for executing a transaction. Can be set\\n /// by the owner only.\\n /// @param _staticGas Static gas cost.\\n function setStaticGas(uint256 _staticGas) external onlyOwner {\\n staticGas = _staticGas;\\n\\n emit StaticGasUpdated(_staticGas);\\n }\\n\\n /// @notice Setting a max gas price for transactions. Can be set by the\\n /// owner only.\\n /// @param _maxGasPrice Max gas price used to reimburse tx submitters.\\n function setMaxGasPrice(uint256 _maxGasPrice) external onlyOwner {\\n maxGasPrice = _maxGasPrice;\\n\\n emit MaxGasPriceUpdated(_maxGasPrice);\\n }\\n\\n /// @notice Withdraws all ETH from this pool which are sent to a given\\n /// address. Can be set by the owner only.\\n /// @param receiver An address where ETH is sent.\\n function withdrawAll(address receiver) external onlyOwner {\\n withdraw(address(this).balance, receiver);\\n }\\n\\n /// @notice Withdraws ETH amount from this pool which are sent to a given\\n /// address. Can be set by the owner only.\\n /// @param amount Amount to withdraw from the pool.\\n /// @param receiver An address where ETH is sent.\\n function withdraw(uint256 amount, address receiver) public onlyOwner {\\n require(\\n address(this).balance >= amount,\\n \\\"Insufficient contract balance\\\"\\n );\\n require(receiver != address(0), \\\"Receiver's address cannot be zero\\\");\\n\\n emit FundsWithdrawn(amount, receiver);\\n\\n /* solhint-disable avoid-low-level-calls */\\n // slither-disable-next-line low-level-calls,arbitrary-send\\n (bool sent, ) = receiver.call{value: amount}(\\\"\\\");\\n /* solhint-enable avoid-low-level-calls */\\n require(sent, \\\"Failed to send Ether\\\");\\n }\\n}\\n\",\"keccak256\":\"0xd6c24368cc4c6349b8b614e878ca961cad8254b8e8db1cc0abe452a70022ce50\",\"license\":\"GPL-3.0-only\"},\"contracts/api/IRandomBeacon.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IRandomBeaconConsumer.sol\\\";\\n\\n/// @title Random Beacon interface\\ninterface IRandomBeacon {\\n /// @notice Creates a request to generate a new relay entry. Requires a\\n /// request fee denominated in T token.\\n /// @param callbackContract Beacon consumer callback contract.\\n function requestRelayEntry(IRandomBeaconConsumer callbackContract) external;\\n}\\n\",\"keccak256\":\"0xc5f6ddbf69b2f2e2c03fe78b3857a1f038982e858679f520101f53c4ebe2f4bf\",\"license\":\"GPL-3.0-only\"},\"contracts/api/IRandomBeaconConsumer.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\ninterface IRandomBeaconConsumer {\\n /// @notice Receives relay entry produced by Keep Random Beacon. This function\\n /// should be called only by Keep Random Beacon.\\n ///\\n /// @param relayEntry Relay entry (random number) produced by Keep Random\\n /// Beacon.\\n /// @param blockNumber Block number at which the relay entry was submitted\\n /// to the chain.\\n function __beaconCallback(uint256 relayEntry, uint256 blockNumber) external;\\n}\\n\",\"keccak256\":\"0x84ce236b4eeb664ccb02782777a05c6ebb410be9b9e586a123a1205437a2ed9f\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/AltBn128.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./ModUtils.sol\\\";\\n\\n/// @title Operations on alt_bn128\\n/// @dev Implementations of common elliptic curve operations on Ethereum's\\n/// (poorly named) alt_bn128 curve. Whenever possible, use post-Byzantium\\n/// pre-compiled contracts to offset gas costs. Note that these\\n/// pre-compiles might not be available on all (eg private) chains.\\nlibrary AltBn128 {\\n using ModUtils for uint256;\\n\\n // G1Point implements a point in G1 group.\\n struct G1Point {\\n uint256 x;\\n uint256 y;\\n }\\n\\n // gfP2 implements a field of size p\\u00b2 as a quadratic extension of the base\\n // field.\\n struct gfP2 {\\n uint256 x;\\n uint256 y;\\n }\\n\\n // G2Point implements a point in G2 group.\\n struct G2Point {\\n gfP2 x;\\n gfP2 y;\\n }\\n\\n // p is a prime over which we form a basic field\\n // Taken from go-ethereum/crypto/bn256/cloudflare/constants.go\\n uint256 internal constant p =\\n 21888242871839275222246405745257275088696311157297823662689037894645226208583;\\n\\n /// @dev Gets generator of G1 group.\\n /// Taken from go-ethereum/crypto/bn256/cloudflare/curve.go\\n uint256 internal constant g1x = 1;\\n uint256 internal constant g1y = 2;\\n\\n /// @dev Gets generator of G2 group.\\n /// Taken from go-ethereum/crypto/bn256/cloudflare/twist.go\\n uint256 internal constant g2xx =\\n 11559732032986387107991004021392285783925812861821192530917403151452391805634;\\n uint256 internal constant g2xy =\\n 10857046999023057135944570762232829481370756359578518086990519993285655852781;\\n uint256 internal constant g2yx =\\n 4082367875863433681332203403145435568316851327593401208105741076214120093531;\\n uint256 internal constant g2yy =\\n 8495653923123431417604973247489272438418190587263600148770280649306958101930;\\n\\n /// @dev Gets twist curve B constant.\\n /// Taken from go-ethereum/crypto/bn256/cloudflare/twist.go\\n uint256 internal constant twistBx =\\n 266929791119991161246907387137283842545076965332900288569378510910307636690;\\n uint256 internal constant twistBy =\\n 19485874751759354771024239261021720505790618469301721065564631296452457478373;\\n\\n /// @dev Gets root of the point where x and y are equal.\\n uint256 internal constant hexRootX =\\n 21573744529824266246521972077326577680729363968861965890554801909984373949499;\\n uint256 internal constant hexRootY =\\n 16854739155576650954933913186877292401521110422362946064090026408937773542853;\\n\\n /// @dev g1YFromX computes a Y value for a G1 point based on an X value.\\n /// This computation is simply evaluating the curve equation for Y on a\\n /// given X, and allows a point on the curve to be represented by just\\n /// an X value + a sign bit.\\n function g1YFromX(uint256 x) internal view returns (uint256) {\\n return ((x.modExp(3, p) + 3) % p).modSqrt(p);\\n }\\n\\n /// @dev Hash a byte array message, m, and map it deterministically to a\\n /// point on G1. Note that this approach was chosen for its simplicity\\n /// and lower gas cost on the EVM, rather than good distribution of\\n /// points on G1.\\n function g1HashToPoint(bytes memory m)\\n internal\\n view\\n returns (G1Point memory)\\n {\\n unchecked {\\n bytes32 h = sha256(m);\\n uint256 x = uint256(h) % p;\\n uint256 y;\\n\\n while (true) {\\n y = g1YFromX(x);\\n if (y > 0) {\\n return G1Point(x, y);\\n }\\n x += 1;\\n }\\n }\\n }\\n\\n /// @dev Decompress a point on G1 from a single uint256.\\n function g1Decompress(bytes32 m) internal view returns (G1Point memory) {\\n unchecked {\\n bytes32 mX = bytes32(0);\\n bytes1 leadX = m[0] & 0x7f;\\n // slither-disable-next-line incorrect-shift\\n uint256 mask = 0xff << (31 * 8);\\n mX = (m & ~bytes32(mask)) | (leadX >> 0);\\n\\n uint256 x = uint256(mX);\\n uint256 y = g1YFromX(x);\\n\\n if (parity(y) != (m[0] & 0x80) >> 7) {\\n y = p - y;\\n }\\n\\n require(\\n isG1PointOnCurve(G1Point(x, y)),\\n \\\"Malformed bn256.G1 point.\\\"\\n );\\n\\n return G1Point(x, y);\\n }\\n }\\n\\n /// @dev Wraps the point addition pre-compile introduced in Byzantium.\\n /// Returns the sum of two points on G1. Revert if the provided points\\n /// are not on the curve.\\n function g1Add(G1Point memory a, G1Point memory b)\\n internal\\n view\\n returns (G1Point memory c)\\n {\\n assembly {\\n let arg := mload(0x40)\\n mstore(arg, mload(a))\\n mstore(add(arg, 0x20), mload(add(a, 0x20)))\\n mstore(add(arg, 0x40), mload(b))\\n mstore(add(arg, 0x60), mload(add(b, 0x20)))\\n // 0x60 is the ECADD precompile address\\n if iszero(staticcall(not(0), 0x06, arg, 0x80, c, 0x40)) {\\n revert(0, 0)\\n }\\n }\\n }\\n\\n /// @dev Returns true if G1 point is on the curve.\\n function isG1PointOnCurve(G1Point memory point)\\n internal\\n view\\n returns (bool)\\n {\\n return point.y.modExp(2, p) == (point.x.modExp(3, p) + 3) % p;\\n }\\n\\n /// @dev Wraps the scalar point multiplication pre-compile introduced in\\n /// Byzantium. The result of a point from G1 multiplied by a scalar\\n /// should match the point added to itself the same number of times.\\n /// Revert if the provided point isn't on the curve.\\n function scalarMultiply(G1Point memory p_1, uint256 scalar)\\n internal\\n view\\n returns (G1Point memory p_2)\\n {\\n assembly {\\n let arg := mload(0x40)\\n mstore(arg, mload(p_1))\\n mstore(add(arg, 0x20), mload(add(p_1, 0x20)))\\n mstore(add(arg, 0x40), scalar)\\n // 0x07 is the ECMUL precompile address\\n if iszero(staticcall(not(0), 0x07, arg, 0x60, p_2, 0x40)) {\\n revert(0, 0)\\n }\\n }\\n }\\n\\n /// @dev Wraps the pairing check pre-compile introduced in Byzantium.\\n /// Returns the result of a pairing check of 2 pairs\\n /// (G1 p1, G2 p2) (G1 p3, G2 p4)\\n function pairing(\\n G1Point memory p1,\\n G2Point memory p2,\\n G1Point memory p3,\\n G2Point memory p4\\n ) internal view returns (bool result) {\\n uint256 _c;\\n assembly {\\n let c := mload(0x40)\\n let arg := add(c, 0x20)\\n\\n mstore(arg, mload(p1))\\n mstore(add(arg, 0x20), mload(add(p1, 0x20)))\\n\\n let p2x := mload(p2)\\n mstore(add(arg, 0x40), mload(p2x))\\n mstore(add(arg, 0x60), mload(add(p2x, 0x20)))\\n\\n let p2y := mload(add(p2, 0x20))\\n mstore(add(arg, 0x80), mload(p2y))\\n mstore(add(arg, 0xa0), mload(add(p2y, 0x20)))\\n\\n mstore(add(arg, 0xc0), mload(p3))\\n mstore(add(arg, 0xe0), mload(add(p3, 0x20)))\\n\\n let p4x := mload(p4)\\n mstore(add(arg, 0x100), mload(p4x))\\n mstore(add(arg, 0x120), mload(add(p4x, 0x20)))\\n\\n let p4y := mload(add(p4, 0x20))\\n mstore(add(arg, 0x140), mload(p4y))\\n mstore(add(arg, 0x160), mload(add(p4y, 0x20)))\\n\\n // call(gasLimit, to, value, inputOffset, inputSize, outputOffset, outputSize)\\n if iszero(staticcall(not(0), 0x08, arg, 0x180, c, 0x20)) {\\n revert(0, 0)\\n }\\n _c := mload(c)\\n }\\n return _c != 0;\\n }\\n\\n function getP() internal pure returns (uint256) {\\n return p;\\n }\\n\\n function g1() internal pure returns (G1Point memory) {\\n return G1Point(g1x, g1y);\\n }\\n\\n function g2() internal pure returns (G2Point memory) {\\n return G2Point(gfP2(g2xx, g2xy), gfP2(g2yx, g2yy));\\n }\\n\\n /// @dev g2YFromX computes a Y value for a G2 point based on an X value.\\n /// This computation is simply evaluating the curve equation for Y on a\\n /// given X, and allows a point on the curve to be represented by just\\n /// an X value + a sign bit.\\n function g2YFromX(gfP2 memory _x) internal pure returns (gfP2 memory y) {\\n (uint256 xx, uint256 xy) = _gfP2CubeAddTwistB(_x.x, _x.y);\\n\\n // Using formula y = x ^ (p^2 + 15) / 32 from\\n // https://github.com/ethereum/beacon_chain/blob/master/beacon_chain/utils/bls.py\\n // (p^2 + 15) / 32 results into a big 512bit value, so breaking it to two uint256 as (a * a + b)\\n uint256 a = 3869331240733915743250440106392954448556483137451914450067252501901456824595;\\n uint256 b = 146360017852723390495514512480590656176144969185739259173561346299185050597;\\n\\n (uint256 xbx, uint256 xby) = _gfP2Pow(xx, xy, b);\\n (uint256 yax, uint256 yay) = _gfP2Pow(xx, xy, a);\\n (uint256 ya2x, uint256 ya2y) = _gfP2Pow(yax, yay, a);\\n (y.x, y.y) = _gfP2Multiply(ya2x, ya2y, xbx, xby);\\n\\n // Multiply y by hexRoot constant to find correct y.\\n while (!_g2X2y(xx, xy, y.x, y.y)) {\\n (y.x, y.y) = _gfP2Multiply(y.x, y.y, hexRootX, hexRootY);\\n }\\n }\\n\\n /// @dev Compress a point on G1 to a single uint256 for serialization.\\n function g1Compress(G1Point memory point) internal pure returns (bytes32) {\\n bytes32 m = bytes32(point.x);\\n\\n bytes1 leadM = m[0] | (parity(point.y) << 7);\\n // slither-disable-next-line incorrect-shift\\n uint256 mask = 0xff << (31 * 8);\\n m = (m & ~bytes32(mask)) | (leadM >> 0);\\n\\n return m;\\n }\\n\\n /// @dev Compress a point on G2 to a pair of uint256 for serialization.\\n function g2Compress(G2Point memory point)\\n internal\\n pure\\n returns (bytes memory)\\n {\\n bytes32 m = bytes32(point.x.x);\\n\\n bytes1 leadM = m[0] | (parity(point.y.x) << 7);\\n // slither-disable-next-line incorrect-shift\\n uint256 mask = 0xff << (31 * 8);\\n m = (m & ~bytes32(mask)) | (leadM >> 0);\\n\\n return abi.encodePacked(m, bytes32(point.x.y));\\n }\\n\\n /// @dev Unmarshals a point on G1 from bytes in an uncompressed form.\\n function g1Unmarshal(bytes memory m)\\n internal\\n pure\\n returns (G1Point memory)\\n {\\n require(m.length == 64, \\\"Invalid G1 bytes length\\\");\\n\\n bytes32 x;\\n bytes32 y;\\n\\n assembly {\\n x := mload(add(m, 0x20))\\n y := mload(add(m, 0x40))\\n }\\n\\n return G1Point(uint256(x), uint256(y));\\n }\\n\\n /// @dev Marshals a point on G1 to bytes form.\\n function g1Marshal(G1Point memory point)\\n internal\\n pure\\n returns (bytes memory)\\n {\\n bytes memory m = new bytes(64);\\n bytes32 x = bytes32(point.x);\\n bytes32 y = bytes32(point.y);\\n\\n assembly {\\n mstore(add(m, 32), x)\\n mstore(add(m, 64), y)\\n }\\n\\n return m;\\n }\\n\\n /// @dev Unmarshals a point on G2 from bytes in an uncompressed form.\\n function g2Unmarshal(bytes memory m)\\n internal\\n pure\\n returns (G2Point memory)\\n {\\n require(m.length == 128, \\\"Invalid G2 bytes length\\\");\\n\\n uint256 xx;\\n uint256 xy;\\n uint256 yx;\\n uint256 yy;\\n\\n assembly {\\n xx := mload(add(m, 0x20))\\n xy := mload(add(m, 0x40))\\n yx := mload(add(m, 0x60))\\n yy := mload(add(m, 0x80))\\n }\\n\\n return G2Point(gfP2(xx, xy), gfP2(yx, yy));\\n }\\n\\n /// @dev Decompress a point on G2 from a pair of uint256.\\n function g2Decompress(bytes memory m)\\n internal\\n pure\\n returns (G2Point memory)\\n {\\n require(m.length == 64, \\\"Invalid G2 compressed bytes length\\\");\\n\\n bytes32 x1;\\n bytes32 x2;\\n uint256 temp;\\n\\n // Extract two bytes32 from bytes array\\n assembly {\\n temp := add(m, 32)\\n x1 := mload(temp)\\n temp := add(m, 64)\\n x2 := mload(temp)\\n }\\n\\n bytes32 mX = bytes32(0);\\n bytes1 leadX = x1[0] & 0x7f;\\n // slither-disable-next-line incorrect-shift\\n uint256 mask = 0xff << (31 * 8);\\n mX = (x1 & ~bytes32(mask)) | (leadX >> 0);\\n\\n gfP2 memory x = gfP2(uint256(mX), uint256(x2));\\n gfP2 memory y = g2YFromX(x);\\n\\n if (parity(y.x) != (m[0] & 0x80) >> 7) {\\n y.x = p - y.x;\\n y.y = p - y.y;\\n }\\n\\n return G2Point(x, y);\\n }\\n\\n /// @dev Returns the sum of two gfP2 field elements.\\n function gfP2Add(gfP2 memory a, gfP2 memory b)\\n internal\\n pure\\n returns (gfP2 memory)\\n {\\n return gfP2(addmod(a.x, b.x, p), addmod(a.y, b.y, p));\\n }\\n\\n /// @dev Returns multiplication of two gfP2 field elements.\\n function gfP2Multiply(gfP2 memory a, gfP2 memory b)\\n internal\\n pure\\n returns (gfP2 memory)\\n {\\n return\\n gfP2(\\n addmod(mulmod(a.x, b.y, p), mulmod(b.x, a.y, p), p),\\n addmod(mulmod(a.y, b.y, p), p - mulmod(a.x, b.x, p), p)\\n );\\n }\\n\\n /// @dev Returns gfP2 element to the power of the provided exponent.\\n function gfP2Pow(gfP2 memory _a, uint256 _exp)\\n internal\\n pure\\n returns (gfP2 memory result)\\n {\\n (uint256 x, uint256 y) = _gfP2Pow(_a.x, _a.y, _exp);\\n return gfP2(x, y);\\n }\\n\\n function gfP2Square(gfP2 memory a) internal pure returns (gfP2 memory) {\\n return gfP2Multiply(a, a);\\n }\\n\\n function gfP2Cube(gfP2 memory a) internal pure returns (gfP2 memory) {\\n return gfP2Multiply(a, gfP2Square(a));\\n }\\n\\n function gfP2CubeAddTwistB(gfP2 memory a)\\n internal\\n pure\\n returns (gfP2 memory)\\n {\\n (uint256 x, uint256 y) = _gfP2CubeAddTwistB(a.x, a.y);\\n return gfP2(x, y);\\n }\\n\\n /// @dev Returns true if G2 point's y^2 equals x.\\n function g2X2y(gfP2 memory x, gfP2 memory y) internal pure returns (bool) {\\n gfP2 memory y2;\\n y2 = gfP2Square(y);\\n\\n return (y2.x == x.x && y2.y == x.y);\\n }\\n\\n /// @dev Returns true if G2 point is on the curve.\\n function isG2PointOnCurve(G2Point memory point)\\n internal\\n pure\\n returns (bool)\\n {\\n (uint256 y2x, uint256 y2y) = _gfP2Square(point.y.x, point.y.y);\\n (uint256 x3x, uint256 x3y) = _gfP2CubeAddTwistB(point.x.x, point.x.y);\\n\\n return (y2x == x3x && y2y == x3y);\\n }\\n\\n function twistB() private pure returns (gfP2 memory) {\\n return gfP2(twistBx, twistBy);\\n }\\n\\n function hexRoot() private pure returns (gfP2 memory) {\\n return gfP2(hexRootX, hexRootY);\\n }\\n\\n /// @dev Calculates whether the provided number is even or odd.\\n /// @return 0x01 if y is an even number and 0x00 if it's odd.\\n function parity(uint256 value) private pure returns (bytes1) {\\n return bytes32(value)[31] & 0x01;\\n }\\n\\n function _gfP2Add(\\n uint256 ax,\\n uint256 ay,\\n uint256 bx,\\n uint256 by\\n ) private pure returns (uint256 x, uint256 y) {\\n x = addmod(ax, bx, p);\\n y = addmod(ay, by, p);\\n }\\n\\n function _gfP2Multiply(\\n uint256 ax,\\n uint256 ay,\\n uint256 bx,\\n uint256 by\\n ) private pure returns (uint256 x, uint256 y) {\\n x = addmod(mulmod(ax, by, p), mulmod(bx, ay, p), p);\\n y = addmod(mulmod(ay, by, p), p - mulmod(ax, bx, p), p);\\n }\\n\\n function _gfP2CubeAddTwistB(uint256 ax, uint256 ay)\\n private\\n pure\\n returns (uint256 x, uint256 y)\\n {\\n (uint256 a3x, uint256 a3y) = _gfP2Cube(ax, ay);\\n return _gfP2Add(a3x, a3y, twistBx, twistBy);\\n }\\n\\n function _gfP2Pow(\\n uint256 _ax,\\n uint256 _ay,\\n uint256 _exp\\n ) private pure returns (uint256 x, uint256 y) {\\n uint256 exp = _exp;\\n x = 0;\\n y = 1;\\n uint256 ax = _ax;\\n uint256 ay = _ay;\\n\\n // Reduce exp dividing by 2 gradually to 0 while computing final\\n // result only when exp is an odd number.\\n while (exp > 0) {\\n if (parity(exp) == 0x01) {\\n (x, y) = _gfP2Multiply(x, y, ax, ay);\\n }\\n\\n unchecked {\\n exp = exp / 2;\\n }\\n (ax, ay) = _gfP2Multiply(ax, ay, ax, ay);\\n }\\n }\\n\\n function _gfP2Square(uint256 _ax, uint256 _ay)\\n private\\n pure\\n returns (uint256 x, uint256 y)\\n {\\n return _gfP2Multiply(_ax, _ay, _ax, _ay);\\n }\\n\\n function _gfP2Cube(uint256 _ax, uint256 _ay)\\n private\\n pure\\n returns (uint256 x, uint256 y)\\n {\\n (uint256 _bx, uint256 _by) = _gfP2Square(_ax, _ay);\\n return _gfP2Multiply(_ax, _ay, _bx, _by);\\n }\\n\\n function _g2X2y(\\n uint256 xx,\\n uint256 xy,\\n uint256 yx,\\n uint256 yy\\n ) private pure returns (bool) {\\n (uint256 y2x, uint256 y2y) = _gfP2Square(yx, yy);\\n\\n return (y2x == xx && y2y == xy);\\n }\\n}\\n\",\"keccak256\":\"0x8a100028820ff5c424f4bb780fbedec1da2576fbc6d5aa4e7309d986b730a319\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BLS.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./AltBn128.sol\\\";\\n\\n/// @title BLS signatures verification\\n/// @dev Library for verification of 2-pairing-check BLS signatures, including\\n/// basic, aggregated, or reconstructed threshold BLS signatures, generated\\n/// using the AltBn128 curve.\\nlibrary BLS {\\n /// @dev Creates a signature over message using the provided secret key.\\n function sign(bytes memory message, uint256 secretKey)\\n external\\n view\\n returns (bytes memory)\\n {\\n AltBn128.G1Point memory p_1 = AltBn128.g1HashToPoint(message);\\n AltBn128.G1Point memory p_2 = AltBn128.scalarMultiply(p_1, secretKey);\\n\\n return AltBn128.g1Marshal(p_2);\\n }\\n\\n /// @dev Wraps the functionality of BLS.verify, but hashes a message to\\n /// a point on G1 and marshal to bytes first to allow raw bytes\\n /// verification.\\n function verifyBytes(\\n bytes memory publicKey,\\n bytes memory message,\\n bytes memory signature\\n ) external view returns (bool) {\\n AltBn128.G1Point memory point = AltBn128.g1HashToPoint(message);\\n bytes memory messageAsPoint = AltBn128.g1Marshal(point);\\n\\n return verify(publicKey, messageAsPoint, signature);\\n }\\n\\n /// @dev Verify performs the pairing operation to check if the signature\\n /// is correct for the provided message and the corresponding public\\n /// key. Public key must be a valid point on G2 curve in an\\n /// uncompressed format. Message must be a valid point on G1 curve in\\n /// an uncompressed format. Signature must be a valid point on G1\\n /// curve in an uncompressed format.\\n function verify(\\n bytes memory publicKey,\\n bytes memory message,\\n bytes memory signature\\n ) public view returns (bool) {\\n AltBn128.G1Point memory _signature = AltBn128.g1Unmarshal(signature);\\n\\n return\\n _verify(\\n AltBn128.g2Unmarshal(publicKey),\\n AltBn128.g1Unmarshal(message),\\n _signature\\n );\\n }\\n\\n function _verify(\\n AltBn128.G2Point memory publicKey,\\n AltBn128.G1Point memory message,\\n AltBn128.G1Point memory signature\\n ) public view returns (bool) {\\n return\\n AltBn128.pairing(\\n AltBn128.G1Point(signature.x, AltBn128.getP() - signature.y),\\n AltBn128.g2(),\\n message,\\n publicKey\\n );\\n }\\n}\\n\",\"keccak256\":\"0x08c7e739c63c31f5f45fb390695eca9e98a9525589ace41526f25060f46e43d4\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BeaconAuthorization.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\n// Initial version copied from Keep Network ECDSA Wallets:\\n// https://github.com/keep-network/keep-core/blob/5286ebc8ff99b2aa6569f9dd97fd6995f25b4630/solidity/ecdsa/contracts/libraries/EcdsaAuthorization.sol\\n//\\n// With the following differences:\\n// - functions' visibility was changed to public/external to deploy it as a linked\\n// library.\\n// - documentation was updated to be more generic.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\nimport \\\"@threshold-network/solidity-contracts/contracts/staking/IStaking.sol\\\";\\n\\n/// @notice Library managing the state of stake authorizations for the operator\\n/// contract and the presence of operators in the sortition\\n/// pool based on the stake authorized for them.\\nlibrary BeaconAuthorization {\\n struct Parameters {\\n // The minimum authorization required by the beacon so that\\n // operator can join the sortition pool and do the work.\\n uint96 minimumAuthorization;\\n // Authorization decrease delay in seconds between the time\\n // authorization decrease is requested and the time the authorization\\n // decrease can be approved. It is always the same value, no matter if\\n // authorization decrease amount is small, significant, or if it is\\n // a decrease to zero.\\n uint64 authorizationDecreaseDelay;\\n // The time period before the authorization decrease delay end,\\n // during which the authorization decrease request can be overwritten.\\n //\\n // When the request is overwritten, the authorization decrease delay is\\n // reset.\\n //\\n // For example, if `authorizationDecraseChangePeriod` is set to 4\\n // days, `authorizationDecreaseDelay` is set to 14 days, and someone\\n // requested authorization decrease, it means they can not\\n // request another decrease for the first 10 days. After 10 days pass,\\n // they can request again and overwrite the previous authorization\\n // decrease request. The delay time will reset for them and they\\n // will have to wait another 10 days to alter it and 14 days to\\n // approve it.\\n //\\n // This value protects against malicious operators who manipulate\\n // their weight by overwriting authorization decrease request, and\\n // lowering or increasing their eligible stake this way.\\n //\\n // If set to a value equal to `authorizationDecreaseDelay, it means\\n // that authorization decrease request can be always overwritten.\\n // If set to zero, it means authorization decrease request can not be\\n // overwritten until the delay end, and one needs to wait for the entire\\n // authorization decrease delay to approve their decrease and request\\n // for another one or to overwrite the pending one.\\n //\\n // (1) authorization decrease requested timestamp\\n // (2) from this moment authorization decrease request can be\\n // overwritten\\n // (3) from this moment authorization decrease request can be\\n // approved, assuming it was NOT overwritten in (2)\\n //\\n // (1) (2) (3)\\n // --x------------------------------x--------------------------x---->\\n // | \\\\________________________/\\n // | authorizationDecreaseChangePeriod\\n // \\\\______________________________________________________/\\n // authorizationDecreaseDelay\\n //\\n uint64 authorizationDecreaseChangePeriod;\\n }\\n\\n struct AuthorizationDecrease {\\n uint96 decreasingBy; // amount\\n uint64 decreasingAt; // timestamp\\n }\\n\\n struct Data {\\n Parameters parameters;\\n mapping(address => address) stakingProviderToOperator;\\n mapping(address => address) operatorToStakingProvider;\\n mapping(address => AuthorizationDecrease) pendingDecreases;\\n }\\n\\n event OperatorRegistered(\\n address indexed stakingProvider,\\n address indexed operator\\n );\\n\\n event AuthorizationIncreased(\\n address indexed stakingProvider,\\n address indexed operator,\\n uint96 fromAmount,\\n uint96 toAmount\\n );\\n\\n event AuthorizationDecreaseRequested(\\n address indexed stakingProvider,\\n address indexed operator,\\n uint96 fromAmount,\\n uint96 toAmount,\\n uint64 decreasingAt\\n );\\n\\n event AuthorizationDecreaseApproved(address indexed stakingProvider);\\n\\n event InvoluntaryAuthorizationDecreaseFailed(\\n address indexed stakingProvider,\\n address indexed operator,\\n uint96 fromAmount,\\n uint96 toAmount\\n );\\n\\n event OperatorJoinedSortitionPool(\\n address indexed stakingProvider,\\n address indexed operator\\n );\\n\\n event OperatorStatusUpdated(\\n address indexed stakingProvider,\\n address indexed operator\\n );\\n\\n /// @notice Updates authorization-related parameters.\\n /// @param _minimumAuthorization New value of the minimum authorization for\\n /// the beacon. Without at least the minimum authorization, staking\\n /// provider is not eligible to join and operate in the network.\\n /// @param _authorizationDecreaseDelay New value of the authorization\\n /// decrease delay. It is the time in seconds that needs to pass\\n /// between the time authorization decrease is requested and the time\\n /// the authorization decrease can be approved, no matter the\\n /// authorization decrease amount.\\n /// @param _authorizationDecreaseChangePeriod New value of the authorization\\n /// decrease change period. It is the time in seconds, before\\n /// authorization decrease delay end, during which the pending\\n /// authorization decrease request can be overwritten.\\n /// If set to 0, pending authorization decrease request can not be\\n /// overwritten until the entire `authorizationDecreaseDelay` ends.\\n /// If set to value equal `authorizationDecreaseDelay`, request can\\n /// always be overwritten.\\n function setParameters(\\n Data storage self,\\n uint96 _minimumAuthorization,\\n uint64 _authorizationDecreaseDelay,\\n uint64 _authorizationDecreaseChangePeriod\\n ) external {\\n self.parameters.minimumAuthorization = _minimumAuthorization;\\n self\\n .parameters\\n .authorizationDecreaseDelay = _authorizationDecreaseDelay;\\n self\\n .parameters\\n .authorizationDecreaseChangePeriod = _authorizationDecreaseChangePeriod;\\n }\\n\\n /// @notice Used by staking provider to set operator address that will\\n /// operate a node. The given staking provider can set operator\\n /// address only one time. The operator address can not be changed\\n /// and must be unique. Reverts if the operator is already set for\\n /// the staking provider or if the operator address is already in\\n /// use. Reverts if there is a pending authorization decrease for\\n /// the staking provider.\\n function registerOperator(Data storage self, address operator) public {\\n address stakingProvider = msg.sender;\\n\\n require(operator != address(0), \\\"Operator can not be zero address\\\");\\n require(\\n self.stakingProviderToOperator[stakingProvider] == address(0),\\n \\\"Operator already set for the staking provider\\\"\\n );\\n require(\\n self.operatorToStakingProvider[operator] == address(0),\\n \\\"Operator address already in use\\\"\\n );\\n\\n // Authorization request for a staking provider who has not yet\\n // registered their operator can be approved immediately.\\n // We need to make sure that the approval happens before operator\\n // is registered to do not let the operator join the sortition pool\\n // with an unresolved authorization decrease request that can be\\n // approved at any point.\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n require(\\n decrease.decreasingAt == 0,\\n \\\"There is a pending authorization decrease request\\\"\\n );\\n\\n emit OperatorRegistered(stakingProvider, operator);\\n\\n self.stakingProviderToOperator[stakingProvider] = operator;\\n self.operatorToStakingProvider[operator] = stakingProvider;\\n }\\n\\n /// @notice Used by T staking contract to inform the beacon that the\\n /// authorized stake amount for the given staking provider increased.\\n ///\\n /// Reverts if the authorization amount is below the minimum.\\n ///\\n /// The function is not updating the sortition pool. Sortition pool\\n /// state needs to be updated by the operator with a call to\\n /// `joinSortitionPool` or `updateOperatorStatus`.\\n ///\\n /// @dev Should only be callable by T staking contract.\\n function authorizationIncreased(\\n Data storage self,\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external {\\n require(\\n toAmount >= self.parameters.minimumAuthorization,\\n \\\"Authorization below the minimum\\\"\\n );\\n\\n // Note that this function does not require the operator address to be\\n // set for the given staking provider. This allows the stake owner\\n // who is also an authorizer to increase the authorization before the\\n // staking provider sets the operator. This allows delegating stake\\n // and increasing authorization immediately one after another without\\n // having to wait for the staking provider to do their part.\\n\\n address operator = self.stakingProviderToOperator[stakingProvider];\\n emit AuthorizationIncreased(\\n stakingProvider,\\n operator,\\n fromAmount,\\n toAmount\\n );\\n }\\n\\n /// @notice Used by T staking contract to inform the beacon that the\\n /// authorization decrease for the given staking provider has been\\n /// requested.\\n ///\\n /// Reverts if the amount after deauthorization would be non-zero\\n /// and lower than the minimum authorization.\\n ///\\n /// Reverts if another authorization decrease request is pending for\\n /// the staking provider and not enough time passed since the\\n /// original request (see `authorizationDecreaseChangePeriod`).\\n ///\\n /// If the operator is not known (`registerOperator` was not called)\\n /// it lets to `approveAuthorizationDecrease` immediately. If the\\n /// operator is known (`registerOperator` was called), the operator\\n /// needs to update state of the sortition pool with a call to\\n /// `joinSortitionPool` or `updateOperatorStatus`. After the\\n /// sortition pool state is in sync, authorization decrease delay\\n /// starts.\\n ///\\n /// After authorization decrease delay passes, authorization\\n /// decrease request needs to be approved with a call to\\n /// `approveAuthorizationDecrease` function.\\n ///\\n /// If there is a pending authorization decrease request, it is\\n /// overwritten, but only if enough time passed since the original\\n /// request. Otherwise, the function reverts.\\n ///\\n /// @dev Should only be callable by T staking contract.\\n function authorizationDecreaseRequested(\\n Data storage self,\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) public {\\n require(\\n toAmount == 0 || toAmount >= self.parameters.minimumAuthorization,\\n \\\"Authorization amount should be 0 or above the minimum\\\"\\n );\\n\\n address operator = self.stakingProviderToOperator[stakingProvider];\\n\\n uint64 decreasingAt;\\n\\n if (operator == address(0)) {\\n // Operator is not known. It means `registerOperator` was not\\n // called yet, and there is no chance the operator could\\n // call `joinSortitionPool`. We can let to approve authorization\\n // decrease immediately because that operator was never in the\\n // sortition pool.\\n\\n // solhint-disable-next-line not-rely-on-time\\n decreasingAt = uint64(block.timestamp);\\n } else {\\n // Operator is known. It means that this operator is or was in\\n // the sortition pool. Before authorization decrease delay starts,\\n // the operator needs to update the state of the sortition pool\\n // with a call to `joinSortitionPool` or `updateOperatorStatus`.\\n // For now, we set `decreasingAt` as \\\"never decreasing\\\" and let\\n // it be updated by `joinSortitionPool` or `updateOperatorStatus`\\n // once we know the sortition pool is in sync.\\n decreasingAt = type(uint64).max;\\n }\\n\\n uint96 decreasingBy = fromAmount - toAmount;\\n\\n AuthorizationDecrease storage decreaseRequest = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n uint64 pendingDecreaseAt = decreaseRequest.decreasingAt;\\n if (pendingDecreaseAt != 0 && pendingDecreaseAt != type(uint64).max) {\\n // If there is already a pending authorization decrease request for\\n // this staking provider and that request has been activated\\n // (sortition pool was updated), require enough time to pass before\\n // it can be overwritten.\\n require(\\n // solhint-disable-next-line not-rely-on-time\\n block.timestamp >=\\n pendingDecreaseAt -\\n self.parameters.authorizationDecreaseChangePeriod,\\n \\\"Not enough time passed since the original request\\\"\\n );\\n }\\n\\n decreaseRequest.decreasingBy = decreasingBy;\\n decreaseRequest.decreasingAt = decreasingAt;\\n\\n emit AuthorizationDecreaseRequested(\\n stakingProvider,\\n operator,\\n fromAmount,\\n toAmount,\\n decreasingAt\\n );\\n }\\n\\n /// @notice Approves the previously registered authorization decrease\\n /// request. Reverts if authorization decrease delay have not passed\\n /// yet or if the authorization decrease was not requested for the\\n /// given staking provider.\\n function approveAuthorizationDecrease(\\n Data storage self,\\n IStaking tokenStaking,\\n address stakingProvider\\n ) public {\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n require(\\n decrease.decreasingAt > 0,\\n \\\"Authorization decrease not requested\\\"\\n );\\n require(\\n decrease.decreasingAt != type(uint64).max,\\n \\\"Authorization decrease request not activated\\\"\\n );\\n require(\\n // solhint-disable-next-line not-rely-on-time\\n block.timestamp >= decrease.decreasingAt,\\n \\\"Authorization decrease delay not passed\\\"\\n );\\n\\n emit AuthorizationDecreaseApproved(stakingProvider);\\n\\n // slither-disable-next-line unused-return\\n tokenStaking.approveAuthorizationDecrease(stakingProvider);\\n delete self.pendingDecreases[stakingProvider];\\n }\\n\\n /// @notice Used by T staking contract to inform the beacon the\\n /// authorization has been decreased for the given staking provider\\n /// involuntarily, as a result of slashing.\\n ///\\n /// If the operator is not known (`registerOperator` was not called)\\n /// the function does nothing. The operator was never in a sortition\\n /// pool so there is nothing to update.\\n ///\\n /// If the operator is known, sortition pool is unlocked, and the\\n /// operator is in the sortition pool, the sortition pool state is\\n /// updated. If the sortition pool is locked, update needs to be\\n /// postponed. Every other staker is incentivized to call\\n /// `updateOperatorStatus` for the problematic operator to increase\\n /// their own rewards in the pool.\\n ///\\n /// @dev Should only be callable by T staking contract.\\n function involuntaryAuthorizationDecrease(\\n Data storage self,\\n IStaking tokenStaking,\\n SortitionPool sortitionPool,\\n address stakingProvider,\\n uint96 fromAmount,\\n uint96 toAmount\\n ) external {\\n address operator = self.stakingProviderToOperator[stakingProvider];\\n\\n if (operator == address(0)) {\\n // Operator is not known. It means `registerOperator` was not\\n // called yet, and there is no chance the operator could\\n // call `joinSortitionPool`. We can just ignore this update because\\n // operator was never in the sortition pool.\\n return;\\n } else {\\n // Operator is known. It means that this operator is or was in the\\n // sortition pool and the sortition pool may need to be updated.\\n //\\n // If the sortition pool is not locked and the operator is in the\\n // sortition pool, we are updating it.\\n //\\n // To keep stakes synchronized between applications when staking\\n // providers are slashed, without the risk of running out of gas,\\n // the staking contract queues up slashings and let users process\\n // the transactions. When an application slashes one or more staking\\n // providers, it adds them to the slashing queue on the staking\\n // contract. A queue entry contains the staking provider\\u2019s address\\n // and the amount they are due to be slashed.\\n //\\n // When there is at least one staking provider in the slashing\\n // queue, any account can submit a transaction processing one or\\n // more staking providers' slashings, and collecting a reward for\\n // doing so. A queued slashing is processed by updating the staking\\n // provider\\u2019s stake to the post-slashing amount, updating authorized\\n // amount for each affected application, and notifying all affected\\n // applications that the staking provider\\u2019s authorized stake has\\n // been reduced due to slashing.\\n //\\n // The entire idea is that the process transaction is expensive\\n // because each application needs to be updated, so the reward for\\n // the processor is hefty and comes from the slashed tokens.\\n // Practically, it means that if the sortition pool is unlocked, and\\n // can be updated, it should be updated because we already paid\\n // someone for updating it.\\n //\\n // If the sortition pool is locked, update needs to wait. Other\\n // sortition pool members are incentivized to call\\n // `updateOperatorStatus` for the problematic operator because they\\n // will increase their rewards this way.\\n if (sortitionPool.isOperatorInPool(operator)) {\\n if (sortitionPool.isLocked()) {\\n emit InvoluntaryAuthorizationDecreaseFailed(\\n stakingProvider,\\n operator,\\n fromAmount,\\n toAmount\\n );\\n } else {\\n updateOperatorStatus(\\n self,\\n tokenStaking,\\n sortitionPool,\\n operator\\n );\\n }\\n }\\n }\\n }\\n\\n /// @notice Lets the operator join the sortition pool. The operator address\\n /// must be known - before calling this function, it has to be\\n /// appointed by the staking provider by calling `registerOperator`.\\n /// Also, the operator must have the minimum authorization required\\n /// by the beacon. Function reverts if there is no minimum stake\\n /// authorized or if the operator is not known. If there was an\\n /// authorization decrease requested, it is activated by starting\\n /// the authorization decrease delay.\\n function joinSortitionPool(\\n Data storage self,\\n IStaking tokenStaking,\\n SortitionPool sortitionPool\\n ) public {\\n address operator = msg.sender;\\n\\n address stakingProvider = self.operatorToStakingProvider[operator];\\n require(stakingProvider != address(0), \\\"Unknown operator\\\");\\n\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n uint96 _eligibleStake = eligibleStake(\\n self,\\n tokenStaking,\\n stakingProvider,\\n decrease.decreasingBy\\n );\\n\\n require(_eligibleStake != 0, \\\"Authorization below the minimum\\\");\\n\\n emit OperatorJoinedSortitionPool(stakingProvider, operator);\\n\\n sortitionPool.insertOperator(operator, _eligibleStake);\\n\\n // If there is a pending authorization decrease request, activate it.\\n // At this point, the sortition pool state is up to date so the\\n // authorization decrease delay can start counting.\\n if (decrease.decreasingAt == type(uint64).max) {\\n decrease.decreasingAt =\\n // solhint-disable-next-line not-rely-on-time\\n uint64(block.timestamp) +\\n self.parameters.authorizationDecreaseDelay;\\n }\\n }\\n\\n /// @notice Updates status of the operator in the sortition pool. If there\\n /// was an authorization decrease requested, it is activated by\\n /// starting the authorization decrease delay.\\n /// Function reverts if the operator is not known.\\n function updateOperatorStatus(\\n Data storage self,\\n IStaking tokenStaking,\\n SortitionPool sortitionPool,\\n address operator\\n ) public {\\n address stakingProvider = self.operatorToStakingProvider[operator];\\n require(stakingProvider != address(0), \\\"Unknown operator\\\");\\n\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n emit OperatorStatusUpdated(stakingProvider, operator);\\n\\n if (sortitionPool.isOperatorInPool(operator)) {\\n uint96 _eligibleStake = eligibleStake(\\n self,\\n tokenStaking,\\n stakingProvider,\\n decrease.decreasingBy\\n );\\n\\n sortitionPool.updateOperatorStatus(operator, _eligibleStake);\\n }\\n\\n // If there is a pending authorization decrease request, activate it.\\n // At this point, the sortition pool state is up to date so the\\n // authorization decrease delay can start counting.\\n if (decrease.decreasingAt == type(uint64).max) {\\n decrease.decreasingAt =\\n // solhint-disable-next-line not-rely-on-time\\n uint64(block.timestamp) +\\n self.parameters.authorizationDecreaseDelay;\\n }\\n }\\n\\n /// @notice Checks if the operator's authorized stake is in sync with\\n /// operator's weight in the sortition pool.\\n /// If the operator is not in the sortition pool and their\\n /// authorized stake is non-zero, function returns false.\\n function isOperatorUpToDate(\\n Data storage self,\\n IStaking tokenStaking,\\n SortitionPool sortitionPool,\\n address operator\\n ) external view returns (bool) {\\n address stakingProvider = self.operatorToStakingProvider[operator];\\n require(stakingProvider != address(0), \\\"Unknown operator\\\");\\n\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n uint96 _eligibleStake = eligibleStake(\\n self,\\n tokenStaking,\\n stakingProvider,\\n decrease.decreasingBy\\n );\\n\\n if (!sortitionPool.isOperatorInPool(operator)) {\\n return _eligibleStake == 0;\\n } else {\\n return sortitionPool.isOperatorUpToDate(operator, _eligibleStake);\\n }\\n }\\n\\n /// @notice Returns the current value of the staking provider's eligible\\n /// stake. Eligible stake is defined as the currently authorized\\n /// stake minus the pending authorization decrease. Eligible stake\\n /// is what is used for operator's weight in the pool. If the\\n /// authorized stake minus the pending authorization decrease is\\n /// below the minimum authorization, eligible stake is 0.\\n /// @dev This function can be exposed to the public in contrast to the\\n /// second variant accepting `decreasingBy` as a parameter.\\n function eligibleStake(\\n Data storage self,\\n IStaking tokenStaking,\\n address stakingProvider\\n ) external view returns (uint96) {\\n return\\n eligibleStake(\\n self,\\n tokenStaking,\\n stakingProvider,\\n pendingAuthorizationDecrease(self, stakingProvider)\\n );\\n }\\n\\n /// @notice Returns the current value of the staking provider's eligible\\n /// stake. Eligible stake is defined as the currently authorized\\n /// stake minus the pending authorization decrease. Eligible stake\\n /// is what is used for operator's weight in the pool. If the\\n /// authorized stake minus the pending authorization decrease is\\n /// below the minimum authorization, eligible stake is 0.\\n /// @dev This function is not intended to be exposes to the public.\\n /// `decreasingBy` must be fetched from `pendingDecreases` mapping and\\n /// it is passed as a parameter to optimize gas usage of functions that\\n /// call `eligibleStake` and need to use `AuthorizationDecrease`\\n /// fetched from `pendingDecreases` for some additional logic.\\n function eligibleStake(\\n Data storage self,\\n IStaking tokenStaking,\\n address stakingProvider,\\n uint96 decreasingBy\\n ) public view returns (uint96) {\\n uint96 authorizedStake = tokenStaking.authorizedStake(\\n stakingProvider,\\n address(this)\\n );\\n\\n uint96 _eligibleStake = authorizedStake > decreasingBy\\n ? authorizedStake - decreasingBy\\n : 0;\\n\\n if (_eligibleStake < self.parameters.minimumAuthorization) {\\n return 0;\\n } else {\\n return _eligibleStake;\\n }\\n }\\n\\n /// @notice Returns the amount of stake that is pending authorization\\n /// decrease for the given staking provider. If no authorization\\n /// decrease has been requested, returns zero.\\n function pendingAuthorizationDecrease(\\n Data storage self,\\n address stakingProvider\\n ) public view returns (uint96) {\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n return decrease.decreasingBy;\\n }\\n\\n /// @notice Returns the remaining time in seconds that needs to pass before\\n /// the requested authorization decrease can be approved.\\n /// If the sortition pool state was not updated yet by the operator\\n /// after requesting the authorization decrease, returns\\n /// `type(uint64).max`.\\n function remainingAuthorizationDecreaseDelay(\\n Data storage self,\\n address stakingProvider\\n ) external view returns (uint64) {\\n AuthorizationDecrease storage decrease = self.pendingDecreases[\\n stakingProvider\\n ];\\n\\n if (decrease.decreasingAt == type(uint64).max) {\\n return type(uint64).max;\\n }\\n\\n // solhint-disable-next-line not-rely-on-time\\n uint64 _now = uint64(block.timestamp);\\n return _now > decrease.decreasingAt ? 0 : decrease.decreasingAt - _now;\\n }\\n}\\n\",\"keccak256\":\"0xe146f4a3c662e971317d0189b2fca613f9f83a163ef682ed1e536e6c1f919a08\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BeaconDkg.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\nimport \\\"./BytesLib.sol\\\";\\nimport {BeaconDkgValidator as DKGValidator} from \\\"../BeaconDkgValidator.sol\\\";\\n\\nlibrary BeaconDkg {\\n using BytesLib for bytes;\\n using ECDSA for bytes32;\\n\\n struct Parameters {\\n // Time in blocks during which a submitted result can be challenged.\\n uint256 resultChallengePeriodLength;\\n // Extra gas required to be left at the end of the challenge DKG result\\n // transaction.\\n uint256 resultChallengeExtraGas;\\n // Time in blocks during which a result is expected to be submitted.\\n uint256 resultSubmissionTimeout;\\n // Time in blocks during which only the result submitter is allowed to\\n // approve it. Once this period ends and the submitter have not approved\\n // the result, anyone can do it.\\n uint256 submitterPrecedencePeriodLength;\\n }\\n\\n struct Data {\\n // Address of the Sortition Pool contract.\\n SortitionPool sortitionPool;\\n // Address of the DKGValidator contract.\\n DKGValidator dkgValidator;\\n // DKG parameters. The parameters should persist between DKG executions.\\n // They should be updated with dedicated set functions only when DKG is not\\n // in progress.\\n Parameters parameters;\\n // Time in blocks at which DKG started.\\n uint256 startBlock;\\n // Seed used to start DKG.\\n uint256 seed;\\n // Time in blocks that should be added to result submission period calculation.\\n // It is used in case of a challenge to adjust DKG timeout calculation.\\n uint256 resultSubmissionStartBlockOffset;\\n // Hash of submitted DKG result.\\n bytes32 submittedResultHash;\\n // Block number from the moment of the DKG result submission.\\n uint256 submittedResultBlock;\\n }\\n\\n /// @notice DKG result.\\n struct Result {\\n // Claimed submitter candidate group member index.\\n // Must be in range [1, groupSize].\\n uint256 submitterMemberIndex;\\n // Generated candidate group public key\\n bytes groupPubKey;\\n // Array of misbehaved members indices (disqualified or inactive).\\n // Indices must be in range [1, groupSize], unique, and sorted in ascending\\n // order.\\n uint8[] misbehavedMembersIndices;\\n // Concatenation of signatures from members supporting the result.\\n // The message to be signed by each member is keccak256 hash of the\\n // calculated group public key, misbehaved members indices and DKG\\n // start block. The calculated hash should be prefixed with prefixed with\\n // `\\\\x19Ethereum signed message:\\\\n` before signing, so the message to\\n // sign is:\\n // `\\\\x19Ethereum signed message:\\\\n${keccak256(\\n // groupPubKey, misbehavedMembersIndices, dkgStartBlock\\n // )}`\\n bytes signatures;\\n // Indices of members corresponding to each signature. Indices must be\\n // be in range [1, groupSize], unique, and sorted in ascending order.\\n uint256[] signingMembersIndices;\\n // Identifiers of candidate group members as outputted by the group\\n // selection protocol.\\n uint32[] members;\\n // Keccak256 hash of group members identifiers that actively took part\\n // in DKG (excluding IA/DQ members).\\n bytes32 membersHash;\\n }\\n\\n /// @notice States for phases of group creation. The states doesn't include\\n /// timeouts which should be tracked and notified individually.\\n enum State {\\n // Group creation is not in progress. It is a state set after group creation\\n // completion either by timeout or by a result approval.\\n IDLE,\\n // Group creation is awaiting the seed and sortition pool is locked.\\n AWAITING_SEED,\\n // Off-chain DKG protocol execution is in progress. A result is being calculated\\n // by the clients in this state. It's not yet possible to submit the result.\\n KEY_GENERATION,\\n // After off-chain DKG protocol execution the contract awaits result submission.\\n // This is a state to which group creation returns in case of a result\\n // challenge notification.\\n AWAITING_RESULT,\\n // DKG result was submitted and awaits an approval or a challenge. If a result\\n // gets challenge the state returns to `AWAITING_RESULT`. If a result gets\\n // approval the state changes to `IDLE`.\\n CHALLENGE\\n }\\n\\n /// @dev Size of a group in the threshold relay.\\n uint256 public constant groupSize = 64;\\n\\n /// @notice Time in blocks after which DKG result is complete and ready to be\\n // published by clients.\\n uint256 public constant offchainDkgTime = 5 * (1 + 5) + 2 * (1 + 10) + 20;\\n\\n event DkgStarted(uint256 indexed seed);\\n\\n // To recreate the members that actively took part in dkg, the selected members\\n // array should be filtered out from misbehavedMembersIndices.\\n event DkgResultSubmitted(\\n bytes32 indexed resultHash,\\n uint256 indexed seed,\\n Result result\\n );\\n\\n event DkgTimedOut();\\n\\n event DkgResultApproved(\\n bytes32 indexed resultHash,\\n address indexed approver\\n );\\n\\n event DkgResultChallenged(\\n bytes32 indexed resultHash,\\n address indexed challenger,\\n string reason\\n );\\n\\n event DkgStateLocked();\\n\\n event DkgSeedTimedOut();\\n\\n /// @notice Initializes SortitionPool and DKGValidator addresses.\\n /// Can be performed only once.\\n /// @param _sortitionPool Sortition Pool reference\\n /// @param _dkgValidator DKGValidator reference\\n function init(\\n Data storage self,\\n SortitionPool _sortitionPool,\\n DKGValidator _dkgValidator\\n ) internal {\\n require(\\n address(self.sortitionPool) == address(0),\\n \\\"Sortition Pool address already set\\\"\\n );\\n\\n require(\\n address(self.dkgValidator) == address(0),\\n \\\"DKG Validator address already set\\\"\\n );\\n\\n self.sortitionPool = _sortitionPool;\\n self.dkgValidator = _dkgValidator;\\n }\\n\\n /// @notice Determines the current state of group creation. It doesn't take\\n /// timeouts into consideration. The timeouts should be tracked and\\n /// notified separately.\\n function currentState(Data storage self)\\n internal\\n view\\n returns (State state)\\n {\\n state = State.IDLE;\\n\\n if (self.sortitionPool.isLocked()) {\\n state = State.AWAITING_SEED;\\n\\n if (self.startBlock > 0) {\\n state = State.KEY_GENERATION;\\n\\n if (block.number > self.startBlock + offchainDkgTime) {\\n state = State.AWAITING_RESULT;\\n\\n if (self.submittedResultBlock > 0) {\\n state = State.CHALLENGE;\\n }\\n }\\n }\\n }\\n }\\n\\n /// @notice Locks the sortition pool and starts awaiting for the\\n /// group creation seed.\\n function lockState(Data storage self) internal {\\n require(currentState(self) == State.IDLE, \\\"Current state is not IDLE\\\");\\n\\n emit DkgStateLocked();\\n\\n self.sortitionPool.lock();\\n }\\n\\n function start(Data storage self, uint256 seed) internal {\\n require(\\n currentState(self) == State.AWAITING_SEED,\\n \\\"Current state is not AWAITING_SEED\\\"\\n );\\n\\n emit DkgStarted(seed);\\n\\n self.startBlock = block.number;\\n self.seed = seed;\\n }\\n\\n /// @notice Allows to submit a DKG result. The submitted result does not go\\n /// through a validation and before it gets accepted, it needs to\\n /// wait through the challenge period during which everyone has\\n /// a chance to challenge the result as invalid one. Submitter of\\n /// the result needs to be in the sortition pool and if the result\\n /// gets challenged, the submitter will get slashed.\\n function submitResult(Data storage self, Result calldata result) external {\\n require(\\n currentState(self) == State.AWAITING_RESULT,\\n \\\"Current state is not AWAITING_RESULT\\\"\\n );\\n require(!hasDkgTimedOut(self), \\\"DKG timeout already passed\\\");\\n\\n SortitionPool sortitionPool = self.sortitionPool;\\n\\n // Submitter must be an operator in the sortition pool.\\n // Declared submitter's member index in the DKG result needs to match\\n // the address calling this function.\\n require(\\n sortitionPool.isOperatorInPool(msg.sender),\\n \\\"Submitter not in the sortition pool\\\"\\n );\\n require(\\n sortitionPool.getIDOperator(\\n result.members[result.submitterMemberIndex - 1]\\n ) == msg.sender,\\n \\\"Unexpected submitter index\\\"\\n );\\n\\n self.submittedResultHash = keccak256(abi.encode(result));\\n self.submittedResultBlock = block.number;\\n\\n emit DkgResultSubmitted(self.submittedResultHash, self.seed, result);\\n }\\n\\n /// @notice Checks if DKG timed out. The DKG timeout period includes time required\\n /// for off-chain protocol execution and time for the result publication.\\n /// After this time a result cannot be submitted and DKG can be notified\\n /// about the timeout. DKG period is adjusted by result submission\\n /// offset that include blocks that were mined while invalid result\\n /// has been registered until it got challenged.\\n /// @return True if DKG timed out, false otherwise.\\n function hasDkgTimedOut(Data storage self) internal view returns (bool) {\\n return\\n currentState(self) == State.AWAITING_RESULT &&\\n block.number >\\n (self.startBlock +\\n offchainDkgTime +\\n self.resultSubmissionStartBlockOffset +\\n self.parameters.resultSubmissionTimeout);\\n }\\n\\n /// @notice Notifies about DKG timeout.\\n function notifyTimeout(Data storage self) internal {\\n require(hasDkgTimedOut(self), \\\"DKG has not timed out\\\");\\n\\n emit DkgTimedOut();\\n\\n complete(self);\\n }\\n\\n /// @notice Notifies about the seed was not delivered and restores the\\n /// initial DKG state (IDLE).\\n function notifySeedTimedOut(Data storage self) internal {\\n require(\\n currentState(self) == State.AWAITING_SEED,\\n \\\"Current state is not AWAITING_SEED\\\"\\n );\\n\\n emit DkgSeedTimedOut();\\n\\n complete(self);\\n }\\n\\n /// @notice Approves DKG result. Can be called when the challenge period for\\n /// the submitted result is finished. Considers the submitted result\\n /// as valid. For the first `submitterPrecedencePeriodLength`\\n /// blocks after the end of the challenge period can be called only\\n /// by the DKG result submitter. After that time, can be called by\\n /// anyone.\\n /// @dev Can be called after a challenge period for the submitted result.\\n /// @param result Result to approve. Must match the submitted result stored\\n /// during `submitResult`.\\n /// @return misbehavedMembers Identifiers of members who misbehaved during DKG.\\n function approveResult(Data storage self, Result calldata result)\\n external\\n returns (uint32[] memory misbehavedMembers)\\n {\\n require(\\n currentState(self) == State.CHALLENGE,\\n \\\"Current state is not CHALLENGE\\\"\\n );\\n\\n uint256 challengePeriodEnd = self.submittedResultBlock +\\n self.parameters.resultChallengePeriodLength;\\n\\n require(\\n block.number > challengePeriodEnd,\\n \\\"Challenge period has not passed yet\\\"\\n );\\n\\n require(\\n keccak256(abi.encode(result)) == self.submittedResultHash,\\n \\\"Result under approval is different than the submitted one\\\"\\n );\\n\\n // Extract submitter member address. Submitter member index is in\\n // range [1, groupSize] so we need to -1 when fetching identifier from members\\n // array.\\n address submitterMember = self.sortitionPool.getIDOperator(\\n result.members[result.submitterMemberIndex - 1]\\n );\\n\\n require(\\n msg.sender == submitterMember ||\\n block.number >\\n challengePeriodEnd +\\n self.parameters.submitterPrecedencePeriodLength,\\n \\\"Only the DKG result submitter can approve the result at this moment\\\"\\n );\\n\\n // Extract misbehaved members identifiers. Misbehaved members indices\\n // are in range [1, groupSize], so we need to -1 when fetching identifiers from\\n // members array.\\n misbehavedMembers = new uint32[](\\n result.misbehavedMembersIndices.length\\n );\\n for (uint256 i = 0; i < result.misbehavedMembersIndices.length; i++) {\\n misbehavedMembers[i] = result.members[\\n result.misbehavedMembersIndices[i] - 1\\n ];\\n }\\n\\n emit DkgResultApproved(self.submittedResultHash, msg.sender);\\n\\n return misbehavedMembers;\\n }\\n\\n /// @notice Challenges DKG result. If the submitted result is proved to be\\n /// invalid it reverts the DKG back to the result submission phase.\\n /// @dev Can be called during a challenge period for the submitted result.\\n /// @param result Result to challenge. Must match the submitted result\\n /// stored during `submitResult`.\\n /// @return maliciousResultHash Hash of the malicious result.\\n /// @return maliciousSubmitter Identifier of the malicious submitter.\\n function challengeResult(Data storage self, Result calldata result)\\n external\\n returns (bytes32 maliciousResultHash, uint32 maliciousSubmitter)\\n {\\n require(\\n currentState(self) == State.CHALLENGE,\\n \\\"Current state is not CHALLENGE\\\"\\n );\\n\\n require(\\n block.number <=\\n self.submittedResultBlock +\\n self.parameters.resultChallengePeriodLength,\\n \\\"Challenge period has already passed\\\"\\n );\\n\\n require(\\n keccak256(abi.encode(result)) == self.submittedResultHash,\\n \\\"Result under challenge is different than the submitted one\\\"\\n );\\n\\n // https://github.com/crytic/slither/issues/982\\n // slither-disable-next-line unused-return\\n try\\n self.dkgValidator.validate(result, self.seed, self.startBlock)\\n returns (\\n // slither-disable-next-line uninitialized-local,variable-scope\\n bool isValid,\\n // slither-disable-next-line uninitialized-local,variable-scope\\n string memory errorMsg\\n ) {\\n if (isValid) {\\n revert(\\\"unjustified challenge\\\");\\n }\\n\\n emit DkgResultChallenged(\\n self.submittedResultHash,\\n msg.sender,\\n errorMsg\\n );\\n } catch {\\n // if the validation reverted we consider the DKG result as invalid\\n emit DkgResultChallenged(\\n self.submittedResultHash,\\n msg.sender,\\n \\\"validation reverted\\\"\\n );\\n }\\n\\n // Consider result hash as malicious.\\n maliciousResultHash = self.submittedResultHash;\\n maliciousSubmitter = result.members[result.submitterMemberIndex - 1];\\n\\n // Adjust DKG result submission block start, so submission stage starts\\n // from the beginning.\\n self.resultSubmissionStartBlockOffset =\\n block.number -\\n self.startBlock -\\n offchainDkgTime;\\n\\n submittedResultCleanup(self);\\n\\n return (maliciousResultHash, maliciousSubmitter);\\n }\\n\\n /// @notice Due to EIP150, 1/64 of the gas is not forwarded to the call, and\\n /// will be kept to execute the remaining operations in the function\\n /// after the call inside the try-catch.\\n ///\\n /// To ensure there is no way for the caller to manipulate gas limit\\n /// in such a way that the call inside try-catch fails with out-of-gas\\n /// and the rest of the function is executed with the remaining\\n /// 1/64 of gas, we require an extra gas amount to be left at the\\n /// end of the call to the function challenging DKG result and\\n /// wrapping the call to BeaconDkgValidator and TokenStaking\\n /// contracts inside a try-catch.\\n function requireChallengeExtraGas(Data storage self) internal view {\\n require(\\n gasleft() >= self.parameters.resultChallengeExtraGas,\\n \\\"Not enough extra gas left\\\"\\n );\\n }\\n\\n /// @notice Updates DKG-related parameters\\n /// @param _resultChallengePeriodLength New value of the result challenge\\n /// period length. It is the number of blocks for which a DKG result\\n /// can be challenged.\\n /// @param _resultChallengeExtraGas New value of the result challenge extra\\n /// gas. It is the extra gas required to be left at the end of the\\n /// challenge DKG result transaction.\\n /// @param _resultSubmissionTimeout New value of the result submission\\n /// timeout in seconds. It is a timeout for a group to provide a DKG\\n /// result.\\n /// @param _submitterPrecedencePeriodLength New value of the submitter\\n /// precedence period length in blocks. It is the time during which\\n /// only the original DKG result submitter can approve it.\\n function setParameters(\\n Data storage self,\\n uint256 _resultChallengePeriodLength,\\n uint256 _resultChallengeExtraGas,\\n uint256 _resultSubmissionTimeout,\\n uint256 _submitterPrecedencePeriodLength\\n ) internal {\\n require(currentState(self) == State.IDLE, \\\"Current state is not IDLE\\\");\\n\\n require(\\n _resultChallengePeriodLength > 0,\\n \\\"Result challenge period length should be greater than zero\\\"\\n );\\n require(\\n _resultSubmissionTimeout > 0,\\n \\\"Result submission timeout should be greater than zero\\\"\\n );\\n require(\\n _submitterPrecedencePeriodLength < _resultSubmissionTimeout,\\n \\\"Submitter precedence period length should be less than the result submission timeout\\\"\\n );\\n\\n self\\n .parameters\\n .resultChallengePeriodLength = _resultChallengePeriodLength;\\n self.parameters.resultChallengeExtraGas = _resultChallengeExtraGas;\\n self.parameters.resultSubmissionTimeout = _resultSubmissionTimeout;\\n self\\n .parameters\\n .submitterPrecedencePeriodLength = _submitterPrecedencePeriodLength;\\n }\\n\\n /// @notice Completes DKG by cleaning up state.\\n /// @dev Should be called after DKG times out or a result is approved.\\n function complete(Data storage self) internal {\\n delete self.startBlock;\\n delete self.seed;\\n delete self.resultSubmissionStartBlockOffset;\\n submittedResultCleanup(self);\\n self.sortitionPool.unlock();\\n }\\n\\n /// @notice Cleans up submitted result state either after DKG completion\\n /// (as part of `complete` method) or after justified challenge.\\n function submittedResultCleanup(Data storage self) private {\\n delete self.submittedResultHash;\\n delete self.submittedResultBlock;\\n }\\n}\\n\",\"keccak256\":\"0x86bea35ab775ec969bc91208305f6f85aa9dd49bb74f8e57e7d453797e8ad98e\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BeaconInactivity.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./BytesLib.sol\\\";\\nimport \\\"./Groups.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\n\\nlibrary BeaconInactivity {\\n using BytesLib for bytes;\\n using ECDSA for bytes32;\\n\\n struct Claim {\\n // ID of the group raising the inactivity claim.\\n uint64 groupId;\\n // Indices of members accused of being inactive. Indices must be in\\n // range [1, groupMembers.length], unique, and sorted in ascending order.\\n uint256[] inactiveMembersIndices;\\n // Concatenation of signatures from members supporting the claim.\\n // The message to be signed by each member is keccak256 hash of the\\n // concatenation of the chain ID, inactivity claim nonce for the given\\n // group, group public key, and inactive members indices. The calculated\\n // hash should be prefixed with `\\\\x19Ethereum signed message:\\\\n` before\\n // signing, so the message to sign is:\\n // `\\\\x19Ethereum signed message:\\\\n${keccak256(\\n // chainID | nonce | groupPubKey | inactiveMembersIndices\\n // )}`\\n bytes signatures;\\n // Indices of members corresponding to each signature. Indices must be\\n // in range [1, groupMembers.length], unique, and sorted in ascending\\n // order.\\n uint256[] signingMembersIndices;\\n }\\n\\n /// @notice The minimum number of group members needed to interact according\\n /// to the protocol to produce a valid inactivity claim.\\n uint256 public constant groupThreshold = 33;\\n\\n /// @notice Size in bytes of a single signature produced by member\\n /// supporting the inactivity claim.\\n uint256 public constant signatureByteSize = 65;\\n\\n /// @notice Verifies the inactivity claim according to the rules defined in\\n /// `Claim` struct documentation. Reverts if verification fails.\\n /// @dev Group members hash is validated upstream in\\n /// RandomBeacon.notifyOperatorInactivity()\\n /// @param sortitionPool Sortition pool reference\\n /// @param claim Inactivity claim\\n /// @param groupPubKey Public key of the group raising the claim\\n /// @param nonce Current nonce for group used in the claim\\n /// @param groupMembers Identifiers of group members\\n /// @return inactiveMembers Identifiers of members who are inactive\\n function verifyClaim(\\n SortitionPool sortitionPool,\\n Claim calldata claim,\\n bytes memory groupPubKey,\\n uint256 nonce,\\n uint32[] calldata groupMembers\\n ) external view returns (uint32[] memory inactiveMembers) {\\n // Validate inactive members indices. Maximum indices count is equal to\\n // the group size and is not limited deliberately to leave a theoretical\\n // possibility to accuse more members than `groupSize - groupThreshold`.\\n validateMembersIndices(\\n claim.inactiveMembersIndices,\\n groupMembers.length\\n );\\n\\n // Validate signatures array is properly formed and number of\\n // signatures and signers is correct.\\n uint256 signaturesCount = claim.signatures.length / signatureByteSize;\\n require(claim.signatures.length != 0, \\\"No signatures provided\\\");\\n require(\\n claim.signatures.length % signatureByteSize == 0,\\n \\\"Malformed signatures array\\\"\\n );\\n require(\\n signaturesCount == claim.signingMembersIndices.length,\\n \\\"Unexpected signatures count\\\"\\n );\\n require(signaturesCount >= groupThreshold, \\\"Too few signatures\\\");\\n require(signaturesCount <= groupMembers.length, \\\"Too many signatures\\\");\\n\\n // Validate signing members indices. Note that `signingMembersIndices`\\n // were already partially validated during `signatures` parameter\\n // validation.\\n validateMembersIndices(\\n claim.signingMembersIndices,\\n groupMembers.length\\n );\\n\\n // Usage of group public key and not group ID is important because it\\n // provides uniqueness of signed messages and prevent against reusing\\n // them in future in case some other application has a group with the\\n // same ID and subset of members.\\n bytes32 signedMessageHash = keccak256(\\n abi.encode(\\n block.chainid,\\n nonce,\\n groupPubKey,\\n claim.inactiveMembersIndices\\n )\\n ).toEthSignedMessageHash();\\n\\n address[] memory groupMembersAddresses = sortitionPool.getIDOperators(\\n groupMembers\\n );\\n\\n // Verify each signature.\\n bytes memory checkedSignature;\\n bool senderSignatureExists = false;\\n for (uint256 i = 0; i < signaturesCount; i++) {\\n uint256 memberIndex = claim.signingMembersIndices[i];\\n checkedSignature = claim.signatures.slice(\\n signatureByteSize * i,\\n signatureByteSize\\n );\\n address recoveredAddress = signedMessageHash.recover(\\n checkedSignature\\n );\\n\\n require(\\n groupMembersAddresses[memberIndex - 1] == recoveredAddress,\\n \\\"Invalid signature\\\"\\n );\\n\\n if (!senderSignatureExists && msg.sender == recoveredAddress) {\\n senderSignatureExists = true;\\n }\\n }\\n\\n require(senderSignatureExists, \\\"Sender must be claim signer\\\");\\n\\n inactiveMembers = new uint32[](claim.inactiveMembersIndices.length);\\n for (uint256 i = 0; i < claim.inactiveMembersIndices.length; i++) {\\n uint256 memberIndex = claim.inactiveMembersIndices[i];\\n inactiveMembers[i] = groupMembers[memberIndex - 1];\\n }\\n\\n return inactiveMembers;\\n }\\n\\n /// @notice Validates members indices array. Array is considered valid\\n /// if its size and each single index are in [1, groupSize] range,\\n /// indexes are unique, and sorted in an ascending order.\\n /// Reverts if validation fails.\\n /// @param indices Array to validate\\n /// @param groupSize Group size used as reference\\n function validateMembersIndices(\\n uint256[] calldata indices,\\n uint256 groupSize\\n ) internal pure {\\n require(\\n indices.length > 0 && indices.length <= groupSize,\\n \\\"Corrupted members indices\\\"\\n );\\n\\n // Check if first and last indices are in range [1, groupSize].\\n // This check combined with the loop below makes sure every single\\n // index is in the correct range.\\n require(\\n indices[0] > 0 && indices[indices.length - 1] <= groupSize,\\n \\\"Corrupted members indices\\\"\\n );\\n\\n for (uint256 i = 0; i < indices.length - 1; i++) {\\n // Check whether given index is smaller than the next one. This\\n // way we are sure indexes are ordered in the ascending order\\n // and there are no duplicates.\\n require(indices[i] < indices[i + 1], \\\"Corrupted members indices\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x8dffb20eb4ffd2e388080c5fbcb648e33480aca3dab4be2254cf30c5e72413bf\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BytesLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\n/*\\nVersion pulled from keep-core v1:\\nhttps://github.com/keep-network/keep-core/blob/f297202db00c027978ad8e7103a356503de5773c/solidity-v1/contracts/utils/BytesLib.sol\\n\\nTo compile it with solidity 0.8 `_preBytes_slot` was replaced with `_preBytes.slot`.\\n*/\\n\\n/*\\nhttps://github.com/GNSPS/solidity-bytes-utils/\\nThis is free and unencumbered software released into the public domain.\\nAnyone is free to copy, modify, publish, use, compile, sell, or\\ndistribute this software, either in source code form or as a compiled\\nbinary, for any purpose, commercial or non-commercial, and by any\\nmeans.\\nIn jurisdictions that recognize copyright laws, the author or authors\\nof this software dedicate any and all copyright interest in the\\nsoftware to the public domain. We make this dedication for the benefit\\nof the public at large and to the detriment of our heirs and\\nsuccessors. We intend this dedication to be an overt act of\\nrelinquishment in perpetuity of all present and future rights to this\\nsoftware under copyright law.\\nTHE SOFTWARE IS PROVIDED \\\"AS IS\\\", WITHOUT WARRANTY OF ANY KIND,\\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\\nIN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\\nOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\\nOTHER DEALINGS IN THE SOFTWARE.\\nFor more information, please refer to \\n*/\\n\\n/** @title BytesLib **/\\n/** @author https://github.com/GNSPS **/\\n\\nlibrary BytesLib {\\n function concatStorage(bytes storage _preBytes, bytes memory _postBytes)\\n internal\\n {\\n assembly {\\n // Read the first 32 bytes of _preBytes storage, which is the length\\n // of the array. (We don't need to use the offset into the slot\\n // because arrays use the entire slot.)\\n let fslot := sload(_preBytes.slot)\\n // Arrays of 31 bytes or less have an even value in their slot,\\n // while longer arrays have an odd value. The actual length is\\n // the slot divided by two for odd values, and the lowest order\\n // byte divided by two for even values.\\n // If the slot is even, bitwise and the slot with 255 and divide by\\n // two to get the length. If the slot is odd, bitwise and the slot\\n // with -1 and divide by two.\\n let slength := div(\\n and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)),\\n 2\\n )\\n let mlength := mload(_postBytes)\\n let newlength := add(slength, mlength)\\n // slength can contain both the length and contents of the array\\n // if length < 32 bytes so let's prepare for that\\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\\n switch add(lt(slength, 32), lt(newlength, 32))\\n case 2 {\\n // Since the new array still fits in the slot, we just need to\\n // update the contents of the slot.\\n // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length\\n sstore(\\n _preBytes.slot,\\n // all the modifications to the slot are inside this\\n // next block\\n add(\\n // we can just add to the slot contents because the\\n // bytes we want to change are the LSBs\\n fslot,\\n add(\\n mul(\\n div(\\n // load the bytes from memory\\n mload(add(_postBytes, 0x20)),\\n // zero all bytes to the right\\n exp(0x100, sub(32, mlength))\\n ),\\n // and now shift left the number of bytes to\\n // leave space for the length in the slot\\n exp(0x100, sub(32, newlength))\\n ),\\n // increase length by the double of the memory\\n // bytes length\\n mul(mlength, 2)\\n )\\n )\\n )\\n }\\n case 1 {\\n // The stored value fits in the slot, but the combined value\\n // will exceed it.\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\\n\\n // save new length\\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\\n\\n // The contents of the _postBytes array start 32 bytes into\\n // the structure. Our first read should obtain the `submod`\\n // bytes that can fit into the unused space in the last word\\n // of the stored array. To get this, we read 32 bytes starting\\n // from `submod`, so the data we read overlaps with the array\\n // contents by `submod` bytes. Masking the lowest-order\\n // `submod` bytes allows us to add that value directly to the\\n // stored value.\\n\\n let submod := sub(32, slength)\\n let mc := add(_postBytes, submod)\\n let end := add(_postBytes, mlength)\\n let mask := sub(exp(0x100, submod), 1)\\n\\n sstore(\\n sc,\\n add(\\n and(\\n fslot,\\n 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00\\n ),\\n and(mload(mc), mask)\\n )\\n )\\n\\n for {\\n mc := add(mc, 0x20)\\n sc := add(sc, 1)\\n } lt(mc, end) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n sstore(sc, mload(mc))\\n }\\n\\n mask := exp(0x100, sub(mc, end))\\n\\n sstore(sc, mul(div(mload(mc), mask), mask))\\n }\\n default {\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n // Start copying to the last used word of the stored array.\\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\\n\\n // save new length\\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\\n\\n // Copy over the first `submod` bytes of the new data as in\\n // case 1 above.\\n let slengthmod := mod(slength, 32)\\n let submod := sub(32, slengthmod)\\n let mc := add(_postBytes, submod)\\n let end := add(_postBytes, mlength)\\n let mask := sub(exp(0x100, submod), 1)\\n\\n sstore(sc, add(sload(sc), and(mload(mc), mask)))\\n\\n for {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } lt(mc, end) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n sstore(sc, mload(mc))\\n }\\n\\n mask := exp(0x100, sub(mc, end))\\n\\n sstore(sc, mul(div(mload(mc), mask), mask))\\n }\\n }\\n }\\n\\n function equalStorage(bytes storage _preBytes, bytes memory _postBytes)\\n internal\\n view\\n returns (bool)\\n {\\n bool success = true;\\n\\n assembly {\\n // we know _preBytes_offset is 0\\n let fslot := sload(_preBytes.slot)\\n // Decode the length of the stored array like in concatStorage().\\n let slength := div(\\n and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)),\\n 2\\n )\\n let mlength := mload(_postBytes)\\n\\n // if lengths don't match the arrays are not equal\\n switch eq(slength, mlength)\\n case 1 {\\n // slength can contain both the length and contents of the array\\n // if length < 32 bytes so let's prepare for that\\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\\n if iszero(iszero(slength)) {\\n switch lt(slength, 32)\\n case 1 {\\n // blank the last byte which is the length\\n fslot := mul(div(fslot, 0x100), 0x100)\\n\\n if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {\\n // unsuccess:\\n success := 0\\n }\\n }\\n default {\\n // cb is a circuit breaker in the for loop since there's\\n // no said feature for inline assembly loops\\n // cb = 1 - don't breaker\\n // cb = 0 - break\\n let cb := 1\\n\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n let sc := keccak256(0x0, 0x20)\\n\\n let mc := add(_postBytes, 0x20)\\n let end := add(mc, mlength)\\n\\n // the next line is the loop condition:\\n // while(uint(mc < end) + cb == 2)\\n for {\\n\\n } eq(add(lt(mc, end), cb), 2) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n if iszero(eq(sload(sc), mload(mc))) {\\n // unsuccess:\\n success := 0\\n cb := 0\\n }\\n }\\n }\\n }\\n }\\n default {\\n // unsuccess:\\n success := 0\\n }\\n }\\n\\n return success;\\n }\\n\\n function concat(bytes memory _preBytes, bytes memory _postBytes)\\n internal\\n pure\\n returns (bytes memory)\\n {\\n bytes memory tempBytes;\\n\\n assembly {\\n // Get a location of some free memory and store it in tempBytes as\\n // Solidity does for memory variables.\\n tempBytes := mload(0x40)\\n\\n // Store the length of the first bytes array at the beginning of\\n // the memory for tempBytes.\\n let length := mload(_preBytes)\\n mstore(tempBytes, length)\\n\\n // Maintain a memory counter for the current write location in the\\n // temp bytes array by adding the 32 bytes for the array length to\\n // the starting location.\\n let mc := add(tempBytes, 0x20)\\n // Stop copying when the memory counter reaches the length of the\\n // first bytes array.\\n let end := add(mc, length)\\n\\n for {\\n // Initialize a copy counter to the start of the _preBytes data,\\n // 32 bytes into its memory.\\n let cc := add(_preBytes, 0x20)\\n } lt(mc, end) {\\n // Increase both counters by 32 bytes each iteration.\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n // Write the _preBytes data into the tempBytes memory 32 bytes\\n // at a time.\\n mstore(mc, mload(cc))\\n }\\n\\n // Add the length of _postBytes to the current length of tempBytes\\n // and store it as the new length in the first 32 bytes of the\\n // tempBytes memory.\\n length := mload(_postBytes)\\n mstore(tempBytes, add(length, mload(tempBytes)))\\n\\n // Move the memory counter back from a multiple of 0x20 to the\\n // actual end of the _preBytes data.\\n mc := end\\n // Stop copying when the memory counter reaches the new combined\\n // length of the arrays.\\n end := add(mc, length)\\n\\n for {\\n let cc := add(_postBytes, 0x20)\\n } lt(mc, end) {\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n mstore(mc, mload(cc))\\n }\\n\\n // Update the free-memory pointer by padding our last write location\\n // to 32 bytes: add 31 bytes to the end of tempBytes to move to the\\n // next 32 byte block, then round down to the nearest multiple of\\n // 32. If the sum of the length of the two arrays is zero then add\\n // one before rounding down to leave a blank 32 bytes (the length block with 0).\\n mstore(\\n 0x40,\\n and(\\n add(add(end, iszero(add(length, mload(_preBytes)))), 31),\\n not(31) // Round down to the nearest 32 bytes.\\n )\\n )\\n }\\n\\n return tempBytes;\\n }\\n\\n function slice(\\n bytes memory _bytes,\\n uint256 _start,\\n uint256 _length\\n ) internal pure returns (bytes memory res) {\\n uint256 _end = _start + _length;\\n require(_end > _start && _bytes.length >= _end, \\\"Slice out of bounds\\\");\\n\\n assembly {\\n // Alloc bytes array with additional 32 bytes afterspace and assign it's size\\n res := mload(0x40)\\n mstore(0x40, add(add(res, 64), _length))\\n mstore(res, _length)\\n\\n // Compute distance between source and destination pointers\\n let diff := sub(res, add(_bytes, _start))\\n\\n for {\\n let src := add(add(_bytes, 32), _start)\\n let end := add(src, _length)\\n } lt(src, end) {\\n src := add(src, 32)\\n } {\\n mstore(add(src, diff), mload(src))\\n }\\n }\\n }\\n\\n function toAddress(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (address)\\n {\\n uint256 _totalLen = _start + 20;\\n require(\\n _totalLen > _start && _bytes.length >= _totalLen,\\n \\\"Address conversion out of bounds.\\\"\\n );\\n address tempAddress;\\n\\n assembly {\\n tempAddress := div(\\n mload(add(add(_bytes, 0x20), _start)),\\n 0x1000000000000000000000000\\n )\\n }\\n\\n return tempAddress;\\n }\\n\\n function toUint8(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (uint8)\\n {\\n require(\\n _bytes.length >= (_start + 1),\\n \\\"Uint8 conversion out of bounds.\\\"\\n );\\n uint8 tempUint;\\n\\n assembly {\\n tempUint := mload(add(add(_bytes, 0x1), _start))\\n }\\n\\n return tempUint;\\n }\\n\\n function toUint(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (uint256)\\n {\\n uint256 _totalLen = _start + 32;\\n require(\\n _totalLen > _start && _bytes.length >= _totalLen,\\n \\\"Uint conversion out of bounds.\\\"\\n );\\n uint256 tempUint;\\n\\n assembly {\\n tempUint := mload(add(add(_bytes, 0x20), _start))\\n }\\n\\n return tempUint;\\n }\\n\\n function equal(bytes memory _preBytes, bytes memory _postBytes)\\n internal\\n pure\\n returns (bool)\\n {\\n bool success = true;\\n\\n assembly {\\n let length := mload(_preBytes)\\n\\n // if lengths don't match the arrays are not equal\\n switch eq(length, mload(_postBytes))\\n case 1 {\\n // cb is a circuit breaker in the for loop since there's\\n // no said feature for inline assembly loops\\n // cb = 1 - don't breaker\\n // cb = 0 - break\\n let cb := 1\\n\\n let mc := add(_preBytes, 0x20)\\n let end := add(mc, length)\\n\\n for {\\n let cc := add(_postBytes, 0x20)\\n // the next line is the loop condition:\\n // while(uint(mc < end) + cb == 2)\\n } eq(add(lt(mc, end), cb), 2) {\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n // if any of these checks fails then arrays are not equal\\n if iszero(eq(mload(mc), mload(cc))) {\\n // unsuccess:\\n success := 0\\n cb := 0\\n }\\n }\\n }\\n default {\\n // unsuccess:\\n success := 0\\n }\\n }\\n\\n return success;\\n }\\n\\n function toBytes32(bytes memory _source)\\n internal\\n pure\\n returns (bytes32 result)\\n {\\n if (_source.length == 0) {\\n return 0x0;\\n }\\n\\n assembly {\\n result := mload(add(_source, 32))\\n }\\n }\\n\\n function keccak256Slice(\\n bytes memory _bytes,\\n uint256 _start,\\n uint256 _length\\n ) internal pure returns (bytes32 result) {\\n uint256 _end = _start + _length;\\n require(_end > _start && _bytes.length >= _end, \\\"Slice out of bounds\\\");\\n\\n assembly {\\n result := keccak256(add(add(_bytes, 32), _start), _length)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3b76e2fe36eb777440250dcf2ea7a689375e8af22f3cc33521095ff6954becdb\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/Callback.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../api/IRandomBeaconConsumer.sol\\\";\\n\\n/// @title Callback library\\n/// @dev Library for handling calls to random beacon consumer.\\nlibrary Callback {\\n struct Data {\\n IRandomBeaconConsumer callbackContract;\\n }\\n\\n event CallbackFailed(uint256 entry, uint256 entrySubmittedBlock);\\n\\n /// @notice Sets callback contract.\\n /// @param callbackContract Callback contract.\\n function setCallbackContract(\\n Data storage self,\\n IRandomBeaconConsumer callbackContract\\n ) internal {\\n self.callbackContract = callbackContract;\\n }\\n\\n /// @notice Executes consumer specified callback for the relay entry request.\\n /// @param entry The generated random number.\\n /// @param callbackGasLimit Callback gas limit.\\n function executeCallback(\\n Data storage self,\\n uint256 entry,\\n uint256 callbackGasLimit\\n ) internal {\\n if (address(self.callbackContract) != address(0)) {\\n try\\n self.callbackContract.__beaconCallback{gas: callbackGasLimit}(\\n entry,\\n block.number\\n )\\n {} catch {\\n // slither-disable-next-line reentrancy-events\\n emit CallbackFailed(entry, block.number);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x258d635d74d8906c73d1c2d0929f033c7e548cdaf9c9a71a7e82b4ab70e5ad29\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/Groups.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\n/// @notice This library is used as a registry of created groups.\\n/// @dev This library should be used along with DKG library that ensures linear\\n/// groups creation (only one group creation happens at a time). A candidate\\n/// group has to be popped or activated before adding a new candidate group.\\nlibrary Groups {\\n struct Group {\\n bytes groupPubKey;\\n uint256 registrationBlockNumber;\\n // Keccak256 hash of group members identifiers array. Group members do not\\n // include operators selected by the sortition pool that misbehaved during DKG.\\n // See how `misbehavedMembersIndices` are used in `hashGroupMembers` function.\\n bytes32 membersHash;\\n // When selected group does not create a relay entry on-time it should\\n // be marked as terminated.\\n bool terminated;\\n }\\n\\n struct Data {\\n // Mapping of keccak256 hashes of group public keys to groups details.\\n mapping(bytes32 => Group) groupsData;\\n // Holds keccak256 hashes of group public keys in the order of registration.\\n bytes32[] groupsRegistry;\\n // Group ids that were active but failed creating a relay entry. When an\\n // active-terminated group qualifies to become 'expired', then it will\\n // be removed from this array.\\n uint64[] activeTerminatedGroups;\\n // Points to the first active group, it is also the expired groups counter.\\n uint64 expiredGroupOffset;\\n // Group lifetime in blocks. When a group reached its lifetime, it\\n // is no longer selected for new relay requests but may still be\\n // responsible for submitting relay entry if relay request assigned\\n // to that group is still pending.\\n uint256 groupLifetime;\\n }\\n\\n event GroupRegistered(uint64 indexed groupId, bytes indexed groupPubKey);\\n\\n /// @notice Performs preliminary validation of a new group public key.\\n /// The group public key must be unique and have 128 bytes in length.\\n /// If the validation fails, the function reverts. This function\\n /// must be called first for a public key of a group added with\\n /// `addGroup` function.\\n /// @param groupPubKey Candidate group public key\\n function validatePublicKey(Data storage self, bytes calldata groupPubKey)\\n internal\\n view\\n {\\n require(groupPubKey.length == 128, \\\"Invalid length of the public key\\\");\\n\\n bytes32 groupPubKeyHash = keccak256(groupPubKey);\\n\\n require(\\n self.groupsData[groupPubKeyHash].registrationBlockNumber == 0,\\n \\\"Group with this public key was already registered\\\"\\n );\\n }\\n\\n /// @notice Adds a new candidate group. The group is stored with group public\\n /// key and group members, but is not yet activated.\\n /// @dev The group members list is stored with all misbehaved members filtered out.\\n /// The code calling this function should ensure that the number of\\n /// candidate (not activated) groups is never more than one.\\n /// @param groupPubKey Generated candidate group public key\\n /// @param membersHash Keccak256 hash of members that actively took part in DKG.\\n function addGroup(\\n Data storage self,\\n bytes calldata groupPubKey,\\n bytes32 membersHash\\n ) internal {\\n bytes32 groupPubKeyHash = keccak256(groupPubKey);\\n\\n // We use group from storage that is assumed to be a struct set to the\\n // default values. We need to remember to overwrite fields in case a\\n // candidate group was already registered before and popped.\\n Group storage group = self.groupsData[groupPubKeyHash];\\n group.groupPubKey = groupPubKey;\\n group.membersHash = membersHash;\\n group.registrationBlockNumber = block.number;\\n\\n self.groupsRegistry.push(groupPubKeyHash);\\n\\n emit GroupRegistered(\\n uint64(self.groupsRegistry.length - 1),\\n groupPubKey\\n );\\n }\\n\\n /// @notice Goes through groups starting from the oldest one that is still\\n /// active and checks if it hasn't expired. If so, updates the information\\n /// about expired groups so that all expired groups are marked as such.\\n function expireOldGroups(Data storage self) internal {\\n // Move expiredGroupOffset as long as there are some groups that should\\n // be marked as expired. It is possible that expired group offset will\\n // move out of the groups array by one position. It means that all groups\\n // are expired (it points to the first active group) and that place in\\n // groups array - currently empty - will be possibly filled later by\\n // a new group.\\n while (\\n self.expiredGroupOffset < self.groupsRegistry.length &&\\n groupLifetimeOf(\\n self,\\n self.groupsRegistry[self.expiredGroupOffset]\\n ) <\\n block.number\\n ) {\\n self.expiredGroupOffset++;\\n }\\n\\n // Go through all activeTerminatedGroups and if some of the terminated\\n // groups are expired, remove them from activeTerminatedGroups collection\\n // and rearrange the array to preserve the original order.\\n // This is needed because we evaluate the shift of selected group index\\n // based on how many non-expired groups have been terminated. Hence it is\\n // important that a number of terminated groups matches the length of\\n // activeTerminatedGroups[].\\n uint256 i = 0;\\n while (i < self.activeTerminatedGroups.length) {\\n if (self.expiredGroupOffset > self.activeTerminatedGroups[i]) {\\n // When 'i'th group qualifies for expiration, we need to remove\\n // it from the activeTerminatedGroups array manually by rearranging\\n // the order starting from 'i'th group.\\n for (\\n uint256 j = i;\\n j < self.activeTerminatedGroups.length - 1;\\n j++\\n ) {\\n self.activeTerminatedGroups[j] = self\\n .activeTerminatedGroups[j + 1];\\n }\\n // Resizing the array length by 1. The last element was copied\\n // over in the loop above to an index \\\"second to last\\\". This is\\n // why we can safely remove it from here.\\n self.activeTerminatedGroups.pop();\\n } else {\\n i++;\\n }\\n }\\n }\\n\\n /// @notice Terminates group with the provided index. Reverts if the group\\n /// is already terminated.\\n /// @param groupId Index in the groupRegistry array.\\n function terminateGroup(Data storage self, uint64 groupId) internal {\\n require(\\n !isGroupTerminated(self, groupId),\\n \\\"Group has been already terminated\\\"\\n );\\n self.groupsData[self.groupsRegistry[groupId]].terminated = true;\\n // Expanding array for a new terminated group that is added below during\\n // sortition in ascending order.\\n self.activeTerminatedGroups.push();\\n\\n // Sorting activeTerminatedGroups by groupId in ascending order so a\\n // non-terminated group is properly selected.\\n uint256 i;\\n for (\\n i = self.activeTerminatedGroups.length - 1;\\n i > 0 && self.activeTerminatedGroups[i - 1] > groupId;\\n i--\\n ) {\\n self.activeTerminatedGroups[i] = self.activeTerminatedGroups[i - 1];\\n }\\n self.activeTerminatedGroups[i] = groupId;\\n }\\n\\n /// @notice Returns an index of a randomly selected active group. Terminated\\n /// and expired groups are not considered as active.\\n /// Before new group is selected, information about expired groups\\n /// is updated. At least one active group needs to be present for this\\n /// function to succeed.\\n /// @param seed Random number used as a group selection seed.\\n function selectGroup(Data storage self, uint256 seed)\\n internal\\n returns (uint64)\\n {\\n expireOldGroups(self);\\n\\n require(numberOfActiveGroups(self) > 0, \\\"No active groups\\\");\\n\\n uint64 selectedGroup = uint64(seed % numberOfActiveGroups(self));\\n uint64 result = shiftByTerminatedGroups(\\n self,\\n shiftByExpiredGroups(self, selectedGroup)\\n );\\n return result;\\n }\\n\\n /// @notice Setter for group lifetime.\\n /// @param lifetime Lifetime of a group in blocks.\\n function setGroupLifetime(Data storage self, uint256 lifetime) internal {\\n self.groupLifetime = lifetime;\\n }\\n\\n /// @notice Checks if group with the given index is terminated.\\n function isGroupTerminated(Data storage self, uint64 groupId)\\n internal\\n view\\n returns (bool)\\n {\\n return self.groupsData[self.groupsRegistry[groupId]].terminated;\\n }\\n\\n /// @notice Gets the cutoff time until which the given group is considered\\n /// to be active assuming it hasn't been terminated before.\\n function groupLifetimeOf(Data storage self, bytes32 groupPubKeyHash)\\n internal\\n view\\n returns (uint256)\\n {\\n return\\n self.groupsData[groupPubKeyHash].registrationBlockNumber +\\n self.groupLifetime;\\n }\\n\\n /// @notice Checks if group with the given index is active and non-terminated.\\n function isGroupActive(Data storage self, uint64 groupId)\\n internal\\n view\\n returns (bool)\\n {\\n return\\n groupLifetimeOf(self, self.groupsRegistry[groupId]) >=\\n block.number &&\\n !isGroupTerminated(self, groupId);\\n }\\n\\n function getGroup(Data storage self, uint64 groupId)\\n internal\\n view\\n returns (Group storage)\\n {\\n return self.groupsData[self.groupsRegistry[groupId]];\\n }\\n\\n function getGroup(Data storage self, bytes memory groupPubKey)\\n internal\\n view\\n returns (Group storage)\\n {\\n return self.groupsData[keccak256(groupPubKey)];\\n }\\n\\n /// @notice Gets the number of active groups. Expired and terminated\\n /// groups are not counted as active.\\n function numberOfActiveGroups(Data storage self)\\n internal\\n view\\n returns (uint64)\\n {\\n if (self.groupsRegistry.length == 0) {\\n return 0;\\n }\\n\\n uint256 activeGroups = self.groupsRegistry.length -\\n self.expiredGroupOffset -\\n self.activeTerminatedGroups.length;\\n\\n return uint64(activeGroups);\\n }\\n\\n /// @notice Evaluates the shift of a selected group index based on the number\\n /// of expired groups.\\n function shiftByExpiredGroups(Data storage self, uint64 selectedIndex)\\n internal\\n view\\n returns (uint64)\\n {\\n return self.expiredGroupOffset + selectedIndex;\\n }\\n\\n /// @notice Evaluates the shift of a selected group index based on the number\\n /// of non-expired but terminated groups.\\n function shiftByTerminatedGroups(Data storage self, uint64 selectedIndex)\\n internal\\n view\\n returns (uint64)\\n {\\n uint64 shiftedIndex = selectedIndex;\\n for (uint64 i = 0; i < self.activeTerminatedGroups.length; i++) {\\n if (self.activeTerminatedGroups[i] <= shiftedIndex) {\\n shiftedIndex++;\\n }\\n }\\n\\n return shiftedIndex;\\n }\\n}\\n\",\"keccak256\":\"0x27a3cee268e5afa5ee3a00089aa82faffff7c3882aa94919499de4ef55dcfb0c\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/ModUtils.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\nlibrary ModUtils {\\n /// @dev Wraps the modular exponent pre-compile introduced in Byzantium.\\n /// Returns base^exponent mod p.\\n function modExp(\\n uint256 base,\\n uint256 exponent,\\n uint256 p\\n ) internal view returns (uint256 o) {\\n assembly {\\n // Args for the precompile: [ \\n // ]\\n let output := mload(0x40)\\n let args := add(output, 0x20)\\n mstore(args, 0x20)\\n mstore(add(args, 0x20), 0x20)\\n mstore(add(args, 0x40), 0x20)\\n mstore(add(args, 0x60), base)\\n mstore(add(args, 0x80), exponent)\\n mstore(add(args, 0xa0), p)\\n\\n // 0x05 is the modular exponent contract address\\n if iszero(staticcall(not(0), 0x05, args, 0xc0, output, 0x20)) {\\n revert(0, 0)\\n }\\n o := mload(output)\\n }\\n }\\n\\n /// @dev Calculates and returns the square root of a mod p if such a square\\n /// root exists. The modulus p must be an odd prime. If a square root\\n /// does not exist, function returns 0.\\n function modSqrt(uint256 a, uint256 p) internal view returns (uint256) {\\n unchecked {\\n if (legendre(a, p) != 1) {\\n return 0;\\n }\\n\\n if (a == 0) {\\n return 0;\\n }\\n\\n if (p % 4 == 3) {\\n return modExp(a, (p + 1) / 4, p);\\n }\\n\\n uint256 s = p - 1;\\n uint256 e = 0;\\n\\n while (s % 2 == 0) {\\n s = s / 2;\\n e = e + 1;\\n }\\n\\n // Note the smaller int- finding n with Legendre symbol or -1\\n // should be quick\\n uint256 n = 2;\\n while (legendre(n, p) != -1) {\\n n = n + 1;\\n }\\n\\n uint256 x = modExp(a, (s + 1) / 2, p);\\n uint256 b = modExp(a, s, p);\\n uint256 g = modExp(n, s, p);\\n uint256 r = e;\\n uint256 gs = 0;\\n uint256 m = 0;\\n uint256 t = b;\\n\\n while (true) {\\n t = b;\\n m = 0;\\n\\n for (m = 0; m < r; m++) {\\n if (t == 1) {\\n break;\\n }\\n t = modExp(t, 2, p);\\n }\\n\\n if (m == 0) {\\n return x;\\n }\\n\\n gs = modExp(g, uint256(2)**(r - m - 1), p);\\n g = (gs * gs) % p;\\n x = (x * gs) % p;\\n b = (b * g) % p;\\n r = m;\\n }\\n }\\n }\\n\\n /// @dev Calculates the Legendre symbol of the given a mod p.\\n /// @return Returns 1 if a is a quadratic residue mod p, -1 if it is\\n /// a non-quadratic residue, and 0 if a is 0.\\n function legendre(uint256 a, uint256 p) internal view returns (int256) {\\n unchecked {\\n uint256 raised = modExp(a, (p - 1) / uint256(2), p);\\n\\n if (raised == 0 || raised == 1) {\\n return int256(raised);\\n } else if (raised == p - 1) {\\n return -1;\\n }\\n\\n require(false, \\\"Failed to calculate legendre.\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x57bb4ab4f257715c6daafa1a4e4bc6dd9edfe45afca797e5b8e98db577826505\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/Relay.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"./AltBn128.sol\\\";\\nimport \\\"./BLS.sol\\\";\\nimport \\\"./Groups.sol\\\";\\n\\nlibrary Relay {\\n using SafeERC20 for IERC20;\\n\\n struct Data {\\n // Total count of all requests.\\n uint64 requestCount;\\n // Data of current request.\\n // Request identifier.\\n uint64 currentRequestID;\\n // Identifier of group responsible for signing.\\n uint64 currentRequestGroupID;\\n // Request start block.\\n uint64 currentRequestStartBlock;\\n // Previous entry value.\\n AltBn128.G1Point previousEntry;\\n // Time in blocks during which a result is expected to be submitted.\\n uint32 relayEntrySoftTimeout;\\n // Hard timeout in blocks for a group to submit the relay entry.\\n uint32 relayEntryHardTimeout;\\n // Slashing amount for not submitting relay entry\\n uint96 relayEntrySubmissionFailureSlashingAmount;\\n }\\n\\n /// @notice Seed used as the first relay entry value.\\n /// It's a G1 point G * PI =\\n /// G * 31415926535897932384626433832795028841971693993751058209749445923078164062862\\n /// Where G is the generator of G1 abstract cyclic group.\\n bytes public constant relaySeed =\\n hex\\\"15c30f4b6cf6dbbcbdcc10fe22f54c8170aea44e198139b776d512d8f027319a1b9e8bfaf1383978231ce98e42bafc8129f473fc993cf60ce327f7d223460663\\\";\\n\\n event RelayEntryRequested(\\n uint256 indexed requestId,\\n uint64 groupId,\\n bytes previousEntry\\n );\\n\\n event RelayEntrySubmitted(\\n uint256 indexed requestId,\\n address submitter,\\n bytes entry\\n );\\n\\n event RelayEntryTimedOut(\\n uint256 indexed requestId,\\n uint64 terminatedGroupId\\n );\\n\\n /// @notice Initializes the very first `previousEntry` with an initial\\n /// `relaySeed` value. Can be performed only once.\\n function initSeedEntry(Data storage self) internal {\\n require(\\n self.previousEntry.x == 0 && self.previousEntry.y == 0,\\n \\\"Seed entry already initialized\\\"\\n );\\n self.previousEntry = AltBn128.g1Unmarshal(relaySeed);\\n }\\n\\n /// @notice Creates a request to generate a new relay entry, which will\\n /// include a random number (by signing the previous entry's\\n /// random number).\\n /// @param groupId Identifier of the group chosen to handle the request.\\n function requestEntry(Data storage self, uint64 groupId) internal {\\n require(\\n !isRequestInProgress(self),\\n \\\"Another relay request in progress\\\"\\n );\\n\\n uint64 currentRequestId = ++self.requestCount;\\n\\n self.currentRequestID = currentRequestId;\\n self.currentRequestGroupID = groupId;\\n self.currentRequestStartBlock = uint64(block.number);\\n\\n emit RelayEntryRequested(\\n currentRequestId,\\n groupId,\\n AltBn128.g1Marshal(self.previousEntry)\\n );\\n }\\n\\n /// @notice Creates a new relay entry. Gas-optimized version that can be\\n /// called only before the soft timeout. This should be the majority\\n /// of cases.\\n /// @param entry Group BLS signature over the previous entry.\\n /// @param groupPubKey Public key of the group which signed the relay entry.\\n function submitEntryBeforeSoftTimeout(\\n Data storage self,\\n bytes calldata entry,\\n bytes storage groupPubKey\\n ) internal {\\n require(\\n block.number < softTimeoutBlock(self),\\n \\\"Relay entry soft timeout passed\\\"\\n );\\n _submitEntry(self, entry, groupPubKey);\\n }\\n\\n /// @notice Creates a new relay entry. Can be called at any time.\\n /// In case the soft timeout has not been exceeded, it is more\\n /// gas-efficient to call the second variation of `submitEntry`.\\n /// @param entry Group BLS signature over the previous entry.\\n /// @param groupPubKey Public key of the group which signed the relay entry.\\n /// @return slashingAmount Amount by which group members should be slashed\\n /// in case the relay entry was submitted after the soft timeout.\\n /// The value is zero if entry was submitted on time.\\n function submitEntry(\\n Data storage self,\\n bytes calldata entry,\\n bytes storage groupPubKey\\n ) internal returns (uint96) {\\n // If the soft timeout has been exceeded apply stake slashing for\\n // all group members. Otherwise, no slashing.\\n uint96 slashingAmount = calculateSlashingAmount(self);\\n\\n _submitEntry(self, entry, groupPubKey);\\n\\n return slashingAmount;\\n }\\n\\n function _submitEntry(\\n Data storage self,\\n bytes calldata entry,\\n bytes storage groupPubKey\\n ) internal {\\n require(isRequestInProgress(self), \\\"No relay request in progress\\\");\\n require(!hasRequestTimedOut(self), \\\"Relay request timed out\\\");\\n\\n require(\\n BLS._verify(\\n AltBn128.g2Unmarshal(groupPubKey),\\n self.previousEntry,\\n AltBn128.g1Unmarshal(entry)\\n ),\\n \\\"Invalid entry\\\"\\n );\\n\\n emit RelayEntrySubmitted(self.currentRequestID, msg.sender, entry);\\n\\n self.previousEntry = AltBn128.g1Unmarshal(entry);\\n self.currentRequestID = 0;\\n self.currentRequestGroupID = 0;\\n self.currentRequestStartBlock = 0;\\n }\\n\\n /// @notice Calculates the slashing amount for all group members.\\n /// @dev Must be used when a soft timeout was hit.\\n /// @return Amount by which group members should be slashed\\n /// in case the relay entry was submitted after the soft timeout.\\n function calculateSlashingAmount(Data storage self)\\n internal\\n view\\n returns (uint96)\\n {\\n uint256 softTimeout = softTimeoutBlock(self);\\n\\n if (block.number > softTimeout) {\\n uint256 submissionDelay = block.number - softTimeout;\\n // The slashing amount is a result of a calculated portion of the submission\\n // delay blocks. The max delay can be set up to relayEntryHardTimeout, which\\n // in consequence sets the max slashing amount.\\n if (submissionDelay > self.relayEntryHardTimeout) {\\n submissionDelay = self.relayEntryHardTimeout;\\n }\\n\\n return\\n uint96(\\n (submissionDelay *\\n self.relayEntrySubmissionFailureSlashingAmount) /\\n self.relayEntryHardTimeout\\n );\\n }\\n\\n return 0;\\n }\\n\\n /// @notice Updates relay-related parameters\\n /// @param _relayEntrySoftTimeout New relay entry soft timeout value.\\n /// It is the time in blocks during which a result is expected to be\\n /// submitted so that the group is not slashed.\\n /// @param _relayEntryHardTimeout New relay entry hard timeout value.\\n /// It is the time in blocks for a group to submit the relay entry\\n /// before slashing for the full slashing amount happens.\\n function setTimeouts(\\n Data storage self,\\n uint256 _relayEntrySoftTimeout,\\n uint256 _relayEntryHardTimeout\\n ) internal {\\n require(!isRequestInProgress(self), \\\"Relay request in progress\\\");\\n\\n self.relayEntrySoftTimeout = uint32(_relayEntrySoftTimeout);\\n self.relayEntryHardTimeout = uint32(_relayEntryHardTimeout);\\n }\\n\\n /// @notice Set relayEntrySubmissionFailureSlashingAmount parameter.\\n /// @param newRelayEntrySubmissionFailureSlashingAmount New value of\\n /// the parameter.\\n function setRelayEntrySubmissionFailureSlashingAmount(\\n Data storage self,\\n uint96 newRelayEntrySubmissionFailureSlashingAmount\\n ) internal {\\n require(!isRequestInProgress(self), \\\"Relay request in progress\\\");\\n\\n self\\n .relayEntrySubmissionFailureSlashingAmount = newRelayEntrySubmissionFailureSlashingAmount;\\n }\\n\\n /// @notice Retries the current relay request in case a relay entry\\n /// timeout was reported.\\n /// @param newGroupId ID of the group chosen to retry the current request.\\n function retryOnEntryTimeout(Data storage self, uint64 newGroupId)\\n internal\\n {\\n require(hasRequestTimedOut(self), \\\"Relay request did not time out\\\");\\n\\n uint64 currentRequestId = self.currentRequestID;\\n uint64 previousGroupId = self.currentRequestGroupID;\\n\\n emit RelayEntryTimedOut(currentRequestId, previousGroupId);\\n\\n self.currentRequestGroupID = newGroupId;\\n self.currentRequestStartBlock = uint64(block.number);\\n\\n emit RelayEntryRequested(\\n currentRequestId,\\n newGroupId,\\n AltBn128.g1Marshal(self.previousEntry)\\n );\\n }\\n\\n /// @notice Cleans up the current relay request in case a relay entry\\n /// timeout was reported.\\n function cleanupOnEntryTimeout(Data storage self) internal {\\n require(hasRequestTimedOut(self), \\\"Relay request did not time out\\\");\\n\\n emit RelayEntryTimedOut(\\n self.currentRequestID,\\n self.currentRequestGroupID\\n );\\n\\n self.currentRequestID = 0;\\n self.currentRequestGroupID = 0;\\n self.currentRequestStartBlock = 0;\\n }\\n\\n /// @notice Returns whether a relay entry request is currently in progress.\\n /// @return True if there is a request in progress. False otherwise.\\n function isRequestInProgress(Data storage self)\\n internal\\n view\\n returns (bool)\\n {\\n return self.currentRequestID != 0;\\n }\\n\\n /// @notice Returns whether the current relay request has timed out.\\n /// @return True if the request timed out. False otherwise.\\n function hasRequestTimedOut(Data storage self)\\n internal\\n view\\n returns (bool)\\n {\\n uint256 _relayEntryTimeout = self.relayEntrySoftTimeout +\\n self.relayEntryHardTimeout;\\n\\n return\\n isRequestInProgress(self) &&\\n block.number > self.currentRequestStartBlock + _relayEntryTimeout;\\n }\\n\\n /// @notice Calculates soft timeout block for the pending relay request.\\n /// @return The soft timeout block\\n function softTimeoutBlock(Data storage self)\\n internal\\n view\\n returns (uint256)\\n {\\n return self.currentRequestStartBlock + self.relayEntrySoftTimeout;\\n }\\n}\\n\",\"keccak256\":\"0x0ff1513ef6dceda503d19d1798d9de97510ec3c033b9a59aa240ce2a3052e6d3\",\"license\":\"GPL-3.0-only\"},\"contracts/test/RandomBeaconStub.sol\":{\"content\":\"pragma solidity ^0.8.6;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\nimport \\\"../RandomBeacon.sol\\\";\\nimport \\\"../libraries/Callback.sol\\\";\\nimport \\\"../libraries/Groups.sol\\\";\\nimport {BeaconDkg as DKG} from \\\"../libraries/BeaconDkg.sol\\\";\\nimport {BeaconDkgValidator as DKGValidator} from \\\"../BeaconDkgValidator.sol\\\";\\n\\ncontract RandomBeaconStub is RandomBeacon {\\n using DKG for DKG.Data;\\n using Groups for Groups.Data;\\n\\n constructor(\\n SortitionPool _sortitionPool,\\n IERC20 _tToken,\\n IStaking _staking,\\n DKGValidator _dkgValidator,\\n ReimbursementPool _reimbursementPool\\n )\\n RandomBeacon(\\n _sortitionPool,\\n _tToken,\\n _staking,\\n _dkgValidator,\\n _reimbursementPool\\n )\\n {}\\n\\n function getDkgData() external view returns (DKG.Data memory) {\\n return dkg;\\n }\\n\\n function getCallbackContract() external view returns (address) {\\n return address(callback.callbackContract);\\n }\\n\\n function roughlyAddGroup(\\n bytes calldata groupPubKey,\\n bytes32 groupMembersHash\\n ) external {\\n groups.addGroup(groupPubKey, groupMembersHash);\\n }\\n\\n function roughlyTerminateGroup(uint64 groupId) public {\\n groups.terminateGroup(groupId);\\n }\\n\\n function dkgLockState() external {\\n dkg.lockState();\\n }\\n}\\n\",\"keccak256\":\"0x0ece5b986f3074db6e9b2cbe506d76eaa1774594d1cafc2480991bb269adc96f\"}},\"version\":1}", + "storageLayout": { + "storage": [ + { + "astId": 9704, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "governance", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 9708, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)49_storage" + }, + { + "astId": 14668, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "reimbursementPool", + "offset": 0, + "slot": "50", + "type": "t_contract(ReimbursementPool)14998" + }, + { + "astId": 14672, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)49_storage" + }, + { + "astId": 9832, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "_callbackGasLimit", + "offset": 0, + "slot": "100", + "type": "t_uint256" + }, + { + "astId": 9835, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "_groupCreationFrequency", + "offset": 0, + "slot": "101", + "type": "t_uint256" + }, + { + "astId": 9838, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "_maliciousDkgResultSlashingAmount", + "offset": 0, + "slot": "102", + "type": "t_uint96" + }, + { + "astId": 9841, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "_unauthorizedSigningSlashingAmount", + "offset": 12, + "slot": "102", + "type": "t_uint96" + }, + { + "astId": 9844, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "_sortitionPoolRewardsBanDuration", + "offset": 0, + "slot": "103", + "type": "t_uint256" + }, + { + "astId": 9847, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "_relayEntryTimeoutNotificationRewardMultiplier", + "offset": 0, + "slot": "104", + "type": "t_uint256" + }, + { + "astId": 9850, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "_unauthorizedSigningNotificationRewardMultiplier", + "offset": 0, + "slot": "105", + "type": "t_uint256" + }, + { + "astId": 9853, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "_dkgMaliciousResultNotificationRewardMultiplier", + "offset": 0, + "slot": "106", + "type": "t_uint256" + }, + { + "astId": 9856, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "_dkgResultSubmissionGas", + "offset": 0, + "slot": "107", + "type": "t_uint256" + }, + { + "astId": 9859, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "_dkgResultApprovalGasOffset", + "offset": 0, + "slot": "108", + "type": "t_uint256" + }, + { + "astId": 9862, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "_notifyOperatorInactivityGasOffset", + "offset": 0, + "slot": "109", + "type": "t_uint256" + }, + { + "astId": 9865, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "_relayEntrySubmissionGasOffset", + "offset": 0, + "slot": "110", + "type": "t_uint256" + }, + { + "astId": 9870, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "inactivityClaimNonce", + "offset": 0, + "slot": "111", + "type": "t_mapping(t_uint64,t_uint256)" + }, + { + "astId": 9875, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "authorizedRequesters", + "offset": 0, + "slot": "112", + "type": "t_mapping(t_address,t_bool)" + }, + { + "astId": 9878, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "sortitionPool", + "offset": 0, + "slot": "113", + "type": "t_contract(SortitionPool)1980" + }, + { + "astId": 9881, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "tToken", + "offset": 0, + "slot": "114", + "type": "t_contract(IERC20)4111" + }, + { + "astId": 9884, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "staking", + "offset": 0, + "slot": "115", + "type": "t_contract(IStaking)9039" + }, + { + "astId": 9887, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "authorization", + "offset": 0, + "slot": "116", + "type": "t_struct(Data)16593_storage" + }, + { + "astId": 9890, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "dkg", + "offset": 0, + "slot": "120", + "type": "t_struct(Data)17523_storage" + }, + { + "astId": 9893, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "groups", + "offset": 0, + "slot": "131", + "type": "t_struct(Data)19026_storage" + }, + { + "astId": 9896, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "relay", + "offset": 0, + "slot": "136", + "type": "t_struct(Data)19920_storage" + }, + { + "astId": 9899, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "callback", + "offset": 0, + "slot": "140", + "type": "t_struct(Data)18930_storage" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_bytes32)dyn_storage": { + "base": "t_bytes32", + "encoding": "dynamic_array", + "label": "bytes32[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)49_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint64)dyn_storage": { + "base": "t_uint64", + "encoding": "dynamic_array", + "label": "uint64[]", + "numberOfBytes": "32" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "encoding": "inplace", + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_bytes_storage": { + "encoding": "bytes", + "label": "bytes", + "numberOfBytes": "32" + }, + "t_contract(BeaconDkgValidator)9699": { + "encoding": "inplace", + "label": "contract BeaconDkgValidator", + "numberOfBytes": "20" + }, + "t_contract(IERC20)4111": { + "encoding": "inplace", + "label": "contract IERC20", + "numberOfBytes": "20" + }, + "t_contract(IRandomBeaconConsumer)15021": { + "encoding": "inplace", + "label": "contract IRandomBeaconConsumer", + "numberOfBytes": "20" + }, + "t_contract(IStaking)9039": { + "encoding": "inplace", + "label": "contract IStaking", + "numberOfBytes": "20" + }, + "t_contract(ReimbursementPool)14998": { + "encoding": "inplace", + "label": "contract ReimbursementPool", + "numberOfBytes": "20" + }, + "t_contract(SortitionPool)1980": { + "encoding": "inplace", + "label": "contract SortitionPool", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_address)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => address)", + "numberOfBytes": "32", + "value": "t_address" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_address,t_struct(AuthorizationDecrease)16576_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct BeaconAuthorization.AuthorizationDecrease)", + "numberOfBytes": "32", + "value": "t_struct(AuthorizationDecrease)16576_storage" + }, + "t_mapping(t_bytes32,t_struct(Group)19010_storage)": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => struct Groups.Group)", + "numberOfBytes": "32", + "value": "t_struct(Group)19010_storage" + }, + "t_mapping(t_uint64,t_uint256)": { + "encoding": "mapping", + "key": "t_uint64", + "label": "mapping(uint64 => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_struct(AuthorizationDecrease)16576_storage": { + "encoding": "inplace", + "label": "struct BeaconAuthorization.AuthorizationDecrease", + "members": [ + { + "astId": 16573, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "decreasingBy", + "offset": 0, + "slot": "0", + "type": "t_uint96" + }, + { + "astId": 16575, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "decreasingAt", + "offset": 12, + "slot": "0", + "type": "t_uint64" + } + ], + "numberOfBytes": "32" + }, + "t_struct(Data)16593_storage": { + "encoding": "inplace", + "label": "struct BeaconAuthorization.Data", + "members": [ + { + "astId": 16579, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "parameters", + "offset": 0, + "slot": "0", + "type": "t_struct(Parameters)16571_storage" + }, + { + "astId": 16583, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "stakingProviderToOperator", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_address,t_address)" + }, + { + "astId": 16587, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "operatorToStakingProvider", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_address,t_address)" + }, + { + "astId": 16592, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "pendingDecreases", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_address,t_struct(AuthorizationDecrease)16576_storage)" + } + ], + "numberOfBytes": "128" + }, + "t_struct(Data)17523_storage": { + "encoding": "inplace", + "label": "struct BeaconDkg.Data", + "members": [ + { + "astId": 17506, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "sortitionPool", + "offset": 0, + "slot": "0", + "type": "t_contract(SortitionPool)1980" + }, + { + "astId": 17509, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "dkgValidator", + "offset": 0, + "slot": "1", + "type": "t_contract(BeaconDkgValidator)9699" + }, + { + "astId": 17512, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "parameters", + "offset": 0, + "slot": "2", + "type": "t_struct(Parameters)17503_storage" + }, + { + "astId": 17514, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "startBlock", + "offset": 0, + "slot": "6", + "type": "t_uint256" + }, + { + "astId": 17516, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "seed", + "offset": 0, + "slot": "7", + "type": "t_uint256" + }, + { + "astId": 17518, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "resultSubmissionStartBlockOffset", + "offset": 0, + "slot": "8", + "type": "t_uint256" + }, + { + "astId": 17520, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "submittedResultHash", + "offset": 0, + "slot": "9", + "type": "t_bytes32" + }, + { + "astId": 17522, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "submittedResultBlock", + "offset": 0, + "slot": "10", + "type": "t_uint256" + } + ], + "numberOfBytes": "352" + }, + "t_struct(Data)18930_storage": { + "encoding": "inplace", + "label": "struct Callback.Data", + "members": [ + { + "astId": 18929, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "callbackContract", + "offset": 0, + "slot": "0", + "type": "t_contract(IRandomBeaconConsumer)15021" + } + ], + "numberOfBytes": "32" + }, + "t_struct(Data)19026_storage": { + "encoding": "inplace", + "label": "struct Groups.Data", + "members": [ + { + "astId": 19015, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "groupsData", + "offset": 0, + "slot": "0", + "type": "t_mapping(t_bytes32,t_struct(Group)19010_storage)" + }, + { + "astId": 19018, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "groupsRegistry", + "offset": 0, + "slot": "1", + "type": "t_array(t_bytes32)dyn_storage" + }, + { + "astId": 19021, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "activeTerminatedGroups", + "offset": 0, + "slot": "2", + "type": "t_array(t_uint64)dyn_storage" + }, + { + "astId": 19023, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "expiredGroupOffset", + "offset": 0, + "slot": "3", + "type": "t_uint64" + }, + { + "astId": 19025, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "groupLifetime", + "offset": 0, + "slot": "4", + "type": "t_uint256" + } + ], + "numberOfBytes": "160" + }, + "t_struct(Data)19920_storage": { + "encoding": "inplace", + "label": "struct Relay.Data", + "members": [ + { + "astId": 19904, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "requestCount", + "offset": 0, + "slot": "0", + "type": "t_uint64" + }, + { + "astId": 19906, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "currentRequestID", + "offset": 8, + "slot": "0", + "type": "t_uint64" + }, + { + "astId": 19908, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "currentRequestGroupID", + "offset": 16, + "slot": "0", + "type": "t_uint64" + }, + { + "astId": 19910, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "currentRequestStartBlock", + "offset": 24, + "slot": "0", + "type": "t_uint64" + }, + { + "astId": 19913, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "previousEntry", + "offset": 0, + "slot": "1", + "type": "t_struct(G1Point)15033_storage" + }, + { + "astId": 19915, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "relayEntrySoftTimeout", + "offset": 0, + "slot": "3", + "type": "t_uint32" + }, + { + "astId": 19917, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "relayEntryHardTimeout", + "offset": 4, + "slot": "3", + "type": "t_uint32" + }, + { + "astId": 19919, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "relayEntrySubmissionFailureSlashingAmount", + "offset": 8, + "slot": "3", + "type": "t_uint96" + } + ], + "numberOfBytes": "128" + }, + "t_struct(G1Point)15033_storage": { + "encoding": "inplace", + "label": "struct AltBn128.G1Point", + "members": [ + { + "astId": 15030, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "x", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 15032, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "y", + "offset": 0, + "slot": "1", + "type": "t_uint256" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Group)19010_storage": { + "encoding": "inplace", + "label": "struct Groups.Group", + "members": [ + { + "astId": 19003, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "groupPubKey", + "offset": 0, + "slot": "0", + "type": "t_bytes_storage" + }, + { + "astId": 19005, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "registrationBlockNumber", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 19007, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "membersHash", + "offset": 0, + "slot": "2", + "type": "t_bytes32" + }, + { + "astId": 19009, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "terminated", + "offset": 0, + "slot": "3", + "type": "t_bool" + } + ], + "numberOfBytes": "128" + }, + "t_struct(Parameters)16571_storage": { + "encoding": "inplace", + "label": "struct BeaconAuthorization.Parameters", + "members": [ + { + "astId": 16566, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "minimumAuthorization", + "offset": 0, + "slot": "0", + "type": "t_uint96" + }, + { + "astId": 16568, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "authorizationDecreaseDelay", + "offset": 12, + "slot": "0", + "type": "t_uint64" + }, + { + "astId": 16570, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "authorizationDecreaseChangePeriod", + "offset": 20, + "slot": "0", + "type": "t_uint64" + } + ], + "numberOfBytes": "32" + }, + "t_struct(Parameters)17503_storage": { + "encoding": "inplace", + "label": "struct BeaconDkg.Parameters", + "members": [ + { + "astId": 17496, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "resultChallengePeriodLength", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 17498, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "resultChallengeExtraGas", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 17500, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "resultSubmissionTimeout", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 17502, + "contract": "contracts/test/RandomBeaconStub.sol:RandomBeaconStub", + "label": "submitterPrecedencePeriodLength", + "offset": 0, + "slot": "3", + "type": "t_uint256" + } + ], + "numberOfBytes": "128" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint32": { + "encoding": "inplace", + "label": "uint32", + "numberOfBytes": "4" + }, + "t_uint64": { + "encoding": "inplace", + "label": "uint64", + "numberOfBytes": "8" + }, + "t_uint96": { + "encoding": "inplace", + "label": "uint96", + "numberOfBytes": "12" + } + } + }, + "userdoc": { + "kind": "user", + "methods": { + "approveAuthorizationDecrease(address)": { + "notice": "Approves the previously registered authorization decrease request. Reverts if authorization decrease delay has not passed yet or if the authorization decrease was not requested for the given staking provider." + }, + "approveDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))": { + "notice": "Approves DKG result. Can be called when the challenge period for the submitted result is finished. Considers the submitted result as valid, bans misbehaved group members from the sortition pool rewards, and completes the group creation by activating the candidate group. For the first `submitterPrecedencePeriodLength` blocks after the end of the challenge period can be called only by the DKG result submitter. After that time, can be called by anyone." + }, + "authorizationDecreaseRequested(address,uint96,uint96)": { + "notice": "Used by T staking contract to inform the beacon that the authorization decrease for the given staking provider has been requested. Reverts if the amount after deauthorization would be non-zero and lower than the minimum authorization. Reverts if another authorization decrease request is pending for the staking provider and not enough time passed since the original request (see `authorizationDecreaseChangePeriod`). If the operator is not known (`registerOperator` was not called) it lets to `approveAuthorizationDecrease` immediately. If the operator is known (`registerOperator` was called), the operator needs to update state of the sortition pool with a call to `joinSortitionPool` or `updateOperatorStatus`. After the sortition pool state is in sync, authorization decrease delay starts. After authorization decrease delay passes, authorization decrease request needs to be approved with a call to `approveAuthorizationDecrease` function. If there is a pending authorization decrease request, it is overwritten, but only if enough time passed since the original request. Otherwise, the function reverts." + }, + "authorizationIncreased(address,uint96,uint96)": { + "notice": "Used by T staking contract to inform the beacon that the authorized stake amount for the given staking provider increased. Reverts if the authorization amount is below the minimum. The function is not updating the sortition pool. Sortition pool state needs to be updated by the operator with a call to `joinSortitionPool` or `updateOperatorStatus`." + }, + "authorizationParameters()": { + "notice": "Returns authorization-related parameters of the beacon." + }, + "authorizedRequesters(address)": { + "notice": "Authorized addresses that can request a relay entry." + }, + "availableRewards(address)": { + "notice": "Returns the amount of rewards available for withdrawal for the given staking provider. Reverts if staking provider has not registered the operator address." + }, + "challengeDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))": { + "notice": "Challenges DKG result. If the submitted result is proved to be invalid it reverts the DKG back to the result submission phase. It removes a candidate group that was previously registered with the DKG result submission." + }, + "eligibleStake(address)": { + "notice": "Returns the current value of the staking provider's eligible stake. Eligible stake is defined as the currently authorized stake minus the pending authorization decrease. Eligible stake is what is used for operator's weight in the sortition pool. If the authorized stake minus the pending authorization decrease is below the minimum authorization, eligible stake is 0." + }, + "gasParameters()": { + "notice": "Returns gas-related parameters of the beacon." + }, + "genesis()": { + "notice": "Triggers group selection if there are no active groups." + }, + "getGroupCreationState()": { + "notice": "Check current group creation state." + }, + "groupCreationParameters()": { + "notice": "Returns group-creation-related parameters of the beacon." + }, + "hasDkgTimedOut()": { + "notice": "Checks if DKG timed out. The DKG timeout period includes time required for off-chain protocol execution and time for the result publication for all group members. After this time result cannot be submitted and DKG can be notified about the timeout." + }, + "inactivityClaimNonce(uint64)": { + "notice": "Stores current operator inactivity claim nonce for given group. Each claim is made with an unique nonce which protects against claim replay." + }, + "involuntaryAuthorizationDecrease(address,uint96,uint96)": { + "notice": "Used by T staking contract to inform the beacon the authorization has been decreased for the given staking provider involuntarily, as a result of slashing. If the operator is not known (`registerOperator` was not called) the function does nothing. The operator was never in a sortition pool so there is nothing to update. If the operator is known, sortition pool is unlocked, and the operator is in the sortition pool, the sortition pool state is updated. If the sortition pool is locked, update needs to be postponed. Every other staker is incentivized to call `updateOperatorStatus` for the problematic operator to increase their own rewards in the pool." + }, + "isOperatorInPool(address)": { + "notice": "Returns true if the given operator is in the sortition pool. Otherwise, returns false." + }, + "isOperatorUpToDate(address)": { + "notice": "Checks if the operator's authorized stake is in sync with operator's weight in the sortition pool. If the operator is not in the sortition pool and their authorized stake is non-zero, function returns false." + }, + "joinSortitionPool()": { + "notice": "Lets the operator join the sortition pool. The operator address must be known - before calling this function, it has to be appointed by the staking provider by calling `registerOperator`. Also, the operator must have the minimum authorization required by the beacon. Function reverts if there is no minimum stake authorized or if the operator is not known. If there was an authorization decrease requested, it is activated by starting the authorization decrease delay." + }, + "minimumAuthorization()": { + "notice": "The minimum authorization amount required so that operator can participate in the random beacon. This amount is required to execute slashing for providing a malicious DKG result or when a relay entry times out." + }, + "notifyDkgTimeout()": { + "notice": "Notifies about DKG timeout." + }, + "notifyOperatorInactivity((uint64,uint256[],bytes,uint256[]),uint256,uint32[])": { + "notice": "Notifies about operators who are inactive. Using this function, a majority of the group can decide about punishing specific group members who constantly fail doing their job. If the provided claim is proved to be valid and signed by sufficient number of group members, operators of members deemed as inactive are banned for sortition pool rewards for duration specified by `_sortitionPoolRewardsBanDuration` parameter. The sender of the claim must be one of the claim signers. This function can be called only for active and non-terminated groups." + }, + "operatorToStakingProvider(address)": { + "notice": "Returns staking provider of the given operator." + }, + "pendingAuthorizationDecrease(address)": { + "notice": "Returns the amount of stake that is pending authorization decrease for the given staking provider. If no authorization decrease has been requested, returns zero." + }, + "registerOperator(address)": { + "notice": "Used by staking provider to set operator address that will operate a node. The given staking provider can set operator address only one time. The operator address can not be changed and must be unique. Reverts if the operator is already set for the staking provider or if the operator address is already in use. Reverts if there is a pending authorization decrease for the staking provider." + }, + "relayEntryParameters()": { + "notice": "Returns relay-entry-related parameters of the beacon." + }, + "remainingAuthorizationDecreaseDelay(address)": { + "notice": "Returns the remaining time in seconds that needs to pass before the requested authorization decrease can be approved. If the sortition pool state was not updated yet by the operator after requesting the authorization decrease, returns `type(uint64).max`." + }, + "reportRelayEntryTimeout(uint32[])": { + "notice": "Reports a relay entry timeout." + }, + "reportUnauthorizedSigning(bytes,uint64,uint32[])": { + "notice": "Reports unauthorized groups signing. Must provide a valid signature of the sender's address as a message. Successful signature verification means the private key has been leaked and all group members should be punished by slashing their tokens. Group has to be active or expired. Unauthorized signing cannot be reported for a terminated group. In case of reporting unauthorized signing for a terminated group, or when the signature is invalid, function reverts." + }, + "requestRelayEntry(address)": { + "notice": "Creates a request to generate a new relay entry, which will include a random number (by signing the previous entry's random number). Requester must be previously authorized by the governance." + }, + "rewardParameters()": { + "notice": "Returns reward-related parameters of the beacon." + }, + "selectGroup()": { + "notice": "Selects a new group of operators. Can only be called when DKG is in progress and the pool is locked. At least one operator has to be registered in the pool, otherwise the function fails reverting the transaction." + }, + "setRequesterAuthorization(address,bool)": { + "notice": "Set authorization for requesters that can request a relay entry." + }, + "slashingParameters()": { + "notice": "Returns slashing-related parameters of the beacon." + }, + "stakingProviderToOperator(address)": { + "notice": "Returns operator registered for the given staking provider." + }, + "submitDkgResult((uint256,bytes,uint8[],bytes,uint256[],uint32[],bytes32))": { + "notice": "`\\x19Ethereum signed message:\\n` before signing, so the message to sign is: `\\x19Ethereum signed message:\\n${keccak256(chainID,groupPubKey,misbehaved,startBlock)}`" + }, + "submitRelayEntry(bytes)": { + "notice": "Creates a new relay entry. Gas-optimized version that can be called only before the soft timeout. This should be the majority of cases." + }, + "submitRelayEntry(bytes,uint32[])": { + "notice": "Creates a new relay entry." + }, + "transferGovernance(address)": { + "notice": "Transfers governance of the contract to `newGovernance`." + }, + "updateAuthorizationParameters(uint96,uint64,uint64)": { + "notice": "Updates the values of authorization parameters." + }, + "updateGasParameters(uint256,uint256,uint256,uint256)": { + "notice": "Updates the values of gas parameters." + }, + "updateGroupCreationParameters(uint256,uint256,uint256,uint256,uint256,uint256)": { + "notice": "Updates the values of group creation parameters." + }, + "updateOperatorStatus(address)": { + "notice": "Updates status of the operator in the sortition pool. If there was an authorization decrease requested, it is activated by starting the authorization decrease delay. Function reverts if the operator is not known." + }, + "updateRelayEntryParameters(uint256,uint256,uint256)": { + "notice": "Updates the values of relay entry parameters." + }, + "updateRewardParameters(uint256,uint256,uint256,uint256)": { + "notice": "Updates the values of reward parameters." + }, + "updateSlashingParameters(uint96,uint96,uint96)": { + "notice": "Updates the values of slashing parameters." + }, + "withdrawIneligibleRewards(address)": { + "notice": "Withdraws rewards belonging to operators marked as ineligible for sortition pool rewards." + }, + "withdrawRewards(address)": { + "notice": "Withdraws application rewards for the given staking provider. Rewards are withdrawn to the staking provider's beneficiary address set in the staking contract. Reverts if staking provider has not registered the operator address." + } + }, + "version": 1 + } +} diff --git a/solidity/ecdsa/external/random-beacon-export/deploy/01_deploy_reimbursement_pool.js b/solidity/ecdsa/external/random-beacon-export/deploy/01_deploy_reimbursement_pool.js index 6a844e251f..a62f0c1198 100644 --- a/solidity/ecdsa/external/random-beacon-export/deploy/01_deploy_reimbursement_pool.js +++ b/solidity/ecdsa/external/random-beacon-export/deploy/01_deploy_reimbursement_pool.js @@ -1,82 +1,32 @@ "use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var func = function (hre) { return __awaiter(void 0, void 0, void 0, function () { - var getNamedAccounts, deployments, helpers, deployer, staticGas, maxGasPrice, ReimbursementPool; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - getNamedAccounts = hre.getNamedAccounts, deployments = hre.deployments, helpers = hre.helpers; - return [4 /*yield*/, getNamedAccounts()]; - case 1: - deployer = (_a.sent()).deployer; - staticGas = 40800 // gas amount consumed by the refund() + tx cost - ; - maxGasPrice = 500000000000 // 500 Gwei - ; - return [4 /*yield*/, deployments.deploy("ReimbursementPool", { - from: deployer, - args: [staticGas, maxGasPrice], - log: true, - waitConfirmations: 1, - })]; - case 2: - ReimbursementPool = _a.sent(); - if (!hre.network.tags.etherscan) return [3 /*break*/, 5]; - return [4 /*yield*/, hre.ethers.provider.waitForTransaction(ReimbursementPool.transactionHash, 2, 300000)]; - case 3: - _a.sent(); - return [4 /*yield*/, helpers.etherscan.verify(ReimbursementPool)]; - case 4: - _a.sent(); - _a.label = 5; - case 5: - if (!hre.network.tags.tenderly) return [3 /*break*/, 7]; - return [4 /*yield*/, hre.tenderly.verify({ - name: "ReimbursementPool", - address: ReimbursementPool.address, - })]; - case 6: - _a.sent(); - _a.label = 7; - case 7: return [2 /*return*/]; - } +const wait_for_confirmations_1 = __importDefault(require("../utils/wait-for-confirmations")); +const func = async (hre) => { + const { getNamedAccounts, deployments, helpers } = hre; + const { deployer } = await getNamedAccounts(); + const staticGas = 40800; // gas amount consumed by the refund() + tx cost + const maxGasPrice = 500000000000; // 500 Gwei + const ReimbursementPool = await deployments.deploy("ReimbursementPool", { + from: deployer, + args: [staticGas, maxGasPrice], + log: true, + waitConfirmations: 1, }); -}); }; + if (hre.network.tags.etherscan) { + if (ReimbursementPool.transactionHash) { + await (0, wait_for_confirmations_1.default)(hre.ethers.provider, ReimbursementPool.transactionHash, 2, 300000); + } + await helpers.etherscan.verify(ReimbursementPool); + } + if (hre.network.tags.tenderly) { + await hre.tenderly.verify({ + name: "ReimbursementPool", + address: ReimbursementPool.address, + }); + } +}; exports.default = func; func.tags = ["ReimbursementPool"]; diff --git a/solidity/ecdsa/external/random-beacon-export/deploy/02_deploy_beacon_sortition_pool.js b/solidity/ecdsa/external/random-beacon-export/deploy/02_deploy_beacon_sortition_pool.js index b75e808381..c43b4f0630 100644 --- a/solidity/ecdsa/external/random-beacon-export/deploy/02_deploy_beacon_sortition_pool.js +++ b/solidity/ecdsa/external/random-beacon-export/deploy/02_deploy_beacon_sortition_pool.js @@ -1,89 +1,37 @@ "use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var func = function (hre) { return __awaiter(void 0, void 0, void 0, function () { - var getNamedAccounts, deployments, helpers, _a, deployer, chaosnetOwner, execute, to1e18, POOL_WEIGHT_DIVISOR, T, BeaconSortitionPool; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - getNamedAccounts = hre.getNamedAccounts, deployments = hre.deployments, helpers = hre.helpers; - return [4 /*yield*/, getNamedAccounts()]; - case 1: - _a = _b.sent(), deployer = _a.deployer, chaosnetOwner = _a.chaosnetOwner; - execute = deployments.execute; - to1e18 = helpers.number.to1e18; - POOL_WEIGHT_DIVISOR = to1e18(1); - return [4 /*yield*/, deployments.get("T")]; - case 2: - T = _b.sent(); - return [4 /*yield*/, deployments.deploy("BeaconSortitionPool", { - contract: "SortitionPool", - from: deployer, - args: [T.address, POOL_WEIGHT_DIVISOR], - log: true, - waitConfirmations: 1, - })]; - case 3: - BeaconSortitionPool = _b.sent(); - return [4 /*yield*/, execute("BeaconSortitionPool", { from: deployer, log: true, waitConfirmations: 1 }, "transferChaosnetOwnerRole", chaosnetOwner)]; - case 4: - _b.sent(); - if (!hre.network.tags.etherscan) return [3 /*break*/, 7]; - return [4 /*yield*/, hre.ethers.provider.waitForTransaction(BeaconSortitionPool.transactionHash, 2, 300000)]; - case 5: - _b.sent(); - return [4 /*yield*/, helpers.etherscan.verify(BeaconSortitionPool)]; - case 6: - _b.sent(); - _b.label = 7; - case 7: - if (!hre.network.tags.tenderly) return [3 /*break*/, 9]; - return [4 /*yield*/, hre.tenderly.verify({ - name: "BeaconSortitionPool", - address: BeaconSortitionPool.address, - })]; - case 8: - _b.sent(); - _b.label = 9; - case 9: return [2 /*return*/]; - } +const wait_for_confirmations_1 = __importDefault(require("../utils/wait-for-confirmations")); +const func = async (hre) => { + const { getNamedAccounts, deployments, helpers } = hre; + const { deployer, chaosnetOwner } = await getNamedAccounts(); + const { execute } = deployments; + const { to1e18 } = helpers.number; + const POOL_WEIGHT_DIVISOR = to1e18(1); + const T = await deployments.get("T"); + const BeaconSortitionPool = await deployments.deploy("BeaconSortitionPool", { + contract: "SortitionPool", + from: deployer, + args: [T.address, POOL_WEIGHT_DIVISOR], + log: true, + waitConfirmations: 1, }); -}); }; + await execute("BeaconSortitionPool", { from: deployer, log: true, waitConfirmations: 1 }, "transferChaosnetOwnerRole", chaosnetOwner); + if (hre.network.tags.etherscan) { + if (BeaconSortitionPool.transactionHash) { + await (0, wait_for_confirmations_1.default)(hre.ethers.provider, BeaconSortitionPool.transactionHash, 2, 300000); + } + await helpers.etherscan.verify(BeaconSortitionPool); + } + if (hre.network.tags.tenderly) { + await hre.tenderly.verify({ + name: "BeaconSortitionPool", + address: BeaconSortitionPool.address, + }); + } +}; exports.default = func; func.tags = ["BeaconSortitionPool"]; // TokenStaking and T deployments are expected to be resolved from diff --git a/solidity/ecdsa/external/random-beacon-export/deploy/03_deploy_beacon_dkg_validator.js b/solidity/ecdsa/external/random-beacon-export/deploy/03_deploy_beacon_dkg_validator.js index 5480770a5a..e6e39eda3d 100644 --- a/solidity/ecdsa/external/random-beacon-export/deploy/03_deploy_beacon_dkg_validator.js +++ b/solidity/ecdsa/external/random-beacon-export/deploy/03_deploy_beacon_dkg_validator.js @@ -1,82 +1,32 @@ "use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var func = function (hre) { return __awaiter(void 0, void 0, void 0, function () { - var getNamedAccounts, deployments, helpers, deployer, BeaconSortitionPool, BeaconDkgValidator; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - getNamedAccounts = hre.getNamedAccounts, deployments = hre.deployments, helpers = hre.helpers; - return [4 /*yield*/, getNamedAccounts()]; - case 1: - deployer = (_a.sent()).deployer; - return [4 /*yield*/, deployments.get("BeaconSortitionPool")]; - case 2: - BeaconSortitionPool = _a.sent(); - return [4 /*yield*/, deployments.deploy("BeaconDkgValidator", { - from: deployer, - args: [BeaconSortitionPool.address], - log: true, - waitConfirmations: 1, - })]; - case 3: - BeaconDkgValidator = _a.sent(); - if (!hre.network.tags.etherscan) return [3 /*break*/, 6]; - return [4 /*yield*/, hre.ethers.provider.waitForTransaction(BeaconDkgValidator.transactionHash, 2, 300000)]; - case 4: - _a.sent(); - return [4 /*yield*/, helpers.etherscan.verify(BeaconDkgValidator)]; - case 5: - _a.sent(); - _a.label = 6; - case 6: - if (!hre.network.tags.tenderly) return [3 /*break*/, 8]; - return [4 /*yield*/, hre.tenderly.verify({ - name: "BeaconDkgValidator", - address: BeaconDkgValidator.address, - })]; - case 7: - _a.sent(); - _a.label = 8; - case 8: return [2 /*return*/]; - } +const wait_for_confirmations_1 = __importDefault(require("../utils/wait-for-confirmations")); +const func = async (hre) => { + const { getNamedAccounts, deployments, helpers } = hre; + const { deployer } = await getNamedAccounts(); + const BeaconSortitionPool = await deployments.get("BeaconSortitionPool"); + const BeaconDkgValidator = await deployments.deploy("BeaconDkgValidator", { + from: deployer, + args: [BeaconSortitionPool.address], + log: true, + waitConfirmations: 1, }); -}); }; + if (hre.network.tags.etherscan) { + if (BeaconDkgValidator.transactionHash) { + await (0, wait_for_confirmations_1.default)(hre.ethers.provider, BeaconDkgValidator.transactionHash, 2, 300000); + } + await helpers.etherscan.verify(BeaconDkgValidator); + } + if (hre.network.tags.tenderly) { + await hre.tenderly.verify({ + name: "BeaconDkgValidator", + address: BeaconDkgValidator.address, + }); + } +}; exports.default = func; func.tags = ["BeaconDkgValidator"]; func.dependencies = ["BeaconSortitionPool"]; diff --git a/solidity/ecdsa/external/random-beacon-export/deploy/04_deploy_random_beacon.js b/solidity/ecdsa/external/random-beacon-export/deploy/04_deploy_random_beacon.js index 55f246154b..d30fc5ea13 100644 --- a/solidity/ecdsa/external/random-beacon-export/deploy/04_deploy_random_beacon.js +++ b/solidity/ecdsa/external/random-beacon-export/deploy/04_deploy_random_beacon.js @@ -1,145 +1,63 @@ "use strict"; -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; - }; - return __assign.apply(this, arguments); +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; }; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); +Object.defineProperty(exports, "__esModule", { value: true }); +const wait_for_confirmations_1 = __importDefault(require("../utils/wait-for-confirmations")); +const func = async (hre) => { + const { getNamedAccounts, deployments, helpers } = hre; + const { deployer } = await getNamedAccounts(); + const T = await deployments.get("T"); + const TokenStaking = await deployments.get("TokenStaking"); + const ReimbursementPool = await deployments.get("ReimbursementPool"); + const BeaconSortitionPool = await deployments.get("BeaconSortitionPool"); + const BeaconDkgValidator = await deployments.get("BeaconDkgValidator"); + const deployOptions = { + from: deployer, + log: true, + waitConfirmations: 1, + }; + const BLS = await deployments.deploy("BLS", deployOptions); + const BeaconAuthorization = await deployments.deploy("BeaconAuthorization", deployOptions); + const BeaconDkg = await deployments.deploy("BeaconDkg", deployOptions); + const BeaconInactivity = await deployments.deploy("BeaconInactivity", deployOptions); + const RandomBeacon = await deployments.deploy("RandomBeacon", { + contract: process.env.TEST_USE_STUBS_BEACON === "true" + ? "RandomBeaconStub" + : undefined, + args: [ + BeaconSortitionPool.address, + T.address, + TokenStaking.address, + BeaconDkgValidator.address, + ReimbursementPool.address, + ], + libraries: { + BLS: BLS.address, + BeaconAuthorization: BeaconAuthorization.address, + BeaconDkg: BeaconDkg.address, + BeaconInactivity: BeaconInactivity.address, + }, + ...deployOptions, }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + await helpers.ownable.transferOwnership("BeaconSortitionPool", RandomBeacon.address, deployer); + if (hre.network.tags.etherscan) { + if (RandomBeacon.transactionHash) { + await (0, wait_for_confirmations_1.default)(hre.ethers.provider, RandomBeacon.transactionHash, 2, 300000); + } + await helpers.etherscan.verify(BLS); + await helpers.etherscan.verify(BeaconAuthorization); + await helpers.etherscan.verify(BeaconDkg); + await helpers.etherscan.verify(BeaconInactivity); + await helpers.etherscan.verify(RandomBeacon); + } + if (hre.network.tags.tenderly) { + await hre.tenderly.verify({ + name: "RandomBeacon", + address: RandomBeacon.address, + }); } }; -Object.defineProperty(exports, "__esModule", { value: true }); -var func = function (hre) { return __awaiter(void 0, void 0, void 0, function () { - var getNamedAccounts, deployments, helpers, deployer, T, TokenStaking, ReimbursementPool, BeaconSortitionPool, BeaconDkgValidator, deployOptions, BLS, BeaconAuthorization, BeaconDkg, BeaconInactivity, RandomBeacon; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - getNamedAccounts = hre.getNamedAccounts, deployments = hre.deployments, helpers = hre.helpers; - return [4 /*yield*/, getNamedAccounts()]; - case 1: - deployer = (_a.sent()).deployer; - return [4 /*yield*/, deployments.get("T")]; - case 2: - T = _a.sent(); - return [4 /*yield*/, deployments.get("TokenStaking")]; - case 3: - TokenStaking = _a.sent(); - return [4 /*yield*/, deployments.get("ReimbursementPool")]; - case 4: - ReimbursementPool = _a.sent(); - return [4 /*yield*/, deployments.get("BeaconSortitionPool")]; - case 5: - BeaconSortitionPool = _a.sent(); - return [4 /*yield*/, deployments.get("BeaconDkgValidator")]; - case 6: - BeaconDkgValidator = _a.sent(); - deployOptions = { - from: deployer, - log: true, - waitConfirmations: 1, - }; - return [4 /*yield*/, deployments.deploy("BLS", deployOptions)]; - case 7: - BLS = _a.sent(); - return [4 /*yield*/, deployments.deploy("BeaconAuthorization", deployOptions)]; - case 8: - BeaconAuthorization = _a.sent(); - return [4 /*yield*/, deployments.deploy("BeaconDkg", deployOptions)]; - case 9: - BeaconDkg = _a.sent(); - return [4 /*yield*/, deployments.deploy("BeaconInactivity", deployOptions)]; - case 10: - BeaconInactivity = _a.sent(); - return [4 /*yield*/, deployments.deploy("RandomBeacon", __assign({ contract: process.env.TEST_USE_STUBS_BEACON === "true" - ? "RandomBeaconStub" - : undefined, args: [ - BeaconSortitionPool.address, - T.address, - TokenStaking.address, - BeaconDkgValidator.address, - ReimbursementPool.address, - ], libraries: { - BLS: BLS.address, - BeaconAuthorization: BeaconAuthorization.address, - BeaconDkg: BeaconDkg.address, - BeaconInactivity: BeaconInactivity.address, - } }, deployOptions))]; - case 11: - RandomBeacon = _a.sent(); - return [4 /*yield*/, helpers.ownable.transferOwnership("BeaconSortitionPool", RandomBeacon.address, deployer)]; - case 12: - _a.sent(); - if (!hre.network.tags.etherscan) return [3 /*break*/, 19]; - return [4 /*yield*/, hre.ethers.provider.waitForTransaction(RandomBeacon.transactionHash, 2, 300000)]; - case 13: - _a.sent(); - return [4 /*yield*/, helpers.etherscan.verify(BLS)]; - case 14: - _a.sent(); - return [4 /*yield*/, helpers.etherscan.verify(BeaconAuthorization)]; - case 15: - _a.sent(); - return [4 /*yield*/, helpers.etherscan.verify(BeaconDkg)]; - case 16: - _a.sent(); - return [4 /*yield*/, helpers.etherscan.verify(BeaconInactivity)]; - case 17: - _a.sent(); - return [4 /*yield*/, helpers.etherscan.verify(RandomBeacon)]; - case 18: - _a.sent(); - _a.label = 19; - case 19: - if (!hre.network.tags.tenderly) return [3 /*break*/, 21]; - return [4 /*yield*/, hre.tenderly.verify({ - name: "RandomBeacon", - address: RandomBeacon.address, - })]; - case 20: - _a.sent(); - _a.label = 21; - case 21: return [2 /*return*/]; - } - }); -}); }; exports.default = func; func.tags = ["RandomBeacon"]; func.dependencies = [ diff --git a/solidity/ecdsa/external/random-beacon-export/deploy/05_approve_random_beacon_in_token_staking.js b/solidity/ecdsa/external/random-beacon-export/deploy/05_approve_random_beacon_in_token_staking.js index 738d85e62c..30ec7b136b 100644 --- a/solidity/ecdsa/external/random-beacon-export/deploy/05_approve_random_beacon_in_token_staking.js +++ b/solidity/ecdsa/external/random-beacon-export/deploy/05_approve_random_beacon_in_token_staking.js @@ -1,31 +1,31 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); // ApplicationStatus enum: NOT_APPROVED=0, APPROVED=1, PAUSED=2, DISABLED=3 -var APPLICATION_STATUS_APPROVED = 1; +const APPLICATION_STATUS_APPROVED = 1n; function ifaceHasFunction(iface, name) { try { - iface.getFunction(name); - return true; + return iface.getFunction(name) !== null; } - catch (_a) { + catch { return false; } } -async function func(hre) { - var deployer = (await hre.getNamedAccounts()).deployer; - var execute = hre.deployments.execute, get = hre.deployments.get; - var ethers = hre.ethers; - var RandomBeacon = await hre.deployments.get("RandomBeacon"); - var TokenStaking = await get("TokenStaking"); - var iface = new ethers.utils.Interface(TokenStaking.abi); +const func = async (hre) => { + const { getNamedAccounts, deployments, ethers } = hre; + const { deployer } = await getNamedAccounts(); + const { execute, get } = deployments; + const RandomBeacon = await deployments.get("RandomBeacon"); + const TokenStaking = await get("TokenStaking"); + const iface = new ethers.Interface(TokenStaking.abi); if (!ifaceHasFunction(iface, "approveApplication")) { hre.deployments.log("TokenStaking does not have approveApplication (Threshold TokenStaking); skipping"); return; } + // Skip if RandomBeacon is already approved (idempotent for re-runs) try { - var tokenStakingContract = await ethers.getContractAt(TokenStaking.abi, TokenStaking.address); + const tokenStakingContract = await ethers.getContractAt(TokenStaking.abi, TokenStaking.address); if (ifaceHasFunction(iface, "applicationInfo")) { - var appInfo = await tokenStakingContract.applicationInfo(RandomBeacon.address); + const appInfo = await tokenStakingContract.applicationInfo(RandomBeacon.address); if (appInfo.status === APPLICATION_STATUS_APPROVED) { hre.deployments.log("RandomBeacon already approved in TokenStaking; skipping"); return; @@ -33,12 +33,12 @@ async function func(hre) { } } catch (e) { - hre.deployments.log("Could not read TokenStaking application status (continuing): ".concat(e)); + hre.deployments.log(`Could not read TokenStaking application status (continuing): ${e}`); } await execute("TokenStaking", { from: deployer, log: true, waitConfirmations: 1 }, "approveApplication", RandomBeacon.address); -} +}; exports.default = func; func.tags = ["RandomBeaconApprove"]; func.dependencies = ["TokenStaking", "RandomBeacon"]; // Skip for mainnet (already approved). -func.skip = async function (hre) { return hre.network.name === "mainnet"; }; +func.skip = async (hre) => hre.network.name === "mainnet"; diff --git a/solidity/ecdsa/external/random-beacon-export/deploy/06_authorize_random_beacon_in_reimbursement_pool.js b/solidity/ecdsa/external/random-beacon-export/deploy/06_authorize_random_beacon_in_reimbursement_pool.js index 2a179fe3a2..c7386d4cc3 100644 --- a/solidity/ecdsa/external/random-beacon-export/deploy/06_authorize_random_beacon_in_reimbursement_pool.js +++ b/solidity/ecdsa/external/random-beacon-export/deploy/06_authorize_random_beacon_in_reimbursement_pool.js @@ -1,61 +1,12 @@ "use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -}; Object.defineProperty(exports, "__esModule", { value: true }); -var func = function (hre) { return __awaiter(void 0, void 0, void 0, function () { - var getNamedAccounts, deployments, deployer, execute, RandomBeacon; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - getNamedAccounts = hre.getNamedAccounts, deployments = hre.deployments; - return [4 /*yield*/, getNamedAccounts()]; - case 1: - deployer = (_a.sent()).deployer; - execute = deployments.execute; - return [4 /*yield*/, deployments.get("RandomBeacon")]; - case 2: - RandomBeacon = _a.sent(); - return [4 /*yield*/, execute("ReimbursementPool", { from: deployer, log: true, waitConfirmations: 1 }, "authorize", RandomBeacon.address)]; - case 3: - _a.sent(); - return [2 /*return*/]; - } - }); -}); }; +const func = async (hre) => { + const { getNamedAccounts, deployments } = hre; + const { deployer } = await getNamedAccounts(); + const { execute } = deployments; + const RandomBeacon = await deployments.get("RandomBeacon"); + await execute("ReimbursementPool", { from: deployer, log: true, waitConfirmations: 1 }, "authorize", RandomBeacon.address); +}; exports.default = func; func.tags = ["RandomBeaconAuthorize"]; func.dependencies = ["ReimbursementPool", "RandomBeacon"]; diff --git a/solidity/ecdsa/external/random-beacon-export/deploy/07_deploy_random_beacon_governance.js b/solidity/ecdsa/external/random-beacon-export/deploy/07_deploy_random_beacon_governance.js index 131d12671f..9eae4c02fb 100644 --- a/solidity/ecdsa/external/random-beacon-export/deploy/07_deploy_random_beacon_governance.js +++ b/solidity/ecdsa/external/random-beacon-export/deploy/07_deploy_random_beacon_governance.js @@ -1,84 +1,33 @@ "use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var func = function (hre) { return __awaiter(void 0, void 0, void 0, function () { - var getNamedAccounts, deployments, helpers, deployer, RandomBeacon, GOVERNANCE_DELAY, RandomBeaconGovernance; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - getNamedAccounts = hre.getNamedAccounts, deployments = hre.deployments, helpers = hre.helpers; - return [4 /*yield*/, getNamedAccounts()]; - case 1: - deployer = (_a.sent()).deployer; - return [4 /*yield*/, deployments.get("RandomBeacon")]; - case 2: - RandomBeacon = _a.sent(); - GOVERNANCE_DELAY = 604800 // 1 week - ; - return [4 /*yield*/, deployments.deploy("RandomBeaconGovernance", { - from: deployer, - args: [RandomBeacon.address, GOVERNANCE_DELAY], - log: true, - waitConfirmations: 1, - })]; - case 3: - RandomBeaconGovernance = _a.sent(); - if (!hre.network.tags.etherscan) return [3 /*break*/, 6]; - return [4 /*yield*/, hre.ethers.provider.waitForTransaction(RandomBeaconGovernance.transactionHash, 2, 300000)]; - case 4: - _a.sent(); - return [4 /*yield*/, helpers.etherscan.verify(RandomBeaconGovernance)]; - case 5: - _a.sent(); - _a.label = 6; - case 6: - if (!hre.network.tags.tenderly) return [3 /*break*/, 8]; - return [4 /*yield*/, hre.tenderly.verify({ - name: "RandomBeaconGovernance", - address: RandomBeaconGovernance.address, - })]; - case 7: - _a.sent(); - _a.label = 8; - case 8: return [2 /*return*/]; - } +const wait_for_confirmations_1 = __importDefault(require("../utils/wait-for-confirmations")); +const func = async (hre) => { + const { getNamedAccounts, deployments, helpers } = hre; + const { deployer } = await getNamedAccounts(); + const RandomBeacon = await deployments.get("RandomBeacon"); + const GOVERNANCE_DELAY = 604800; // 1 week + const RandomBeaconGovernance = await deployments.deploy("RandomBeaconGovernance", { + from: deployer, + args: [RandomBeacon.address, GOVERNANCE_DELAY], + log: true, + waitConfirmations: 1, }); -}); }; + if (hre.network.tags.etherscan) { + if (RandomBeaconGovernance.transactionHash) { + await (0, wait_for_confirmations_1.default)(hre.ethers.provider, RandomBeaconGovernance.transactionHash, 2, 300000); + } + await helpers.etherscan.verify(RandomBeaconGovernance); + } + if (hre.network.tags.tenderly) { + await hre.tenderly.verify({ + name: "RandomBeaconGovernance", + address: RandomBeaconGovernance.address, + }); + } +}; exports.default = func; func.tags = ["RandomBeaconGovernance"]; func.dependencies = ["RandomBeacon"]; diff --git a/solidity/ecdsa/external/random-beacon-export/deploy/08_transfer_governance.js b/solidity/ecdsa/external/random-beacon-export/deploy/08_transfer_governance.js index 9538cdad39..13494d1cbb 100644 --- a/solidity/ecdsa/external/random-beacon-export/deploy/08_transfer_governance.js +++ b/solidity/ecdsa/external/random-beacon-export/deploy/08_transfer_governance.js @@ -1,63 +1,12 @@ "use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -}; Object.defineProperty(exports, "__esModule", { value: true }); -var func = function (hre) { return __awaiter(void 0, void 0, void 0, function () { - var getNamedAccounts, deployments, helpers, _a, deployer, governance, RandomBeaconGovernance; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - getNamedAccounts = hre.getNamedAccounts, deployments = hre.deployments, helpers = hre.helpers; - return [4 /*yield*/, getNamedAccounts()]; - case 1: - _a = _b.sent(), deployer = _a.deployer, governance = _a.governance; - return [4 /*yield*/, deployments.get("RandomBeaconGovernance")]; - case 2: - RandomBeaconGovernance = _b.sent(); - return [4 /*yield*/, helpers.ownable.transferOwnership("RandomBeaconGovernance", governance, deployer)]; - case 3: - _b.sent(); - return [4 /*yield*/, deployments.execute("RandomBeacon", { from: deployer, log: true, waitConfirmations: 1 }, "transferGovernance", RandomBeaconGovernance.address)]; - case 4: - _b.sent(); - return [2 /*return*/]; - } - }); -}); }; +const func = async (hre) => { + const { getNamedAccounts, deployments, helpers } = hre; + const { deployer, governance } = await getNamedAccounts(); + const RandomBeaconGovernance = await deployments.get("RandomBeaconGovernance"); + await helpers.ownable.transferOwnership("RandomBeaconGovernance", governance, deployer); + await deployments.execute("RandomBeacon", { from: deployer, log: true, waitConfirmations: 1 }, "transferGovernance", RandomBeaconGovernance.address); +}; exports.default = func; func.tags = ["RandomBeaconTransferGovernance"]; func.dependencies = ["RandomBeaconGovernance"]; diff --git a/solidity/ecdsa/external/random-beacon-export/deploy/09_deploy_random_beacon_chaosnet.js b/solidity/ecdsa/external/random-beacon-export/deploy/09_deploy_random_beacon_chaosnet.js index 5ac1f93b8c..3ee769357d 100644 --- a/solidity/ecdsa/external/random-beacon-export/deploy/09_deploy_random_beacon_chaosnet.js +++ b/solidity/ecdsa/external/random-beacon-export/deploy/09_deploy_random_beacon_chaosnet.js @@ -1,89 +1,32 @@ "use strict"; -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; - }; - return __assign.apply(this, arguments); +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; }; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); +Object.defineProperty(exports, "__esModule", { value: true }); +const wait_for_confirmations_1 = __importDefault(require("../utils/wait-for-confirmations")); +const func = async (hre) => { + const { getNamedAccounts, deployments, helpers } = hre; + const { deployer } = await getNamedAccounts(); + const deployOptions = { + from: deployer, + log: true, + waitConfirmations: 1, + }; + const RandomBeaconChaosnet = await deployments.deploy("RandomBeaconChaosnet", { + ...deployOptions, }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + if (hre.network.tags.etherscan) { + if (RandomBeaconChaosnet.transactionHash) { + await (0, wait_for_confirmations_1.default)(hre.ethers.provider, RandomBeaconChaosnet.transactionHash, 2, 300000); + } + await helpers.etherscan.verify(RandomBeaconChaosnet); + } + if (hre.network.tags.tenderly) { + await hre.tenderly.verify({ + name: "RandomBeaconChaosnet", + address: RandomBeaconChaosnet.address, + }); } }; -Object.defineProperty(exports, "__esModule", { value: true }); -var func = function (hre) { return __awaiter(void 0, void 0, void 0, function () { - var getNamedAccounts, deployments, helpers, deployer, deployOptions, RandomBeaconChaosnet; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - getNamedAccounts = hre.getNamedAccounts, deployments = hre.deployments, helpers = hre.helpers; - return [4 /*yield*/, getNamedAccounts()]; - case 1: - deployer = (_a.sent()).deployer; - deployOptions = { - from: deployer, - log: true, - waitConfirmations: 1, - }; - return [4 /*yield*/, deployments.deploy("RandomBeaconChaosnet", __assign({}, deployOptions))]; - case 2: - RandomBeaconChaosnet = _a.sent(); - if (!hre.network.tags.etherscan) return [3 /*break*/, 5]; - return [4 /*yield*/, hre.ethers.provider.waitForTransaction(RandomBeaconChaosnet.transactionHash, 2, 300000)]; - case 3: - _a.sent(); - return [4 /*yield*/, helpers.etherscan.verify(RandomBeaconChaosnet)]; - case 4: - _a.sent(); - _a.label = 5; - case 5: - if (!hre.network.tags.tenderly) return [3 /*break*/, 7]; - return [4 /*yield*/, hre.tenderly.verify({ - name: "RandomBeaconChaosnet", - address: RandomBeaconChaosnet.address, - })]; - case 6: - _a.sent(); - _a.label = 7; - case 7: return [2 /*return*/]; - } - }); -}); }; exports.default = func; func.tags = ["RandomBeaconChaosnet"]; diff --git a/solidity/ecdsa/external/random-beacon-export/tasks/initialize.js b/solidity/ecdsa/external/random-beacon-export/tasks/initialize.js new file mode 100644 index 0000000000..2d0ded1b58 --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/tasks/initialize.js @@ -0,0 +1,89 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TASK_ADD_BETA_OPERATOR = exports.TASK_REGISTER = exports.TASK_AUTHORIZE = exports.TASK_STAKE = exports.TASK_MINT = exports.TASK_INITIALIZE_STAKING = exports.TASK_INITIALIZE = void 0; +const ethers_1 = require("ethers"); +const config_1 = require("hardhat/config"); +const utils_1 = require("./utils"); +// Main task executing all child tasks. +exports.TASK_INITIALIZE = "initialize"; +// Subtask for staking. +exports.TASK_INITIALIZE_STAKING = `${exports.TASK_INITIALIZE}:staking`; +// Staking tasks. +exports.TASK_MINT = "mint"; +exports.TASK_STAKE = "stake"; +// Name prefix that should be used in tasks implementation for specific application. +exports.TASK_AUTHORIZE = "authorize"; +exports.TASK_REGISTER = "register"; +exports.TASK_ADD_BETA_OPERATOR = "add_beta_operator"; +// Subtask for the Random Beacon application. +const TASK_INITIALIZE_BEACON = `${exports.TASK_INITIALIZE}:beacon`; +const TASK_AUTHORIZE_BEACON = `${exports.TASK_AUTHORIZE}:beacon`; +const TASK_REGISTER_BEACON = `${exports.TASK_REGISTER}:beacon`; +const TASK_ADD_BETA_OPERATOR_BEACON = `${exports.TASK_ADD_BETA_OPERATOR}:beacon`; +(0, config_1.task)(exports.TASK_INITIALIZE, "Initializes staking and the Random Beacon application for a staking provider and an operator") + .addParam("owner", "Stake Owner address", undefined, config_1.types.string) + .addParam("provider", "Staking Provider", undefined, config_1.types.string) + .addParam("operator", "Staking Operator", undefined, config_1.types.string) + .addOptionalParam("beneficiary", "Stake Beneficiary", undefined, config_1.types.string) + .addOptionalParam("authorizer", "Stake Authorizer", undefined, config_1.types.string) + .addOptionalParam("amount", "Stake amount", 1000000, config_1.types.int) + .addOptionalParam("authorization", "Authorization amount (default: minimumAuthorization)", undefined, config_1.types.int) + .setAction(async (args, hre) => { + // Initialize staking + await hre.run(exports.TASK_INITIALIZE_STAKING, args); + // Initialize Beacon + await hre.run(TASK_INITIALIZE_BEACON, args); + // Set the operator as a beta operator + await hre.run(TASK_ADD_BETA_OPERATOR_BEACON, args); +}); +(0, config_1.task)(exports.TASK_INITIALIZE_STAKING, "Initializes staking for a service provider") + .addParam("owner", "Stake Owner address", undefined, config_1.types.string) + .addParam("provider", "Staking Provider", undefined, config_1.types.string) + .addOptionalParam("beneficiary", "Stake Beneficiary", undefined, config_1.types.string) + .addOptionalParam("authorizer", "Stake Authorizer", undefined, config_1.types.string) + .addOptionalParam("amount", "Stake amount", 1000000, config_1.types.int) + .setAction(async (args, hre) => { + const tokensToMint = await (0, utils_1.calculateTokensNeededForStake)(hre, args.provider, args.amount); + if (tokensToMint !== 0n) { + await hre.run(exports.TASK_MINT, { ...args, amount: (0, ethers_1.getNumber)(tokensToMint) }); + } + await hre.run(exports.TASK_STAKE, args); +}); +(0, config_1.task)(exports.TASK_MINT, "Mints T tokens") + .addParam("owner", "Stake Owner address", undefined, config_1.types.string) + .addOptionalParam("amount", "Stake amount", 1000000, config_1.types.int) + .setAction(async (args, hre) => { + await (0, utils_1.mint)(hre, args.owner, args.amount); +}); +(0, config_1.task)(exports.TASK_STAKE, "Stakes T tokens") + .addParam("owner", "Stake Owner address", undefined, config_1.types.string) + .addParam("provider", "Staking Provider", undefined, config_1.types.string) + .addOptionalParam("beneficiary", "Stake Beneficiary", undefined, config_1.types.string) + .addOptionalParam("authorizer", "Stake Authorizer", undefined, config_1.types.string) + .addOptionalParam("amount", "Stake amount", 1000000, config_1.types.int) + .setAction(async (args, hre) => { + await (0, utils_1.stake)(hre, args.owner, args.provider, args.amount, args.beneficiary, args.authorizer); +}); +(0, config_1.task)(TASK_INITIALIZE_BEACON, "Initializes operator for Beacon").setAction(async (args, hre) => { + await hre.run(TASK_AUTHORIZE_BEACON, args); + await hre.run(TASK_REGISTER_BEACON, args); +}); +(0, config_1.task)(TASK_AUTHORIZE_BEACON, "Sets authorization for Beacon") + .addParam("owner", "Stake Owner address", undefined, config_1.types.string) + .addParam("provider", "Staking Provider", undefined, config_1.types.string) + .addOptionalParam("authorizer", "Stake Authorizer", undefined, config_1.types.string) + .addOptionalParam("authorization", "Authorization amount (default: minimumAuthorization)", undefined, config_1.types.int) + .setAction(async (args, hre) => { + await (0, utils_1.authorize)(hre, "RandomBeacon", args.owner, args.provider, args.authorizer, args.authorization); +}); +(0, config_1.task)(TASK_REGISTER_BEACON, "Registers an operator for a staking provider in Beacon") + .addParam("provider", "Staking Provider", undefined, config_1.types.string) + .addParam("operator", "Operator Address", undefined, config_1.types.string) + .setAction(async (args, hre) => { + await (0, utils_1.register)(hre, "RandomBeacon", args.provider, args.operator); +}); +(0, config_1.task)(TASK_ADD_BETA_OPERATOR_BEACON, "Adds an operator to the set of beta operators in Beacon") + .addParam("operator", "Operator Address", undefined, config_1.types.string) + .setAction(async (args, hre) => { + await (0, utils_1.addBetaOperator)(hre, "BeaconSortitionPool", args.operator); +}); diff --git a/solidity/ecdsa/external/random-beacon-export/tasks/unlock-eth-accounts.js b/solidity/ecdsa/external/random-beacon-export/tasks/unlock-eth-accounts.js new file mode 100644 index 0000000000..28197bcd10 --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/tasks/unlock-eth-accounts.js @@ -0,0 +1,31 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const config_1 = require("hardhat/config"); +(0, config_1.task)("unlock-accounts", "Unlock ethereum accounts").setAction(async (args, hre) => { + const { ethers } = hre; + if (hre.network.name === "development") { + const password = process.env.KEEP_ETHEREUM_PASSWORD || "password"; + const provider = new ethers.JsonRpcProvider(hre.network.config.url); + const accounts = await provider.listAccounts(); + console.log(`Total accounts: ${accounts.length}`); + console.log("---------------------------------"); + for (let i = 0; i < accounts.length; i++) { + const account = await accounts[i].getAddress(); + try { + console.log(`\nUnlocking account: ${account}`); + // An explicit duration of zero seconds unlocks the key until geth exits. + await provider.send("personal_unlockAccount", [ + account.toLowerCase(), + password, + 0, + ]); + console.log("Account unlocked!"); + } + catch (error) { + console.log(`\nAccount: ${account} not unlocked!`); + console.error(error); + } + console.log("\n---------------------------------"); + } + } +}); diff --git a/solidity/ecdsa/external/random-beacon-export/tasks/utils/add_beta_operator.js b/solidity/ecdsa/external/random-beacon-export/tasks/utils/add_beta_operator.js new file mode 100644 index 0000000000..fd27d63265 --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/tasks/utils/add_beta_operator.js @@ -0,0 +1,17 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.addBetaOperator = addBetaOperator; +// eslint-disable-next-line import/prefer-default-export +async function addBetaOperator(hre, sortitionPoolDeploymentName, operator) { + const { ethers, helpers } = hre; + const sortitionPool = await helpers.contracts.getContract(sortitionPoolDeploymentName); + const chaosnetOwner = await sortitionPool.chaosnetOwner(); + if (await sortitionPool.isBetaOperator(operator)) { + console.log(`Operator ${operator} is already a beta operator`); + return; + } + console.log(`Adding ${operator} to the set of beta operators...`); + await (await sortitionPool + .connect(await ethers.getSigner(chaosnetOwner)) + .getFunction("addBetaOperators")([operator])).wait(); +} diff --git a/solidity/ecdsa/external/random-beacon-export/tasks/utils/authorize.js b/solidity/ecdsa/external/random-beacon-export/tasks/utils/authorize.js new file mode 100644 index 0000000000..2d5d78e9d4 --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/tasks/utils/authorize.js @@ -0,0 +1,32 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.authorize = authorize; +// eslint-disable-next-line import/prefer-default-export +async function authorize(hre, deploymentName, // TODO: Change to IApplication +owner, provider, authorizer, authorization) { + const { ethers, helpers } = hre; + const ownerAddress = ethers.getAddress(owner); + const providerAddress = ethers.getAddress(provider); + const application = await helpers.contracts.getContract(deploymentName); + console.log(`Authorizing provider's ${providerAddress} stake in ${deploymentName} application (${await application.getAddress()})`); + // Authorizer can equal to the owner if not set otherwise. This simplification + // is used for development purposes. + const authorizerAddress = authorizer + ? ethers.getAddress(authorizer) + : ownerAddress; + const { to1e18, from1e18 } = helpers.number; + const staking = await helpers.contracts.getContract("TokenStaking"); + const authorizationBN = authorization + ? to1e18(authorization) + : await application.minimumAuthorization(); + const currentAuthorization = await staking.authorizedStake(providerAddress, await application.getAddress()); + if (currentAuthorization >= authorizationBN) { + console.log(`Authorized stake is already ${from1e18(currentAuthorization)} T`); + return; + } + const increaseAmount = authorizationBN - currentAuthorization; + console.log(`Increasing authorization by ${from1e18(increaseAmount)} T to ${from1e18(authorizationBN)} T...`); + await (await staking + .connect(await ethers.getSigner(authorizerAddress)) + .getFunction("increaseAuthorization")(providerAddress, await application.getAddress(), increaseAmount)).wait(); +} diff --git a/solidity/ecdsa/external/random-beacon-export/tasks/utils/ether.js b/solidity/ecdsa/external/random-beacon-export/tasks/utils/ether.js new file mode 100644 index 0000000000..32ef8f4aef --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/tasks/utils/ether.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.parseValue = parseValue; +// eslint-disable-next-line import/prefer-default-export +function parseValue(value, hre) { + const parsed = String(value).trim().split(" "); + if (parsed.length === 0 || parsed.length > 2) { + throw new Error(`invalid value: ${value}`); + } + return hre.ethers.parseUnits(parsed[0], parsed[1] || "wei"); +} diff --git a/solidity/ecdsa/external/random-beacon-export/tasks/utils/index.js b/solidity/ecdsa/external/random-beacon-export/tasks/utils/index.js new file mode 100644 index 0000000000..0c2f16611d --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/tasks/utils/index.js @@ -0,0 +1,22 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +__exportStar(require("./authorize"), exports); +__exportStar(require("./ether"), exports); +__exportStar(require("./mint"), exports); +__exportStar(require("./register"), exports); +__exportStar(require("./stake"), exports); +__exportStar(require("./add_beta_operator"), exports); diff --git a/solidity/ecdsa/external/random-beacon-export/tasks/utils/mint.js b/solidity/ecdsa/external/random-beacon-export/tasks/utils/mint.js new file mode 100644 index 0000000000..043b7d751b --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/tasks/utils/mint.js @@ -0,0 +1,30 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.mint = mint; +// eslint-disable-next-line import/prefer-default-export +async function mint(hre, owner, amount) { + const { ethers, helpers } = hre; + const { to1e18, from1e18 } = helpers.number; + const ownerAddress = ethers.getAddress(owner); + const stakeAmount = to1e18(amount); + const t = await helpers.contracts.getContract("T"); + const staking = await helpers.contracts.getContract("TokenStaking"); + const tokenContractOwner = await t.owner(); + const currentBalance = await t.balanceOf(ownerAddress); + console.log(`Account ${ownerAddress} balance is ${from1e18(currentBalance)} T`); + if (currentBalance < stakeAmount) { + const mintAmount = stakeAmount - currentBalance; + console.log(`Minting ${from1e18(mintAmount)} T for ${ownerAddress}...`); + await (await t + .connect(await ethers.getSigner(tokenContractOwner)) + .getFunction("mint")(ownerAddress, mintAmount)).wait(); + } + const currentAllowance = await t.allowance(ownerAddress, await staking.getAddress()); + console.log(`Account ${ownerAddress} allowance for ${await staking.getAddress()} is ${from1e18(currentAllowance)} T`); + if (currentAllowance < stakeAmount) { + console.log(`Approving ${from1e18(stakeAmount)} T for ${await staking.getAddress()}...`); + await (await t + .connect(await ethers.getSigner(ownerAddress)) + .getFunction("approve")(await staking.getAddress(), stakeAmount)).wait(); + } +} diff --git a/solidity/ecdsa/external/random-beacon-export/tasks/utils/register.js b/solidity/ecdsa/external/random-beacon-export/tasks/utils/register.js new file mode 100644 index 0000000000..9415824ba9 --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/tasks/utils/register.js @@ -0,0 +1,28 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.register = register; +// eslint-disable-next-line import/prefer-default-export +async function register(hre, deploymentName, provider, operator) { + const { ethers, helpers } = hre; + const providerAddress = ethers.getAddress(provider); + const operatorAddress = ethers.getAddress(operator); + const application = await helpers.contracts.getContract(deploymentName); + console.log(`Registering operator ${operatorAddress} in ${deploymentName} application (${await application.getAddress()})`); + const currentProvider = ethers.getAddress(await application.operatorToStakingProvider.staticCall(operatorAddress)); + switch (currentProvider) { + case providerAddress: { + console.log(`Current staking provider for operator ${operatorAddress} is ${currentProvider}`); + return; + } + case ethers.ZeroAddress: { + console.log(`Registering operator ${operatorAddress} for a staking provider ${providerAddress}...`); + await (await application + .connect(await ethers.getSigner(providerAddress)) + .getFunction("registerOperator")(operatorAddress)).wait(); + break; + } + default: { + throw new Error(`Operator [${operatorAddress}] has already been registered for another staking provider [${currentProvider}]`); + } + } +} diff --git a/solidity/ecdsa/external/random-beacon-export/tasks/utils/stake.js b/solidity/ecdsa/external/random-beacon-export/tasks/utils/stake.js new file mode 100644 index 0000000000..0098dbac75 --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/tasks/utils/stake.js @@ -0,0 +1,48 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.stake = stake; +exports.calculateTokensNeededForStake = calculateTokensNeededForStake; +async function stake(hre, owner, provider, amount, beneficiary, authorizer) { + const { ethers, helpers } = hre; + const { to1e18, from1e18 } = helpers.number; + const ownerAddress = ethers.getAddress(owner); + const providerAddress = ethers.getAddress(provider); + const stakeAmount = to1e18(amount); + // Beneficiary can equal to the owner if not set otherwise. This simplification + // is used for development purposes. + const beneficiaryAddress = beneficiary + ? ethers.getAddress(beneficiary) + : ownerAddress; + // Authorizer can equal to the owner if not set otherwise. This simplification + // is used for development purposes. + const authorizerAddress = authorizer + ? ethers.getAddress(authorizer) + : ownerAddress; + const staking = await helpers.contracts.getContract("TokenStaking"); + const { tStake: currentStake } = await staking.stakes.staticCall(providerAddress); + console.log(`Current stake for ${providerAddress} is ${from1e18(currentStake)} T`); + if (currentStake === 0n) { + console.log(`Staking ${from1e18(stakeAmount)} T to the staking provider ${providerAddress}...`); + await (await staking + .connect(await ethers.getSigner(ownerAddress)) + .getFunction("stake")(providerAddress, beneficiaryAddress, authorizerAddress, stakeAmount)).wait(); + } + else if (currentStake < stakeAmount) { + const topUpAmount = stakeAmount - currentStake; + console.log(`Topping up ${from1e18(topUpAmount)} T to the staking provider ${providerAddress}...`); + await (await staking + .connect(await ethers.getSigner(ownerAddress)) + .getFunction("topUp")(providerAddress, topUpAmount)).wait(); + } +} +async function calculateTokensNeededForStake(hre, provider, amount) { + const { ethers, helpers } = hre; + const { to1e18, from1e18 } = helpers.number; + const stakeAmount = to1e18(amount); + const staking = await helpers.contracts.getContract("TokenStaking"); + const { tStake: currentStake } = await staking.stakes.staticCall(provider); + if (currentStake < stakeAmount) { + return BigInt(from1e18(stakeAmount - currentStake)); + } + return 0n; +} diff --git a/solidity/ecdsa/external/random-beacon-export/utils/wait-for-confirmations.js b/solidity/ecdsa/external/random-beacon-export/utils/wait-for-confirmations.js new file mode 100644 index 0000000000..df31cc60d3 --- /dev/null +++ b/solidity/ecdsa/external/random-beacon-export/utils/wait-for-confirmations.js @@ -0,0 +1,26 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = waitForConfirmations; +/** Wait through the transaction response; Hardhat's ethers v6 provider does not implement waitForTransaction. */ +async function waitForConfirmations(provider, transactionHash, confirmations = 2, timeout = 300000) { + const pollInterval = 2000; + const deadline = Date.now() + timeout; + // ethers v5 waitForTransaction polled, so a load-balanced endpoint that does + // not see the just-mined transaction yet must not fail the deployment. + let transaction = await provider.getTransaction(transactionHash); + while (!transaction) { + const remaining = deadline - Date.now(); + if (remaining <= 0) { + throw new Error(`Deployment transaction ${transactionHash} was not found`); + } + await new Promise((resolve) => { + setTimeout(resolve, Math.min(pollInterval, remaining)); + }); + transaction = await provider.getTransaction(transactionHash); + } + const receipt = await transaction.wait(confirmations, Math.max(deadline - Date.now(), 1)); + if (!receipt) { + throw new Error(`Deployment transaction ${transactionHash} is not confirmed`); + } + return receipt; +} diff --git a/solidity/ecdsa/hardhat.config.ts b/solidity/ecdsa/hardhat.config.ts index 8038e26de3..a4f7480373 100644 --- a/solidity/ecdsa/hardhat.config.ts +++ b/solidity/ecdsa/hardhat.config.ts @@ -5,6 +5,7 @@ import fs from "fs" import path from "path" +import "@nomicfoundation/hardhat-ethers" import "@nomicfoundation/hardhat-chai-matchers" import "@nomicfoundation/hardhat-verify" import "@keep-network/hardhat-helpers" @@ -12,7 +13,7 @@ import "@keep-network/hardhat-local-networks-config" import "@openzeppelin/hardhat-upgrades" import "@typechain/hardhat" import "hardhat-deploy" -import "@tenderly/hardhat-tenderly" +import { setup as setupTenderly } from "@tenderly/hardhat-tenderly" import "hardhat-contract-sizer" import "hardhat-dependency-compiler" import "hardhat-gas-reporter" @@ -22,37 +23,15 @@ import "./tasks" import { task } from "hardhat/config" import { TASK_TEST } from "hardhat/builtin-tasks/task-names" +import resolveRandomBeaconExport from "./utils/random-beacon-export" + import type { HardhatUserConfig } from "hardhat/config" const TASK_CHECK_ACCOUNTS_COUNT = "check-accounts-count" const hardhatVerifyEnabled = process.env.DISABLE_HARDHAT_VERIFY !== "true" -/** - * Random-beacon `export/` is gitignored in the random-beacon package, so CI never - * has ../random-beacon/export. Prefer committed `external/random-beacon-export/deploy` - * (mirrors npm export scripts with a fixed 05_approve_*) before falling back to node_modules. - */ -function resolveRandomBeaconExport(subdir: "deploy" | "artifacts"): string { - const local = path.join(__dirname, "../random-beacon/export", subdir) - if (fs.existsSync(local)) { - return local - } - if (subdir === "deploy") { - const bundledDeploy = path.join( - __dirname, - "external/random-beacon-export/deploy" - ) - if (fs.existsSync(bundledDeploy)) { - return bundledDeploy - } - } - return path.join( - __dirname, - "node_modules/@keep-network/random-beacon/export", - subdir - ) -} +setupTenderly({ automaticVerifications: false }) const thresholdSolidityCompilerConfig = { version: "0.8.9", @@ -236,11 +215,11 @@ const config: HardhatUserConfig = { // with `yarn link` command. development: [ "node_modules/@threshold-network/solidity-contracts/deployments/development", - fs.existsSync( - path.join(__dirname, "../random-beacon/deployments/development") + ...(fs.existsSync( + path.join(__dirname, "../random-beacon/deployments/development"), ) - ? path.join(__dirname, "../random-beacon/deployments/development") - : "node_modules/@keep-network/random-beacon/deployments/development", + ? [path.join(__dirname, "../random-beacon/deployments/development")] + : []), ], // Use local deployments/sepolia only - npm artifacts have transactionHash // that causes "cannot get the transaction" errors with some RPC nodes. @@ -257,7 +236,6 @@ const config: HardhatUserConfig = { paths: [ "@threshold-network/solidity-contracts/contracts/token/T.sol", "@threshold-network/solidity-contracts/contracts/staking/TokenStaking.sol", - "@keep-network/random-beacon/contracts/api/IRandomBeacon.sol", "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol", ], keep: true, @@ -273,6 +251,7 @@ const config: HardhatUserConfig = { timeout: 60000, }, typechain: { + target: "ethers-v6", outDir: "typechain", }, docgen: { @@ -290,14 +269,14 @@ task(TASK_TEST, "Runs mocha tests").setAction(async (args, hre, runSuper) => { }) task(TASK_CHECK_ACCOUNTS_COUNT, "Checks accounts count").setAction(async () => { - // eslint-disable-next-line @typescript-eslint/no-var-requires,global-require + // eslint-disable-next-line @typescript-eslint/no-require-imports,global-require const { constants } = require("./test/fixtures") if (testConfig.operatorsCount < constants.groupSize) { throw new Error( "not enough accounts predefined for configured group size: " + `expected group size: ${constants.groupSize} ` + - `number of predefined accounts: ${testConfig.operatorsCount}` + `number of predefined accounts: ${testConfig.operatorsCount}`, ) } }) diff --git a/solidity/ecdsa/package-lock.json b/solidity/ecdsa/package-lock.json deleted file mode 100644 index 843c71368f..0000000000 --- a/solidity/ecdsa/package-lock.json +++ /dev/null @@ -1,15791 +0,0 @@ -{ - "name": "@keep-network/ecdsa", - "version": "2.1.0-dev", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@keep-network/ecdsa", - "version": "2.1.0-dev", - "license": "MIT", - "dependencies": { - "@keep-network/random-beacon": "development", - "@keep-network/sortition-pools": "^2.0.0-pre.16", - "@openzeppelin/contracts": "^4.9.6", - "@openzeppelin/contracts-upgradeable": "^4.9.6", - "@threshold-network/solidity-contracts": "development" - }, - "devDependencies": { - "@defi-wonderland/smock": "^2.0.7", - "@keep-network/hardhat-helpers": "^0.6.0-pre.15", - "@keep-network/hardhat-local-networks-config": "^0.1.0-pre.4", - "@nomicfoundation/hardhat-chai-matchers": "^1.0.6", - "@nomicfoundation/hardhat-verify": "^2.1.3", - "@nomiclabs/hardhat-ethers": "^2.0.6", - "@openzeppelin/hardhat-upgrades": "^1.20.4", - "@tenderly/hardhat-tenderly": ">=1.0.13 <1.2.0", - "@thesis-co/eslint-config": "github:thesis/eslint-config", - "@typechain/ethers-v5": "^8.0.5", - "@typechain/hardhat": "^4.0.0", - "@types/chai": "^4.3.0", - "@types/chai-as-promised": "^7.1.5", - "@types/mocha": "^9.1.0", - "@types/node": "^17.0.10", - "chai": "^4.3.4", - "chai-as-promised": "^7.1.1", - "eslint": "^7.32.0", - "ethers": "^5.5.3", - "hardhat": "^2.10.0", - "hardhat-contract-sizer": "^2.3.0", - "hardhat-dependency-compiler": "^1.1.2", - "hardhat-deploy": "^0.11.11", - "hardhat-gas-reporter": "^1.0.8", - "prettier": "^2.5.1", - "prettier-plugin-sh": "^0.8.1", - "prettier-plugin-solidity": "^1.0.0-beta.19", - "solhint": "^3.3.6", - "solhint-config-keep": "github:keep-network/solhint-config-keep", - "solidity-docgen": "^0.6.0-beta.35", - "ts-node": "^10.4.0", - "typechain": "^6.1.0", - "typescript": "^4.5.4" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@aws-crypto/sha256-js": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-1.2.2.tgz", - "integrity": "sha512-Nr1QJIbW/afYYGzYvrF70LtaHrIRtd4TNAglX8BvlfxJLZ45SAmueIKYl5tWoNBPzp65ymXGFK0Bb1vZUpuc9g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/util": "^1.2.2", - "@aws-sdk/types": "^3.1.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-crypto/util": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-1.2.2.tgz", - "integrity": "sha512-H8PjG5WJ4wz0UXAFXeJjWCW1vkvIJ3qUUD+rGRwJ2/hj+xT58Qle2MTql/2MGzkU+1JLAFuR6aJpLAjHwhmwwg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.1.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-sdk/types": { - "version": "3.734.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.734.0.tgz", - "integrity": "sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/types/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD" - }, - "node_modules/@aws-sdk/util-utf8-browser": { - "version": "3.259.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", - "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.3.1" - } - }, - "node_modules/@aws-sdk/util-utf8-browser/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD" - }, - "node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bytecodealliance/preview2-shim": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@bytecodealliance/preview2-shim/-/preview2-shim-0.17.0.tgz", - "integrity": "sha512-JorcEwe4ud0x5BS/Ar2aQWOQoFzjq/7jcnxYXCvSMh0oRm0dQXzOA+hqLDBnOMks1LLBA7dmiLLsEBl09Yd6iQ==", - "dev": true, - "license": "(Apache-2.0 WITH LLVM-exception)" - }, - "node_modules/@cspotcode/source-map-consumer": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", - "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">= 12" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", - "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspotcode/source-map-consumer": "0.8.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@defi-wonderland/smock": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@defi-wonderland/smock/-/smock-2.4.1.tgz", - "integrity": "sha512-SvWg0joZppEWEB1XopkJazH1+whLw48KgwYLblml0Y7meJLK+J33uuPNtEsmAwgXWCCt6CouK2fXtSEDz2zKVw==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "dev": true, - "license": "MIT", - "dependencies": { - "@nomicfoundation/ethereumjs-util": "^9.0.4", - "diff": "^5.0.0", - "lodash.isequal": "^4.5.0", - "lodash.isequalwith": "^4.4.0", - "rxjs": "^7.2.0", - "semver": "^7.3.5" - }, - "peerDependencies": { - "@ethersproject/abi": "^5", - "@ethersproject/abstract-provider": "^5", - "@ethersproject/abstract-signer": "^5", - "@nomiclabs/hardhat-ethers": "^2", - "ethers": "^5", - "hardhat": "^2.21.0" - } - }, - "node_modules/@defi-wonderland/smock/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@ethereumjs/rlp": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-5.0.2.tgz", - "integrity": "sha512-DziebCdg4JpGlEqEdGgXmjqcFoJi+JGulUXwEjsZGAscAQ7MyD/7LE/GVCP29vEQxKc7AAwjT3A2ywHp2xfoCA==", - "dev": true, - "license": "MPL-2.0", - "bin": { - "rlp": "bin/rlp.cjs" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@ethereumjs/util": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-9.1.0.tgz", - "integrity": "sha512-XBEKsYqLGXLah9PNJbgdkigthkG7TAGvlD/sH12beMXEyHDyigfcbdvHhmLyDWgDyOJn4QwiQUaF7yeuhnjdog==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "@ethereumjs/rlp": "^5.0.2", - "ethereum-cryptography": "^2.2.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@ethereumjs/util/node_modules/@noble/curves": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", - "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.4.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@ethereumjs/util/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@ethereumjs/util/node_modules/@scure/bip32": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", - "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", - "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/@ethereumjs/util/node_modules/@scure/bip39": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", - "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@ethereumjs/util/node_modules/ethereum-cryptography": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", - "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "1.4.2", - "@noble/hashes": "1.4.0", - "@scure/bip32": "1.4.0", - "@scure/bip39": "1.3.0" - } - }, - "node_modules/@ethersproject/abi": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.8.0.tgz", - "integrity": "sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q==", - "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.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/constants": "^5.8.0", - "@ethersproject/hash": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/strings": "^5.8.0" - } - }, - "node_modules/@ethersproject/abstract-provider": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.8.0.tgz", - "integrity": "sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg==", - "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.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/networks": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/transactions": "^5.8.0", - "@ethersproject/web": "^5.8.0" - } - }, - "node_modules/@ethersproject/abstract-signer": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.8.0.tgz", - "integrity": "sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA==", - "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.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0" - } - }, - "node_modules/@ethersproject/address": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.8.0.tgz", - "integrity": "sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA==", - "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.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/rlp": "^5.8.0" - } - }, - "node_modules/@ethersproject/base64": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.8.0.tgz", - "integrity": "sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ==", - "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.8.0" - } - }, - "node_modules/@ethersproject/basex": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.8.0.tgz", - "integrity": "sha512-PIgTszMlDRmNwW9nhS6iqtVfdTAKosA7llYXNmGPw4YAI1PUyMv28988wAb41/gHF/WqGdoLv0erHaRcHRKW2Q==", - "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.8.0", - "@ethersproject/properties": "^5.8.0" - } - }, - "node_modules/@ethersproject/bignumber": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.8.0.tgz", - "integrity": "sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==", - "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.8.0", - "@ethersproject/logger": "^5.8.0", - "bn.js": "^5.2.1" - } - }, - "node_modules/@ethersproject/bignumber/node_modules/bn.js": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", - "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@ethersproject/bytes": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", - "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", - "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.8.0" - } - }, - "node_modules/@ethersproject/constants": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.8.0.tgz", - "integrity": "sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==", - "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.8.0" - } - }, - "node_modules/@ethersproject/contracts": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.8.0.tgz", - "integrity": "sha512-0eFjGz9GtuAi6MZwhb4uvUM216F38xiuR0yYCjKJpNfSEy4HUM8hvqqBj9Jmm0IUz8l0xKEhWwLIhPgxNY0yvQ==", - "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/abi": "^5.8.0", - "@ethersproject/abstract-provider": "^5.8.0", - "@ethersproject/abstract-signer": "^5.8.0", - "@ethersproject/address": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/constants": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/transactions": "^5.8.0" - } - }, - "node_modules/@ethersproject/hash": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.8.0.tgz", - "integrity": "sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA==", - "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.8.0", - "@ethersproject/address": "^5.8.0", - "@ethersproject/base64": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/strings": "^5.8.0" - } - }, - "node_modules/@ethersproject/hdnode": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.8.0.tgz", - "integrity": "sha512-4bK1VF6E83/3/Im0ERnnUeWOY3P1BZml4ZD3wcH8Ys0/d1h1xaFt6Zc+Dh9zXf9TapGro0T4wvO71UTCp3/uoA==", - "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.8.0", - "@ethersproject/basex": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/pbkdf2": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/sha2": "^5.8.0", - "@ethersproject/signing-key": "^5.8.0", - "@ethersproject/strings": "^5.8.0", - "@ethersproject/transactions": "^5.8.0", - "@ethersproject/wordlists": "^5.8.0" - } - }, - "node_modules/@ethersproject/json-wallets": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.8.0.tgz", - "integrity": "sha512-HxblNck8FVUtNxS3VTEYJAcwiKYsBIF77W15HufqlBF9gGfhmYOJtYZp8fSDZtn9y5EaXTE87zDwzxRoTFk11w==", - "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.8.0", - "@ethersproject/address": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/hdnode": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/pbkdf2": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/random": "^5.8.0", - "@ethersproject/strings": "^5.8.0", - "@ethersproject/transactions": "^5.8.0", - "aes-js": "3.0.0", - "scrypt-js": "3.0.1" - } - }, - "node_modules/@ethersproject/keccak256": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.8.0.tgz", - "integrity": "sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng==", - "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.8.0", - "js-sha3": "0.8.0" - } - }, - "node_modules/@ethersproject/logger": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz", - "integrity": "sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==", - "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.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.8.0.tgz", - "integrity": "sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg==", - "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.8.0" - } - }, - "node_modules/@ethersproject/pbkdf2": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.8.0.tgz", - "integrity": "sha512-wuHiv97BrzCmfEaPbUFpMjlVg/IDkZThp9Ri88BpjRleg4iePJaj2SW8AIyE8cXn5V1tuAaMj6lzvsGJkGWskg==", - "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.8.0", - "@ethersproject/sha2": "^5.8.0" - } - }, - "node_modules/@ethersproject/properties": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.8.0.tgz", - "integrity": "sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==", - "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.8.0" - } - }, - "node_modules/@ethersproject/providers": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.8.0.tgz", - "integrity": "sha512-3Il3oTzEx3o6kzcg9ZzbE+oCZYyY+3Zh83sKkn4s1DZfTUjIegHnN2Cm0kbn9YFy45FDVcuCLLONhU7ny0SsCw==", - "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.8.0", - "@ethersproject/abstract-signer": "^5.8.0", - "@ethersproject/address": "^5.8.0", - "@ethersproject/base64": "^5.8.0", - "@ethersproject/basex": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/constants": "^5.8.0", - "@ethersproject/hash": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/networks": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/random": "^5.8.0", - "@ethersproject/rlp": "^5.8.0", - "@ethersproject/sha2": "^5.8.0", - "@ethersproject/strings": "^5.8.0", - "@ethersproject/transactions": "^5.8.0", - "@ethersproject/web": "^5.8.0", - "bech32": "1.1.4", - "ws": "8.18.0" - } - }, - "node_modules/@ethersproject/random": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.8.0.tgz", - "integrity": "sha512-E4I5TDl7SVqyg4/kkA/qTfuLWAQGXmSOgYyO01So8hLfwgKvYK5snIlzxJMk72IFdG/7oh8yuSqY2KX7MMwg+A==", - "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.8.0", - "@ethersproject/logger": "^5.8.0" - } - }, - "node_modules/@ethersproject/rlp": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.8.0.tgz", - "integrity": "sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q==", - "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.8.0", - "@ethersproject/logger": "^5.8.0" - } - }, - "node_modules/@ethersproject/sha2": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.8.0.tgz", - "integrity": "sha512-dDOUrXr9wF/YFltgTBYS0tKslPEKr6AekjqDW2dbn1L1xmjGR+9GiKu4ajxovnrDbwxAKdHjW8jNcwfz8PAz4A==", - "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.8.0", - "@ethersproject/logger": "^5.8.0", - "hash.js": "1.1.7" - } - }, - "node_modules/@ethersproject/signing-key": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.8.0.tgz", - "integrity": "sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==", - "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.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "bn.js": "^5.2.1", - "elliptic": "6.6.1", - "hash.js": "1.1.7" - } - }, - "node_modules/@ethersproject/signing-key/node_modules/bn.js": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", - "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@ethersproject/signing-key/node_modules/elliptic": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", - "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", - "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/@ethersproject/signing-key/node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", - "dev": true, - "license": "MIT" - }, - "node_modules/@ethersproject/solidity": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.8.0.tgz", - "integrity": "sha512-4CxFeCgmIWamOHwYN9d+QWGxye9qQLilpgTU0XhYs1OahkclF+ewO+3V1U0mvpiuQxm5EHHmv8f7ClVII8EHsA==", - "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.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/sha2": "^5.8.0", - "@ethersproject/strings": "^5.8.0" - } - }, - "node_modules/@ethersproject/strings": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.8.0.tgz", - "integrity": "sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg==", - "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.8.0", - "@ethersproject/constants": "^5.8.0", - "@ethersproject/logger": "^5.8.0" - } - }, - "node_modules/@ethersproject/transactions": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.8.0.tgz", - "integrity": "sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==", - "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.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/constants": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/rlp": "^5.8.0", - "@ethersproject/signing-key": "^5.8.0" - } - }, - "node_modules/@ethersproject/units": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.8.0.tgz", - "integrity": "sha512-lxq0CAnc5kMGIiWW4Mr041VT8IhNM+Pn5T3haO74XZWFulk7wH1Gv64HqE96hT4a7iiNMdOCFEBgaxWuk8ETKQ==", - "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.8.0", - "@ethersproject/constants": "^5.8.0", - "@ethersproject/logger": "^5.8.0" - } - }, - "node_modules/@ethersproject/wallet": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.8.0.tgz", - "integrity": "sha512-G+jnzmgg6UxurVKRKvw27h0kvG75YKXZKdlLYmAHeF32TGUzHkOFd7Zn6QHOTYRFWnfjtSSFjBowKo7vfrXzPA==", - "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.8.0", - "@ethersproject/abstract-signer": "^5.8.0", - "@ethersproject/address": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/hash": "^5.8.0", - "@ethersproject/hdnode": "^5.8.0", - "@ethersproject/json-wallets": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/random": "^5.8.0", - "@ethersproject/signing-key": "^5.8.0", - "@ethersproject/transactions": "^5.8.0", - "@ethersproject/wordlists": "^5.8.0" - } - }, - "node_modules/@ethersproject/web": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.8.0.tgz", - "integrity": "sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw==", - "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.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/strings": "^5.8.0" - } - }, - "node_modules/@ethersproject/wordlists": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.8.0.tgz", - "integrity": "sha512-2df9bbXicZws2Sb5S6ET493uJ0Z84Fjr3pC4tu/qlnZERibZCeUVuqdtt+7Tv9xxhUxHoIekIA7avrKUWHrezg==", - "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.8.0", - "@ethersproject/hash": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/strings": "^5.8.0" - } - }, - "node_modules/@fastify/busboy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", - "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@keep-network/hardhat-helpers": { - "version": "0.6.0-pre.15", - "resolved": "https://registry.npmjs.org/@keep-network/hardhat-helpers/-/hardhat-helpers-0.6.0-pre.15.tgz", - "integrity": "sha512-yPjpUy4vjXzj6/t6DNtXZ2V/ZYLZReUXPvND2L70wqlWXc9d9tUVaTjdl/r9J9iSFJprAv74rAADeKqRPXmGFg==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@nomiclabs/hardhat-ethers": "^2.1.0", - "@nomiclabs/hardhat-etherscan": "^3.1.0", - "@openzeppelin/hardhat-upgrades": "^1.20.0", - "ethers": "^5.6.9", - "hardhat": "^2.10.0", - "hardhat-deploy": "^0.11.11" - } - }, - "node_modules/@keep-network/hardhat-local-networks-config": { - "version": "0.1.0-pre.4", - "resolved": "https://registry.npmjs.org/@keep-network/hardhat-local-networks-config/-/hardhat-local-networks-config-0.1.0-pre.4.tgz", - "integrity": "sha512-HSQv1xXMUoJCJKrjDJg2Afxj5VmCxEshWZUGNxk1d6D5p5+GBpakb/m6COwMkdwa6cVIcZqUMEBEAnf0fKLWog==", - "dev": true, - "license": "MIT", - "dependencies": { - "deepmerge": "^4.2.2", - "untildify": "^4.0.0" - }, - "peerDependencies": { - "hardhat": "^2.0.8" - } - }, - "node_modules/@keep-network/keep-core": { - "version": "1.8.1-dev.0", - "resolved": "https://registry.npmjs.org/@keep-network/keep-core/-/keep-core-1.8.1-dev.0.tgz", - "integrity": "sha512-gFXkgN4PYOYCZ14AskL7fZHEFW5mu3BDd+TJKBuKZc1q9CgRMOK+dxpJnSctxmSH1tV+Ln9v9yqlSkfPCoiBHw==", - "license": "MIT", - "dependencies": { - "@openzeppelin/upgrades": "^2.7.2", - "openzeppelin-solidity": "2.4.0" - } - }, - "node_modules/@keep-network/random-beacon": { - "version": "2.1.0-dev.18", - "resolved": "https://registry.npmjs.org/@keep-network/random-beacon/-/random-beacon-2.1.0-dev.18.tgz", - "integrity": "sha512-UrVq///+jqOLQ5k8/aFvD1ZUMvVe49iS81U8mDoi9A005FiQzKUK9QFKv3Z0h6joG4prF/hlABRTEQ1UA7tgRA==", - "dependencies": { - "@keep-network/sortition-pools": "^2.0.0-pre.16", - "@openzeppelin/contracts": "4.7.3", - "@thesis/solidity-contracts": "github:thesis/solidity-contracts#4985bcf", - "@threshold-network/solidity-contracts": "1.3.0-dev.11" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@keep-network/random-beacon/node_modules/@openzeppelin/contracts": { - "version": "4.7.3", - "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.7.3.tgz", - "integrity": "sha512-dGRS0agJzu8ybo44pCIf3xBaPQN/65AIXNgK8+4gzKd5kbvlqyxryUYVLJv7fK98Seyd2hDZzVEHSWAh0Bt1Yw==", - "license": "MIT" - }, - "node_modules/@keep-network/random-beacon/node_modules/@openzeppelin/contracts-upgradeable": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.5.2.tgz", - "integrity": "sha512-xgWZYaPlrEOQo3cBj97Ufiuv79SPd8Brh4GcFYhPgb6WvAq4ppz8dWKL6h+jLAK01rUqMRp/TS9AdXgAeNvCLA==", - "license": "MIT" - }, - "node_modules/@keep-network/random-beacon/node_modules/@threshold-network/solidity-contracts": { - "version": "1.3.0-dev.11", - "resolved": "https://registry.npmjs.org/@threshold-network/solidity-contracts/-/solidity-contracts-1.3.0-dev.11.tgz", - "integrity": "sha512-QQJB17BvuU/7UaitneoD7zFmIA3fZQ3FAvOAP2q+FkWEBZPYtAMf3+vB7y+Y+QlrcUl1kcA9wXD5auirsdxCBQ==", - "license": "GPL-3.0-or-later", - "dependencies": { - "@keep-network/keep-core": ">1.8.1-dev <1.8.1-goerli", - "@openzeppelin/contracts": "~4.5.0", - "@openzeppelin/contracts-upgradeable": "~4.5.2", - "@thesis/solidity-contracts": "github:thesis/solidity-contracts#4985bcf" - }, - "peerDependencies": { - "@keep-network/keep-core": ">1.8.1-dev <1.8.1-goerli" - } - }, - "node_modules/@keep-network/random-beacon/node_modules/@threshold-network/solidity-contracts/node_modules/@openzeppelin/contracts": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.5.0.tgz", - "integrity": "sha512-fdkzKPYMjrRiPK6K4y64e6GzULR7R7RwxSigHS8DDp7aWDeoReqsQI+cxHV1UuhAqX69L1lAaWDxenfP+xiqzA==", - "license": "MIT" - }, - "node_modules/@keep-network/sortition-pools": { - "version": "2.0.0-pre.16+main.dd9a1099e88a2738826436219d1cc3171eec2e76", - "license": "ISC", - "dependencies": { - "@openzeppelin/contracts": "^4.3.2", - "@thesis/solidity-contracts": "github:thesis/solidity-contracts#4985bcf" - } - }, - "node_modules/@noble/curves": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", - "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.7.2" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/curves/node_modules/@noble/hashes": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", - "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.2.tgz", - "integrity": "sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT" - }, - "node_modules/@noble/secp256k1": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.6.0.tgz", - "integrity": "sha512-DWSsg8zMHOYMYBqIQi96BQuthZrp98LCeMNcUOaffCIVYQ5yxDbNikLF+H7jEnmNNmXbtVic46iCuVWzar+MgA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT" - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nomicfoundation/edr": { - "version": "0.12.0-next.23", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.12.0-next.23.tgz", - "integrity": "sha512-F2/6HZh8Q9RsgkOIkRrckldbhPjIZY7d4mT9LYuW68miwGQ5l7CkAgcz9fRRiurA0+YJhtsbx/EyrD9DmX9BOw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nomicfoundation/edr-darwin-arm64": "0.12.0-next.23", - "@nomicfoundation/edr-darwin-x64": "0.12.0-next.23", - "@nomicfoundation/edr-linux-arm64-gnu": "0.12.0-next.23", - "@nomicfoundation/edr-linux-arm64-musl": "0.12.0-next.23", - "@nomicfoundation/edr-linux-x64-gnu": "0.12.0-next.23", - "@nomicfoundation/edr-linux-x64-musl": "0.12.0-next.23", - "@nomicfoundation/edr-win32-x64-msvc": "0.12.0-next.23" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/@nomicfoundation/edr-darwin-arm64": { - "version": "0.12.0-next.23", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.12.0-next.23.tgz", - "integrity": "sha512-Amh7mRoDzZyJJ4efqoePqdoZOzharmSOttZuJDlVE5yy07BoE8hL6ZRpa5fNYn0LCqn/KoWs8OHANWxhKDGhvQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - } - }, - "node_modules/@nomicfoundation/edr-darwin-x64": { - "version": "0.12.0-next.23", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.12.0-next.23.tgz", - "integrity": "sha512-9wn489FIQm7m0UCD+HhktjWx6vskZzeZD9oDc2k9ZvbBzdXwPp5tiDqUBJ+eQpByAzCDfteAJwRn2lQCE0U+Iw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - } - }, - "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { - "version": "0.12.0-next.23", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.12.0-next.23.tgz", - "integrity": "sha512-nlk5EejSzEUfEngv0Jkhqq3/wINIfF2ED9wAofc22w/V1DV99ASh9l3/e/MIHOQFecIZ9MDqt0Em9/oDyB1Uew==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - } - }, - "node_modules/@nomicfoundation/edr-linux-arm64-musl": { - "version": "0.12.0-next.23", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.12.0-next.23.tgz", - "integrity": "sha512-SJuPBp3Rc6vM92UtVTUxZQ/QlLhLfwTftt2XUiYohmGKB3RjGzpgduEFMCA0LEnucUckU6UHrJNFHiDm77C4PQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - } - }, - "node_modules/@nomicfoundation/edr-linux-x64-gnu": { - "version": "0.12.0-next.23", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.12.0-next.23.tgz", - "integrity": "sha512-NU+Qs3u7Qt6t3bJFdmmjd5CsvgI2bPPzO31KifM2Ez96/jsXYho5debtTQnimlb5NAqiHTSlxjh/F8ROcptmeQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - } - }, - "node_modules/@nomicfoundation/edr-linux-x64-musl": { - "version": "0.12.0-next.23", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.12.0-next.23.tgz", - "integrity": "sha512-F78fZA2h6/ssiCSZOovlgIu0dUeI7ItKPsDDF3UUlIibef052GCXmliMinC90jVPbrjUADMd1BUwjfI0Z8OllQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - } - }, - "node_modules/@nomicfoundation/edr-win32-x64-msvc": { - "version": "0.12.0-next.23", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.12.0-next.23.tgz", - "integrity": "sha512-IfJZQJn7d/YyqhmguBIGoCKjE9dKjbu6V6iNEPApfwf5JyyjHYyyfkLU4rf7hygj57bfH4sl1jtQ6r8HnT62lw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - } - }, - "node_modules/@nomicfoundation/ethereumjs-rlp": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.4.tgz", - "integrity": "sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw==", - "dev": true, - "license": "MPL-2.0", - "bin": { - "rlp": "bin/rlp.cjs" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@nomicfoundation/ethereumjs-util": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.4.tgz", - "integrity": "sha512-sLOzjnSrlx9Bb9EFNtHzK/FJFsfg2re6bsGqinFinH1gCqVfz9YYlXiMWwDM4C/L4ywuHFCYwfKTVr/QHQcU0Q==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "@nomicfoundation/ethereumjs-rlp": "5.0.4", - "ethereum-cryptography": "0.1.3" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "c-kzg": "^2.1.2" - }, - "peerDependenciesMeta": { - "c-kzg": { - "optional": true - } - } - }, - "node_modules/@nomicfoundation/hardhat-chai-matchers": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-1.0.6.tgz", - "integrity": "sha512-f5ZMNmabZeZegEfuxn/0kW+mm7+yV7VNDxLpMOMGXWFJ2l/Ct3QShujzDRF9cOkK9Ui/hbDeOWGZqyQALDXVCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ethersproject/abi": "^5.1.2", - "@types/chai-as-promised": "^7.1.3", - "chai-as-promised": "^7.1.1", - "deep-eql": "^4.0.1", - "ordinal": "^1.0.3" - }, - "peerDependencies": { - "@nomiclabs/hardhat-ethers": "^2.0.0", - "chai": "^4.2.0", - "ethers": "^5.0.0", - "hardhat": "^2.9.4" - } - }, - "node_modules/@nomicfoundation/hardhat-chai-matchers/node_modules/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@nomicfoundation/hardhat-verify": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.1.3.tgz", - "integrity": "sha512-danbGjPp2WBhLkJdQy9/ARM3WQIK+7vwzE0urNem1qZJjh9f54Kf5f1xuQv8DvqewUAkuPxVt/7q4Grz5WjqSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ethersproject/abi": "^5.1.2", - "@ethersproject/address": "^5.0.2", - "cbor": "^8.1.0", - "debug": "^4.1.1", - "lodash.clonedeep": "^4.5.0", - "picocolors": "^1.1.0", - "semver": "^6.3.0", - "table": "^6.8.0", - "undici": "^5.14.0" - }, - "peerDependencies": { - "hardhat": "^2.26.0" - } - }, - "node_modules/@nomicfoundation/hardhat-verify/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@nomicfoundation/slang": { - "version": "0.18.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/slang/-/slang-0.18.3.tgz", - "integrity": "sha512-YqAWgckqbHM0/CZxi9Nlf4hjk9wUNLC9ngWCWBiqMxPIZmzsVKYuChdlrfeBPQyvQQBoOhbx+7C1005kLVQDZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@bytecodealliance/preview2-shim": "0.17.0" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.2.tgz", - "integrity": "sha512-q4n32/FNKIhQ3zQGGw5CvPF6GTvDCpYwIf7bEY/dZTZbgfDsHyjJwURxUJf3VQuuJj+fDIFl4+KkBVbw4Ef6jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12" - }, - "optionalDependencies": { - "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.2", - "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.2", - "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.2", - "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.2", - "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.2", - "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.2", - "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.2" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-darwin-arm64": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.2.tgz", - "integrity": "sha512-JaqcWPDZENCvm++lFFGjrDd8mxtf+CtLd2MiXvMNTBD33dContTZ9TWETwNFwg7JTJT5Q9HEecH7FA+HTSsIUw==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.2.tgz", - "integrity": "sha512-fZNmVztrSXC03e9RONBT+CiksSeYcxI1wlzqyr0L7hsQlK1fzV+f04g2JtQ1c/Fe74ZwdV6aQBdd6Uwl1052sw==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.2.tgz", - "integrity": "sha512-3d54oc+9ZVBuB6nbp8wHylk4xh0N0Gc+bk+/uJae+rUgbOBwQSfuGIbAZt1wBXs5REkSmynEGcqx6DutoK0tPA==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.2.tgz", - "integrity": "sha512-iDJfR2qf55vgsg7BtJa7iPiFAsYf2d0Tv/0B+vhtnI16+wfQeTbP7teookbGvAo0eJo7aLLm0xfS/GTkvHIucA==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.2.tgz", - "integrity": "sha512-9dlHMAt5/2cpWyuJ9fQNOUXFB/vgSFORg1jpjX1Mh9hJ/MfZXlDdHQ+DpFCs32Zk5pxRBb07yGvSHk9/fezL+g==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.2.tgz", - "integrity": "sha512-GzzVeeJob3lfrSlDKQw2bRJ8rBf6mEYaWY+gW0JnTDHINA0s2gPR4km5RLIj1xeZZOYz4zRw+AEeYgLRqB2NXg==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.2.tgz", - "integrity": "sha512-Fdjli4DCcFHb4Zgsz0uEJXZ2K7VEO+w5KVv7HmT7WO10iODdU9csC2az4jrhEsRtiR9Gfd74FlG0NYlw1BMdyA==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomiclabs/hardhat-ethers": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.2.3.tgz", - "integrity": "sha512-YhzPdzb612X591FOe68q+qXVXGG2ANZRvDo0RRUtimev85rCrAlv/TLMEZw5c+kq9AbzocLTVX/h2jVIFPL9Xg==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "ethers": "^5.0.0", - "hardhat": "^2.0.0" - } - }, - "node_modules/@nomiclabs/hardhat-etherscan": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-3.1.8.tgz", - "integrity": "sha512-v5F6IzQhrsjHh6kQz4uNrym49brK9K5bYCq2zQZ729RYRaifI9hHbtmK+KkIVevfhut7huQFEQ77JLRMAzWYjQ==", - "deprecated": "The @nomiclabs/hardhat-etherscan package is deprecated, please use @nomicfoundation/hardhat-verify instead", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@ethersproject/abi": "^5.1.2", - "@ethersproject/address": "^5.0.2", - "cbor": "^8.1.0", - "chalk": "^2.4.2", - "debug": "^4.1.1", - "fs-extra": "^7.0.1", - "lodash": "^4.17.11", - "semver": "^6.3.0", - "table": "^6.8.0", - "undici": "^5.14.0" - }, - "peerDependencies": { - "hardhat": "^2.0.4" - } - }, - "node_modules/@nomiclabs/hardhat-etherscan/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@openzeppelin/contracts": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.9.6.tgz", - "integrity": "sha512-xSmezSupL+y9VkHZJGDoCBpmnB2ogM13ccaYDWqJTfS3dbuHkgjuwDFUmaFauBCboQMGB/S5UqUl2y54X99BmA==", - "license": "MIT" - }, - "node_modules/@openzeppelin/contracts-upgradeable": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.9.6.tgz", - "integrity": "sha512-m4iHazOsOCv1DgM7eD7GupTJ+NFVujRZt1wzddDPSVGpWdKq1SKkla5htKG7+IS4d2XOCtzkUNwRZ7Vq5aEUMA==", - "license": "MIT" - }, - "node_modules/@openzeppelin/defender-base-client": { - "version": "1.54.6", - "resolved": "https://registry.npmjs.org/@openzeppelin/defender-base-client/-/defender-base-client-1.54.6.tgz", - "integrity": "sha512-PTef+rMxkM5VQ7sLwLKSjp2DBakYQd661ZJiSRywx+q/nIpm3B/HYGcz5wPZCA5O/QcEP6TatXXDoeMwimbcnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "amazon-cognito-identity-js": "^6.0.1", - "async-retry": "^1.3.3", - "axios": "^1.4.0", - "lodash": "^4.17.19", - "node-fetch": "^2.6.0" - } - }, - "node_modules/@openzeppelin/defender-base-client/node_modules/axios": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.14.0.tgz", - "integrity": "sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.11", - "form-data": "^4.0.5", - "proxy-from-env": "^2.1.0" - } - }, - "node_modules/@openzeppelin/defender-base-client/node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "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/@openzeppelin/hardhat-upgrades": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/hardhat-upgrades/-/hardhat-upgrades-1.28.0.tgz", - "integrity": "sha512-7sb/Jf+X+uIufOBnmHR0FJVWuxEs2lpxjJnLNN6eCJCP8nD0v+Ot5lTOW2Qb/GFnh+fLvJtEkhkowz4ZQ57+zQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@openzeppelin/defender-base-client": "^1.46.0", - "@openzeppelin/platform-deploy-client": "^0.8.0", - "@openzeppelin/upgrades-core": "^1.27.0", - "chalk": "^4.1.0", - "debug": "^4.1.1", - "proper-lockfile": "^4.1.1" - }, - "bin": { - "migrate-oz-cli-project": "dist/scripts/migrate-oz-cli-project.js" - }, - "peerDependencies": { - "@nomiclabs/hardhat-ethers": "^2.0.0", - "@nomiclabs/hardhat-etherscan": "^3.1.0", - "ethers": "^5.0.5", - "hardhat": "^2.0.2" - }, - "peerDependenciesMeta": { - "@nomiclabs/harhdat-etherscan": { - "optional": true - } - } - }, - "node_modules/@openzeppelin/hardhat-upgrades/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "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/@openzeppelin/hardhat-upgrades/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/@openzeppelin/hardhat-upgrades/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@openzeppelin/hardhat-upgrades/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@openzeppelin/hardhat-upgrades/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@openzeppelin/hardhat-upgrades/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@openzeppelin/platform-deploy-client": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/platform-deploy-client/-/platform-deploy-client-0.8.0.tgz", - "integrity": "sha512-POx3AsnKwKSV/ZLOU/gheksj0Lq7Is1q2F3pKmcFjGZiibf+4kjGxr4eSMrT+2qgKYZQH1ZLQZ+SkbguD8fTvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ethersproject/abi": "^5.6.3", - "@openzeppelin/defender-base-client": "^1.46.0", - "axios": "^0.21.2", - "lodash": "^4.17.19", - "node-fetch": "^2.6.0" - } - }, - "node_modules/@openzeppelin/platform-deploy-client/node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "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/@openzeppelin/upgrades": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades/-/upgrades-2.8.0.tgz", - "integrity": "sha512-LzjTQPeljPsgHDPdZyH9cMCbIHZILgd2cpNcYEkdsC2IylBYRHShlbEDXJV9snnqg9JWfzPiKIqyj3XVliwtqQ==", - "deprecated": "The OpenZeppelin SDK is no longer being developed. For smart contract upgrades check out the OpenZeppelin Upgrades Plugins. https://zpl.in/upgrades-plugins", - "license": "MIT", - "dependencies": { - "@types/cbor": "^2.0.0", - "axios": "^0.18.0", - "bignumber.js": "^7.2.0", - "cbor": "^4.1.5", - "chalk": "^2.4.1", - "ethers": "^4.0.20", - "glob": "^7.1.3", - "lodash": "^4.17.15", - "semver": "^5.5.1", - "spinnies": "^0.4.2", - "truffle-flattener": "^1.4.0", - "web3": "1.2.2", - "web3-eth": "1.2.2", - "web3-eth-contract": "1.2.2", - "web3-utils": "1.2.2" - } - }, - "node_modules/@openzeppelin/upgrades-core": { - "version": "1.42.1", - "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.42.1.tgz", - "integrity": "sha512-8qnz2XfQrco8R8u9NjV+KiSLrVn7DnWFd+3BuhTUjhVy0bzCSu2SMKCVpZLtXbxf4f2dpz8jYPQYRa6s23PhLA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nomicfoundation/slang": "^0.18.3", - "cbor": "^10.0.0", - "chalk": "^4.1.0", - "compare-versions": "^6.0.0", - "debug": "^4.1.1", - "ethereumjs-util": "^7.0.3", - "minimatch": "^9.0.5", - "minimist": "^1.2.7", - "proper-lockfile": "^4.1.1", - "solidity-ast": "^0.4.51" - }, - "bin": { - "openzeppelin-upgrades-core": "dist/cli/cli.js" - } - }, - "node_modules/@openzeppelin/upgrades-core/node_modules/@types/bn.js": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.0.tgz", - "integrity": "sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@openzeppelin/upgrades-core/node_modules/@types/node": { - "version": "18.7.23", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.23.tgz", - "integrity": "sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@openzeppelin/upgrades-core/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "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/@openzeppelin/upgrades-core/node_modules/bn.js": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", - "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@openzeppelin/upgrades-core/node_modules/brace-expansion": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", - "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@openzeppelin/upgrades-core/node_modules/cbor": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/cbor/-/cbor-10.0.3.tgz", - "integrity": "sha512-72Jnj81xMsqepqdcSdf2+fflz/UDsThOHy5hj2MW5F5xzHL8Oa0KQ6I6V9CwVUPxg5pf+W9xp6W2KilaRXWWtw==", - "dev": true, - "license": "MIT", - "dependencies": { - "nofilter": "^3.0.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@openzeppelin/upgrades-core/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/@openzeppelin/upgrades-core/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@openzeppelin/upgrades-core/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@openzeppelin/upgrades-core/node_modules/ethereumjs-util": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.4.tgz", - "integrity": "sha512-p6KmuPCX4mZIqsQzXfmSx9Y0l2hqf+VkAiwSisW3UKUFdk8ZkAt+AYaor83z2nSi6CU2zSsXMlD80hAbNEGM0A==", - "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/@openzeppelin/upgrades-core/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@openzeppelin/upgrades-core/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@openzeppelin/upgrades-core/node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/@openzeppelin/upgrades-core/node_modules/nofilter": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", - "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.19" - } - }, - "node_modules/@openzeppelin/upgrades-core/node_modules/solidity-ast": { - "version": "0.4.59", - "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.59.tgz", - "integrity": "sha512-I+CX0wrYUN9jDfYtcgWSe+OAowaXy8/1YQy7NS4ni5IBDmIYBq7ZzaP/7QqouLjzZapmQtvGLqCaYgoUWqBo5g==", - "dev": true, - "license": "MIT" - }, - "node_modules/@openzeppelin/upgrades-core/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@openzeppelin/upgrades/node_modules/axios": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz", - "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==", - "deprecated": "Critical security vulnerability fixed in v0.21.1. For more information, see https://github.com/axios/axios/pull/3410", - "license": "MIT", - "dependencies": { - "follow-redirects": "1.5.10", - "is-buffer": "^2.0.2" - } - }, - "node_modules/@openzeppelin/upgrades/node_modules/bignumber.js": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", - "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/@openzeppelin/upgrades/node_modules/cbor": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/cbor/-/cbor-4.3.0.tgz", - "integrity": "sha512-CvzaxQlaJVa88sdtTWvLJ++MbdtPHtZOBBNjm7h3YKUHILMs9nQyD4AC6hvFZy7GBVB3I6bRibJcxeHydyT2IQ==", - "license": "MIT", - "dependencies": { - "bignumber.js": "^9.0.0", - "commander": "^3.0.0", - "json-text-sequence": "^0.1", - "nofilter": "^1.0.3" - }, - "bin": { - "cbor2comment": "bin/cbor2comment", - "cbor2diag": "bin/cbor2diag", - "cbor2json": "bin/cbor2json", - "json2cbor": "bin/json2cbor" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@openzeppelin/upgrades/node_modules/cbor/node_modules/bignumber.js": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", - "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/@openzeppelin/upgrades/node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/@openzeppelin/upgrades/node_modules/ethers": { - "version": "4.0.49", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.49.tgz", - "integrity": "sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg==", - "license": "MIT", - "dependencies": { - "aes-js": "3.0.0", - "bn.js": "^4.11.9", - "elliptic": "6.5.4", - "hash.js": "1.1.3", - "js-sha3": "0.5.7", - "scrypt-js": "2.0.4", - "setimmediate": "1.0.4", - "uuid": "2.0.1", - "xmlhttprequest": "1.8.0" - } - }, - "node_modules/@openzeppelin/upgrades/node_modules/follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", - "license": "MIT", - "dependencies": { - "debug": "=3.1.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/@openzeppelin/upgrades/node_modules/hash.js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/@openzeppelin/upgrades/node_modules/is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "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", - "engines": { - "node": ">=4" - } - }, - "node_modules/@openzeppelin/upgrades/node_modules/js-sha3": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", - "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", - "license": "MIT" - }, - "node_modules/@openzeppelin/upgrades/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/@openzeppelin/upgrades/node_modules/scrypt-js": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", - "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==", - "license": "MIT" - }, - "node_modules/@openzeppelin/upgrades/node_modules/setimmediate": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", - "integrity": "sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog==", - "license": "MIT" - }, - "node_modules/@pkgr/core": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", - "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/pkgr" - } - }, - "node_modules/@resolver-engine/core": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@resolver-engine/core/-/core-0.2.1.tgz", - "integrity": "sha512-nsLQHmPJ77QuifqsIvqjaF5B9aHnDzJjp73Q1z6apY3e9nqYrx4Dtowhpsf7Jwftg/XzVDEMQC+OzUBNTS+S1A==", - "license": "LGPL-3.0-or-later", - "dependencies": { - "debug": "^3.1.0", - "request": "^2.85.0" - } - }, - "node_modules/@resolver-engine/core/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/@rtsao/scc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", - "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", - "dev": true, - "license": "MIT" - }, - "node_modules/@scure/base": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", - "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip32": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.0.tgz", - "integrity": "sha512-ftTW3kKX54YXLCxH6BB7oEEoJfoE2pIgw7MINKAs5PsS6nqKPuKk1haTF/EuHmYqG330t5GSrdmtRuHaY1a62Q==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.1.1", - "@noble/secp256k1": "~1.6.0", - "@scure/base": "~1.1.0" - } - }, - "node_modules/@scure/bip39": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.0.tgz", - "integrity": "sha512-pwrPOS16VeTKg98dYXQyIjJEcWfz7/1YJIwxUEPFfQPtc86Ym/1sVgQ2RLoD43AazMk2l/unK4ITySSpW2+82w==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.1.1", - "@scure/base": "~1.1.0" - } - }, - "node_modules/@sentry/core": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", - "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sentry/hub": "5.30.0", - "@sentry/minimal": "5.30.0", - "@sentry/types": "5.30.0", - "@sentry/utils": "5.30.0", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/hub": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", - "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sentry/types": "5.30.0", - "@sentry/utils": "5.30.0", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/minimal": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", - "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sentry/hub": "5.30.0", - "@sentry/types": "5.30.0", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/node": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.30.0.tgz", - "integrity": "sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sentry/core": "5.30.0", - "@sentry/hub": "5.30.0", - "@sentry/tracing": "5.30.0", - "@sentry/types": "5.30.0", - "@sentry/utils": "5.30.0", - "cookie": "^0.4.1", - "https-proxy-agent": "^5.0.0", - "lru_map": "^0.3.3", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/tracing": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.30.0.tgz", - "integrity": "sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sentry/hub": "5.30.0", - "@sentry/minimal": "5.30.0", - "@sentry/types": "5.30.0", - "@sentry/utils": "5.30.0", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/types": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", - "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/utils": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", - "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sentry/types": "5.30.0", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/types/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD" - }, - "node_modules/@solidity-parser/parser": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.5.tgz", - "integrity": "sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==", - "license": "MIT", - "dependencies": { - "antlr4ts": "^0.5.0-alpha.4" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "license": "MIT", - "dependencies": { - "defer-to-connect": "^1.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@tenderly/hardhat-tenderly": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@tenderly/hardhat-tenderly/-/hardhat-tenderly-1.1.6.tgz", - "integrity": "sha512-B6vVdDAxQwjahrvsxjNirJW2ynDENLBD8LLFy8sYVJ+RCb4B8HXT1IGSceqpySNPr2iLYcD5cKC/YCHX+/O48Q==", - "dev": true, - "dependencies": { - "@ethersproject/bignumber": "^5.6.2", - "@nomiclabs/hardhat-ethers": "^2.0.6", - "axios": "^0.21.1", - "ethers": "^5.6.8", - "fs-extra": "^9.0.1", - "hardhat-deploy": "^0.11.10", - "js-yaml": "^3.14.0" - }, - "peerDependencies": { - "hardhat": "^2.10.1" - } - }, - "node_modules/@tenderly/hardhat-tenderly/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@tenderly/hardhat-tenderly/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@thesis-co/eslint-config": { - "version": "0.8.0-pre", - "resolved": "git+ssh://git@github.com/thesis/eslint-config.git#3b7128d0489ec49c3b290c32e5536281550cd1eb", - "dev": true, - "license": "MIT", - "dependencies": { - "@thesis-co/prettier-config": "github:thesis/prettier-config", - "@typescript-eslint/eslint-plugin": ">=6.4.1", - "@typescript-eslint/parser": ">=6.4.1", - "eslint-config-airbnb": "^19.0.4", - "eslint-config-airbnb-base": "^15.0.0", - "eslint-config-airbnb-typescript": "^17.1.0", - "eslint-config-prettier": "^9.0.0", - "eslint-plugin-import": "^2.28.1", - "eslint-plugin-jsx-a11y": "^6.7.1", - "eslint-plugin-no-only-tests": "^3.1.0", - "eslint-plugin-prettier": "^5.0.0", - "eslint-plugin-react": "^7.33.2", - "eslint-plugin-react-hooks": "^4.6.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "eslint": ">=6.8.0" - } - }, - "node_modules/@thesis-co/prettier-config": { - "name": "@thesis/prettier-config", - "version": "0.0.2", - "resolved": "git+ssh://git@github.com/thesis/prettier-config.git#daeaac564056a7885e4366ce12bfde6fd823fc90", - "dev": true, - "license": "MIT", - "peerDependencies": { - "prettier": ">=2.3.0 <4" - } - }, - "node_modules/@thesis/solidity-contracts": { - "version": "0.0.1", - "resolved": "git+ssh://git@github.com/thesis/solidity-contracts.git#4985bcfc28e36eed9838993b16710e1b500f9e85", - "license": "MIT", - "dependencies": { - "@openzeppelin/contracts": "^4.1.0" - } - }, - "node_modules/@threshold-network/solidity-contracts": { - "version": "1.3.0-dev.16", - "resolved": "https://registry.npmjs.org/@threshold-network/solidity-contracts/-/solidity-contracts-1.3.0-dev.16.tgz", - "integrity": "sha512-/sXWbjTPxRxnzs8FsV3a9rAk7k+4dCBkv/Rsa5aGwQy3AlVDjNRCbKkg4kzZXYQGZ8DgjZeqfUm3ZjbUXeWajw==", - "license": "GPL-3.0-or-later", - "dependencies": { - "@openzeppelin/contracts": "~4.5.0", - "@openzeppelin/contracts-upgradeable": "~4.5.2", - "@thesis/solidity-contracts": "github:thesis/solidity-contracts#4985bcf" - } - }, - "node_modules/@threshold-network/solidity-contracts/node_modules/@openzeppelin/contracts": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.5.0.tgz", - "integrity": "sha512-fdkzKPYMjrRiPK6K4y64e6GzULR7R7RwxSigHS8DDp7aWDeoReqsQI+cxHV1UuhAqX69L1lAaWDxenfP+xiqzA==", - "license": "MIT" - }, - "node_modules/@threshold-network/solidity-contracts/node_modules/@openzeppelin/contracts-upgradeable": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.5.2.tgz", - "integrity": "sha512-xgWZYaPlrEOQo3cBj97Ufiuv79SPd8Brh4GcFYhPgb6WvAq4ppz8dWKL6h+jLAK01rUqMRp/TS9AdXgAeNvCLA==", - "license": "MIT" - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", - "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", - "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", - "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", - "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@typechain/ethers-v5": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/@typechain/ethers-v5/-/ethers-v5-8.0.5.tgz", - "integrity": "sha512-ntpj4cS3v4WlDu+hSKSyj9A3o1tKtWC30RX1gobeYymZColeJiUemC1Kgfa0MWGmInm5CKxoHVhEvYVgPOZn1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "lodash": "^4.17.15", - "ts-essentials": "^7.0.1" - }, - "peerDependencies": { - "@ethersproject/abi": "^5.0.0", - "@ethersproject/bytes": "^5.0.0", - "@ethersproject/providers": "^5.0.0", - "ethers": "^5.1.3", - "typechain": "^6.0.4", - "typescript": ">=4.0.0" - } - }, - "node_modules/@typechain/hardhat": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@typechain/hardhat/-/hardhat-4.0.0.tgz", - "integrity": "sha512-SeEKtiHu4Io3LHhE8VV3orJbsj7dwJZX8pzSTv7WQR38P18vOLm2M52GrykVinMpkLK0uVc88ICT58emvfn74w==", - "dev": true, - "license": "MIT", - "dependencies": { - "fs-extra": "^9.1.0" - }, - "peerDependencies": { - "hardhat": "^2.0.10", - "lodash": "^4.17.15", - "typechain": "^7.0.0" - } - }, - "node_modules/@typechain/hardhat/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typechain/hardhat/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@types/bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/bn.js/node_modules/@types/node": { - "version": "18.7.23", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.23.tgz", - "integrity": "sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg==", - "license": "MIT" - }, - "node_modules/@types/cbor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/cbor/-/cbor-2.0.0.tgz", - "integrity": "sha512-yQH0JLcrHrH/GBIFFFq6DAsj9M4rmYsmSpGGGs67JrLGWPepYr2c1YugGjMd2Ib5pebluRAfNPJ4O1p80qX9HQ==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/chai": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.0.tgz", - "integrity": "sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/chai-as-promised": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.5.tgz", - "integrity": "sha512-jStwss93SITGBwt/niYrkf2C+/1KTeZCZl1LaeezTlqppAKeoQC7jxyqYuP72sxBGKCIbw7oHgbYssIRzT5FCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/chai": "*" - } - }, - "node_modules/@types/concat-stream": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", - "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/concat-stream/node_modules/@types/node": { - "version": "18.7.23", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.23.tgz", - "integrity": "sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/form-data": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", - "integrity": "sha1-yayFsqX9GENbjIXZ7LUObWyJP/g=", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/form-data/node_modules/@types/node": { - "version": "18.7.23", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.23.tgz", - "integrity": "sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/mocha": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.0.tgz", - "integrity": "sha512-QCWHkbMv4Y5U9oW10Uxbr45qMMSzl4OzijsozynUAgx3kEHUdXB00udx2dWDQ7f2TU2a2uuiFaRZjCe3unPpeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "17.0.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.10.tgz", - "integrity": "sha512-S/3xB4KzyFxYGCppyDt68yzBU9ysL88lSdIah4D6cptdcltc4NCPCAMc0+PCpg/lLIyC7IPvj2Z52OJWeIUkog==", - "license": "MIT" - }, - "node_modules/@types/pbkdf2": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz", - "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/pbkdf2/node_modules/@types/node": { - "version": "18.7.23", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.23.tgz", - "integrity": "sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg==", - "license": "MIT" - }, - "node_modules/@types/prettier": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.3.tgz", - "integrity": "sha512-QzSuZMBuG5u8HqYz01qtMdg/Jfctlnvj1z/lYnIDXs/golxw0fxtRAHd9KrzjR7Yxz1qVeI00o0kiO3PmVdJ9w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/secp256k1": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.3.tgz", - "integrity": "sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/secp256k1/node_modules/@types/node": { - "version": "18.7.23", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.23.tgz", - "integrity": "sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg==", - "license": "MIT" - }, - "node_modules/@types/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", - "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", - "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", - "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", - "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", - "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/adm-zip": { - "version": "0.4.16", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", - "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.3.0" - } - }, - "node_modules/aes-js": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", - "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", - "license": "MIT" - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", - "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/amazon-cognito-identity-js": { - "version": "6.3.12", - "resolved": "https://registry.npmjs.org/amazon-cognito-identity-js/-/amazon-cognito-identity-js-6.3.12.tgz", - "integrity": "sha512-s7NKDZgx336cp+oDeUtB2ZzT8jWJp/v2LWuYl+LQtMEODe22RF1IJ4nRiDATp+rp1pTffCZcm44Quw4jx2bqNg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-js": "1.2.2", - "buffer": "4.9.2", - "fast-base64-decode": "^1.0.0", - "isomorphic-unfetch": "^3.0.0", - "js-cookie": "^2.2.1" - } - }, - "node_modules/amazon-cognito-identity-js/node_modules/buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "dev": true, - "license": "MIT", - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "node_modules/ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.1.0" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/antlr4": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.7.1.tgz", - "integrity": "sha512-haHyTW7Y9joE5MVs37P2lNYfU2RWBLfcRDD8OWldcdZm5TiCE91B5Xl1oWSwiDUSd4rlExpt2pu1fksYQjRBYQ==", - "dev": true, - "license": "BSD" - }, - "node_modules/antlr4ts": { - "version": "0.5.0-alpha.4", - "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", - "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==", - "license": "BSD-3-Clause" - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "license": "MIT" - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, - "license": "MIT" - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/aria-query": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", - "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", - "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "is-array-buffer": "^3.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "license": "MIT" - }, - "node_modules/array-includes": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", - "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.24.0", - "es-object-atoms": "^1.1.1", - "get-intrinsic": "^1.3.0", - "is-string": "^1.1.1", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array.prototype.findlast": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", - "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", - "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-shim-unscopables": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", - "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", - "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", - "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", - "dev": true, - "license": "MIT", - "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" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", - "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", - "dev": true, - "license": "MIT" - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "license": "MIT", - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/ast-parents": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/ast-parents/-/ast-parents-0.0.1.tgz", - "integrity": "sha1-UI/Q8F0MSHddnszaLhdEIyYejdM=", - "dev": true, - "license": "MIT" - }, - "node_modules/ast-types-flow": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", - "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/async-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", - "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", - "license": "MIT" - }, - "node_modules/async-retry": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", - "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "retry": "0.13.1" - } - }, - "node_modules/async-retry/node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "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", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "license": "Apache-2.0", - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "license": "MIT" - }, - "node_modules/axe-core": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.0.tgz", - "integrity": "sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==", - "dev": true, - "license": "MPL-2.0", - "engines": { - "node": ">=4" - } - }, - "node_modules/axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.14.0" - } - }, - "node_modules/axobject-query": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", - "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" - }, - "node_modules/base-x": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", - "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "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", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "license": "BSD-3-Clause", - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/bech32": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", - "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/bl": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", - "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", - "license": "MIT", - "dependencies": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" - } - }, - "node_modules/bl/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/bl/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/blakejs": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", - "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", - "license": "MIT" - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "license": "MIT" - }, - "node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", - "license": "MIT" - }, - "node_modules/body-parser": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", - "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", - "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.1", - "iconv-lite": "~0.4.24", - "on-finished": "~2.4.1", - "qs": "~6.14.0", - "raw-body": "~2.5.3", - "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", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.14.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", - "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/boxen/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "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/boxen/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/boxen/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/boxen/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/boxen/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/boxen/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/boxen/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/boxen/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/boxen/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", - "license": "MIT" - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true, - "license": "ISC" - }, - "node_modules/browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "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/browserify-aes/node_modules/buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", - "license": "MIT" - }, - "node_modules/browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "license": "MIT", - "dependencies": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "node_modules/browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/browserify-rsa": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", - "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", - "license": "MIT", - "dependencies": { - "bn.js": "^5.2.1", - "randombytes": "^2.1.0", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/browserify-rsa/node_modules/bn.js": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", - "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", - "license": "MIT" - }, - "node_modules/browserify-sign": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.5.tgz", - "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", - "license": "ISC", - "dependencies": { - "bn.js": "^5.2.2", - "browserify-rsa": "^4.1.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.6.1", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.9", - "readable-stream": "^2.3.8", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/browserify-sign/node_modules/bn.js": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", - "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", - "license": "MIT" - }, - "node_modules/browserify-sign/node_modules/elliptic": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", - "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", - "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/browserify-sign/node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", - "license": "MIT" - }, - "node_modules/browserify-sign/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/browserify-sign/node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/bs58": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", - "license": "MIT", - "dependencies": { - "base-x": "^3.0.2" - } - }, - "node_modules/bs58check": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", - "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", - "license": "MIT", - "dependencies": { - "bs58": "^4.0.0", - "create-hash": "^1.1.0", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "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/buffer-alloc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", - "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", - "license": "MIT", - "dependencies": { - "buffer-alloc-unsafe": "^1.1.0", - "buffer-fill": "^1.0.0" - } - }, - "node_modules/buffer-alloc-unsafe": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", - "license": "MIT" - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/buffer-fill": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==", - "license": "MIT" - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/buffer-to-arraybuffer": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", - "integrity": "sha512-3dthu5CYiVB1DEJp61FtApNnNndTckcqe4pFcLdvHtrpG+kcyekCJKg4MRiDcFW7A6AODnXB9U4dwQiCW5kzJQ==", - "license": "MIT" - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "license": "MIT", - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "license": "MIT", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cacheable-request/node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/caller-callsite/node_modules/callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dev": true, - "license": "MIT", - "dependencies": { - "caller-callsite": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "license": "Apache-2.0" - }, - "node_modules/cbor": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz", - "integrity": "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==", - "dev": true, - "license": "MIT", - "dependencies": { - "nofilter": "^3.1.0" - }, - "engines": { - "node": ">=12.19" - } - }, - "node_modules/cbor/node_modules/nofilter": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", - "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.19" - } - }, - "node_modules/chai": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz", - "integrity": "sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==", - "dev": true, - "license": "MIT", - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "pathval": "^1.1.1", - "type-detect": "^4.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chai-as-promised": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", - "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", - "dev": true, - "license": "WTFPL", - "dependencies": { - "check-error": "^1.0.2" - }, - "peerDependencies": { - "chai": ">= 2.1.2 < 5" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true, - "license": "MIT" - }, - "node_modules/charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": "*" - } - }, - "node_modules/check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "license": "ISC" - }, - "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/cipher-base": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz", - "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1", - "to-buffer": "^1.2.2" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cli-table3": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.1.tgz", - "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==", - "dev": true, - "license": "MIT", - "dependencies": { - "string-width": "^4.2.0" - }, - "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "colors": "1.4.0" - } - }, - "node_modules/cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true, - "license": "ISC" - }, - "node_modules/clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "license": "MIT", - "dependencies": { - "mimic-response": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "license": "MIT" - }, - "node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/command-exists": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", - "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", - "dev": true, - "license": "MIT" - }, - "node_modules/command-line-args": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.0.tgz", - "integrity": "sha512-4zqtU1hYsSJzcJBOcNZIbW5Fbk9BkjCp1pZVhQKoRaWL5J7N4XphDLwo8aWwdQpTugxwu+jf9u2ZhkXiqp5Z6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-back": "^3.1.0", - "find-replace": "^3.0.0", - "lodash.camelcase": "^4.3.0", - "typical": "^4.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/command-line-args/node_modules/array-back": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", - "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/command-line-args/node_modules/typical": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", - "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/command-line-usage": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.1.tgz", - "integrity": "sha512-F59pEuAR9o1SF/bD0dQBDluhpT4jJQNWUHEuVBqpDmCUo6gPjCi+m9fCWnWZVR/oG6cMTUms4h+3NPl74wGXvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-back": "^4.0.1", - "chalk": "^2.4.2", - "table-layout": "^1.0.1", - "typical": "^5.2.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/command-line-usage/node_modules/array-back": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", - "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/command-line-usage/node_modules/typical": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", - "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/commander": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", - "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", - "license": "MIT" - }, - "node_modules/compare-versions": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", - "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "license": "MIT" - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/concat-stream/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/concat-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/confusing-browser-globals": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", - "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", - "dev": true, - "license": "MIT" - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", - "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", - "license": "MIT" - }, - "node_modules/cookiejar": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", - "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", - "license": "MIT" - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "license": "MIT" - }, - "node_modules/cors": { - "version": "2.8.6", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", - "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", - "dev": true, - "license": "MIT", - "dependencies": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cosmiconfig/node_modules/import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "dev": true, - "license": "MIT", - "dependencies": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - } - }, - "node_modules/create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "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", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "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/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", - "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", - "dev": true, - "license": "MIT", - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": "*" - } - }, - "node_modules/crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "license": "MIT", - "dependencies": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - }, - "engines": { - "node": "*" - } - }, - "node_modules/d": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", - "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", - "license": "ISC", - "dependencies": { - "es5-ext": "^0.10.64", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "license": "MIT", - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/data-view-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", - "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", - "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/inspect-js" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", - "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/decompress": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.1.tgz", - "integrity": "sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ==", - "license": "MIT", - "dependencies": { - "decompress-tar": "^4.0.0", - "decompress-tarbz2": "^4.0.0", - "decompress-targz": "^4.0.0", - "decompress-unzip": "^4.0.1", - "graceful-fs": "^4.1.10", - "make-dir": "^1.0.0", - "pify": "^2.3.0", - "strip-dirs": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", - "license": "MIT", - "dependencies": { - "mimic-response": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-tar": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", - "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", - "license": "MIT", - "dependencies": { - "file-type": "^5.2.0", - "is-stream": "^1.1.0", - "tar-stream": "^1.5.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-tarbz2": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", - "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", - "license": "MIT", - "dependencies": { - "decompress-tar": "^4.1.0", - "file-type": "^6.1.0", - "is-stream": "^1.1.0", - "seek-bzip": "^1.0.5", - "unbzip2-stream": "^1.0.9" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-tarbz2/node_modules/file-type": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", - "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-targz": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", - "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", - "license": "MIT", - "dependencies": { - "decompress-tar": "^4.1.1", - "file-type": "^5.2.0", - "is-stream": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-unzip": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", - "integrity": "sha512-1fqeluvxgnn86MOh66u8FjbtJpAFv5wgCT9Iw8rcBqQcCo5tO8eiJw7NNTrvt9n4CRBVq7CstiS922oPgyGLrw==", - "license": "MIT", - "dependencies": { - "file-type": "^3.8.0", - "get-stream": "^2.2.0", - "pify": "^2.3.0", - "yauzl": "^2.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-unzip/node_modules/file-type": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", - "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decompress-unzip/node_modules/get-stream": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", - "integrity": "sha512-AUGhbbemXxrZJRD5cDvKtQxLuYaIbNtDTK8YqupCI393Q2KSTreEsLUN3ZxAWFGiKTzL6nKuzfcIvieflUX9qA==", - "license": "MIT", - "dependencies": { - "object-assign": "^4.0.1", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", - "license": "MIT" - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "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/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/delimit-stream": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/delimit-stream/-/delimit-stream-0.1.0.tgz", - "integrity": "sha512-a02fiQ7poS5CnjiJBAsjGLPp5EwVoGHNeu9sziBd9huppRfsAFIpv5zNLv0V1gbop53ilngAf5Kf331AwcoRBQ==", - "license": "BSD-2-Clause" - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/des.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", - "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/diff": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.2.tgz", - "integrity": "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dir-glob/node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/dom-walk": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", - "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/duplexer3": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", - "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==", - "license": "BSD-3-Clause" - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "license": "MIT", - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, - "node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "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/emoji-regex": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.0.0.tgz", - "integrity": "sha512-KmJa8l6uHi1HrBI34udwlzZY1jOEuID/ft4d8BSSEdRyap7PwBEt910453PJa5MuGvxkLqlt4Uvhu7tttFHViw==", - "dev": true, - "license": "MIT" - }, - "node_modules/encode-utf8": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz", - "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==", - "dev": true, - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.2", - "arraybuffer.prototype.slice": "^1.0.4", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "data-view-buffer": "^1.0.2", - "data-view-byte-length": "^1.0.2", - "data-view-byte-offset": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-set-tostringtag": "^2.1.0", - "es-to-primitive": "^1.3.0", - "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.3.0", - "get-proto": "^1.0.1", - "get-symbol-description": "^1.1.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "internal-slot": "^1.1.0", - "is-array-buffer": "^3.0.5", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.2", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.2.1", - "is-set": "^2.0.3", - "is-shared-array-buffer": "^1.0.4", - "is-string": "^1.1.1", - "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.1", - "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.7", - "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.4", - "safe-array-concat": "^1.1.3", - "safe-push-apply": "^1.0.0", - "safe-regex-test": "^1.1.0", - "set-proto": "^1.0.0", - "stop-iteration-iterator": "^1.1.0", - "string.prototype.trim": "^1.2.10", - "string.prototype.trimend": "^1.0.9", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.3", - "typed-array-byte-length": "^1.0.3", - "typed-array-byte-offset": "^1.0.4", - "typed-array-length": "^1.0.7", - "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.19" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-abstract/node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-iterator-helpers": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", - "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.6", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.3", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.6", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "internal-slot": "^1.1.0", - "iterator.prototype": "^1.1.4", - "safe-array-concat": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", - "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-to-primitive": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", - "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7", - "is-date-object": "^1.0.5", - "is-symbol": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es5-ext": { - "version": "0.10.64", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", - "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", - "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", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "license": "MIT", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", - "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", - "license": "ISC", - "dependencies": { - "d": "^1.0.2", - "ext": "^1.7.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-airbnb": { - "version": "19.0.4", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz", - "integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-config-airbnb-base": "^15.0.0", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5" - }, - "engines": { - "node": "^10.12.0 || ^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.3", - "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.28.0", - "eslint-plugin-react-hooks": "^4.3.0" - } - }, - "node_modules/eslint-config-airbnb-base": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", - "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", - "dev": true, - "license": "MIT", - "dependencies": { - "confusing-browser-globals": "^1.0.10", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5", - "semver": "^6.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "peerDependencies": { - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.2" - } - }, - "node_modules/eslint-config-airbnb-base/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-config-airbnb-typescript": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.1.0.tgz", - "integrity": "sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-config-airbnb-base": "^15.0.0" - }, - "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^5.13.0 || ^6.0.0", - "@typescript-eslint/parser": "^5.0.0 || ^6.0.0", - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.3" - } - }, - "node_modules/eslint-config-prettier": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.2.tgz", - "integrity": "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==", - "dev": true, - "license": "MIT", - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", - "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.32.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", - "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rtsao/scc": "^1.1.0", - "array-includes": "^3.1.9", - "array.prototype.findlastindex": "^1.2.6", - "array.prototype.flat": "^1.3.3", - "array.prototype.flatmap": "^1.3.3", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.12.1", - "hasown": "^2.0.2", - "is-core-module": "^2.16.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "object.groupby": "^1.0.3", - "object.values": "^1.2.1", - "semver": "^6.3.1", - "string.prototype.trimend": "^1.0.9", - "tsconfig-paths": "^3.15.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", - "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "aria-query": "^5.3.2", - "array-includes": "^3.1.8", - "array.prototype.flatmap": "^1.3.2", - "ast-types-flow": "^0.0.8", - "axe-core": "^4.10.0", - "axobject-query": "^4.1.0", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "hasown": "^2.0.2", - "jsx-ast-utils": "^3.3.5", - "language-tags": "^1.0.9", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "safe-regex-test": "^1.0.3", - "string.prototype.includes": "^2.0.1" - }, - "engines": { - "node": ">=4.0" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" - } - }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/eslint-plugin-no-only-tests": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-no-only-tests/-/eslint-plugin-no-only-tests-3.3.0.tgz", - "integrity": "sha512-brcKcxGnISN2CcVhXJ/kEQlNa0MEfGRtwKtWA16SkqXHKitaKIMrfemJKLKX1YqDU5C/5JY3PvZXd5jEW04e0Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=5.0.0" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.4.tgz", - "integrity": "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==", - "dev": true, - "license": "MIT", - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.11.7" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-react": { - "version": "7.37.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", - "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-includes": "^3.1.8", - "array.prototype.findlast": "^1.2.5", - "array.prototype.flatmap": "^1.3.3", - "array.prototype.tosorted": "^1.1.4", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.2.1", - "estraverse": "^5.3.0", - "hasown": "^2.0.2", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.9", - "object.fromentries": "^2.0.8", - "object.values": "^1.2.1", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.5", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.12", - "string.prototype.repeat": "^1.0.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", - "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/eslint-plugin-react/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-scope/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "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/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/eslint/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/eslint/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/eslint/node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/eslint/node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/esniff": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", - "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", - "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/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eth-ens-namehash": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz", - "integrity": "sha512-VWEI1+KJfz4Km//dadyvBBoBeSQ0MHTXPvr8UIXiLW6IanxvAV+DmlZAijZwAyggqGUfwQBeHf7tc9wzc1piSw==", - "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", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", - "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", - "license": "MIT" - }, - "node_modules/eth-gas-reporter": { - "version": "0.2.27", - "resolved": "https://registry.npmjs.org/eth-gas-reporter/-/eth-gas-reporter-0.2.27.tgz", - "integrity": "sha512-femhvoAM7wL0GcI8ozTdxfuBtBFJ9qsyIAsmKVjlWAHUbdnnXHt+lKzz/kmldM5lA9jLuNHGwuIxorNpLbR1Zw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@solidity-parser/parser": "^0.14.0", - "axios": "^1.5.1", - "cli-table3": "^0.5.0", - "colors": "1.4.0", - "ethereum-cryptography": "^1.0.3", - "ethers": "^5.7.2", - "fs-readdir-recursive": "^1.1.0", - "lodash": "^4.17.14", - "markdown-table": "^1.1.3", - "mocha": "^10.2.0", - "req-cwd": "^2.0.0", - "sha1": "^1.1.1", - "sync-request": "^6.0.0" - }, - "peerDependencies": { - "@codechecks/client": "^0.1.0" - }, - "peerDependenciesMeta": { - "@codechecks/client": { - "optional": true - } - } - }, - "node_modules/eth-gas-reporter/node_modules/@noble/hashes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", - "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT" - }, - "node_modules/eth-gas-reporter/node_modules/@noble/secp256k1": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", - "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT" - }, - "node_modules/eth-gas-reporter/node_modules/@scure/bip32": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", - "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.2.0", - "@noble/secp256k1": "~1.7.0", - "@scure/base": "~1.1.0" - } - }, - "node_modules/eth-gas-reporter/node_modules/@scure/bip39": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", - "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.2.0", - "@scure/base": "~1.1.0" - } - }, - "node_modules/eth-gas-reporter/node_modules/ansi-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/eth-gas-reporter/node_modules/axios": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.14.0.tgz", - "integrity": "sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.11", - "form-data": "^4.0.5", - "proxy-from-env": "^2.1.0" - } - }, - "node_modules/eth-gas-reporter/node_modules/cli-table3": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", - "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "object-assign": "^4.1.0", - "string-width": "^2.1.1" - }, - "engines": { - "node": ">=6" - }, - "optionalDependencies": { - "colors": "^1.1.2" - } - }, - "node_modules/eth-gas-reporter/node_modules/ethereum-cryptography": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", - "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.2.0", - "@noble/secp256k1": "1.7.1", - "@scure/bip32": "1.1.5", - "@scure/bip39": "1.1.1" - } - }, - "node_modules/eth-gas-reporter/node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eth-gas-reporter/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eth-lib": { - "version": "0.1.29", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.29.tgz", - "integrity": "sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ==", - "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/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/eth-lib/node_modules/ws": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", - "license": "MIT", - "dependencies": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0", - "ultron": "~1.1.0" - } - }, - "node_modules/ethereum-bloom-filters": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz", - "integrity": "sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==", - "license": "MIT", - "dependencies": { - "js-sha3": "^0.8.0" - } - }, - "node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "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-common": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-1.5.2.tgz", - "integrity": "sha512-hTfZjwGX52GS2jcVO6E2sx4YuFnf0Fhp5ylo4pEPhEffNln7vS59Hr5sLnp3/QCazFLluuBZ+FZ6J5HTp0EqCA==", - "license": "MIT" - }, - "node_modules/ethereumjs-tx": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz", - "integrity": "sha512-zZEK1onCeiORb0wyCXUvg94Ve5It/K6GD1K+26KfFKodiBiS6d9lfCXlUKGBBdQ+bv7Day+JK0tj1K+BeNFRAw==", - "license": "MPL-2.0", - "dependencies": { - "ethereumjs-common": "^1.5.0", - "ethereumjs-util": "^6.0.0" - } - }, - "node_modules/ethereumjs-tx/node_modules/ethereumjs-util": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", - "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", - "license": "MPL-2.0", - "dependencies": { - "@types/bn.js": "^4.11.3", - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "elliptic": "^6.5.2", - "ethereum-cryptography": "^0.1.3", - "ethjs-util": "0.1.6", - "rlp": "^2.2.3" - } - }, - "node_modules/ethers": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.8.0.tgz", - "integrity": "sha512-DUq+7fHrCg1aPDFCHx6UIPb3nmt2XMpM7Y/g2gLhsl3lIBqeAfOJIl1qEvRf2uq3BiKxmh6Fh5pfp2ieyek7Kg==", - "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/abi": "5.8.0", - "@ethersproject/abstract-provider": "5.8.0", - "@ethersproject/abstract-signer": "5.8.0", - "@ethersproject/address": "5.8.0", - "@ethersproject/base64": "5.8.0", - "@ethersproject/basex": "5.8.0", - "@ethersproject/bignumber": "5.8.0", - "@ethersproject/bytes": "5.8.0", - "@ethersproject/constants": "5.8.0", - "@ethersproject/contracts": "5.8.0", - "@ethersproject/hash": "5.8.0", - "@ethersproject/hdnode": "5.8.0", - "@ethersproject/json-wallets": "5.8.0", - "@ethersproject/keccak256": "5.8.0", - "@ethersproject/logger": "5.8.0", - "@ethersproject/networks": "5.8.0", - "@ethersproject/pbkdf2": "5.8.0", - "@ethersproject/properties": "5.8.0", - "@ethersproject/providers": "5.8.0", - "@ethersproject/random": "5.8.0", - "@ethersproject/rlp": "5.8.0", - "@ethersproject/sha2": "5.8.0", - "@ethersproject/signing-key": "5.8.0", - "@ethersproject/solidity": "5.8.0", - "@ethersproject/strings": "5.8.0", - "@ethersproject/transactions": "5.8.0", - "@ethersproject/units": "5.8.0", - "@ethersproject/wallet": "5.8.0", - "@ethersproject/web": "5.8.0", - "@ethersproject/wordlists": "5.8.0" - } - }, - "node_modules/ethjs-unit": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", - "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==", - "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", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", - "license": "MIT" - }, - "node_modules/ethjs-util": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", - "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", - "license": "MIT", - "dependencies": { - "is-hex-prefixed": "1.0.0", - "strip-hex-prefix": "1.0.0" - }, - "engines": { - "node": ">=6.5.0", - "npm": ">=3" - } - }, - "node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", - "license": "MIT", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "node_modules/eventemitter3": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", - "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==", - "license": "MIT" - }, - "node_modules/evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "license": "MIT", - "dependencies": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "node_modules/express": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", - "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "~1.20.3", - "content-disposition": "~0.5.4", - "content-type": "~1.0.4", - "cookie": "~0.7.1", - "cookie-signature": "~1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.3.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "~0.1.12", - "proxy-addr": "~2.0.7", - "qs": "~6.14.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "~0.19.0", - "serve-static": "~1.16.2", - "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" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express/node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/express/node_modules/qs": { - "version": "6.14.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", - "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/ext": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", - "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", - "license": "ISC", - "dependencies": { - "type": "^2.7.2" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "license": "MIT" - }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "license": "MIT", - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "engines": [ - "node >=0.6.0" - ], - "license": "MIT" - }, - "node_modules/fast-base64-decode": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz", - "integrity": "sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, - "node_modules/fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", - "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "license": "MIT", - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/file-type": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", - "integrity": "sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", - "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "statuses": "~2.0.2", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/find-replace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", - "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-back": "^3.0.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/find-replace/node_modules/array-back": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", - "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", - "license": "MIT", - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "license": "BSD-3-Clause", - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flat-cache/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/flatted": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", - "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", - "dev": true, - "license": "ISC" - }, - "node_modules/fmix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/fmix/-/fmix-0.1.0.tgz", - "integrity": "sha1-x7vxJN7ELJ0ZHPuUfQqXeN2YbAw=", - "dev": true, - "license": "MIT", - "dependencies": { - "imul": "^1.0.0" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/for-each": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "license": "Apache-2.0", - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", - "dev": true, - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fp-ts": { - "version": "1.19.3", - "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", - "integrity": "sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==", - "dev": true, - "license": "MIT" - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "license": "MIT" - }, - "node_modules/fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/fs-extra/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/fs-minipass": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", - "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", - "license": "ISC", - "dependencies": { - "minipass": "^2.6.0" - } - }, - "node_modules/fs-readdir-recursive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", - "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", - "dev": true, - "license": "MIT" - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", - "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "functions-have-names": "^1.2.3", - "hasown": "^2.0.2", - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true, - "license": "MIT" - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/generator-function": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", - "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-port": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", - "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "license": "MIT", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/get-symbol-description": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", - "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "license": "MIT", - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/global": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", - "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", - "license": "MIT", - "dependencies": { - "min-document": "^2.19.0", - "process": "^0.11.10" - } - }, - "node_modules/globals": { - "version": "13.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", - "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/globby/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "license": "MIT", - "dependencies": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "license": "ISC" - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, - "node_modules/handlebars": { - "version": "4.7.9", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", - "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/handlebars/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", - "license": "ISC", - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "license": "MIT", - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/hardhat": { - "version": "2.28.6", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.28.6.tgz", - "integrity": "sha512-zQze7qe+8ltwHvhX5NQ8sN1N37WWZGw8L63y+2XcPxGwAjc/SMF829z3NS6o1krX0sryhAsVBK/xrwUqlsot4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ethereumjs/util": "^9.1.0", - "@ethersproject/abi": "^5.1.2", - "@nomicfoundation/edr": "0.12.0-next.23", - "@nomicfoundation/solidity-analyzer": "^0.1.0", - "@sentry/node": "^5.18.1", - "adm-zip": "^0.4.16", - "aggregate-error": "^3.0.0", - "ansi-escapes": "^4.3.0", - "boxen": "^5.1.2", - "chokidar": "^4.0.0", - "ci-info": "^2.0.0", - "debug": "^4.1.1", - "enquirer": "^2.3.0", - "env-paths": "^2.2.0", - "ethereum-cryptography": "^1.0.3", - "find-up": "^5.0.0", - "fp-ts": "1.19.3", - "fs-extra": "^7.0.1", - "immutable": "^4.0.0-rc.12", - "io-ts": "1.10.4", - "json-stream-stringify": "^3.1.4", - "keccak": "^3.0.2", - "lodash": "^4.17.11", - "micro-eth-signer": "^0.14.0", - "mnemonist": "^0.38.0", - "mocha": "^10.0.0", - "p-map": "^4.0.0", - "picocolors": "^1.1.0", - "raw-body": "^2.4.1", - "resolve": "1.17.0", - "semver": "^6.3.0", - "solc": "0.8.26", - "source-map-support": "^0.5.13", - "stacktrace-parser": "^0.1.10", - "tinyglobby": "^0.2.6", - "tsort": "0.0.1", - "undici": "^5.14.0", - "uuid": "^8.3.2", - "ws": "^7.4.6" - }, - "bin": { - "hardhat": "internal/cli/bootstrap.js" - }, - "peerDependencies": { - "ts-node": "*", - "typescript": "*" - }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - }, - "typescript": { - "optional": true - } - } - }, - "node_modules/hardhat-contract-sizer": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/hardhat-contract-sizer/-/hardhat-contract-sizer-2.4.0.tgz", - "integrity": "sha512-ww+Fw5Fq+q6gkVxB8KFvicqZFH5pH9HGZwV4ZSTxd0QrxA162qzLdbScJseUP30VvIBPYN9wpdj0cWlz6M9j6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "cli-table3": "^0.6.0" - }, - "peerDependencies": { - "hardhat": "^2.0.0" - } - }, - "node_modules/hardhat-contract-sizer/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "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/hardhat-contract-sizer/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/hardhat-contract-sizer/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/hardhat-contract-sizer/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/hardhat-contract-sizer/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/hardhat-contract-sizer/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/hardhat-dependency-compiler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/hardhat-dependency-compiler/-/hardhat-dependency-compiler-1.1.2.tgz", - "integrity": "sha512-LVnsPSZnGvzWVvlpewlkPKlPtFP/S9V41RC1fd/ygZc4jkG8ubNlfE82nwiGw5oPueHSmFi6TACgmyrEOokK8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.14.0" - }, - "peerDependencies": { - "hardhat": "^2.0.0" - } - }, - "node_modules/hardhat-deploy": { - "version": "0.11.45", - "resolved": "https://registry.npmjs.org/hardhat-deploy/-/hardhat-deploy-0.11.45.tgz", - "integrity": "sha512-aC8UNaq3JcORnEUIwV945iJuvBwi65tjHVDU3v6mOcqik7WAzHVCJ7cwmkkipsHrWysrB5YvGF1q9S1vIph83w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ethersproject/abi": "^5.7.0", - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/contracts": "^5.7.0", - "@ethersproject/providers": "^5.7.2", - "@ethersproject/solidity": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/wallet": "^5.7.0", - "@types/qs": "^6.9.7", - "axios": "^0.21.1", - "chalk": "^4.1.2", - "chokidar": "^3.5.2", - "debug": "^4.3.2", - "enquirer": "^2.3.6", - "ethers": "^5.7.0", - "form-data": "^4.0.0", - "fs-extra": "^10.0.0", - "match-all": "^1.2.6", - "murmur-128": "^0.2.1", - "qs": "^6.9.4", - "zksync-web3": "^0.14.3" - } - }, - "node_modules/hardhat-deploy/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "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/hardhat-deploy/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/hardhat-deploy/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/hardhat-deploy/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/hardhat-deploy/node_modules/fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/hardhat-deploy/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/hardhat-deploy/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/hardhat-deploy/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/hardhat-gas-reporter": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.8.tgz", - "integrity": "sha512-1G5thPnnhcwLHsFnl759f2tgElvuwdkzxlI65fC9PwxYMEe9cmjkVAAWTf3/3y8uP6ZSPiUiOW8PgZnykmZe0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-uniq": "1.0.3", - "eth-gas-reporter": "^0.2.24", - "sha1": "^1.1.1" - }, - "peerDependencies": { - "hardhat": "^2.0.2" - } - }, - "node_modules/hardhat/node_modules/@noble/hashes": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.1.tgz", - "integrity": "sha512-Lkp9+NijmV7eSVZqiUvt3UCuuHeJpUVmRrvh430gyJjJiuJMqkeHf6/A9lQ/smmbWV/0spDeJscscPzyB4waZg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT" - }, - "node_modules/hardhat/node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/hardhat/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/hardhat/node_modules/ethereum-cryptography": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.1.0.tgz", - "integrity": "sha512-wyNVTBR4wIR2yoXdMv4Qt44mTVBpPgSW/DQCTmNO6nQluwpyrAIvmL4mxPbziFuc6VWJQa3rwUxn0nUFU03nyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.1.1", - "@noble/secp256k1": "1.6.0", - "@scure/bip32": "1.1.0", - "@scure/bip39": "1.1.0" - } - }, - "node_modules/hardhat/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/hardhat/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/hardhat/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/hardhat/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/hardhat/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/hardhat/node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/hardhat/node_modules/resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hardhat/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/hardhat/node_modules/solc": { - "version": "0.8.26", - "resolved": "https://registry.npmjs.org/solc/-/solc-0.8.26.tgz", - "integrity": "sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "command-exists": "^1.2.8", - "commander": "^8.1.0", - "follow-redirects": "^1.12.1", - "js-sha3": "0.8.0", - "memorystream": "^0.3.1", - "semver": "^5.5.0", - "tmp": "0.0.33" - }, - "bin": { - "solcjs": "solc.js" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/hardhat/node_modules/solc/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/hardhat/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/hardhat/node_modules/ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/has-bigints": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", - "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", - "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbol-support-x": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", - "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-to-string-tag-x": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", - "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", - "license": "MIT", - "dependencies": { - "has-symbol-support-x": "^1.4.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "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.2", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", - "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "^2.3.8", - "safe-buffer": "^5.2.1", - "to-buffer": "^1.2.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/hash-base/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/hash-base/node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "license": "MIT", - "bin": { - "he": "bin/he" - } - }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "license": "MIT", - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "license": "ISC" - }, - "node_modules/http-basic": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz", - "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "caseless": "^0.12.0", - "concat-stream": "^1.6.2", - "http-response-object": "^3.0.1", - "parse-cache-control": "^1.0.1" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", - "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", - "license": "BSD-2-Clause" - }, - "node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/http-https": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", - "integrity": "sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg==", - "license": "ISC" - }, - "node_modules/http-response-object": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", - "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "^10.0.3" - } - }, - "node_modules/http-response-object/node_modules/@types/node": { - "version": "10.17.60", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", - "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", - "dev": true, - "license": "MIT" - }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "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/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/idna-uts46-hx": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz", - "integrity": "sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA==", - "license": "MIT", - "dependencies": { - "punycode": "2.1.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/idna-uts46-hx/node_modules/punycode": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", - "integrity": "sha512-Yxz2kRwT90aPiWEMHVYnEf4+rhwF1tBmmZ4KepCP+Wkium9JxtWnUm1nqGwpiAHr/tnTSeHqr3wb++jgSkXjhA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "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": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/immutable": { - "version": "4.3.8", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.8.tgz", - "integrity": "sha512-d/Ld9aLbKpNwyl0KiM2CT1WYvkitQ1TSvmRtkcV8FKStiDoA7Slzgjmb/1G2yhKM1p0XeNOieaTbFZmU1d3Xuw==", - "dev": true, - "license": "MIT" - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "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", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/imul": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/imul/-/imul-1.0.1.tgz", - "integrity": "sha1-nVhnFh6LPelsLDjV3HyxAvNeKsk=", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/inquirer/node_modules/ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/ansi-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/inquirer/node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/string-width/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/internal-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", - "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.2", - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/io-ts": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", - "integrity": "sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fp-ts": "^1.0.0" - } - }, - "node_modules/io-ts/node_modules/fp-ts": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.5.tgz", - "integrity": "sha512-wDNqTimnzs8QqpldiId9OavWK2NptormjXnRJTQecNjzwfyp6P/8s/zG8e4h3ja3oqkKaY72UlTjQYt/1yXf9A==", - "dev": true, - "license": "MIT" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", - "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true, - "license": "MIT" - }, - "node_modules/is-async-function": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", - "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "async-function": "^1.0.0", - "call-bound": "^1.0.3", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", - "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-bigints": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", - "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-view": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", - "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", - "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-finalizationregistry": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", - "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/is-function": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", - "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", - "license": "MIT" - }, - "node_modules/is-generator-function": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", - "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.4", - "generator-function": "^2.0.0", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-hex-prefixed": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", - "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==", - "license": "MIT", - "engines": { - "node": ">=6.5.0", - "npm": ">=3" - } - }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-natural-number": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", - "integrity": "sha512-Y4LTamMe0DDQIIAlaer9eKebAlDSV6huy+TWhJVPlzZh2o4tRP5SQWFlLn5N0To4mDD22/qdOq+veo1cSISLgQ==", - "license": "MIT" - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", - "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", - "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-retry-allowed": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", - "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", - "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-string": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", - "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", - "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-symbols": "^1.1.0", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", - "license": "MIT", - "dependencies": { - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "license": "MIT" - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", - "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", - "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true, - "license": "ISC" - }, - "node_modules/isomorphic-unfetch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz", - "integrity": "sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "node-fetch": "^2.6.1", - "unfetch": "^4.2.0" - } - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "license": "MIT" - }, - "node_modules/isurl": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", - "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", - "license": "MIT", - "dependencies": { - "has-to-string-tag-x": "^1.2.0", - "is-object": "^1.0.1" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/iterator.prototype": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", - "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.6", - "get-proto": "^1.0.0", - "has-symbols": "^1.1.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/js-cookie": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz", - "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/js-sha3": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", - "license": "MIT" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "license": "MIT" - }, - "node_modules/json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", - "license": "MIT" - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "license": "(AFL-2.1 OR BSD-3-Clause)" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stream-stringify": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-3.1.6.tgz", - "integrity": "sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=7.10.1" - } - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "license": "ISC" - }, - "node_modules/json-text-sequence": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/json-text-sequence/-/json-text-sequence-0.1.1.tgz", - "integrity": "sha512-L3mEegEWHRekSHjc7+sc8eJhba9Clq1PZ8kMkzf8OxElhXc8O4TS5MwcVlj9aEbm5dr81N90WHC5nAz3UO971w==", - "license": "MIT", - "dependencies": { - "delimit-stream": "0.1.0" - } - }, - "node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "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/jsx-ast-utils": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", - "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/keccak": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.2.tgz", - "integrity": "sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ==", - "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/keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.0" - } - }, - "node_modules/language-subtag-registry": { - "version": "0.3.23", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", - "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", - "dev": true, - "license": "CC0-1.0" - }, - "node_modules/language-tags": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", - "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", - "dev": true, - "license": "MIT", - "dependencies": { - "language-subtag-registry": "^0.3.20" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", - "license": "MIT", - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/lodash": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", - "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", - "license": "MIT" - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.isequalwith": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.isequalwith/-/lodash.isequalwith-4.4.0.tgz", - "integrity": "sha1-Jmcm3dUo+FTyH06pigZWBuD7xrA=", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true, - "license": "MIT" - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "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/log-symbols/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/log-symbols/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/log-symbols/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/log-symbols/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lru_map": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", - "integrity": "sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0=", - "dev": true, - "license": "MIT" - }, - "node_modules/make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "license": "MIT", - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/make-dir/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "license": "ISC" - }, - "node_modules/markdown-table": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", - "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/match-all": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/match-all/-/match-all-1.2.6.tgz", - "integrity": "sha512-0EESkXiTkWzrQQntBu2uzKvLu6vVkUGz40nGPbSZuegcfE5UuSzNjLaIu76zJWuaT/2I3Z/8M06OlUOZLGwLlQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "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", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", - "dev": true, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micro-eth-signer": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/micro-eth-signer/-/micro-eth-signer-0.14.0.tgz", - "integrity": "sha512-5PLLzHiVYPWClEvZIXXFu5yutzpadb73rnQCpUqIHu3No3coFuWQNfE5tkBQJ7djuLYl6aRLaS0MgWJYGoqiBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.8.1", - "@noble/hashes": "~1.7.1", - "micro-packed": "~0.7.2" - } - }, - "node_modules/micro-eth-signer/node_modules/@noble/hashes": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", - "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/micro-packed": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/micro-packed/-/micro-packed-0.7.3.tgz", - "integrity": "sha512-2Milxs+WNC00TRlem41oRswvw31146GiSaoCT7s3Xi2gMUglW5QBeqlQaZeHr5tJx9nm3i57LNXPqxOOaWtTYg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@scure/base": "~1.2.5" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/micro-packed/node_modules/@scure/base": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", - "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "bin": { - "miller-rabin": "bin/miller-rabin" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/min-document": { - "version": "2.19.2", - "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.2.tgz", - "integrity": "sha512-8S5I8db/uZN8r9HSLFVWPdJCvYOejMcEC82VIzNUc6Zkklf/d1gg2psfE79/vyhWOj4+J8MtwmoOz3TmvaGu5A==", - "license": "MIT", - "dependencies": { - "dom-walk": "^0.1.0" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "license": "ISC" - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", - "license": "MIT" - }, - "node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "license": "MIT" - }, - "node_modules/minipass": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", - "license": "ISC", - "dependencies": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "node_modules/minizlib": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", - "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", - "license": "MIT", - "dependencies": { - "minipass": "^2.9.0" - } - }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "license": "MIT", - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/mkdirp-promise": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz", - "integrity": "sha512-Hepn5kb1lJPtVW84RFT40YG1OddBNTOVUZR2bzQUHc+Z03en8/3uX0+060JDhcEzyO08HmipsN9DcnFMxhIL9w==", - "deprecated": "This package is broken and no longer maintained. 'mkdirp' itself supports promises now, please switch to that.", - "license": "ISC", - "dependencies": { - "mkdirp": "*" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mnemonist": { - "version": "0.38.5", - "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz", - "integrity": "sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==", - "dev": true, - "license": "MIT", - "dependencies": { - "obliterator": "^2.0.0" - } - }, - "node_modules/mocha": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", - "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-colors": "^4.1.3", - "browser-stdout": "^1.3.1", - "chokidar": "^3.5.3", - "debug": "^4.3.5", - "diff": "^5.2.0", - "escape-string-regexp": "^4.0.0", - "find-up": "^5.0.0", - "glob": "^8.1.0", - "he": "^1.2.0", - "js-yaml": "^4.1.0", - "log-symbols": "^4.1.0", - "minimatch": "^5.1.6", - "ms": "^2.1.3", - "serialize-javascript": "^6.0.2", - "strip-json-comments": "^3.1.1", - "supports-color": "^8.1.1", - "workerpool": "^6.5.1", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.9", - "yargs-unparser": "^2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/mocha/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "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/mocha/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", - "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/mocha/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/mocha/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/mocha/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/mocha/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "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/mocha/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/mocha/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", - "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/mocha/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/mocha/node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mock-fs": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.14.0.tgz", - "integrity": "sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw==", - "license": "MIT" - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/murmur-128": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/murmur-128/-/murmur-128-0.2.1.tgz", - "integrity": "sha512-WseEgiRkI6aMFBbj8Cg9yBj/y+OdipwVC7zUo3W2W1JAJITwouUOtpqsmGSg67EQmwwSyod7hsVsWY5LsrfQVg==", - "dev": true, - "license": "MIT", - "dependencies": { - "encode-utf8": "^1.0.2", - "fmix": "^0.1.0", - "imul": "^1.0.0" - } - }, - "node_modules/mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true, - "license": "ISC" - }, - "node_modules/mvdan-sh": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/mvdan-sh/-/mvdan-sh-0.5.0.tgz", - "integrity": "sha512-UWbdl4LHd2fUnaEcOUFVWRdWGLkNoV12cKVIPiirYd8qM5VkCoCTXErlDubevrkEG7kGohvjRxAlTQmOqG80tw==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/nan": { - "version": "2.26.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.26.2.tgz", - "integrity": "sha512-0tTvBTYkt3tdGw22nrAy50x7gpbGCCFH3AFcyS5WiUu7Eu4vWlri1woE6qHBSfy11vksDqkiwjOnlR7WV8G1Hw==", - "license": "MIT" - }, - "node_modules/nano-json-stream-parser": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", - "integrity": "sha512-9MqxMH/BSJC7dnLsEMPyfN5Dvoo49IsPFYMcHw3Bcfc2kN0lpHRBSzlMSVx4HGyJ7s9B31CyBTVehWJoQ8Ctew==", - "license": "MIT" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true, - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true, - "license": "MIT" - }, - "node_modules/next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", - "license": "ISC" - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-addon-api": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", - "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", - "license": "MIT" - }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "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.5.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz", - "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==", - "license": "MIT", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, - "node_modules/nofilter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-1.0.4.tgz", - "integrity": "sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/number-to-bn": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", - "integrity": "sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==", - "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", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", - "license": "MIT" - }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "license": "Apache-2.0", - "engines": { - "node": "*" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", - "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0", - "has-symbols": "^1.1.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", - "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", - "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.groupby": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", - "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.values": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", - "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/obliterator": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.1.tgz", - "integrity": "sha512-XnkiCrrBcIZQitJPAI36mrrpEUvatbte8hLcTcQwKA1v9NkCKasSi+UAguLsLDs/out7MoRzAlmz7VXvY6ph6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/oboe": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.4.tgz", - "integrity": "sha512-ymBJ4xSC6GBXLT9Y7lirj+xbqBLa+jADGJldGEYG7u8sZbS9GyG+u1Xk9c5cbriKwSpCg41qUhPjvU5xOpvIyQ==", - "license": "BSD", - "dependencies": { - "http-https": "^1.0.0" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/openzeppelin-solidity": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/openzeppelin-solidity/-/openzeppelin-solidity-2.4.0.tgz", - "integrity": "sha512-533gc5jkspxW5YT0qJo02Za5q1LHwXK9CJCc48jNj/22ncNM/3M/3JfWLqfpB90uqLwOKOovpl0JfaMQTR+gXQ==", - "license": "MIT" - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/optionator/node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/optionator/node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/optionator/node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ordinal": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ordinal/-/ordinal-1.0.3.tgz", - "integrity": "sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/own-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", - "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.6", - "object-keys": "^1.1.1", - "safe-push-apply": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "license": "MIT", - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", - "license": "MIT", - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-timeout": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", - "integrity": "sha512-gb0ryzr+K2qFqFv6qi3khoeqMZF/+ajxQipEF6NteZVnvz9tzdsfAVj3lYtn1gAXvH5lfLwfxEII799gt/mRIA==", - "license": "MIT", - "dependencies": { - "p-finally": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-asn1": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", - "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", - "license": "ISC", - "dependencies": { - "asn1.js": "^4.10.1", - "browserify-aes": "^1.2.0", - "evp_bytestokey": "^1.0.3", - "pbkdf2": "^3.1.5", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/parse-cache-control": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", - "integrity": "sha1-juqz5U+laSD+Fro493+iGqzC104=", - "dev": true - }, - "node_modules/parse-headers": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", - "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==", - "license": "MIT" - }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "license": "MIT", - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true, - "license": "(WTFPL OR MIT)" - }, - "node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/path-to-regexp": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", - "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", - "license": "MIT" - }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/pbkdf2": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", - "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", - "license": "MIT", - "dependencies": { - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "ripemd160": "^2.0.3", - "safe-buffer": "^5.2.1", - "sha.js": "^2.4.12", - "to-buffer": "^1.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "license": "MIT" - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", - "license": "MIT", - "dependencies": { - "pinkie": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/possible-typed-array-names": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/prettier": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", - "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/prettier-plugin-sh": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/prettier-plugin-sh/-/prettier-plugin-sh-0.8.1.tgz", - "integrity": "sha512-tz0g6y+ZaJF0PWaa1F7vhCv4nLgYYl2zYzYU4XJFD1McoY0oHI+l2osvXqv1s5yQdtjdlzKszN6VY7WTaw2Gqw==", - "dev": true, - "license": "MIT", - "dependencies": { - "mvdan-sh": "^0.5.0" - }, - "peerDependencies": { - "prettier": "^2.0.0" - } - }, - "node_modules/prettier-plugin-solidity": { - "version": "1.0.0-beta.19", - "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.19.tgz", - "integrity": "sha512-xxRQ5ZiiZyUoMFLE9h7HnUDXI/daf1tnmL1msEdcKmyh7ZGQ4YklkYLC71bfBpYU2WruTb5/SFLUaEb3RApg5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@solidity-parser/parser": "^0.14.0", - "emoji-regex": "^10.0.0", - "escape-string-regexp": "^4.0.0", - "semver": "^7.3.5", - "solidity-comments-extractor": "^0.0.7", - "string-width": "^4.2.3" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "prettier": "^2.3.0" - } - }, - "node_modules/prettier-plugin-solidity/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/prettier-plugin-solidity/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "license": "MIT", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT" - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/promise": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", - "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "asap": "~2.0.6" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, - "license": "MIT", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/proper-lockfile": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", - "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "retry": "^0.12.0", - "signal-exit": "^3.0.2" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-from-env": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", - "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "license": "MIT" - }, - "node_modules/public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/pump": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", - "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", - "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/query-string": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", - "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", - "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/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "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/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "license": "MIT", - "dependencies": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", - "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readable-stream/node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/reduce-flatten": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", - "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", - "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.1", - "which-builtin-type": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", - "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/req-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-2.0.0.tgz", - "integrity": "sha1-1AgrTURZgDZkD7c93qAe1T20nrw=", - "dev": true, - "license": "MIT", - "dependencies": { - "req-from": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/req-from": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/req-from/-/req-from-2.0.0.tgz", - "integrity": "sha1-10GI5H+TeW9Kpx327jWuaJ8+DnA=", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-from": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "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", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "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.5", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.5.tgz", - "integrity": "sha512-mzR4sElr1bfCaPJe7m8ilJ6ZXdDaGoObcYR0ZHSsktM/Lt21MVHj5De30GQH2eiZ1qGRTO7LCAzQsUeXTNexWQ==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/request/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "license": "MIT", - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", - "license": "MIT", - "dependencies": { - "lowercase-keys": "^1.0.0" - } - }, - "node_modules/restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "license": "MIT", - "dependencies": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/ripemd160": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", - "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", - "license": "MIT", - "dependencies": { - "hash-base": "^3.1.2", - "inherits": "^2.0.4" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/rlp": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", - "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", - "license": "MPL-2.0", - "dependencies": { - "bn.js": "^5.2.0" - }, - "bin": { - "rlp": "bin/rlp" - } - }, - "node_modules/rlp/node_modules/bn.js": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", - "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", - "license": "MIT" - }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "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": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rxjs": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.3.tgz", - "integrity": "sha512-6162iC/N7L7K8q3UvdOMWix1ju+esADGrDaPrTu5XJmCv69YNdYoUaop/iatN8GHK+YHOdszPP+qygA0yi04zQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/rxjs/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true, - "license": "0BSD" - }, - "node_modules/safe-array-concat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", - "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "has-symbols": "^1.1.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-array-concat/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, - "license": "MIT" - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "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/safe-push-apply": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", - "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-push-apply/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, - "license": "MIT" - }, - "node_modules/safe-regex-test": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-regex-test/node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/scrypt-js": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", - "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", - "license": "MIT" - }, - "node_modules/scrypt-shim": { - "name": "@web3-js/scrypt-shim", - "version": "0.1.0", - "resolved": "git+ssh://git@github.com/web3-js/scrypt-shim.git#aafdadda13e660e25e1c525d1f5b2443f5eb1ebb", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "scryptsy": "^2.1.0", - "semver": "^6.3.0" - } - }, - "node_modules/scrypt-shim/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/scryptsy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/scryptsy/-/scryptsy-2.1.0.tgz", - "integrity": "sha512-1CdSqHQowJBnMAFyPEBRfqag/YP9OF394FV+4YREIJX4ljD7OxvQRDayyoyyCk+senRjSkP6VnUNQmVQqB6g7w==", - "license": "MIT" - }, - "node_modules/secp256k1": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.4.tgz", - "integrity": "sha512-6JfvwvjUOn8F/jUoBY2Q1v5WY5XS+rj8qSe0v8Y4ezH4InLgTEeOOPQsRll9OV429Pvo6BCHGavIyJfr3TAhsw==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "elliptic": "^6.5.7", - "node-addon-api": "^5.0.0", - "node-gyp-build": "^4.2.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/secp256k1/node_modules/elliptic": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", - "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", - "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/secp256k1/node_modules/node-addon-api": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", - "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", - "license": "MIT" - }, - "node_modules/seek-bzip": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz", - "integrity": "sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ==", - "license": "MIT", - "dependencies": { - "commander": "^2.8.1" - }, - "bin": { - "seek-bunzip": "bin/seek-bunzip", - "seek-table": "bin/seek-bzip-table" - } - }, - "node_modules/seek-bzip/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/send": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", - "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.4.1", - "range-parser": "~1.2.1", - "statuses": "~2.0.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/serve-static": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", - "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", - "license": "MIT", - "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "~0.19.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/servify": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/servify/-/servify-0.1.12.tgz", - "integrity": "sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw==", - "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", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "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/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-proto": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", - "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "license": "MIT" - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "node_modules/sha.js": { - "version": "2.4.12", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", - "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", - "license": "(MIT AND BSD-3-Clause)", - "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1", - "to-buffer": "^1.2.0" - }, - "bin": { - "sha.js": "bin.js" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/sha1": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", - "integrity": "sha1-rdqnqTFo85PxnrKxUJFhjicA+Eg=", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "charenc": ">= 0.0.1", - "crypt": ">= 0.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC" - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "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", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz", - "integrity": "sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw==", - "license": "MIT", - "dependencies": { - "decompress-response": "^3.3.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "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", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "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", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "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", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/solhint": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.3.6.tgz", - "integrity": "sha512-HWUxTAv2h7hx3s3hAab3ifnlwb02ZWhwFU/wSudUHqteMS3ll9c+m1FlGn9V8ztE2rf3Z82fQZA005Wv7KpcFA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@solidity-parser/parser": "^0.13.2", - "ajv": "^6.6.1", - "antlr4": "4.7.1", - "ast-parents": "0.0.1", - "chalk": "^2.4.2", - "commander": "2.18.0", - "cosmiconfig": "^5.0.7", - "eslint": "^5.6.0", - "fast-diff": "^1.1.2", - "glob": "^7.1.3", - "ignore": "^4.0.6", - "js-yaml": "^3.12.0", - "lodash": "^4.17.11", - "semver": "^6.3.0" - }, - "bin": { - "solhint": "solhint.js" - }, - "optionalDependencies": { - "prettier": "^1.14.3" - } - }, - "node_modules/solhint-config-keep": { - "version": "0.1.0", - "resolved": "git+ssh://git@github.com/keep-network/solhint-config-keep.git#5e1751e58c0f1c507305ffc8c7f6c58047657ada", - "dev": true, - "engines": { - "node": ">=0.10.0" - }, - "peerDependencies": { - "solhint": ">=3.3.4" - } - }, - "node_modules/solhint/node_modules/@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/solhint/node_modules/@solidity-parser/parser": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.13.2.tgz", - "integrity": "sha512-RwHnpRnfrnD2MSPveYoPh8nhofEvX7fgjHk1Oq+NNvCcLx4r1js91CO9o+F/F3fBzOCyvm8kKRTriFICX/odWw==", - "dev": true, - "license": "MIT", - "dependencies": { - "antlr4ts": "^0.5.0-alpha.4" - } - }, - "node_modules/solhint/node_modules/acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/solhint/node_modules/ansi-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/solhint/node_modules/astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/solhint/node_modules/commander": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.18.0.tgz", - "integrity": "sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/solhint/node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/solhint/node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true, - "license": "MIT" - }, - "node_modules/solhint/node_modules/eslint": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", - "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.9.1", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^4.0.3", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^5.0.1", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.7.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^6.2.2", - "js-yaml": "^3.13.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.11", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^6.14.0 || ^8.10.0 || >=9.10.0" - } - }, - "node_modules/solhint/node_modules/eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/solhint/node_modules/eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/solhint/node_modules/eslint/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/solhint/node_modules/espree": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", - "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^6.0.7", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/solhint/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/solhint/node_modules/file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/solhint/node_modules/flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/solhint/node_modules/flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true, - "license": "ISC" - }, - "node_modules/solhint/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/solhint/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/solhint/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/solhint/node_modules/prettier": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", - "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", - "dev": true, - "license": "MIT", - "optional": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/solhint/node_modules/regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.5.0" - } - }, - "node_modules/solhint/node_modules/rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/solhint/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/solhint/node_modules/slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/solhint/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/solhint/node_modules/string-width/node_modules/ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/solhint/node_modules/string-width/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/solhint/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/solhint/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/solhint/node_modules/table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/solidity-ast": { - "version": "0.4.46", - "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.46.tgz", - "integrity": "sha512-MlPZQfPhjWXqh7YxWcBGDXaPZIfMYCOHYoLEhGDWulNwEPIQQZuB7mA9eP17CU0jY/bGR4avCEUVVpvHtT2gbA==", - "dev": true, - "license": "MIT" - }, - "node_modules/solidity-comments-extractor": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz", - "integrity": "sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw==", - "dev": true, - "license": "MIT" - }, - "node_modules/solidity-docgen": { - "version": "0.6.0-beta.35", - "resolved": "https://registry.npmjs.org/solidity-docgen/-/solidity-docgen-0.6.0-beta.35.tgz", - "integrity": "sha512-9QdwK1THk/MWIdq1PEW/6dvtND0pUqpFTsbKwwU9YQIMYuRhH1lek9SsgnsGGYtdJ0VTrXXcVT30q20a8Y610A==", - "dev": true, - "license": "MIT", - "dependencies": { - "handlebars": "^4.7.7", - "solidity-ast": "^0.4.38" - }, - "peerDependencies": { - "hardhat": "^2.8.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/spinnies": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/spinnies/-/spinnies-0.4.3.tgz", - "integrity": "sha512-TTA2vWXrXJpfThWAl2t2hchBnCMI1JM5Wmb2uyI7Zkefdw/xO98LDy6/SBYwQPiYXL3swx3Eb44ZxgoS8X5wpA==", - "license": "MIT", - "dependencies": { - "chalk": "^2.4.2", - "cli-cursor": "^3.0.0", - "strip-ansi": "^5.2.0" - } - }, - "node_modules/spinnies/node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "license": "MIT", - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/spinnies/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/spinnies/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/spinnies/node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "license": "MIT", - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "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/stacktrace-parser": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", - "integrity": "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.7.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/stacktrace-parser/node_modules/type-fest": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", - "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=8" - } - }, - "node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/stop-iteration-iterator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", - "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "internal-slot": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/strict-uri-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/string-format": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/string-format/-/string-format-2.0.0.tgz", - "integrity": "sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==", - "dev": true, - "license": "WTFPL OR MIT" - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "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/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/string-width/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.includes": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", - "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/string.prototype.matchall": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", - "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.6", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.6", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "internal-slot": "^1.1.0", - "regexp.prototype.flags": "^1.5.3", - "set-function-name": "^2.0.2", - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.repeat": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", - "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", - "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-data-property": "^1.1.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-object-atoms": "^1.0.0", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", - "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-dirs": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", - "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", - "license": "MIT", - "dependencies": { - "is-natural-number": "^4.0.1" - } - }, - "node_modules/strip-hex-prefix": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", - "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==", - "license": "MIT", - "dependencies": { - "is-hex-prefixed": "1.0.0" - }, - "engines": { - "node": ">=6.5.0", - "npm": ">=3" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/swarm-js": { - "version": "0.1.39", - "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.39.tgz", - "integrity": "sha512-QLMqL2rzF6n5s50BptyD6Oi0R1aWlJC5Y17SRIVXRj6OR1DRIPM7nepvrxxkjA1zNzFz6mUOMjfeqeDaWB7OOg==", - "license": "MIT", - "dependencies": { - "bluebird": "^3.5.0", - "buffer": "^5.0.5", - "decompress": "^4.0.0", - "eth-lib": "^0.1.26", - "fs-extra": "^4.0.2", - "got": "^7.1.0", - "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-promise": "^0.1.2" - } - }, - "node_modules/swarm-js/node_modules/fs-extra": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", - "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", - "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": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/swarm-js/node_modules/got": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", - "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", - "license": "MIT", - "dependencies": { - "decompress-response": "^3.2.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-plain-obj": "^1.1.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "isurl": "^1.0.0-alpha5", - "lowercase-keys": "^1.0.0", - "p-cancelable": "^0.3.0", - "p-timeout": "^1.1.1", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "url-parse-lax": "^1.0.0", - "url-to-options": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/swarm-js/node_modules/p-cancelable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", - "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/swarm-js/node_modules/prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/swarm-js/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/swarm-js/node_modules/url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha512-BVA4lR5PIviy2PMseNd2jbFQ+jwSwQGdJejf5ctd1rEXt0Ypd7yanUK9+lYechVlN5VaTJGsu2U/3MDDu6KgBA==", - "license": "MIT", - "dependencies": { - "prepend-http": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sync-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz", - "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "http-response-object": "^3.0.1", - "sync-rpc": "^1.2.1", - "then-request": "^6.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/sync-rpc": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz", - "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-port": "^3.1.0" - } - }, - "node_modules/synckit": { - "version": "0.11.11", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", - "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@pkgr/core": "^0.2.9" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/synckit" - } - }, - "node_modules/table": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", - "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", - "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-layout": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", - "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-back": "^4.0.1", - "deep-extend": "~0.6.0", - "typical": "^5.2.0", - "wordwrapjs": "^4.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/table-layout/node_modules/array-back": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", - "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/table-layout/node_modules/typical": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", - "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/table/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar": { - "version": "4.4.19", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", - "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", - "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "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/tar-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", - "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", - "license": "MIT", - "dependencies": { - "bl": "^1.0.0", - "buffer-alloc": "^1.2.0", - "end-of-stream": "^1.0.0", - "fs-constants": "^1.0.0", - "readable-stream": "^2.3.0", - "to-buffer": "^1.1.1", - "xtend": "^4.0.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/tar-stream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/tar-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true, - "license": "MIT" - }, - "node_modules/then-request": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", - "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/concat-stream": "^1.6.0", - "@types/form-data": "0.0.33", - "@types/node": "^8.0.0", - "@types/qs": "^6.2.31", - "caseless": "~0.12.0", - "concat-stream": "^1.6.0", - "form-data": "^2.2.0", - "http-basic": "^8.1.1", - "http-response-object": "^3.0.1", - "promise": "^8.0.0", - "qs": "^6.4.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/then-request/node_modules/@types/node": { - "version": "8.10.66", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", - "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/then-request/node_modules/form-data": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.5.tgz", - "integrity": "sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A==", - "dev": true, - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.35", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "license": "MIT" - }, - "node_modules/timed-out": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/to-buffer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", - "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", - "license": "MIT", - "dependencies": { - "isarray": "^2.0.5", - "safe-buffer": "^5.2.1", - "typed-array-buffer": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/to-buffer/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "license": "MIT" - }, - "node_modules/to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/to-regex-range/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "license": "BSD-3-Clause", - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", - "dev": true, - "license": "MIT" - }, - "node_modules/truffle-flattener": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/truffle-flattener/-/truffle-flattener-1.6.0.tgz", - "integrity": "sha512-scS5Bsi4CZyvlrmD4iQcLHTiG2RQFUXVheTgWeH6PuafmI+Lk5U87Es98loM3w3ImqC9/fPHq+3QIXbcPuoJ1Q==", - "license": "MIT", - "dependencies": { - "@resolver-engine/imports-fs": "^0.2.2", - "@solidity-parser/parser": "^0.14.1", - "find-up": "^2.1.0", - "mkdirp": "^1.0.4", - "tsort": "0.0.1" - }, - "bin": { - "truffle-flattener": "index.js" - } - }, - "node_modules/truffle-flattener/node_modules/@resolver-engine/fs": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@resolver-engine/fs/-/fs-0.2.1.tgz", - "integrity": "sha512-7kJInM1Qo2LJcKyDhuYzh9ZWd+mal/fynfL9BNjWOiTcOpX+jNfqb/UmGUqros5pceBITlWGqS4lU709yHFUbg==", - "license": "LGPL-3.0-or-later", - "dependencies": { - "@resolver-engine/core": "^0.2.1", - "debug": "^3.1.0" - } - }, - "node_modules/truffle-flattener/node_modules/@resolver-engine/imports": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@resolver-engine/imports/-/imports-0.2.2.tgz", - "integrity": "sha512-u5/HUkvo8q34AA+hnxxqqXGfby5swnH0Myw91o3Sm2TETJlNKXibFGSKBavAH+wvWdBi4Z5gS2Odu0PowgVOUg==", - "license": "LGPL-3.0-or-later", - "dependencies": { - "@resolver-engine/core": "^0.2.1", - "debug": "^3.1.0", - "hosted-git-info": "^2.6.0" - } - }, - "node_modules/truffle-flattener/node_modules/@resolver-engine/imports-fs": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@resolver-engine/imports-fs/-/imports-fs-0.2.2.tgz", - "integrity": "sha512-gFCgMvCwyppjwq0UzIjde/WI+yDs3oatJhozG9xdjJdewwtd7LiF0T5i9lrHAUtqrQbqoFE4E+ZMRVHWpWHpKQ==", - "license": "LGPL-3.0-or-later", - "dependencies": { - "@resolver-engine/fs": "^0.2.1", - "@resolver-engine/imports": "^0.2.2", - "debug": "^3.1.0" - } - }, - "node_modules/truffle-flattener/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/truffle-flattener/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ts-api-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", - "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/ts-command-line-args": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ts-command-line-args/-/ts-command-line-args-2.2.0.tgz", - "integrity": "sha512-RedEejZyhiEAOgBkIVxB4QC/SRYtl98D7b7epWB9e6E+TmK8KstXBu3WdnhGbMHicLkHoG7sCAmu+F+ASzLFHA==", - "dev": true, - "license": "ISC", - "dependencies": { - "chalk": "^4.1.0", - "command-line-args": "^5.1.1", - "command-line-usage": "^6.1.0", - "string-format": "^2.0.0" - }, - "bin": { - "write-markdown": "dist/write-markdown.js" - } - }, - "node_modules/ts-command-line-args/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "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/ts-command-line-args/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/ts-command-line-args/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/ts-command-line-args/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/ts-command-line-args/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ts-command-line-args/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ts-essentials": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-7.0.3.tgz", - "integrity": "sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "typescript": ">=3.7.0" - } - }, - "node_modules/ts-node": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz", - "integrity": "sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspotcode/source-map-support": "0.7.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/ts-node/node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ts-node/node_modules/diff": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", - "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true, - "license": "0BSD" - }, - "node_modules/tsort": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", - "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==", - "license": "MIT" - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "license": "Unlicense" - }, - "node_modules/type": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", - "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", - "license": "ISC" - }, - "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "license": "MIT", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typechain": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/typechain/-/typechain-6.1.0.tgz", - "integrity": "sha512-GGfkK0p3fUgz8kYxjSS4nKcWXE0Lo+teHTetghousIK5njbNoYNDlwn91QIyD181L3fVqlTvBE0a/q3AZmjNfw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/prettier": "^2.1.1", - "debug": "^4.1.1", - "fs-extra": "^7.0.0", - "glob": "^7.1.6", - "js-sha3": "^0.8.0", - "lodash": "^4.17.15", - "mkdirp": "^1.0.4", - "prettier": "^2.1.2", - "ts-command-line-args": "^2.2.0", - "ts-essentials": "^7.0.1" - }, - "bin": { - "typechain": "dist/cli/cli.js" - }, - "peerDependencies": { - "typescript": ">=4.1.0" - } - }, - "node_modules/typechain/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", - "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", - "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", - "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.15", - "reflect.getprototypeof": "^1.0.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", - "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0", - "reflect.getprototypeof": "^1.0.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true, - "license": "MIT" - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "license": "MIT", - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/typescript": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", - "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/ultron": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", - "license": "MIT" - }, - "node_modules/unbox-primitive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", - "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-bigints": "^1.0.2", - "has-symbols": "^1.1.0", - "which-boxed-primitive": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/unbzip2-stream": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", - "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", - "license": "MIT", - "dependencies": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, - "node_modules/underscore": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", - "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==", - "license": "MIT" - }, - "node_modules/undici": { - "version": "5.29.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", - "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@fastify/busboy": "^2.0.0" - }, - "engines": { - "node": ">=14.0" - } - }, - "node_modules/unfetch": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz", - "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==", - "dev": true, - "license": "MIT" - }, - "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", - "license": "MIT", - "dependencies": { - "prepend-http": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/url-set-query": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", - "integrity": "sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg==", - "license": "MIT" - }, - "node_modules/url-to-options": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", - "integrity": "sha512-0kQLIzG4fdk/G5NONku64rSH/x32NOA39LVQqlK8Le6lvTF6GGRJpqaQFGgU+CLwySIqBSMdwYM0sYcW9f6P4A==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", - "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==", - "license": "MIT" - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", - "integrity": "sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg==" - }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true, - "license": "MIT" - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "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", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "license": "MIT" - }, - "node_modules/verror/node_modules/extsprintf": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz", - "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==", - "engines": [ - "node >=0.6.0" - ], - "license": "MIT" - }, - "node_modules/web3": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3/-/web3-1.2.2.tgz", - "integrity": "sha512-/ChbmB6qZpfGx6eNpczt5YSUBHEA5V2+iUCbn85EVb3Zv6FVxrOo5Tv7Lw0gE2tW7EEjASbCyp3mZeiZaCCngg==", - "hasInstallScript": true, - "license": "LGPL-3.0", - "dependencies": { - "@types/node": "^12.6.1", - "web3-bzz": "1.2.2", - "web3-core": "1.2.2", - "web3-eth": "1.2.2", - "web3-eth-personal": "1.2.2", - "web3-net": "1.2.2", - "web3-shh": "1.2.2", - "web3-utils": "1.2.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/web3-bzz": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.2.2.tgz", - "integrity": "sha512-b1O2ObsqUN1lJxmFSjvnEC4TsaCbmh7Owj3IAIWTKqL9qhVgx7Qsu5O9cD13pBiSPNZJ68uJPaKq380QB4NWeA==", - "license": "LGPL-3.0", - "dependencies": { - "@types/node": "^10.12.18", - "got": "9.6.0", - "swarm-js": "0.1.39", - "underscore": "1.9.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/web3-bzz/node_modules/@types/node": { - "version": "10.17.60", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", - "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", - "license": "MIT" - }, - "node_modules/web3-core": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.2.2.tgz", - "integrity": "sha512-miHAX3qUgxV+KYfaOY93Hlc3kLW2j5fH8FJy6kSxAv+d4d5aH0wwrU2IIoJylQdT+FeenQ38sgsCnFu9iZ1hCQ==", - "license": "LGPL-3.0", - "dependencies": { - "@types/bn.js": "^4.11.4", - "@types/node": "^12.6.1", - "web3-core-helpers": "1.2.2", - "web3-core-method": "1.2.2", - "web3-core-requestmanager": "1.2.2", - "web3-utils": "1.2.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/web3-core-helpers": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.2.tgz", - "integrity": "sha512-HJrRsIGgZa1jGUIhvGz4S5Yh6wtOIo/TMIsSLe+Xay+KVnbseJpPprDI5W3s7H2ODhMQTbogmmUFquZweW2ImQ==", - "license": "LGPL-3.0", - "dependencies": { - "underscore": "1.9.1", - "web3-eth-iban": "1.2.2", - "web3-utils": "1.2.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/web3-core-method": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.2.2.tgz", - "integrity": "sha512-szR4fDSBxNHaF1DFqE+j6sFR/afv9Aa36OW93saHZnrh+iXSrYeUUDfugeNcRlugEKeUCkd4CZylfgbK2SKYJA==", - "license": "LGPL-3.0", - "dependencies": { - "underscore": "1.9.1", - "web3-core-helpers": "1.2.2", - "web3-core-promievent": "1.2.2", - "web3-core-subscriptions": "1.2.2", - "web3-utils": "1.2.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/web3-core-promievent": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.2.2.tgz", - "integrity": "sha512-tKvYeT8bkUfKABcQswK6/X79blKTKYGk949urZKcLvLDEaWrM3uuzDwdQT3BNKzQ3vIvTggFPX9BwYh0F1WwqQ==", - "license": "LGPL-3.0", - "dependencies": { - "any-promise": "1.3.0", - "eventemitter3": "3.1.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/web3-core-requestmanager": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.2.2.tgz", - "integrity": "sha512-a+gSbiBRHtHvkp78U2bsntMGYGF2eCb6219aMufuZWeAZGXJ63Wc2321PCbA8hF9cQrZI4EoZ4kVLRI4OF15Hw==", - "license": "LGPL-3.0", - "dependencies": { - "underscore": "1.9.1", - "web3-core-helpers": "1.2.2", - "web3-providers-http": "1.2.2", - "web3-providers-ipc": "1.2.2", - "web3-providers-ws": "1.2.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/web3-core-subscriptions": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.2.2.tgz", - "integrity": "sha512-QbTgigNuT4eicAWWr7ahVpJyM8GbICsR1Ys9mJqzBEwpqS+RXTRVSkwZ2IsxO+iqv6liMNwGregbJLq4urMFcQ==", - "license": "LGPL-3.0", - "dependencies": { - "eventemitter3": "3.1.2", - "underscore": "1.9.1", - "web3-core-helpers": "1.2.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/web3-core/node_modules/@types/node": { - "version": "12.20.55", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", - "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", - "license": "MIT" - }, - "node_modules/web3-eth": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.2.2.tgz", - "integrity": "sha512-UXpC74mBQvZzd4b+baD4Ocp7g+BlwxhBHumy9seyE/LMIcMlePXwCKzxve9yReNpjaU16Mmyya6ZYlyiKKV8UA==", - "license": "LGPL-3.0", - "dependencies": { - "underscore": "1.9.1", - "web3-core": "1.2.2", - "web3-core-helpers": "1.2.2", - "web3-core-method": "1.2.2", - "web3-core-subscriptions": "1.2.2", - "web3-eth-abi": "1.2.2", - "web3-eth-accounts": "1.2.2", - "web3-eth-contract": "1.2.2", - "web3-eth-ens": "1.2.2", - "web3-eth-iban": "1.2.2", - "web3-eth-personal": "1.2.2", - "web3-net": "1.2.2", - "web3-utils": "1.2.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/web3-eth-abi": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.2.2.tgz", - "integrity": "sha512-Yn/ZMgoOLxhTVxIYtPJ0eS6pnAnkTAaJgUJh1JhZS4ekzgswMfEYXOwpMaD5eiqPJLpuxmZFnXnBZlnQ1JMXsw==", - "license": "LGPL-3.0", - "dependencies": { - "ethers": "4.0.0-beta.3", - "underscore": "1.9.1", - "web3-utils": "1.2.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/web3-eth-abi/node_modules/@types/node": { - "version": "10.17.60", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", - "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", - "license": "MIT" - }, - "node_modules/web3-eth-abi/node_modules/elliptic": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.3.3.tgz", - "integrity": "sha512-cIky9SO2H8W2eU1NOLySnhOYJnuEWCq9ZJeHvHd/lXzEL9vyraIMfilZSn57X3aVX+wkfYmqkch2LvmTzkjFpA==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "inherits": "^2.0.1" - } - }, - "node_modules/web3-eth-abi/node_modules/ethers": { - "version": "4.0.0-beta.3", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.0-beta.3.tgz", - "integrity": "sha512-YYPogooSknTwvHg3+Mv71gM/3Wcrx+ZpCzarBj3mqs9njjRkrOo2/eufzhHloOCo3JSoNI4TQJJ6yU5ABm3Uog==", - "license": "MIT", - "dependencies": { - "@types/node": "^10.3.2", - "aes-js": "3.0.0", - "bn.js": "^4.4.0", - "elliptic": "6.3.3", - "hash.js": "1.1.3", - "js-sha3": "0.5.7", - "scrypt-js": "2.0.3", - "setimmediate": "1.0.4", - "uuid": "2.0.1", - "xmlhttprequest": "1.8.0" - } - }, - "node_modules/web3-eth-abi/node_modules/hash.js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/web3-eth-abi/node_modules/js-sha3": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", - "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", - "license": "MIT" - }, - "node_modules/web3-eth-abi/node_modules/scrypt-js": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.3.tgz", - "integrity": "sha512-d8DzQxNivoNDogyYmb/9RD5mEQE/Q7vG2dLDUgvfPmKL9xCVzgqUntOdS0me9Cq9Sh9VxIZuoNEFcsfyXRnyUw==", - "license": "MIT" - }, - "node_modules/web3-eth-abi/node_modules/setimmediate": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", - "integrity": "sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog==", - "license": "MIT" - }, - "node_modules/web3-eth-accounts": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.2.2.tgz", - "integrity": "sha512-KzHOEyXOEZ13ZOkWN3skZKqSo5f4Z1ogPFNn9uZbKCz+kSp+gCAEKxyfbOsB/JMAp5h7o7pb6eYsPCUBJmFFiA==", - "license": "LGPL-3.0", - "dependencies": { - "any-promise": "1.3.0", - "crypto-browserify": "3.12.0", - "eth-lib": "0.2.7", - "ethereumjs-common": "^1.3.2", - "ethereumjs-tx": "^2.1.1", - "scrypt-shim": "github:web3-js/scrypt-shim", - "underscore": "1.9.1", - "uuid": "3.3.2", - "web3-core": "1.2.2", - "web3-core-helpers": "1.2.2", - "web3-core-method": "1.2.2", - "web3-utils": "1.2.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/web3-eth-accounts/node_modules/eth-lib": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", - "integrity": "sha512-VqEBQKH92jNsaE8lG9CTq8M/bc12gdAfb5MY8Ro1hVyXkh7rOtY3m5tRHK3Hus5HqIAAwU2ivcUjTLVwsvf/kw==", - "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": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "license": "MIT", - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/web3-eth-contract": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.2.2.tgz", - "integrity": "sha512-EKT2yVFws3FEdotDQoNsXTYL798+ogJqR2//CaGwx3p0/RvQIgfzEwp8nbgA6dMxCsn9KOQi7OtklzpnJMkjtA==", - "license": "LGPL-3.0", - "dependencies": { - "@types/bn.js": "^4.11.4", - "underscore": "1.9.1", - "web3-core": "1.2.2", - "web3-core-helpers": "1.2.2", - "web3-core-method": "1.2.2", - "web3-core-promievent": "1.2.2", - "web3-core-subscriptions": "1.2.2", - "web3-eth-abi": "1.2.2", - "web3-utils": "1.2.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/web3-eth-ens": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.2.2.tgz", - "integrity": "sha512-CFjkr2HnuyMoMFBoNUWojyguD4Ef+NkyovcnUc/iAb9GP4LHohKrODG4pl76R5u61TkJGobC2ij6TyibtsyVYg==", - "license": "LGPL-3.0", - "dependencies": { - "eth-ens-namehash": "2.0.8", - "underscore": "1.9.1", - "web3-core": "1.2.2", - "web3-core-helpers": "1.2.2", - "web3-core-promievent": "1.2.2", - "web3-eth-abi": "1.2.2", - "web3-eth-contract": "1.2.2", - "web3-utils": "1.2.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/web3-eth-iban": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.2.2.tgz", - "integrity": "sha512-gxKXBoUhaTFHr0vJB/5sd4i8ejF/7gIsbM/VvemHT3tF5smnmY6hcwSMmn7sl5Gs+83XVb/BngnnGkf+I/rsrQ==", - "license": "LGPL-3.0", - "dependencies": { - "bn.js": "4.11.8", - "web3-utils": "1.2.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/web3-eth-iban/node_modules/bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "license": "MIT" - }, - "node_modules/web3-eth-personal": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.2.2.tgz", - "integrity": "sha512-4w+GLvTlFqW3+q4xDUXvCEMU7kRZ+xm/iJC8gm1Li1nXxwwFbs+Y+KBK6ZYtoN1qqAnHR+plYpIoVo27ixI5Rg==", - "license": "LGPL-3.0", - "dependencies": { - "@types/node": "^12.6.1", - "web3-core": "1.2.2", - "web3-core-helpers": "1.2.2", - "web3-core-method": "1.2.2", - "web3-net": "1.2.2", - "web3-utils": "1.2.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/web3-eth-personal/node_modules/@types/node": { - "version": "12.20.55", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", - "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", - "license": "MIT" - }, - "node_modules/web3-net": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.2.2.tgz", - "integrity": "sha512-K07j2DXq0x4UOJgae65rWZKraOznhk8v5EGSTdFqASTx7vWE/m+NqBijBYGEsQY1lSMlVaAY9UEQlcXK5HzXTw==", - "license": "LGPL-3.0", - "dependencies": { - "web3-core": "1.2.2", - "web3-core-method": "1.2.2", - "web3-utils": "1.2.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/web3-providers-http": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.2.2.tgz", - "integrity": "sha512-BNZ7Hguy3eBszsarH5gqr9SIZNvqk9eKwqwmGH1LQS1FL3NdoOn7tgPPdddrXec4fL94CwgNk4rCU+OjjZRNDg==", - "license": "LGPL-3.0", - "dependencies": { - "web3-core-helpers": "1.2.2", - "xhr2-cookies": "1.1.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/web3-providers-ipc": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.2.2.tgz", - "integrity": "sha512-t97w3zi5Kn/LEWGA6D9qxoO0LBOG+lK2FjlEdCwDQatffB/+vYrzZ/CLYVQSoyFZAlsDoBasVoYSWZK1n39aHA==", - "license": "LGPL-3.0", - "dependencies": { - "oboe": "2.1.4", - "underscore": "1.9.1", - "web3-core-helpers": "1.2.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/web3-providers-ws": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.2.2.tgz", - "integrity": "sha512-Wb1mrWTGMTXOpJkL0yGvL/WYLt8fUIXx8k/l52QB2IiKzvyd42dTWn4+j8IKXGSYYzOm7NMqv6nhA5VDk12VfA==", - "license": "LGPL-3.0", - "dependencies": { - "underscore": "1.9.1", - "web3-core-helpers": "1.2.2", - "websocket": "github:web3-js/WebSocket-Node#polyfill/globalThis" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/web3-shh": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.2.2.tgz", - "integrity": "sha512-og258NPhlBn8yYrDWjoWBBb6zo1OlBgoWGT+LL5/LPqRbjPe09hlOYHgscAAr9zZGtohTOty7RrxYw6Z6oDWCg==", - "license": "LGPL-3.0", - "dependencies": { - "web3-core": "1.2.2", - "web3-core-method": "1.2.2", - "web3-core-subscriptions": "1.2.2", - "web3-net": "1.2.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/web3-utils": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.2.tgz", - "integrity": "sha512-joF+s3243TY5cL7Z7y4h1JsJpUCf/kmFmj+eJar7Y2yNIGVcW961VyrAms75tjUysSuHaUQ3eQXjBEUJueT52A==", - "license": "LGPL-3.0", - "dependencies": { - "bn.js": "4.11.8", - "eth-lib": "0.2.7", - "ethereum-bloom-filters": "^1.0.6", - "ethjs-unit": "0.1.6", - "number-to-bn": "1.7.0", - "randombytes": "^2.1.0", - "underscore": "1.9.1", - "utf8": "3.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/web3-utils/node_modules/bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "license": "MIT" - }, - "node_modules/web3-utils/node_modules/eth-lib": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", - "integrity": "sha512-VqEBQKH92jNsaE8lG9CTq8M/bc12gdAfb5MY8Ro1hVyXkh7rOtY3m5tRHK3Hus5HqIAAwU2ivcUjTLVwsvf/kw==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.11.6", - "elliptic": "^6.4.0", - "xhr-request-promise": "^0.1.2" - } - }, - "node_modules/web3/node_modules/@types/node": { - "version": "12.20.55", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", - "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", - "license": "MIT" - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/websocket": { - "version": "1.0.29", - "resolved": "git+ssh://git@github.com/web3-js/WebSocket-Node.git#ef5ea2f41daf4a2113b80c9223df884b4d56c400", - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "debug": "^2.2.0", - "es5-ext": "^0.10.50", - "nan": "^2.14.0", - "typedarray-to-buffer": "^3.1.5", - "yaeti": "^0.0.6" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/websocket/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/websocket/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "dev": true, - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", - "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-bigint": "^1.1.0", - "is-boolean-object": "^1.2.1", - "is-number-object": "^1.1.1", - "is-string": "^1.1.1", - "is-symbol": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", - "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "function.prototype.name": "^1.1.6", - "has-tostringtag": "^1.0.2", - "is-async-function": "^2.0.0", - "is-date-object": "^1.1.0", - "is-finalizationregistry": "^1.1.0", - "is-generator-function": "^1.0.10", - "is-regex": "^1.2.1", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.1.0", - "which-collection": "^1.0.2", - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type/node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, - "license": "MIT" - }, - "node_modules/which-collection": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", - "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.19", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", - "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "for-each": "^0.3.5", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dev": true, - "license": "MIT", - "dependencies": { - "string-width": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/wordwrapjs": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", - "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", - "dev": true, - "license": "MIT", - "dependencies": { - "reduce-flatten": "^2.0.0", - "typical": "^5.2.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/wordwrapjs/node_modules/typical": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", - "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/workerpool": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", - "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "license": "MIT", - "dependencies": { - "mkdirp": "^0.5.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "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", - "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", - "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==", - "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", - "resolved": "https://registry.npmjs.org/xhr-request/-/xhr-request-1.1.0.tgz", - "integrity": "sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==", - "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", - "resolved": "https://registry.npmjs.org/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz", - "integrity": "sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg==", - "license": "MIT", - "dependencies": { - "xhr-request": "^1.1.0" - } - }, - "node_modules/xhr2-cookies": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz", - "integrity": "sha512-hjXUA6q+jl/bd8ADHcVfFsSPIf+tyLIjuO9TwJC9WI6JP2zKcS7C+p56I9kCLLsaCiNT035iYvEUUzdEFj/8+g==", - "license": "MIT", - "dependencies": { - "cookiejar": "^2.1.1" - } - }, - "node_modules/xmlhttprequest": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", - "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/yaeti": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", - "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "license": "MIT", - "engines": { - "node": ">=0.10.32" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "license": "ISC" - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yargs-unparser/node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yargs-unparser/node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "license": "MIT", - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zksync-web3": { - "version": "0.14.4", - "resolved": "https://registry.npmjs.org/zksync-web3/-/zksync-web3-0.14.4.tgz", - "integrity": "sha512-kYehMD/S6Uhe1g434UnaMN+sBr9nQm23Ywn0EUP5BfQCsbjcr3ORuS68PosZw8xUTu3pac7G6YMSnNHk+fwzvg==", - "deprecated": "This package has been deprecated in favor of zksync-ethers@5.0.0", - "dev": true, - "license": "MIT", - "peerDependencies": { - "ethers": "^5.7.0" - } - } - } -} diff --git a/solidity/ecdsa/package.json b/solidity/ecdsa/package.json index 5b0feb6670..ac0bdf0a83 100644 --- a/solidity/ecdsa/package.json +++ b/solidity/ecdsa/package.json @@ -11,78 +11,89 @@ "!**/test/", "deploy/", "export/", + "external/random-beacon-export/", "tasks/", + "types/random-beacon.d.ts", + "utils/", "export.json" ], "scripts": { - "install:deps": "corepack enable && corepack prepare yarn@4.8.1 --activate && yarn install", + "install:deps": "corepack enable && corepack prepare yarn@4.12.0 --activate && yarn install", "prepare": "npx tsc -p tsconfig.export.json", "format": "npm run lint", "format:fix": "npm run lint:fix", - "lint": "npm run lint:eslint && npm run lint:sol && npm run lint:config", - "lint:fix": "npm run lint:fix:eslint && npm run lint:fix:sol && npm run lint:config:fix", - "lint:eslint": "eslint .", - "lint:fix:eslint": "eslint . --fix", + "lint": "npm run lint:ts && npm run lint:sol && npm run lint:config", + "lint:fix": "npm run lint:fix:ts && npm run lint:fix:sol && npm run lint:config:fix", + "lint:ts": "eslint . && prettier --check '**/*.@(js|ts|mjs|cjs)' && npm run lint:eslint-policy", + "lint:fix:ts": "eslint . --fix && prettier --write '**/*.@(js|ts|mjs|cjs)'", + "lint:eslint-policy": "node scripts/test-eslint-policy.mjs && node --test scripts/test-eslint-policy.test.mjs", "lint:sol": "solhint 'contracts/**/*.sol' && prettier --check '**/*.sol'", "lint:fix:sol": "solhint 'contracts/**/*.sol' --fix && prettier --write '**/*.sol'", "lint:config": "prettier --check '**/*.@(json|yaml)'", "lint:config:fix": "prettier --write '**/*.@(json|yaml)'", + "typecheck": "tsc --noEmit -p tsconfig.json", "clean": "hardhat clean && rm -rf cache/ export/ external/npm typechain/ export.json", "build": "hardhat compile", "test": "USE_EXTERNAL_DEPLOY=true TEST_USE_STUBS_ECDSA=true hardhat test", "deploy": "hardhat deploy --export export.json", "deploy:test": "USE_EXTERNAL_DEPLOY=true TEST_USE_STUBS_ECDSA=true hardhat deploy", "prepack": "tsc -p tsconfig.export.json && hardhat export-artifacts --including-no-public-functions export/artifacts", - "prepublishOnly": "hardhat prepare-artifacts --network $npm_config_network" + "prepublishOnly": "hardhat export-deployment-artifacts --network \"${npm_config_network:-hardhat}\"" }, "devDependencies": { - "@keep-network/hardhat-helpers": "^0.6.0-pre.15", - "@keep-network/hardhat-local-networks-config": "^0.1.0-pre.4", - "@nomicfoundation/hardhat-chai-matchers": "^1.0.6", + "@keep-network/hardhat-helpers": "patch:@keep-network/hardhat-helpers@npm%3A0.7.2#~/.yarn/patches/@keep-network-hardhat-helpers-npm-0.7.2-086cf3da54.patch", + "@keep-network/hardhat-local-networks-config": "github:threshold-network/hardhat-local-networks-config#6dff5bc8648127ca5d8696c321076bddb6d4142a", + "@nomicfoundation/hardhat-chai-matchers": "^2.1.2", + "@nomicfoundation/hardhat-ethers": "^3.1.3", + "@nomicfoundation/hardhat-network-helpers": "^1.1.2", "@nomicfoundation/hardhat-verify": "^2.1.3", - "@nomiclabs/hardhat-ethers": "^2.0.6", - "@openzeppelin/hardhat-upgrades": "^1.20.4", - "@tenderly/hardhat-tenderly": ">=1.0.13 <1.2.0", - "@thesis-co/eslint-config": "https://codeload.github.com/thesis/eslint-config/tar.gz/778365bbebb6b056bf973d25c57b8b466d21cbcf", - "@typechain/ethers-v5": "^8.0.5", - "@typechain/hardhat": "^4.0.0", - "@types/chai": "^4.3.0", + "@openzeppelin/hardhat-upgrades": "patch:@openzeppelin/hardhat-upgrades@npm%3A2.5.1#~/.yarn/patches/@openzeppelin-hardhat-upgrades-npm-2.5.1-etherscan-v2.patch", + "@stylistic/eslint-plugin": "^5.10.0", + "@tenderly/hardhat-tenderly": "2.1.1", + "@typechain/ethers-v6": "patch:@typechain/ethers-v6@npm%3A0.5.1#~/.yarn/patches/@typechain-ethers-v6-npm-0.5.1-e825560376.patch", + "@typechain/hardhat": "^9.1.0", + "@types/chai": "^4.3.20", "@types/chai-as-promised": "^7.1.5", - "@types/mocha": "^9.1.0", - "@types/node": "^17.0.10", + "@types/mocha": "^10.0.10", + "@types/node": "^24.13.3", "chai": "^4.3.4", "chai-as-promised": "^7.1.1", - "eslint": "^7.32.0", - "ethers": "^5.5.3", + "commander": "^14.0.3", + "eslint": "^10.10.0", + "eslint-import-resolver-typescript": "^4.4.5", + "eslint-plugin-import-x": "^4.17.1", + "eslint-plugin-no-only-tests": "^3.4.0", + "ethers": "^6.17.0", "fs-extra": "^11.2.0", + "globals": "^17.12.0", "hardhat": "2.29.0", "hardhat-contract-sizer": "^2.3.0", "hardhat-dependency-compiler": "^1.1.2", - "hardhat-deploy": "^0.11.11", + "hardhat-deploy": "^1.0.4", "hardhat-gas-reporter": "^2.3.0", - "prettier": "^2.5.1", - "prettier-plugin-sh": "^0.8.1", - "prettier-plugin-solidity": "^1.0.0-beta.19", - "solhint": "^3.3.6", - "solhint-config-keep": "https://codeload.github.com/keep-network/solhint-config-keep/tar.gz/5e1751e58c0f1c507305ffc8c7f6c58047657ada", + "prettier": "^3.9.6", + "prettier-plugin-sh": "^0.19.0", + "prettier-plugin-solidity": "^2.4.1", + "solhint": "^6.2.4", "solidity-docgen": "^0.6.0-beta.35", "ts-node": "^10.4.0", - "typechain": "^6.1.0", - "typescript": "^4.5.4" + "typechain": "^8.3.2", + "typescript": "^6.0.3", + "typescript-eslint": "^8.70.0" }, "dependencies": { - "@keep-network/random-beacon": "development", - "@keep-network/sortition-pools": "^2.0.0-pre.16", "@openzeppelin/contracts": "^4.9.6", "@openzeppelin/contracts-upgradeable": "^4.9.6", "@threshold-network/solidity-contracts": "1.3.0-dev.14" }, "engines": { - "node": ">=22.0.0" + "node": ">=24.0.0" }, "resolutions": { + "axios": "^1.8.4", "ethereumjs-abi": "npm:0.6.8", - "get-func-name": "^2.0.2" + "get-func-name": "^2.0.2", + "@threshold-network/solidity-contracts@npm:1.3.0-dev.14": "patch:@threshold-network/solidity-contracts@npm%3A1.3.0-dev.14#./.yarn/patches/@threshold-network-solidity-contracts-npm-1.3.0-dev.14-ethers-v6.patch" }, - "packageManager": "yarn@4.8.1+sha512.bc946f2a022d7a1a38adfc15b36a66a3807a67629789496c3714dd1703d2e6c6b1c69ff9ec3b43141ac7a1dd853b7685638eb0074300386a59c18df351ef8ff6" + "packageManager": "yarn@4.12.0+sha512.f45ab632439a67f8bc759bf32ead036a1f413287b9042726b7cc4818b7b49e14e9423ba49b18f9e06ea4941c1ad062385b1d8760a8d5091a1a31e5f6219afca8" } diff --git a/solidity/ecdsa/scripts/consolidate_beta_stakers.ts b/solidity/ecdsa/scripts/consolidate_beta_stakers.ts index 6e8c4f5c5e..3a6539cfbc 100644 --- a/solidity/ecdsa/scripts/consolidate_beta_stakers.ts +++ b/solidity/ecdsa/scripts/consolidate_beta_stakers.ts @@ -1,7 +1,18 @@ -/* eslint-disable import/no-extraneous-dependencies, no-restricted-syntax, no-await-in-loop, no-continue, no-plusplus, global-require, @typescript-eslint/no-var-requires */ -import { ethers } from "hardhat" +/* eslint-disable import/no-extraneous-dependencies, no-restricted-syntax, no-await-in-loop, no-continue, no-plusplus */ +import fs from "fs" + +import { ethers, helpers } from "hardhat" import { Command } from "commander" +interface StatusOptions { + allowlist: string +} + +interface ExecuteOptions extends StatusOptions { + signer: string + dryRun?: boolean +} + const program = new Command() // Authoritative consolidation plan: Keep 1 operator per entity, consolidate the rest @@ -79,7 +90,7 @@ program .requiredOption("-a, --allowlist
", "Allowlist contract address") .option("-s, --signer ", "Named signer to use", "governance") .option("--dry-run", "Show what would be done without executing") - .action(async (options) => { + .action(async (options: ExecuteOptions) => { console.log("🚀 BETA STAKER CONSOLIDATION") console.log("=".repeat(50)) console.log(`Allowlist: ${options.allowlist}`) @@ -88,7 +99,10 @@ program console.log() const allowlist = await ethers.getContractAt("Allowlist", options.allowlist) - const signer = await ethers.getNamedSigner(options.signer) + const { [options.signer]: signer } = await helpers.signers.getNamedSigners() + if (!signer) { + throw new Error(`Unknown named signer: ${options.signer}`) + } // Step 1: Check current state console.log("📋 STEP 1: Checking current operator state...") @@ -101,12 +115,12 @@ program try { const weight = await allowlist.authorizedStake( operator, - ethers.constants.AddressZero + ethers.ZeroAddress, ) const entity = ENTITY_MAPPINGS[operator.toLowerCase()] || "UNKNOWN" currentStates[operator] = { - weight: ethers.utils.formatEther(weight), + weight: ethers.formatEther(weight), entity, } @@ -114,9 +128,7 @@ program ? "→ CONSOLIDATE" : "✅ KEEP" console.log( - `${operator} (${entity}): ${ethers.utils.formatEther( - weight - )} T ${status}` + `${operator} (${entity}): ${ethers.formatEther(weight)} T ${status}`, ) } catch (error: any) { console.error(`❌ Error checking ${operator}: ${error.message}`) @@ -126,7 +138,7 @@ program // Validation const missingOperators = allOperators.filter( - (op) => !currentStates[op] || currentStates[op].weight === "0.0" + (op) => !currentStates[op] || currentStates[op].weight === "0.0", ) if (missingOperators.length > 0) { @@ -208,7 +220,7 @@ program const providerInfo = await allowlist.stakingProviders(operator) const pendingWeight = providerInfo.pendingNewWeight - if (pendingWeight.eq(0)) { + if (pendingWeight === 0n) { console.log(`✅ ${operator}: Pending decrease to 0`) } else { console.log(`⚠️ ${operator}: No pending decrease found`) @@ -237,21 +249,20 @@ program console.log("\n⚠️ NEXT STEPS:") console.log("- Weight decreases have been requested") console.log( - "- WalletRegistry will approve these after the decrease delay" + "- WalletRegistry will approve these after the decrease delay", ) console.log( - "- Operators will be unable to create new wallets once approved" + "- Operators will be unable to create new wallets once approved", ) console.log( - "- Existing wallets will continue operating and drain naturally" + "- Existing wallets will continue operating and drain naturally", ) console.log( - "- Monitor progress monthly until operators reach zero custody" + "- Monitor progress monthly until operators reach zero custody", ) } // Save results - const fs = require("fs") const resultsFile = `consolidation-results-${Date.now()}.json` fs.writeFileSync( resultsFile, @@ -270,8 +281,8 @@ program results, }, null, - 2 - ) + 2, + ), ) console.log(`\n💾 Results saved to: ${resultsFile}`) @@ -286,7 +297,7 @@ program .command("status") .description("Check current status of all operators") .requiredOption("-a, --allowlist
", "Allowlist contract address") - .action(async (options) => { + .action(async (options: StatusOptions) => { const allowlist = await ethers.getContractAt("Allowlist", options.allowlist) console.log("CURRENT OPERATOR STATUS") @@ -298,7 +309,7 @@ program const entity = ENTITY_MAPPINGS[operator.toLowerCase()] || "UNKNOWN" const weight = await allowlist.authorizedStake( operator, - ethers.constants.AddressZero + ethers.ZeroAddress, ) const providerInfo = await allowlist.stakingProviders(operator) const pendingWeight = providerInfo.pendingNewWeight @@ -306,16 +317,20 @@ program const status = OPERATORS_TO_CONSOLIDATE.includes(operator) ? "CONSOLIDATE" : "KEEP" - const pending = pendingWeight.gt(0) - ? ` (pending: ${ethers.utils.formatEther(pendingWeight)})` - : "" + const pending = + pendingWeight > 0n + ? ` (pending: ${ethers.formatEther(pendingWeight)})` + : "" console.log(`${operator} (${entity})`) - console.log(` Weight: ${ethers.utils.formatEther(weight)} T${pending}`) + console.log(` Weight: ${ethers.formatEther(weight)} T${pending}`) console.log(` Plan: ${status}`) } }) -program.parse() +program.parseAsync(process.argv).catch((error: unknown) => { + console.error(error instanceof Error ? error.message : String(error)) + process.exitCode = 1 +}) export { OPERATORS_TO_CONSOLIDATE, OPERATORS_TO_KEEP } diff --git a/solidity/ecdsa/scripts/test-eslint-policy.mjs b/solidity/ecdsa/scripts/test-eslint-policy.mjs new file mode 100644 index 0000000000..8b288714bb --- /dev/null +++ b/solidity/ecdsa/scripts/test-eslint-policy.mjs @@ -0,0 +1,107 @@ +// Smoke-test the ecdsa ESLint config to verify: +// (a) no-only-tests fires on it.only() in test files +// (b) ignored paths (typechain/**) produce zero real lint messages +// (c) ordinary test files are actually linted (not silently skipped) +// +// Fixtures are written as real, temporary files directly under this package's +// test/ and typechain/ directories (then deleted) so ESLint's `files`/`ignores` +// globs and the type-aware TS project both see a real, in-project path. +// Checks (a) and (c) deliberately reuse the SAME test/ path, overwritten in +// place: typescript-eslint's project-based parser resolves its TS program +// once per process and never discovers a brand-new path added afterward +// (it fatal-errors "file was not found in any of the provided project(s)"), +// but it does correctly re-lint a path it has already resolved once its +// content changes - confirmed empirically before relying on it here. + +/* eslint-disable import/no-extraneous-dependencies -- eslint is a legitimate devDependency used + here to smoke-test this package's own lint config; it is not a runtime dependency. */ +import { randomUUID } from "node:crypto" +import { mkdirSync, rmSync, writeFileSync } from "node:fs" +import { dirname, join } from "node:path" +import { ESLint } from "eslint" + +const projectRoot = join(import.meta.dirname, "..") +const configPath = join(projectRoot, "eslint.config.mjs") + +let failures = 0 + +function assert(condition, message) { + if (!condition) { + failures += 1 + console.error(`FAIL: ${message}`) + } else { + console.log(`PASS: ${message}`) + } +} + +async function lintFixture(relativePath, code) { + const fullPath = join(projectRoot, relativePath) + mkdirSync(dirname(fullPath), { recursive: true }) + writeFileSync(fullPath, code) + const eslint = new ESLint({ + cwd: projectRoot, + overrideConfigFile: configPath, + }) + const results = await eslint.lintFiles([fullPath]) + const messages = results[0]?.messages ?? [] + // Exclude ESLint's own synthetic "file ignored" notice (ruleId: null) so a + // genuinely-ignored path with zero rule violations reads as zero messages. + return messages.filter((m) => m.ruleId !== null) +} + +const nonce = randomUUID() +const sharedTestFixture = `test/policy-fixture-${nonce}.ts` +const ignoredFixture = `typechain/policy-fixture-ignored-${nonce}.ts` + +function cleanup() { + rmSync(join(projectRoot, sharedTestFixture), { force: true }) + rmSync(join(projectRoot, ignoredFixture), { force: true }) +} + +process.once("SIGINT", () => { + cleanup() + process.kill(process.pid, "SIGINT") +}) +process.once("SIGTERM", () => { + cleanup() + process.kill(process.pid, "SIGTERM") +}) +try { + // Fixture (a): it.only in a test file should trigger no-only-tests + const onlyMessages = await lintFixture( + sharedTestFixture, + 'it.only("x", () => {})\n', + ) + assert( + onlyMessages.some((m) => m.ruleId === "no-only-tests/no-only-tests"), + "it.only() in test/**/*.ts triggers no-only-tests/no-only-tests", + ) + + // Fixture (c): an ordinary test file should be linted (at least one rule evaluated). + // Reuses sharedTestFixture's already-resolved path, overwritten with new content. + const lintedMessages = await lintFixture(sharedTestFixture, "var y = 1\n") + assert( + lintedMessages.length > 0, + "ordinary test/**/*.ts fixture is actually linted (not silently skipped)", + ) + + // Fixture (b): file matching an ignores glob (typechain/**) should have zero messages + const ignoredMessages = await lintFixture( + ignoredFixture, + "const x: any = 1\n", + ) + assert( + ignoredMessages.length === 0, + "typechain/**/*.ts fixture produces zero lint messages (ignored)", + ) +} finally { + cleanup() +} + +if (failures > 0) { + console.error(`\n${failures} policy assertion(s) failed.`) + process.exit(1) +} else { + console.log("\nAll ESLint policy assertions passed.") + process.exit(0) +} diff --git a/solidity/ecdsa/scripts/test-eslint-policy.test.mjs b/solidity/ecdsa/scripts/test-eslint-policy.test.mjs new file mode 100644 index 0000000000..db8cf2d421 --- /dev/null +++ b/solidity/ecdsa/scripts/test-eslint-policy.test.mjs @@ -0,0 +1,169 @@ +// Automated tests for the SIGINT/SIGTERM cleanup contract in +// `test-eslint-policy.mjs`. The smoke-test script writes temporary fixture +// files under this package's test/ and typechain/ directories and depends +// on its signal handlers removing them when the process is interrupted +// before the script's `finally` block can run. These tests spawn the smoke +// test as a child process, interrupt it with SIGINT and SIGTERM mid-run, +// and verify that no `policy-fixture-*.ts` files are left behind in either +// directory. A normal-completion run is also covered so a regression that +// breaks the `finally` cleanup shows up here as well. +// +// Run from this directory with: node --test scripts/test-eslint-policy.test.mjs + +import { test, beforeEach, afterEach } from "node:test" +import assert from "node:assert/strict" +import { spawn } from "node:child_process" +import { existsSync, readdirSync, rmSync } from "node:fs" +import { join } from "node:path" +import { setTimeout as sleep } from "node:timers/promises" + +const scriptPath = new URL("./test-eslint-policy.mjs", import.meta.url).pathname +const projectRoot = join(import.meta.dirname, "..") +const testDir = join(projectRoot, "test") +const typechainDir = join(projectRoot, "typechain") + +// The smoke test scopes every temporary fixture it creates under a +// `policy-fixture-.ts` filename. Matching that prefix is enough to +// distinguish smoke-test fixtures from any other file the package may +// legitimately have under test/ or typechain/. +const FIXTURE_PATTERN = /^policy-fixture-.*\.ts$/ + +function findPolicyFixtures(dir) { + if (!existsSync(dir)) return [] + return readdirSync(dir).filter((f) => FIXTURE_PATTERN.test(f)) +} + +function listFixtures() { + return { + test: findPolicyFixtures(testDir), + typechain: findPolicyFixtures(typechainDir), + } +} + +function cleanupFixtures() { + ;[testDir, typechainDir].forEach((dir) => { + findPolicyFixtures(dir).forEach((f) => { + rmSync(join(dir, f), { force: true }) + }) + }) +} + +// Poll until at least one prefixed fixture exists, then return. The smoke +// test creates the first fixture file very early in its run, so once any +// file is present the script is mid-execution and SIGINT/SIGTERM can +// interrupt it before the `finally` cleanup runs. Recursive tail call to +// keep the await outside of any loop body. +async function waitForAnyFixture(timeoutMs = 30_000, pollMs = 25) { + const fixtures = listFixtures() + if (fixtures.test.length > 0 || fixtures.typechain.length > 0) { + return fixtures + } + if (timeoutMs <= 0) { + return null + } + await sleep(pollMs) + return waitForAnyFixture(timeoutMs - pollMs, pollMs) +} + +function spawnSmokeTest() { + return spawn(process.execPath, [scriptPath], { + cwd: projectRoot, + stdio: ["ignore", "pipe", "pipe"], + }) +} + +function awaitExit(child) { + if (child.exitCode !== null || child.signalCode !== null) { + return Promise.resolve({ code: child.exitCode, signal: child.signalCode }) + } + return new Promise((resolve) => { + child.once("exit", (code, signal) => resolve({ code, signal })) + }) +} + +function assertExitShape(actual, expectedCode, expectedSignal, message) { + const { code, signal } = actual + if (code !== expectedCode && signal !== expectedSignal) { + throw new Error( + `${message}: expected code=${expectedCode} or signal=${expectedSignal}; got code=${code} signal=${signal}`, + ) + } +} + +beforeEach(cleanupFixtures) +afterEach(cleanupFixtures) + +test("normal completion exits 0 and leaves no prefixed fixtures", async (t) => { + const child = spawnSmokeTest() + // Guarantee no leaked process if the test times out. + t.after(() => { + if (child.exitCode === null && child.signalCode === null) { + child.kill("SIGKILL") + } + }) + + const exitInfo = await awaitExit(child) + assertExitShape(exitInfo, 0, null, "normal completion exit") + + // Brief grace period so a lazy async filesystem flush cannot give a + // false positive on the cleanup check. + await sleep(100) + + assert.deepEqual( + listFixtures(), + { test: [], typechain: [] }, + "no prefixed fixtures should remain after normal completion", + ) +}) + +test("SIGINT cleans up fixtures and exits 130 (or via SIGINT signal)", async (t) => { + const child = spawnSmokeTest() + t.after(() => { + if (child.exitCode === null && child.signalCode === null) { + child.kill("SIGKILL") + } + }) + + const observed = await waitForAnyFixture() + assert.ok( + observed, + "smoke test did not create a prefixed fixture within the polling window; cannot interrupt", + ) + + child.kill("SIGINT") + const exitInfo = await awaitExit(child) + assertExitShape(exitInfo, 130, "SIGINT", "SIGINT exit shape") + + await sleep(100) + assert.deepEqual( + listFixtures(), + { test: [], typechain: [] }, + "no prefixed fixtures should remain after SIGINT", + ) +}) + +test("SIGTERM cleans up fixtures and exits 143 (or via SIGTERM signal)", async (t) => { + const child = spawnSmokeTest() + t.after(() => { + if (child.exitCode === null && child.signalCode === null) { + child.kill("SIGKILL") + } + }) + + const observed = await waitForAnyFixture() + assert.ok( + observed, + "smoke test did not create a prefixed fixture within the polling window; cannot interrupt", + ) + + child.kill("SIGTERM") + const exitInfo = await awaitExit(child) + assertExitShape(exitInfo, 143, "SIGTERM", "SIGTERM exit shape") + + await sleep(100) + assert.deepEqual( + listFixtures(), + { test: [], typechain: [] }, + "no prefixed fixtures should remain after SIGTERM", + ) +}) diff --git a/solidity/ecdsa/slither.config.json b/solidity/ecdsa/slither.config.json index 73166200ad..af8f4d8195 100644 --- a/solidity/ecdsa/slither.config.json +++ b/solidity/ecdsa/slither.config.json @@ -1,5 +1,5 @@ { "detectors_to_exclude": "assembly,timestamp,solc-version,naming-convention,name-reused", "hardhat_artifacts_directory": "./build", - "filter_paths": "test|node_modules|BytesLib.sol" + "filter_paths": "test|node_modules|BytesLib.sol|contracts/legacy/" } diff --git a/solidity/ecdsa/tasks/index.ts b/solidity/ecdsa/tasks/index.ts index ed30fceb50..e827e04de6 100644 --- a/solidity/ecdsa/tasks/index.ts +++ b/solidity/ecdsa/tasks/index.ts @@ -1,3 +1,2 @@ import "./initialize-wallet-owner" import "./initialize" -import "@keep-network/random-beacon/export/tasks/unlock-eth-accounts" diff --git a/solidity/ecdsa/tasks/initialize-wallet-owner.ts b/solidity/ecdsa/tasks/initialize-wallet-owner.ts index 3071fb2733..152ba8a2a6 100644 --- a/solidity/ecdsa/tasks/initialize-wallet-owner.ts +++ b/solidity/ecdsa/tasks/initialize-wallet-owner.ts @@ -13,14 +13,14 @@ task("initialize-wallet-owner", "Initializes Wallet Owner for Wallet Registry") async function initializeWalletOwner( hre: HardhatRuntimeEnvironment, - walletOwnerAddress: string + walletOwnerAddress: string, ): Promise { const { getNamedAccounts, ethers, deployments, helpers } = hre const { read, execute } = deployments const { deployer, governance } = await getNamedAccounts() - const ZERO = ethers.constants.AddressZero + const ZERO = ethers.ZeroAddress - if (!ethers.utils.isAddress(walletOwnerAddress)) { + if (!ethers.isAddress(walletOwnerAddress)) { throw Error(`invalid address: ${walletOwnerAddress}`) } @@ -31,24 +31,24 @@ async function initializeWalletOwner( if (!helpers.address.equal(wr.address, wrLinked)) { throw new Error( `WalletRegistryGovernance (${wrg.address}) is wired to WalletRegistry ${wrLinked} but deployments WalletRegistry is ${wr.address}. ` + - "Align keep-core Phase F artifacts with tbtc-v2 Phase G copies before initializeWalletOwner." + "Align keep-core Phase F artifacts with tbtc-v2 Phase G copies before initializeWalletOwner.", ) } if (!helpers.address.equal(wrg.address, wrGovernance)) { console.log( "WalletRegistry governance is not this WalletRegistryGovernance deployment; skipping initializeWalletOwner " + - "(use the on-chain governance contract from keep-core Phase F, or governance-delay updates)." + "(use the on-chain governance contract from keep-core Phase F, or governance-delay updates).", ) return } const woRaw = String( - await read("WalletRegistry", {}, "walletOwner") + await read("WalletRegistry", {}, "walletOwner"), ).toLowerCase() if (woRaw !== ZERO.toLowerCase()) { console.log( - "WalletRegistry wallet owner already initialized; skipping initializeWalletOwner" + "WalletRegistry wallet owner already initialized; skipping initializeWalletOwner", ) return } @@ -59,7 +59,7 @@ async function initializeWalletOwner( const wrGovernanceNow = await read("WalletRegistry", {}, "governance") if (!helpers.address.equal(wrg.address, wrGovernanceNow)) { throw new Error( - `WalletRegistry.governance() drifted before initializeWalletOwner (now ${wrGovernanceNow}, expected WRG ${wrg.address}).` + `WalletRegistry.governance() drifted before initializeWalletOwner (now ${wrGovernanceNow}, expected WRG ${wrg.address}).`, ) } @@ -76,7 +76,7 @@ async function initializeWalletOwner( } else { throw new Error( `WalletRegistryGovernance owner is ${wrgOwner}; expected deployer (${deployer}) or governance (${governance}). ` + - "Ownable.transferOwnership must leave the deploy key as owner for this step, or call initializeWalletOwner with the current owner key." + "Ownable.transferOwnership must leave the deploy key as owner for this step, or call initializeWalletOwner with the current owner key.", ) } @@ -84,11 +84,11 @@ async function initializeWalletOwner( "WalletRegistryGovernance", { from, log: true, waitConfirmations: 1 }, "initializeWalletOwner", - walletOwnerAddress + walletOwnerAddress, ) console.log( - `Initialized Wallet Owner address: ${walletOwnerAddress} in transaction: ${tx.transactionHash}` + `Initialized Wallet Owner address: ${walletOwnerAddress} in transaction: ${tx.transactionHash}`, ) } diff --git a/solidity/ecdsa/tasks/initialize.ts b/solidity/ecdsa/tasks/initialize.ts index 1ebf93ffc7..014cd63431 100644 --- a/solidity/ecdsa/tasks/initialize.ts +++ b/solidity/ecdsa/tasks/initialize.ts @@ -1,16 +1,15 @@ import { task, types } from "hardhat/config" + import { TASK_INITIALIZE, TASK_AUTHORIZE, TASK_REGISTER, TASK_INITIALIZE_STAKING, TASK_ADD_BETA_OPERATOR, -} from "@keep-network/random-beacon/export/tasks/initialize" -import { authorize, register, addBetaOperator, -} from "@keep-network/random-beacon/export/tasks/utils" +} from "./random-beacon" // Tasks for the ECDSA application. const TASK_INITIALIZE_ECDSA = `${TASK_INITIALIZE}:ecdsa` @@ -20,7 +19,7 @@ const TASK_ADD_BETA_OPERATOR_ECDSA = `${TASK_ADD_BETA_OPERATOR}:ecdsa` task( TASK_INITIALIZE, - "Initializes staking and the ECDSA application for a staking provider and an operator" + "Initializes staking and the ECDSA application for a staking provider and an operator", ).setAction(async (args, hre) => { // Initialize staking await hre.run(TASK_INITIALIZE_STAKING, args) @@ -37,7 +36,7 @@ task(TASK_INITIALIZE_ECDSA, "Initializes operator for ECDSA") "authorization", "Authorization amount (default: minimumAuthorization)", undefined, - types.int + types.int, ) .setAction(async (args, hre) => { await hre.run(TASK_AUTHORIZE_ECDSA, args) @@ -53,7 +52,7 @@ task(TASK_AUTHORIZE_ECDSA, "Sets authorization for ECDSA") "authorization", "Authorization amount (default: minimumAuthorization)", undefined, - types.int + types.int, ) .setAction(async (args, hre) => { await authorize( @@ -62,13 +61,13 @@ task(TASK_AUTHORIZE_ECDSA, "Sets authorization for ECDSA") args.owner, args.provider, args.authorizer, - args.authorization + args.authorization, ) }) task( TASK_REGISTER_ECDSA, - "Registers an operator for a staking provider in ECDSA" + "Registers an operator for a staking provider in ECDSA", ) .addParam("provider", "Staking Provider", undefined, types.string) .addParam("operator", "Staking Operator", undefined, types.string) @@ -78,7 +77,7 @@ task( task( TASK_ADD_BETA_OPERATOR_ECDSA, - "Adds an operator to the set of beta operators in ECDSA" + "Adds an operator to the set of beta operators in ECDSA", ) .addParam("operator", "Operator Address", undefined, types.string) .setAction(async (args, hre) => { diff --git a/solidity/ecdsa/tasks/legacy-random-beacon/LICENSE b/solidity/ecdsa/tasks/legacy-random-beacon/LICENSE new file mode 100644 index 0000000000..e72bfddabc --- /dev/null +++ b/solidity/ecdsa/tasks/legacy-random-beacon/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/solidity/ecdsa/tasks/legacy-random-beacon/initialize.js b/solidity/ecdsa/tasks/legacy-random-beacon/initialize.js new file mode 100644 index 0000000000..72c098c2ae --- /dev/null +++ b/solidity/ecdsa/tasks/legacy-random-beacon/initialize.js @@ -0,0 +1,210 @@ +"use strict"; +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TASK_ADD_BETA_OPERATOR = exports.TASK_REGISTER = exports.TASK_AUTHORIZE = exports.TASK_STAKE = exports.TASK_MINT = exports.TASK_INITIALIZE_STAKING = exports.TASK_INITIALIZE = void 0; +var config_1 = require("hardhat/config"); +var utils_1 = require("./utils"); +// Main task executing all child tasks. +exports.TASK_INITIALIZE = "initialize"; +// Subtask for staking. +exports.TASK_INITIALIZE_STAKING = exports.TASK_INITIALIZE + ":staking"; +// Staking tasks. +exports.TASK_MINT = "mint"; +exports.TASK_STAKE = "stake"; +// Name prefix that should be used in tasks implementation for specific application. +exports.TASK_AUTHORIZE = "authorize"; +exports.TASK_REGISTER = "register"; +exports.TASK_ADD_BETA_OPERATOR = "add_beta_operator"; +// Subtask for the Random Beacon application. +var TASK_INITIALIZE_BEACON = exports.TASK_INITIALIZE + ":beacon"; +var TASK_AUTHORIZE_BEACON = exports.TASK_AUTHORIZE + ":beacon"; +var TASK_REGISTER_BEACON = exports.TASK_REGISTER + ":beacon"; +var TASK_ADD_BETA_OPERATOR_BEACON = exports.TASK_ADD_BETA_OPERATOR + ":beacon"; +(0, config_1.task)(exports.TASK_INITIALIZE, "Initializes staking and the Random Beacon application for a staking provider and an operator") + .addParam("owner", "Stake Owner address", undefined, config_1.types.string) + .addParam("provider", "Staking Provider", undefined, config_1.types.string) + .addParam("operator", "Staking Operator", undefined, config_1.types.string) + .addOptionalParam("beneficiary", "Stake Beneficiary", undefined, config_1.types.string) + .addOptionalParam("authorizer", "Stake Authorizer", undefined, config_1.types.string) + .addOptionalParam("amount", "Stake amount", 1000000, config_1.types.int) + .addOptionalParam("authorization", "Authorization amount (default: minimumAuthorization)", undefined, config_1.types.int) + .setAction(function (args, hre) { return __awaiter(void 0, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + // Initialize staking + return [4 /*yield*/, hre.run(exports.TASK_INITIALIZE_STAKING, args) + // Initialize Beacon + ]; + case 1: + // Initialize staking + _a.sent(); + // Initialize Beacon + return [4 /*yield*/, hre.run(TASK_INITIALIZE_BEACON, args) + // Set the operator as a beta operator + ]; + case 2: + // Initialize Beacon + _a.sent(); + // Set the operator as a beta operator + return [4 /*yield*/, hre.run(TASK_ADD_BETA_OPERATOR_BEACON, args)]; + case 3: + // Set the operator as a beta operator + _a.sent(); + return [2 /*return*/]; + } + }); +}); }); +(0, config_1.task)(exports.TASK_INITIALIZE_STAKING, "Initializes staking for a service provider") + .addParam("owner", "Stake Owner address", undefined, config_1.types.string) + .addParam("provider", "Staking Provider", undefined, config_1.types.string) + .addOptionalParam("beneficiary", "Stake Beneficiary", undefined, config_1.types.string) + .addOptionalParam("authorizer", "Stake Authorizer", undefined, config_1.types.string) + .addOptionalParam("amount", "Stake amount", 1000000, config_1.types.int) + .setAction(function (args, hre) { return __awaiter(void 0, void 0, void 0, function () { + var tokensToMint; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, (0, utils_1.calculateTokensNeededForStake)(hre, args.provider, args.amount)]; + case 1: + tokensToMint = _a.sent(); + if (!!tokensToMint.isZero()) return [3 /*break*/, 3]; + return [4 /*yield*/, hre.run(exports.TASK_MINT, __assign(__assign({}, args), { amount: tokensToMint.toNumber() }))]; + case 2: + _a.sent(); + _a.label = 3; + case 3: return [4 /*yield*/, hre.run(exports.TASK_STAKE, args)]; + case 4: + _a.sent(); + return [2 /*return*/]; + } + }); +}); }); +(0, config_1.task)(exports.TASK_MINT, "Mints T tokens") + .addParam("owner", "Stake Owner address", undefined, config_1.types.string) + .addOptionalParam("amount", "Stake amount", 1000000, config_1.types.int) + .setAction(function (args, hre) { return __awaiter(void 0, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, (0, utils_1.mint)(hre, args.owner, args.amount)]; + case 1: + _a.sent(); + return [2 /*return*/]; + } + }); +}); }); +(0, config_1.task)(exports.TASK_STAKE, "Stakes T tokens") + .addParam("owner", "Stake Owner address", undefined, config_1.types.string) + .addParam("provider", "Staking Provider", undefined, config_1.types.string) + .addOptionalParam("beneficiary", "Stake Beneficiary", undefined, config_1.types.string) + .addOptionalParam("authorizer", "Stake Authorizer", undefined, config_1.types.string) + .addOptionalParam("amount", "Stake amount", 1000000, config_1.types.int) + .setAction(function (args, hre) { return __awaiter(void 0, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, (0, utils_1.stake)(hre, args.owner, args.provider, args.amount, args.beneficiary, args.authorizer)]; + case 1: + _a.sent(); + return [2 /*return*/]; + } + }); +}); }); +(0, config_1.task)(TASK_INITIALIZE_BEACON, "Initializes operator for Beacon").setAction(function (args, hre) { return __awaiter(void 0, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, hre.run(TASK_AUTHORIZE_BEACON, args)]; + case 1: + _a.sent(); + return [4 /*yield*/, hre.run(TASK_REGISTER_BEACON, args)]; + case 2: + _a.sent(); + return [2 /*return*/]; + } + }); +}); }); +(0, config_1.task)(TASK_AUTHORIZE_BEACON, "Sets authorization for Beacon") + .addParam("owner", "Stake Owner address", undefined, config_1.types.string) + .addParam("provider", "Staking Provider", undefined, config_1.types.string) + .addOptionalParam("authorizer", "Stake Authorizer", undefined, config_1.types.string) + .addOptionalParam("authorization", "Authorization amount (default: minimumAuthorization)", undefined, config_1.types.int) + .setAction(function (args, hre) { return __awaiter(void 0, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, (0, utils_1.authorize)(hre, "RandomBeacon", args.owner, args.provider, args.authorizer, args.authorization)]; + case 1: + _a.sent(); + return [2 /*return*/]; + } + }); +}); }); +(0, config_1.task)(TASK_REGISTER_BEACON, "Registers an operator for a staking provider in Beacon") + .addParam("provider", "Staking Provider", undefined, config_1.types.string) + .addParam("operator", "Operator Address", undefined, config_1.types.string) + .setAction(function (args, hre) { return __awaiter(void 0, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, (0, utils_1.register)(hre, "RandomBeacon", args.provider, args.operator)]; + case 1: + _a.sent(); + return [2 /*return*/]; + } + }); +}); }); +(0, config_1.task)(TASK_ADD_BETA_OPERATOR_BEACON, "Adds an operator to the set of beta operators in Beacon") + .addParam("operator", "Operator Address", undefined, config_1.types.string) + .setAction(function (args, hre) { return __awaiter(void 0, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, (0, utils_1.addBetaOperator)(hre, "BeaconSortitionPool", args.operator)]; + case 1: + _a.sent(); + return [2 /*return*/]; + } + }); +}); }); diff --git a/solidity/ecdsa/tasks/legacy-random-beacon/unlock-eth-accounts.js b/solidity/ecdsa/tasks/legacy-random-beacon/unlock-eth-accounts.js new file mode 100644 index 0000000000..174da6e2b8 --- /dev/null +++ b/solidity/ecdsa/tasks/legacy-random-beacon/unlock-eth-accounts.js @@ -0,0 +1,88 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var config_1 = require("hardhat/config"); +(0, config_1.task)("unlock-accounts", "Unlock ethereum accounts").setAction(function (args, hre) { return __awaiter(void 0, void 0, void 0, function () { + var ethers, password, provider, accounts, i, account, error_1; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + ethers = hre.ethers; + if (!(hre.network.name === "development")) return [3 /*break*/, 8]; + password = process.env.KEEP_ETHEREUM_PASSWORD || "password"; + provider = new ethers.providers.JsonRpcProvider(hre.network.config.url); + return [4 /*yield*/, provider.listAccounts()]; + case 1: + accounts = _a.sent(); + console.log("Total accounts: " + accounts.length); + console.log("---------------------------------"); + i = 0; + _a.label = 2; + case 2: + if (!(i < accounts.length)) return [3 /*break*/, 8]; + account = accounts[i]; + _a.label = 3; + case 3: + _a.trys.push([3, 5, , 6]); + console.log("\nUnlocking account: " + account); + // An explicit duration of zero seconds unlocks the key until geth exits. + return [4 /*yield*/, provider.send("personal_unlockAccount", [ + account.toLowerCase(), + password, + 0, + ])]; + case 4: + // An explicit duration of zero seconds unlocks the key until geth exits. + _a.sent(); + console.log("Account unlocked!"); + return [3 /*break*/, 6]; + case 5: + error_1 = _a.sent(); + console.log("\nAccount: " + account + " not unlocked!"); + console.error(error_1); + return [3 /*break*/, 6]; + case 6: + console.log("\n---------------------------------"); + _a.label = 7; + case 7: + i++; + return [3 /*break*/, 2]; + case 8: return [2 /*return*/]; + } + }); +}); }); diff --git a/solidity/ecdsa/tasks/legacy-random-beacon/utils/add_beta_operator.js b/solidity/ecdsa/tasks/legacy-random-beacon/utils/add_beta_operator.js new file mode 100644 index 0000000000..c7844c2359 --- /dev/null +++ b/solidity/ecdsa/tasks/legacy-random-beacon/utils/add_beta_operator.js @@ -0,0 +1,68 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.addBetaOperator = void 0; +// eslint-disable-next-line import/prefer-default-export +function addBetaOperator(hre, sortitionPoolDeploymentName, operator) { + return __awaiter(this, void 0, void 0, function () { + var ethers, helpers, sortitionPool, chaosnetOwner, _a, _b; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + ethers = hre.ethers, helpers = hre.helpers; + return [4 /*yield*/, helpers.contracts.getContract(sortitionPoolDeploymentName)]; + case 1: + sortitionPool = _c.sent(); + return [4 /*yield*/, sortitionPool.chaosnetOwner()]; + case 2: + chaosnetOwner = _c.sent(); + console.log("Adding " + operator + " to the set of beta operators..."); + _b = (_a = sortitionPool) + .connect; + return [4 /*yield*/, ethers.getSigner(chaosnetOwner)]; + case 3: return [4 /*yield*/, _b.apply(_a, [_c.sent()]) + .addBetaOperators([operator])]; + case 4: return [4 /*yield*/, (_c.sent()).wait()]; + case 5: + _c.sent(); + return [2 /*return*/]; + } + }); + }); +} +exports.addBetaOperator = addBetaOperator; diff --git a/solidity/ecdsa/tasks/legacy-random-beacon/utils/authorize.js b/solidity/ecdsa/tasks/legacy-random-beacon/utils/authorize.js new file mode 100644 index 0000000000..2ffad09716 --- /dev/null +++ b/solidity/ecdsa/tasks/legacy-random-beacon/utils/authorize.js @@ -0,0 +1,93 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.authorize = void 0; +// eslint-disable-next-line import/prefer-default-export +function authorize(hre, deploymentName, // TODO: Change to IApplication +owner, provider, authorizer, authorization) { + return __awaiter(this, void 0, void 0, function () { + var ethers, helpers, ownerAddress, providerAddress, application, authorizerAddress, _a, to1e18, from1e18, staking, authorizationBN, _b, currentAuthorization, increaseAmount, _c, _d; + return __generator(this, function (_e) { + switch (_e.label) { + case 0: + ethers = hre.ethers, helpers = hre.helpers; + ownerAddress = ethers.utils.getAddress(owner); + providerAddress = ethers.utils.getAddress(provider); + return [4 /*yield*/, helpers.contracts.getContract(deploymentName)]; + case 1: + application = _e.sent(); + console.log("Authorizing provider's " + providerAddress + " stake in " + deploymentName + " application (" + application.address + ")"); + authorizerAddress = authorizer + ? ethers.utils.getAddress(authorizer) + : ownerAddress; + _a = helpers.number, to1e18 = _a.to1e18, from1e18 = _a.from1e18; + return [4 /*yield*/, helpers.contracts.getContract("TokenStaking")]; + case 2: + staking = _e.sent(); + if (!authorization) return [3 /*break*/, 3]; + _b = to1e18(authorization); + return [3 /*break*/, 5]; + case 3: return [4 /*yield*/, application.minimumAuthorization()]; + case 4: + _b = _e.sent(); + _e.label = 5; + case 5: + authorizationBN = _b; + return [4 /*yield*/, staking.authorizedStake(providerAddress, application.address)]; + case 6: + currentAuthorization = _e.sent(); + if (currentAuthorization.gte(authorizationBN)) { + console.log("Authorized stake is already " + from1e18(currentAuthorization) + " T"); + return [2 /*return*/]; + } + increaseAmount = authorizationBN.sub(currentAuthorization); + console.log("Increasing authorization by " + from1e18(increaseAmount) + " T to " + from1e18(authorizationBN) + " T..."); + _d = (_c = staking) + .connect; + return [4 /*yield*/, ethers.getSigner(authorizerAddress)]; + case 7: return [4 /*yield*/, _d.apply(_c, [_e.sent()]) + .increaseAuthorization(providerAddress, application.address, increaseAmount)]; + case 8: return [4 /*yield*/, (_e.sent()).wait()]; + case 9: + _e.sent(); + return [2 /*return*/]; + } + }); + }); +} +exports.authorize = authorize; diff --git a/solidity/ecdsa/tasks/legacy-random-beacon/utils/ether.js b/solidity/ecdsa/tasks/legacy-random-beacon/utils/ether.js new file mode 100644 index 0000000000..5413d4b8fa --- /dev/null +++ b/solidity/ecdsa/tasks/legacy-random-beacon/utils/ether.js @@ -0,0 +1,12 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.parseValue = void 0; +// eslint-disable-next-line import/prefer-default-export +function parseValue(value, hre) { + var parsed = String(value).trim().split(" "); + if (parsed.length === 0 || parsed.length > 2) { + throw new Error("invalid value: " + value); + } + return hre.ethers.utils.parseUnits(parsed[0], parsed[1] || "wei"); +} +exports.parseValue = parseValue; diff --git a/solidity/ecdsa/tasks/legacy-random-beacon/utils/index.js b/solidity/ecdsa/tasks/legacy-random-beacon/utils/index.js new file mode 100644 index 0000000000..50ca45e357 --- /dev/null +++ b/solidity/ecdsa/tasks/legacy-random-beacon/utils/index.js @@ -0,0 +1,18 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +__exportStar(require("./authorize"), exports); +__exportStar(require("./ether"), exports); +__exportStar(require("./mint"), exports); +__exportStar(require("./register"), exports); +__exportStar(require("./stake"), exports); +__exportStar(require("./add_beta_operator"), exports); diff --git a/solidity/ecdsa/tasks/legacy-random-beacon/utils/mint.js b/solidity/ecdsa/tasks/legacy-random-beacon/utils/mint.js new file mode 100644 index 0000000000..eb6789f96f --- /dev/null +++ b/solidity/ecdsa/tasks/legacy-random-beacon/utils/mint.js @@ -0,0 +1,96 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.mint = void 0; +// eslint-disable-next-line import/prefer-default-export +function mint(hre, owner, amount) { + return __awaiter(this, void 0, void 0, function () { + var ethers, helpers, _a, to1e18, from1e18, ownerAddress, stakeAmount, t, staking, tokenContractOwner, currentBalance, mintAmount, _b, _c, currentAllowance, _d, _e; + return __generator(this, function (_f) { + switch (_f.label) { + case 0: + ethers = hre.ethers, helpers = hre.helpers; + _a = helpers.number, to1e18 = _a.to1e18, from1e18 = _a.from1e18; + ownerAddress = ethers.utils.getAddress(owner); + stakeAmount = to1e18(amount); + return [4 /*yield*/, helpers.contracts.getContract("T")]; + case 1: + t = _f.sent(); + return [4 /*yield*/, helpers.contracts.getContract("TokenStaking")]; + case 2: + staking = _f.sent(); + return [4 /*yield*/, t.owner()]; + case 3: + tokenContractOwner = _f.sent(); + return [4 /*yield*/, t.balanceOf(ownerAddress)]; + case 4: + currentBalance = _f.sent(); + console.log("Account " + ownerAddress + " balance is " + from1e18(currentBalance) + " T"); + if (!currentBalance.lt(stakeAmount)) return [3 /*break*/, 8]; + mintAmount = stakeAmount.sub(currentBalance); + console.log("Minting " + from1e18(mintAmount) + " T for " + ownerAddress + "..."); + _c = (_b = t) + .connect; + return [4 /*yield*/, ethers.getSigner(tokenContractOwner)]; + case 5: return [4 /*yield*/, _c.apply(_b, [_f.sent()]) + .mint(ownerAddress, mintAmount)]; + case 6: return [4 /*yield*/, (_f.sent()).wait()]; + case 7: + _f.sent(); + _f.label = 8; + case 8: return [4 /*yield*/, t.allowance(ownerAddress, staking.address)]; + case 9: + currentAllowance = _f.sent(); + console.log("Account " + ownerAddress + " allowance for " + staking.address + " is " + from1e18(currentAllowance) + " T"); + if (!currentAllowance.lt(stakeAmount)) return [3 /*break*/, 13]; + console.log("Approving " + from1e18(stakeAmount) + " T for " + staking.address + "..."); + _e = (_d = t) + .connect; + return [4 /*yield*/, ethers.getSigner(ownerAddress)]; + case 10: return [4 /*yield*/, _e.apply(_d, [_f.sent()]) + .approve(staking.address, stakeAmount)]; + case 11: return [4 /*yield*/, (_f.sent()).wait()]; + case 12: + _f.sent(); + _f.label = 13; + case 13: return [2 /*return*/]; + } + }); + }); +} +exports.mint = mint; diff --git a/solidity/ecdsa/tasks/legacy-random-beacon/utils/register.js b/solidity/ecdsa/tasks/legacy-random-beacon/utils/register.js new file mode 100644 index 0000000000..c6fb29d1ca --- /dev/null +++ b/solidity/ecdsa/tasks/legacy-random-beacon/utils/register.js @@ -0,0 +1,91 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.register = void 0; +// eslint-disable-next-line import/prefer-default-export +function register(hre, deploymentName, provider, operator) { + return __awaiter(this, void 0, void 0, function () { + var ethers, helpers, providerAddress, operatorAddress, application, currentProvider, _a, _b, _c, _d, _e; + return __generator(this, function (_f) { + switch (_f.label) { + case 0: + ethers = hre.ethers, helpers = hre.helpers; + providerAddress = ethers.utils.getAddress(provider); + operatorAddress = ethers.utils.getAddress(operator); + return [4 /*yield*/, helpers.contracts.getContract(deploymentName)]; + case 1: + application = _f.sent(); + console.log("Registering operator " + operatorAddress + " in " + deploymentName + " application (" + application.address + ")"); + _b = (_a = ethers.utils).getAddress; + return [4 /*yield*/, application.callStatic.operatorToStakingProvider(operatorAddress)]; + case 2: + currentProvider = _b.apply(_a, [_f.sent()]); + _c = currentProvider; + switch (_c) { + case providerAddress: return [3 /*break*/, 3]; + case ethers.constants.AddressZero: return [3 /*break*/, 4]; + } + return [3 /*break*/, 8]; + case 3: + { + console.log("Current staking provider for operator " + operatorAddress + " is " + currentProvider); + return [2 /*return*/]; + } + _f.label = 4; + case 4: + console.log("Registering operator " + operatorAddress + " for a staking provider " + providerAddress + "..."); + _e = (_d = application) + .connect; + return [4 /*yield*/, ethers.getSigner(providerAddress)]; + case 5: return [4 /*yield*/, _e.apply(_d, [_f.sent()]) + .registerOperator(operatorAddress)]; + case 6: return [4 /*yield*/, (_f.sent()).wait()]; + case 7: + _f.sent(); + return [3 /*break*/, 9]; + case 8: + { + throw new Error("Operator [" + operatorAddress + "] has already been registered for another staking provider [" + currentProvider + "]"); + } + _f.label = 9; + case 9: return [2 /*return*/]; + } + }); + }); +} +exports.register = register; diff --git a/solidity/ecdsa/tasks/legacy-random-beacon/utils/stake.js b/solidity/ecdsa/tasks/legacy-random-beacon/utils/stake.js new file mode 100644 index 0000000000..96721550c4 --- /dev/null +++ b/solidity/ecdsa/tasks/legacy-random-beacon/utils/stake.js @@ -0,0 +1,117 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.calculateTokensNeededForStake = exports.stake = void 0; +function stake(hre, owner, provider, amount, beneficiary, authorizer) { + return __awaiter(this, void 0, void 0, function () { + var ethers, helpers, _a, to1e18, from1e18, ownerAddress, providerAddress, stakeAmount, beneficiaryAddress, authorizerAddress, staking, currentStake, _b, _c, topUpAmount, _d, _e; + return __generator(this, function (_f) { + switch (_f.label) { + case 0: + ethers = hre.ethers, helpers = hre.helpers; + _a = helpers.number, to1e18 = _a.to1e18, from1e18 = _a.from1e18; + ownerAddress = ethers.utils.getAddress(owner); + providerAddress = ethers.utils.getAddress(provider); + stakeAmount = to1e18(amount); + beneficiaryAddress = beneficiary + ? ethers.utils.getAddress(beneficiary) + : ownerAddress; + authorizerAddress = authorizer + ? ethers.utils.getAddress(authorizer) + : ownerAddress; + return [4 /*yield*/, helpers.contracts.getContract("TokenStaking")]; + case 1: + staking = _f.sent(); + return [4 /*yield*/, staking.callStatic.stakes(providerAddress)]; + case 2: + currentStake = (_f.sent()).tStake; + console.log("Current stake for " + providerAddress + " is " + from1e18(currentStake) + " T"); + if (!currentStake.eq(0)) return [3 /*break*/, 6]; + console.log("Staking " + from1e18(stakeAmount) + " T to the staking provider " + providerAddress + "..."); + _c = (_b = staking) + .connect; + return [4 /*yield*/, ethers.getSigner(ownerAddress)]; + case 3: return [4 /*yield*/, _c.apply(_b, [_f.sent()]) + .stake(providerAddress, beneficiaryAddress, authorizerAddress, stakeAmount)]; + case 4: return [4 /*yield*/, (_f.sent()).wait()]; + case 5: + _f.sent(); + return [3 /*break*/, 10]; + case 6: + if (!currentStake.lt(stakeAmount)) return [3 /*break*/, 10]; + topUpAmount = stakeAmount.sub(currentStake); + console.log("Topping up " + from1e18(topUpAmount) + " T to the staking provider " + providerAddress + "..."); + _e = (_d = staking) + .connect; + return [4 /*yield*/, ethers.getSigner(ownerAddress)]; + case 7: return [4 /*yield*/, _e.apply(_d, [_f.sent()]) + .topUp(providerAddress, topUpAmount)]; + case 8: return [4 /*yield*/, (_f.sent()).wait()]; + case 9: + _f.sent(); + _f.label = 10; + case 10: return [2 /*return*/]; + } + }); + }); +} +exports.stake = stake; +function calculateTokensNeededForStake(hre, provider, amount) { + return __awaiter(this, void 0, void 0, function () { + var ethers, helpers, _a, to1e18, from1e18, stakeAmount, staking, currentStake; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + ethers = hre.ethers, helpers = hre.helpers; + _a = helpers.number, to1e18 = _a.to1e18, from1e18 = _a.from1e18; + stakeAmount = to1e18(amount); + return [4 /*yield*/, helpers.contracts.getContract("TokenStaking")]; + case 1: + staking = _b.sent(); + return [4 /*yield*/, staking.callStatic.stakes(provider)]; + case 2: + currentStake = (_b.sent()).tStake; + if (currentStake.lt(stakeAmount)) { + return [2 /*return*/, ethers.BigNumber.from(from1e18(stakeAmount.sub(currentStake)))]; + } + return [2 /*return*/, ethers.constants.Zero]; + } + }); + }); +} +exports.calculateTokensNeededForStake = calculateTokensNeededForStake; diff --git a/solidity/ecdsa/tasks/random-beacon.ts b/solidity/ecdsa/tasks/random-beacon.ts new file mode 100644 index 0000000000..7121d2bfd7 --- /dev/null +++ b/solidity/ecdsa/tasks/random-beacon.ts @@ -0,0 +1,23 @@ +import { createRequire } from "module" +import path from "path" + +import resolveRandomBeaconExport from "../utils/random-beacon-export" + +import type { InitializationTasks, TaskUtils } from "../types/random-beacon" + +const requireBeaconTask = createRequire( + path.join(resolveRandomBeaconExport("tasks"), "initialize.js"), +) + +export const { + TASK_INITIALIZE, + TASK_INITIALIZE_STAKING, + TASK_AUTHORIZE, + TASK_REGISTER, + TASK_ADD_BETA_OPERATOR, +}: InitializationTasks = requireBeaconTask("./initialize") + +export const { authorize, register, addBetaOperator }: TaskUtils = + requireBeaconTask("./utils") + +requireBeaconTask("./unlock-eth-accounts") diff --git a/solidity/ecdsa/test/Allowlist.test.ts b/solidity/ecdsa/test/Allowlist.test.ts index 10ac085ab5..9ddea8722e 100644 --- a/solidity/ecdsa/test/Allowlist.test.ts +++ b/solidity/ecdsa/test/Allowlist.test.ts @@ -1,16 +1,16 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions, no-restricted-syntax, no-await-in-loop */ +/* eslint-disable no-restricted-syntax, no-await-in-loop */ import { ethers, helpers } from "hardhat" import { expect } from "chai" import { createMock, expectCalledWith } from "./helpers/mock" import type { Mock } from "./helpers/mock" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" import type { Allowlist, WalletRegistry } from "../typechain" const { createSnapshot, restoreSnapshot } = helpers.snapshot -const ZERO_ADDRESS = ethers.constants.AddressZero +const ZERO_ADDRESS = ethers.ZeroAddress describe("Allowlist", () => { let allowlist: Allowlist @@ -44,7 +44,7 @@ describe("Allowlist", () => { // approveAuthorizationDecrease which checks msg.sender == walletRegistry). await governance.sendTransaction({ to: walletRegistry.address, - value: ethers.utils.parseEther("10"), + value: ethers.parseEther("10"), }) // Deploy Allowlist proxy using ERC1967Proxy directly instead of @@ -58,17 +58,23 @@ describe("Allowlist", () => { // call deployments.fixture(). const AllowlistFactory = await ethers.getContractFactory("Allowlist") const impl = await AllowlistFactory.deploy() - await impl.deployed() + await impl.waitForDeployment() const initData = AllowlistFactory.interface.encodeFunctionData( "initialize", - [walletRegistry.address] + [walletRegistry.address], ) const ERC1967ProxyFactory = await ethers.getContractFactory("ERC1967Proxy") - const proxy = await ERC1967ProxyFactory.deploy(impl.address, initData) - await proxy.deployed() - allowlist = AllowlistFactory.attach(proxy.address) as Allowlist + const proxy = await ERC1967ProxyFactory.deploy( + await impl.getAddress(), + initData, + ) + await proxy.waitForDeployment() + allowlist = AllowlistFactory.attach(await proxy.getAddress()) as Allowlist }) + // The first two cases verify initializer wiring (values read back as the proxy was + // constructed with); the two reverting cases in this group are the behavioural arms, + // and the behavioural coverage for the other operations lives in the groups below. describe("initialization", () => { it("should set the wallet registry address", async () => { expect(await allowlist.walletRegistry()).to.equal(walletRegistry.address) @@ -80,48 +86,48 @@ describe("Allowlist", () => { it("should not allow re-initialization", async () => { await expect( - allowlist.initialize(walletRegistry.address) + allowlist.initialize(walletRegistry.address), ).to.be.revertedWith("Initializable: contract is already initialized") }) it("should revert if initialized with zero address", async () => { const AllowlistFactory = await ethers.getContractFactory("Allowlist") const impl = await AllowlistFactory.deploy() - await impl.deployed() + await impl.waitForDeployment() const initData = AllowlistFactory.interface.encodeFunctionData( "initialize", - [ZERO_ADDRESS] - ) - const ERC1967ProxyFactory = await ethers.getContractFactory( - "ERC1967Proxy" + [ZERO_ADDRESS], ) - await expect(ERC1967ProxyFactory.deploy(impl.address, initData)).to.be - .reverted + const ERC1967ProxyFactory = + await ethers.getContractFactory("ERC1967Proxy") + await expect( + ERC1967ProxyFactory.deploy(await impl.getAddress(), initData), + ).to.be.reverted }) }) describe("addStakingProvider", () => { context("when called by the owner", () => { it("should add a new staking provider with the specified weight", async () => { - const weight = ethers.utils.parseEther("40000") // 40k T equivalent + const weight = ethers.parseEther("40000") // 40k T equivalent await expect( allowlist .connect(governance) - .addStakingProvider(stakingProvider1.address, weight) + .addStakingProvider(stakingProvider1.address, weight), ) .to.emit(allowlist, "StakingProviderAdded") .withArgs(stakingProvider1.address, weight) const providerInfo = await allowlist.stakingProviders( - stakingProvider1.address + stakingProvider1.address, ) expect(providerInfo.weight).to.equal(weight) expect(providerInfo.pendingNewWeight).to.equal(0) }) it("should call authorizationIncreased on WalletRegistry", async () => { - const weight = ethers.utils.parseEther("50000") + const weight = ethers.parseEther("50000") await allowlist .connect(governance) @@ -135,7 +141,7 @@ describe("Allowlist", () => { }) it("should revert if staking provider already exists", async () => { - const weight = ethers.utils.parseEther("40000") + const weight = ethers.parseEther("40000") await allowlist .connect(governance) @@ -144,15 +150,17 @@ describe("Allowlist", () => { await expect( allowlist .connect(governance) - .addStakingProvider(stakingProvider1.address, weight) + .addStakingProvider(stakingProvider1.address, weight), ).to.be.reverted }) it("should revert if staking provider is zero address", async () => { - const weight = ethers.utils.parseEther("40000") + const weight = ethers.parseEther("40000") await expect( - allowlist.connect(governance).addStakingProvider(ZERO_ADDRESS, weight) + allowlist + .connect(governance) + .addStakingProvider(ZERO_ADDRESS, weight), ).to.be.revertedWithCustomError(allowlist, "ZeroAddress") }) @@ -160,26 +168,26 @@ describe("Allowlist", () => { await expect( allowlist .connect(governance) - .addStakingProvider(stakingProvider1.address, 0) + .addStakingProvider(stakingProvider1.address, 0), ).to.be.revertedWithCustomError(allowlist, "ZeroWeight") }) }) context("when called by non-owner", () => { it("should revert", async () => { - const weight = ethers.utils.parseEther("40000") + const weight = ethers.parseEther("40000") await expect( allowlist .connect(thirdParty) - .addStakingProvider(stakingProvider1.address, weight) + .addStakingProvider(stakingProvider1.address, weight), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) }) describe("requestWeightDecrease", () => { - const initialWeight = ethers.utils.parseEther("50000") + const initialWeight = ethers.parseEther("50000") beforeEach(async () => { // Add a staking provider first @@ -190,25 +198,25 @@ describe("Allowlist", () => { context("when called by the owner", () => { it("should request weight decrease for existing provider", async () => { - const newWeight = ethers.utils.parseEther("30000") + const newWeight = ethers.parseEther("30000") await expect( allowlist .connect(governance) - .requestWeightDecrease(stakingProvider1.address, newWeight) + .requestWeightDecrease(stakingProvider1.address, newWeight), ) .to.emit(allowlist, "WeightDecreaseRequested") .withArgs(stakingProvider1.address, initialWeight, newWeight) const providerInfo = await allowlist.stakingProviders( - stakingProvider1.address + stakingProvider1.address, ) expect(providerInfo.weight).to.equal(initialWeight) // unchanged expect(providerInfo.pendingNewWeight).to.equal(newWeight) }) it("should call authorizationDecreaseRequested on WalletRegistry", async () => { - const newWeight = ethers.utils.parseEther("30000") + const newWeight = ethers.parseEther("30000") await allowlist .connect(governance) @@ -227,20 +235,20 @@ describe("Allowlist", () => { await expect( allowlist .connect(governance) - .requestWeightDecrease(stakingProvider1.address, newWeight) + .requestWeightDecrease(stakingProvider1.address, newWeight), ) .to.emit(allowlist, "WeightDecreaseRequested") .withArgs(stakingProvider1.address, initialWeight, newWeight) const providerInfo = await allowlist.stakingProviders( - stakingProvider1.address + stakingProvider1.address, ) expect(providerInfo.pendingNewWeight).to.equal(newWeight) }) it("should overwrite pending weight decrease request", async () => { - const firstNewWeight = ethers.utils.parseEther("30000") - const secondNewWeight = ethers.utils.parseEther("20000") + const firstNewWeight = ethers.parseEther("30000") + const secondNewWeight = ethers.parseEther("20000") await allowlist .connect(governance) @@ -250,18 +258,18 @@ describe("Allowlist", () => { .requestWeightDecrease(stakingProvider1.address, secondNewWeight) const providerInfo = await allowlist.stakingProviders( - stakingProvider1.address + stakingProvider1.address, ) expect(providerInfo.pendingNewWeight).to.equal(secondNewWeight) }) it("should revert if staking provider is unknown", async () => { - const newWeight = ethers.utils.parseEther("30000") + const newWeight = ethers.parseEther("30000") await expect( allowlist .connect(governance) - .requestWeightDecrease(stakingProvider2.address, newWeight) + .requestWeightDecrease(stakingProvider2.address, newWeight), ).to.be.reverted }) @@ -269,34 +277,34 @@ describe("Allowlist", () => { await expect( allowlist .connect(governance) - .requestWeightDecrease(stakingProvider1.address, initialWeight) + .requestWeightDecrease(stakingProvider1.address, initialWeight), ).to.be.reverted - const higherWeight = ethers.utils.parseEther("60000") + const higherWeight = ethers.parseEther("60000") await expect( allowlist .connect(governance) - .requestWeightDecrease(stakingProvider1.address, higherWeight) + .requestWeightDecrease(stakingProvider1.address, higherWeight), ).to.be.reverted }) }) context("when called by non-owner", () => { it("should revert", async () => { - const newWeight = ethers.utils.parseEther("30000") + const newWeight = ethers.parseEther("30000") await expect( allowlist .connect(thirdParty) - .requestWeightDecrease(stakingProvider1.address, newWeight) + .requestWeightDecrease(stakingProvider1.address, newWeight), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) }) describe("approveAuthorizationDecrease", () => { - const initialWeight = ethers.utils.parseEther("50000") - const newWeight = ethers.utils.parseEther("30000") + const initialWeight = ethers.parseEther("50000") + const newWeight = ethers.parseEther("30000") beforeEach(async () => { // Add a staking provider and request weight decrease @@ -313,13 +321,13 @@ describe("Allowlist", () => { await expect( allowlist .connect(walletRegistry.wallet) - .approveAuthorizationDecrease(stakingProvider1.address) + .approveAuthorizationDecrease(stakingProvider1.address), ) .to.emit(allowlist, "WeightDecreaseFinalized") .withArgs(stakingProvider1.address, initialWeight, newWeight) const providerInfo = await allowlist.stakingProviders( - stakingProvider1.address + stakingProvider1.address, ) expect(providerInfo.weight).to.equal(newWeight) expect(providerInfo.pendingNewWeight).to.equal(0) @@ -328,7 +336,7 @@ describe("Allowlist", () => { it("should return the new weight", async () => { const result = await allowlist .connect(walletRegistry.wallet) - .callStatic.approveAuthorizationDecrease(stakingProvider1.address) + .approveAuthorizationDecrease.staticCall(stakingProvider1.address) expect(result).to.equal(newWeight) }) @@ -336,7 +344,7 @@ describe("Allowlist", () => { await expect( allowlist .connect(walletRegistry.wallet) - .approveAuthorizationDecrease(stakingProvider2.address) + .approveAuthorizationDecrease(stakingProvider2.address), ).to.be.reverted }) @@ -350,7 +358,7 @@ describe("Allowlist", () => { await expect( allowlist .connect(walletRegistry.wallet) - .approveAuthorizationDecrease(stakingProvider2.address) + .approveAuthorizationDecrease(stakingProvider2.address), ).to.be.revertedWithCustomError(allowlist, "NoDecreasePending") }) }) @@ -360,14 +368,14 @@ describe("Allowlist", () => { await expect( allowlist .connect(thirdParty) - .approveAuthorizationDecrease(stakingProvider1.address) + .approveAuthorizationDecrease(stakingProvider1.address), ).to.be.reverted }) }) }) describe("authorizedStake", () => { - const weight = ethers.utils.parseEther("40000") + const weight = ethers.parseEther("40000") beforeEach(async () => { await allowlist @@ -378,7 +386,7 @@ describe("Allowlist", () => { it("should return the current weight for existing provider", async () => { const result = await allowlist.authorizedStake( stakingProvider1.address, - ZERO_ADDRESS + ZERO_ADDRESS, ) expect(result).to.equal(weight) }) @@ -386,7 +394,7 @@ describe("Allowlist", () => { it("should return zero for non-existing provider", async () => { const result = await allowlist.authorizedStake( stakingProvider2.address, - ZERO_ADDRESS + ZERO_ADDRESS, ) expect(result).to.equal(0) }) @@ -394,11 +402,11 @@ describe("Allowlist", () => { it("should ignore the second parameter (application address)", async () => { const result1 = await allowlist.authorizedStake( stakingProvider1.address, - ZERO_ADDRESS + ZERO_ADDRESS, ) const result2 = await allowlist.authorizedStake( stakingProvider1.address, - thirdParty.address + thirdParty.address, ) expect(result1).to.equal(result2) }) @@ -413,11 +421,11 @@ describe("Allowlist", () => { await expect( allowlist.seize( - ethers.utils.parseEther("1000"), // amount (ignored) + ethers.parseEther("1000"), // amount (ignored) 100, // rewardMultiplier (ignored) thirdParty.address, // notifier - stakingProviders - ) + stakingProviders, + ), ) .to.emit(allowlist, "MaliciousBehaviorIdentified") .withArgs(thirdParty.address, stakingProviders) @@ -430,11 +438,11 @@ describe("Allowlist", () => { allowlist .connect(thirdParty) .seize( - ethers.utils.parseEther("500"), + ethers.parseEther("500"), 50, governance.address, - stakingProviders - ) + stakingProviders, + ), ).to.not.be.reverted }) }) @@ -442,7 +450,7 @@ describe("Allowlist", () => { describe("rolesOf", () => { it("should return owner as stakeOwner, stakingProvider as beneficiary, and zero address as authorizer", async () => { const [stakeOwner, beneficiary, authorizer] = await allowlist.rolesOf( - stakingProvider1.address + stakingProvider1.address, ) expect(stakeOwner).to.equal(governance.address) // owner of allowlist @@ -452,7 +460,7 @@ describe("Allowlist", () => { it("should work for any address", async () => { const [stakeOwner, beneficiary, authorizer] = await allowlist.rolesOf( - thirdParty.address + thirdParty.address, ) expect(stakeOwner).to.equal(governance.address) @@ -465,7 +473,7 @@ describe("Allowlist", () => { it("should support beta staker consolidation workflow", async () => { // Add multiple staking providers (simulating existing beta stakers) const providers = [stakingProvider1.address, stakingProvider2.address] - const initialWeight = ethers.utils.parseEther("40000") + const initialWeight = ethers.parseEther("40000") for (const provider of providers) { await allowlist @@ -492,11 +500,11 @@ describe("Allowlist", () => { // Verify consolidation result const consolidatedStake = await allowlist.authorizedStake( stakingProvider1.address, - ZERO_ADDRESS + ZERO_ADDRESS, ) const activeStake = await allowlist.authorizedStake( stakingProvider2.address, - ZERO_ADDRESS + ZERO_ADDRESS, ) expect(consolidatedStake).to.equal(0) // Consolidated provider has no weight diff --git a/solidity/ecdsa/test/DKGValidator.test.ts b/solidity/ecdsa/test/DKGValidator.test.ts index b6522dd6b5..843fd7d303 100644 --- a/solidity/ecdsa/test/DKGValidator.test.ts +++ b/solidity/ecdsa/test/DKGValidator.test.ts @@ -1,5 +1,5 @@ /* eslint-disable no-await-in-loop */ -import { BigNumber } from "ethers" + import { ethers, helpers } from "hardhat" import { expect } from "chai" @@ -13,28 +13,26 @@ import { } from "./utils/dkg" import ecdsaData from "./data/ecdsa" -import type { IWalletOwner } from "../typechain/IWalletOwner" -import type { Mock } from "./helpers/mock" -import type { DkgResult } from "./utils/dkg" -import type { Operator } from "./utils/operators" import type { + IWalletOwner, SortitionPool, EcdsaDkgValidator, WalletRegistry, } from "../typechain" +import type { Mock } from "./helpers/mock" +import type { DkgResult } from "./utils/dkg" +import type { Operator } from "./utils/operators" const { createSnapshot, restoreSnapshot } = helpers.snapshot describe("EcdsaDkgValidator", () => { - const dkgSeed: BigNumber = BigNumber.from( - "31415926535897932384626433832795028841971693993751058209749445923078164062862" + const dkgSeed = BigInt( + "31415926535897932384626433832795028841971693993751058209749445923078164062862", ) const dkgStartBlock = 1337 - const groupPublicKey: string = ethers.utils.hexValue( - ecdsaData.group1.publicKey - ) + const groupPublicKey: string = ethers.toQuantity(ecdsaData.group1.publicKey) - let selectedOperators + let selectedOperators: Operator[] let prepareDkgResult: ( _groupMembers: Operator[], @@ -44,7 +42,7 @@ describe("EcdsaDkgValidator", () => { _startBlock: number, _numberOfSignatures?: number, _submitterIndex?: number, - _membersHash?: string + _membersHash?: string, ) => Promise let walletRegistry: WalletRegistry @@ -53,7 +51,6 @@ describe("EcdsaDkgValidator", () => { let validator: EcdsaDkgValidator before("load test fixture", async () => { - // eslint-disable-next-line @typescript-eslint/no-extra-semi ;({ walletRegistry, sortitionPool, walletOwner } = await walletRegistryFixture({ useAllowlist: true })) @@ -71,7 +68,7 @@ describe("EcdsaDkgValidator", () => { _startBlock: number, _numberOfSignatures = 51, _submitterIndex = 1, - _membersHash?: string + _membersHash?: string, ): Promise => { const { signingMembersIndices, signaturesBytes } = await signDkgResult( _signers, @@ -79,7 +76,7 @@ describe("EcdsaDkgValidator", () => { _misbehaved, _startBlock, _submitterIndex, - _numberOfSignatures + _numberOfSignatures, ) const dkgResult: DkgResult = { @@ -93,7 +90,7 @@ describe("EcdsaDkgValidator", () => { _membersHash || hashDKGMembers( _groupMembers.map((m) => m.id), - _misbehaved + _misbehaved, ), } @@ -107,7 +104,7 @@ describe("EcdsaDkgValidator", () => { _signers: Operator[], _groupPublicKey: string, _misbehaved: number[], - _membersHash: string + _membersHash: string, ) => { const dkgResult = await prepareDkgResult( _groupMembers, @@ -117,7 +114,7 @@ describe("EcdsaDkgValidator", () => { dkgStartBlock, undefined, undefined, - _membersHash + _membersHash, ) const result = await validator.validate(dkgResult, dkgSeed, dkgStartBlock) @@ -152,7 +149,7 @@ describe("EcdsaDkgValidator", () => { selectedOperators, groupPublicKey, misbehavedMemberIds, - hashUint32Array(expectedMembersIds) + hashUint32Array(expectedMembersIds), ) await expect(result.isValid).to.be.true @@ -173,7 +170,7 @@ describe("EcdsaDkgValidator", () => { selectedOperators, groupPublicKey, misbehavedMemberIds, - hashUint32Array(expectedMembersIds) + hashUint32Array(expectedMembersIds), ) await expect(result.isValid).to.be.true @@ -192,7 +189,7 @@ describe("EcdsaDkgValidator", () => { selectedOperators, groupPublicKey, misbehavedMemberIds, - hashUint32Array(expectedMembersIds) + hashUint32Array(expectedMembersIds), ) await expect(result.isValid).to.be.true @@ -212,7 +209,7 @@ describe("EcdsaDkgValidator", () => { selectedOperators, groupPublicKey, misbehavedMemberIndices, - hashUint32Array(invalidMembersIndices) + hashUint32Array(invalidMembersIndices), ) await expect(result.isValid).to.be.false @@ -228,7 +225,7 @@ describe("EcdsaDkgValidator", () => { selectedOperators, groupPublicKey, noMisbehaved, - hashUint32Array(selectedOperators.map((m) => m.id)) + hashUint32Array(selectedOperators.map((m) => m.id)), ) await expect(result.isValid).to.be.true @@ -248,7 +245,7 @@ describe("EcdsaDkgValidator", () => { shuffledOperators, groupPublicKey, noMisbehaved, - hashUint32Array(selectedOperators.map((m) => m.id)) + hashUint32Array(selectedOperators.map((m) => m.id)), ) await expect(result.isValid).to.be.false @@ -268,7 +265,7 @@ describe("EcdsaDkgValidator", () => { shuffledOperators, groupPublicKey, noMisbehaved, - hashUint32Array(selectedOperators.map((m) => m.id)) + hashUint32Array(selectedOperators.map((m) => m.id)), ) await expect(result.isValid).to.be.false @@ -279,10 +276,10 @@ describe("EcdsaDkgValidator", () => { describe("validateFields", () => { const testValidateFields = async ( - _groupMembers, - _groupPublicKey, - _misbehaved, - _numberOfSignatures = 51 + _groupMembers: Operator[], + _groupPublicKey: string, + _misbehaved: number[], + _numberOfSignatures = 51, ) => { const dkgResult = await prepareDkgResult( _groupMembers, @@ -290,7 +287,7 @@ describe("EcdsaDkgValidator", () => { _groupPublicKey, _misbehaved, dkgStartBlock, - _numberOfSignatures + _numberOfSignatures, ) const result = await validator.validateFields(dkgResult) @@ -306,7 +303,7 @@ describe("EcdsaDkgValidator", () => { const result = await testValidateFields( selectedOperators, groupPublicKey, - noMisbehaved + noMisbehaved, ) await expect(result.isValid).to.be.true @@ -321,7 +318,7 @@ describe("EcdsaDkgValidator", () => { const result = await testValidateFields( selectedOperators, empty, - noMisbehaved + noMisbehaved, ) await expect(result.isValid).to.be.false @@ -333,12 +330,12 @@ describe("EcdsaDkgValidator", () => { it("should return validation error", async () => { const tooShort = groupPublicKey.substring( 0, - groupPublicKey.length - 2 + groupPublicKey.length - 2, ) const result = await testValidateFields( selectedOperators, tooShort, - noMisbehaved + noMisbehaved, ) await expect(result.isValid).to.be.false @@ -352,7 +349,7 @@ describe("EcdsaDkgValidator", () => { const result = await testValidateFields( selectedOperators, tooLong, - noMisbehaved + noMisbehaved, ) await expect(result.isValid).to.be.false @@ -368,12 +365,12 @@ describe("EcdsaDkgValidator", () => { const result = await testValidateFields( selectedOperators, groupPublicKey, - lessThanOne + lessThanOne, ) await expect(result.isValid).to.be.false await expect(result.errorMsg).to.equal( - "Corrupted misbehaved members indices" + "Corrupted misbehaved members indices", ) }) }) @@ -384,12 +381,12 @@ describe("EcdsaDkgValidator", () => { const result = await testValidateFields( selectedOperators, groupPublicKey, - higherThanGroupSize + higherThanGroupSize, ) await expect(result.isValid).to.be.false await expect(result.errorMsg).to.equal( - "Corrupted misbehaved members indices" + "Corrupted misbehaved members indices", ) }) }) @@ -400,12 +397,12 @@ describe("EcdsaDkgValidator", () => { const result = await testValidateFields( selectedOperators, groupPublicKey, - unsorted + unsorted, ) await expect(result.isValid).to.be.false await expect(result.errorMsg).to.equal( - "Corrupted misbehaved members indices" + "Corrupted misbehaved members indices", ) }) }) @@ -416,12 +413,12 @@ describe("EcdsaDkgValidator", () => { const result = await testValidateFields( selectedOperators, groupPublicKey, - duplicated + duplicated, ) await expect(result.isValid).to.be.false await expect(result.errorMsg).to.equal( - "Corrupted misbehaved members indices" + "Corrupted misbehaved members indices", ) }) }) @@ -432,12 +429,12 @@ describe("EcdsaDkgValidator", () => { const result = await testValidateFields( selectedOperators, groupPublicKey, - tooMany + tooMany, ) await expect(result.isValid).to.be.false await expect(result.errorMsg).to.equal( - "Too many members misbehaving during DKG" + "Too many members misbehaving during DKG", ) }) }) @@ -451,7 +448,7 @@ describe("EcdsaDkgValidator", () => { selectedOperators, groupPublicKey, noMisbehaved, - noSignatures + noSignatures, ) await expect(result.isValid).to.be.false @@ -466,7 +463,7 @@ describe("EcdsaDkgValidator", () => { selectedOperators, groupPublicKey, noMisbehaved, - dkgStartBlock + dkgStartBlock, ) dkgResult.signatures += "ff" const result = await validator.validateFields(dkgResult) @@ -484,7 +481,7 @@ describe("EcdsaDkgValidator", () => { selectedOperators, groupPublicKey, noMisbehaved, - dkgStartBlock + dkgStartBlock, ) dkgResult.signatures += "f".repeat(signatureHexStrLength) const result = await validator.validateFields(dkgResult) @@ -501,7 +498,7 @@ describe("EcdsaDkgValidator", () => { selectedOperators, groupPublicKey, noMisbehaved, - tooFewSignatures + tooFewSignatures, ) await expect(result.isValid).to.be.false @@ -519,7 +516,7 @@ describe("EcdsaDkgValidator", () => { groupPublicKey, noMisbehaved, dkgStartBlock, - maxSignatures + maxSignatures, ) dkgResult.signatures += "f".repeat(signatureHexStrLength) dkgResult.signingMembersIndices.push(maxSignatures + 1) @@ -532,13 +529,13 @@ describe("EcdsaDkgValidator", () => { }) context("when signing members indices array is malformed", async () => { - const testSigningMembers = async (_signingMembersIndices) => { + const testSigningMembers = async (_signingMembersIndices: number[]) => { const dkgResult = await prepareDkgResult( selectedOperators, selectedOperators, groupPublicKey, noMisbehaved, - dkgStartBlock + dkgStartBlock, ) dkgResult.signingMembersIndices = _signingMembersIndices @@ -562,7 +559,7 @@ describe("EcdsaDkgValidator", () => { await expect(result.isValid).to.be.false await expect(result.errorMsg).to.equal( - "Corrupted signing member indices" + "Corrupted signing member indices", ) }) }) @@ -578,7 +575,7 @@ describe("EcdsaDkgValidator", () => { await expect(result.isValid).to.be.false await expect(result.errorMsg).to.equal( - "Corrupted signing member indices" + "Corrupted signing member indices", ) }) }) @@ -594,7 +591,7 @@ describe("EcdsaDkgValidator", () => { await expect(result.isValid).to.be.false await expect(result.errorMsg).to.equal( - "Corrupted signing member indices" + "Corrupted signing member indices", ) }) }) @@ -602,13 +599,13 @@ describe("EcdsaDkgValidator", () => { }) describe("validateGroupMembers", () => { - const testValidateGroupMembers = async (_groupMembers) => { + const testValidateGroupMembers = async (_groupMembers: Operator[]) => { const dkgResult = await prepareDkgResult( _groupMembers, _groupMembers, groupPublicKey, noMisbehaved, - dkgStartBlock + dkgStartBlock, ) return validator.validateGroupMembers(dkgResult, dkgSeed) @@ -624,7 +621,7 @@ describe("EcdsaDkgValidator", () => { context("when there are operators other then selected", () => { it("should fail the validation", async () => { const isValid = await testValidateGroupMembers( - shuffle(selectedOperators) + shuffle(selectedOperators), ) await expect(isValid).to.be.false }) @@ -632,13 +629,16 @@ describe("EcdsaDkgValidator", () => { }) describe("validateSignatures", () => { - const testValidateSignatures = async (_groupMembers, _signers) => { + const testValidateSignatures = async ( + _groupMembers: Operator[], + _signers: Operator[], + ) => { const dkgResult = await prepareDkgResult( _groupMembers, _signers, groupPublicKey, noMisbehaved, - dkgStartBlock + dkgStartBlock, ) return validator.validateSignatures(dkgResult, dkgStartBlock) @@ -648,7 +648,7 @@ describe("EcdsaDkgValidator", () => { it("should pass", async () => { const isValid = await testValidateSignatures( selectedOperators, - selectedOperators + selectedOperators, ) await expect(isValid).to.be.true @@ -660,16 +660,16 @@ describe("EcdsaDkgValidator", () => { () => { it("should fail the validation", async () => { const maliciousSigners = Array(constants.groupSize).fill( - selectedOperators[0] + selectedOperators[0], ) const isValid = await testValidateSignatures( selectedOperators, - maliciousSigners + maliciousSigners, ) await expect(isValid).to.be.false }) - } + }, ) context("when signatures do not matching signers", () => { @@ -679,7 +679,7 @@ describe("EcdsaDkgValidator", () => { selectedOperators, groupPublicKey, noMisbehaved, - dkgStartBlock + dkgStartBlock, ) // reverse order of signers ;[ @@ -691,7 +691,7 @@ describe("EcdsaDkgValidator", () => { ] const isValid = await validator.validateSignatures( dkgResult, - dkgStartBlock + dkgStartBlock, ) await expect(isValid).to.be.false @@ -700,26 +700,26 @@ describe("EcdsaDkgValidator", () => { context("when signatures contain wrong result hash", () => { const signWithWrongResultHash = async (signingOperators: Operator[]) => { - const wrongResultHash = ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode( + const wrongResultHash = ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( ["uint256", "bytes", "uint8[]", "uint256"], [ hardhatNetworkId, groupPublicKey, noMisbehaved, dkgStartBlock + 12345, - ] - ) + ], + ), ) const signatures = [] for (let i = 0; i < signingOperators.length; i++) { const { signer: ethersSigner } = signingOperators[i] const signature = await ethersSigner.signMessage( - ethers.utils.arrayify(wrongResultHash) + ethers.getBytes(wrongResultHash), ) signatures.push(signature) } - const signaturesBytes = ethers.utils.hexConcat(signatures) + const signaturesBytes = ethers.concat(signatures) return signaturesBytes } @@ -731,14 +731,14 @@ describe("EcdsaDkgValidator", () => { groupPublicKey, noMisbehaved, dkgStartBlock, - numberOfSignatures + numberOfSignatures, ) dkgResult.signatures = await signWithWrongResultHash( - selectedOperators.slice(numberOfSignatures - 1) + selectedOperators.slice(numberOfSignatures - 1), ) const isValid = await validator.validateSignatures( dkgResult, - dkgStartBlock + dkgStartBlock, ) await expect(isValid).to.be.false @@ -755,15 +755,15 @@ describe("EcdsaDkgValidator", () => { groupPublicKey, noMisbehaved, dkgStartBlock, - numberOfSignatures + numberOfSignatures, ) const wrongSignatures = `0x${"a".repeat( - signatureHexStrLength * numberOfSignatures + signatureHexStrLength * numberOfSignatures, )}` dkgResult.signatures = wrongSignatures await expect( - validator.validateSignatures(dkgResult, dkgStartBlock) + validator.validateSignatures(dkgResult, dkgStartBlock), ).to.be.revertedWith("ECDSA: invalid signature 's' value") }) }) diff --git a/solidity/ecdsa/test/WalletRegistry.Authorization.test.ts b/solidity/ecdsa/test/WalletRegistry.Authorization.test.ts index 63447eb514..3806048acd 100644 --- a/solidity/ecdsa/test/WalletRegistry.Authorization.test.ts +++ b/solidity/ecdsa/test/WalletRegistry.Authorization.test.ts @@ -1,310 +1,80 @@ /* eslint-disable @typescript-eslint/no-unused-expressions */ -import { deployments, ethers, getUnnamedAccounts, helpers } from "hardhat" +import { deployments, ethers, helpers } from "hardhat" import { expect } from "chai" -import { createMock } from "./helpers/mock" import { constants, params, - initializeWalletOwner, - updateWalletRegistryParams, + setupAllowlist, + walletRegistryFixture, } from "./fixtures" -import { legacyTokenStakingAt } from "./utils/operators" +import { + shouldOverwritePreviousRequest, + shouldRequireUpdatingPoolBeforeApproving, +} from "./behaviors/authorization" -import type { IWalletOwner } from "../typechain/IWalletOwner" -import type { Mock } from "./helpers/mock" -import type { ContractTransaction } from "ethers" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import type { ContractTransactionResponse, Signer } from "ethers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" import type { + Allowlist, WalletRegistry, - SortitionPool, - TokenStaking, - T, - IApplication, WalletRegistryGovernance, - IStaking, + SortitionPool, } from "../typechain" -const { mineBlocks } = helpers.time const { to1e18 } = helpers.number - const { createSnapshot, restoreSnapshot } = helpers.snapshot +const ZERO_ADDRESS = ethers.ZeroAddress +const MAX_UINT64 = BigInt("18446744073709551615") -const ZERO_ADDRESS = ethers.constants.AddressZero -const MAX_UINT64 = ethers.BigNumber.from("18446744073709551615") // 2^64 - 1 - -/* - * LEGACY TESTS DEPRECATED - TIP-092 Migration - * - * The following code block (lines 154-3679) contains legacy authorization tests - * that were written for the pre-TIP-092 TokenStaking API. These tests use methods - * that were removed during the Beta Staker Consolidation (TIP-092): - * - TokenStaking.stake() - * - TokenStaking.increaseAuthorization() - * - TokenStaking.processSlashing() - * - TokenStaking.approveApplication() - * - TokenStaking.topUp() - * - * Current State: - * - These tests CANNOT execute due to TypeScript compilation errors - * - The deprecated methods no longer exist in TokenStaking v1.3.0-dev.16+ - * - Uncommenting this block will break TypeScript compilation for entire file - * - * Migration Path: - * - Issue #3839: "Migrate ECDSA tests to Allowlist mode" - * - Target: Rewrite these tests using Allowlist-based authorization - * - Pattern: Follow Migration Scenario Tests (lines 3700-4254) as reference - * - Timeline: Tracked in project roadmap - * - * Why Preserved: - * - Valuable test patterns for authorization workflows - * - Reference for understanding pre-TIP-092 behavior - * - Edge cases worth preserving during migration - * - Documentation of legacy authorization model - * - * Active Tests: - * - Migration Scenario Tests (lines 3700-4254) are ACTIVE and PASSING - * - These tests validate dual-mode authorization (TokenStaking vs Allowlist) - * - 100% branch coverage for _currentAuthorizationSource() function - */ - -/** - * Helper Functions for Migration Scenario Tests - * - * These helpers extract common patterns from test setups to improve - * code maintainability and reduce duplication. - */ - -/** - * Sets up real TokenStaking authorization for a staking provider using actual - * contract calls instead of smock.fake. This avoids a known smock issue where - * createMock({address: existingAddress}) corrupts EVM storage in a way that - * evm_revert cannot restore, breaking subsequent test suites. - * - * @param t - T token contract for minting - * @param staking - TokenStaking contract - * @param walletRegistry - WalletRegistry contract (application to authorize) - * @param deployer - Deployer signer (can mint tokens) - * @param stakingProvider - Staking provider signer - * @param beneficiary - Beneficiary signer - * @param amount - Amount to stake and authorize - */ -async function setupRealStaking( - t: T, - staking: TokenStaking, - walletRegistry: WalletRegistry, - deployer: SignerWithAddress, - stakingProvider: SignerWithAddress, - beneficiary: SignerWithAddress, - amount: any -): Promise { - await t.connect(deployer).mint(stakingProvider.address, amount) - await t.connect(stakingProvider).approve(staking.address, amount) - await legacyTokenStakingAt(staking, stakingProvider).stake( - stakingProvider.address, - beneficiary.address, - stakingProvider.address, - amount - ) - await legacyTokenStakingAt(staking, stakingProvider).increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - amount - ) -} - -/** - * Deactivates chaosnet mode on the SortitionPool to allow operators to join. - * SortitionPool deploys in chaosnet mode by default, requiring explicit deactivation. - * - * @param sortitionPool - The SortitionPool contract instance - */ -async function deactivateChaosnetMode( - sortitionPool: SortitionPool -): Promise { - const { chaosnetOwner } = await helpers.signers.getNamedSigners() - await sortitionPool.connect(chaosnetOwner).deactivateChaosnet() -} - -/** - * Triggers authorization callback by impersonating the staking/allowlist contract. - * WalletRegistry validates that authorizationIncreased() is called by the staking contract, - * so we must impersonate the contract address to successfully trigger the callback. - * - * @param walletRegistry - The WalletRegistry contract instance - * @param contractAddress - Address of staking or allowlist contract to impersonate - * @param stakingProvider - Staking provider receiving authorization - * @param fromAmount - Previous authorization amount (typically 0 for new authorization) - * @param toAmount - New authorization amount - */ -async function triggerAuthorizationCallback( - walletRegistry: WalletRegistry, - contractAddress: string, - stakingProvider: string, - fromAmount: any, - toAmount: any -): Promise { - await ethers.provider.send("hardhat_impersonateAccount", [contractAddress]) - await ethers.provider.send("hardhat_setBalance", [ - contractAddress, - "0x56BC75E2D63100000", // 100 ETH for gas - ]) - const contractSigner = await ethers.getSigner(contractAddress) - - await walletRegistry - .connect(contractSigner) - .authorizationIncreased(stakingProvider, fromAmount, toAmount) - - await ethers.provider.send("hardhat_stopImpersonatingAccount", [ - contractAddress, - ]) -} - -/** - * Joins sortition pool if operator is not already in the pool. - * Prevents "already in pool" errors by checking membership first. - * - * @param walletRegistry - The WalletRegistry contract instance - * @param operator - The operator signer to join the pool - */ -async function joinPoolIfNotMember( - walletRegistry: WalletRegistry, - operator: SignerWithAddress -): Promise { - const isInPool = await walletRegistry.isOperatorInPool(operator.address) - if (!isInPool) { - await walletRegistry.connect(operator).joinSortitionPool() - } -} - -/* TEMPORARILY COMMENTED OUT - START - -describe.skip("TokenStaking Integration (DEPRECATED TIP-092)", () => { - /** - * DEPRECATED: These tests validate TokenStaking.approveApplication() - * which does not exist in production TokenStaking v1.3.0-dev.16. - * - * Production State: - * - RandomBeacon/ECDSA applications are FROZEN (skipApplication = true) - * - approveApplication() method removed from production contract - * - Only TACo application remains functional in TokenStaking - * - * Migration: - * - Issue: #3839 "Migrate ECDSA tests to Allowlist mode" - * - New approach: walletRegistryFixture({ useAllowlist: true }) - * - * References: - * - TIP-092: Beta Staker Consolidation - * - TIP-100: TokenStaking sunset timeline - * - Allowlist.sol: Replacement authorization contract - * - * Implementation Status: - * - Dual-mode fixtures implemented and working - * - TypeScript compilation successful - * - Full test validation deferred pending Allowlist migration - * - Strategic migration tracked in issue #3839 - */ - -// Original tests preserved for reference during migration -// Will be rewritten for Allowlist mode or archived - -/* TEMPORARILY COMMENTED OUT - START (Second legacy test block) - -describe("WalletRegistry - Authorization", () => { - let t: T +describe("WalletRegistry - Allowlist Authorization", () => { let walletRegistry: WalletRegistry let walletRegistryGovernance: WalletRegistryGovernance let sortitionPool: SortitionPool - let staking: TokenStaking - + let allowlist: Allowlist let deployer: SignerWithAddress let governance: SignerWithAddress - - let owner: SignerWithAddress let stakingProvider: SignerWithAddress let operator: SignerWithAddress - let authorizer: SignerWithAddress - let beneficiary: SignerWithAddress let thirdParty: SignerWithAddress - let walletOwner: Mock - let slasher: Mock - - const stakedAmount = to1e18(1000000) // 1M T - let minimumAuthorization + let walletOwnerSigner: Signer + const providerWeight = to1e18(1000000) + const { minimumAuthorization } = params - before("load test fixture", async () => { - await deployments.fixture(["WalletRegistry"]) + // Deploy separately so a cold run and the 100-operator setup each have their + // own hook timeout. + before("deploy contracts", async () => { + await deployments.fixture() + }) - t = await helpers.contracts.getContract("T") - walletRegistry = await helpers.contracts.getContract("WalletRegistry") - walletRegistryGovernance = await helpers.contracts.getContract( - "WalletRegistryGovernance" - ) - sortitionPool = await helpers.contracts.getContract("EcdsaSortitionPool") - staking = await helpers.contracts.getContract("TokenStaking") - - const accounts = await getUnnamedAccounts() - owner = await ethers.getSigner(accounts[1]) - stakingProvider = await ethers.getSigner(accounts[2]) - operator = await ethers.getSigner(accounts[3]) - authorizer = await ethers.getSigner(accounts[4]) - beneficiary = await ethers.getSigner(accounts[5]) - thirdParty = await ethers.getSigner(accounts[6]) - ;({ deployer, governance } = await helpers.signers.getNamedSigners()) - - const { chaosnetOwner } = await helpers.signers.getNamedSigners() - await sortitionPool.connect(chaosnetOwner).deactivateChaosnet() - - walletOwner = await initializeWalletOwner( + before("load Allowlist fixture", async () => { + const fixture = await walletRegistryFixture({ useAllowlist: true }) + ;({ + walletRegistry, walletRegistryGovernance, - governance - ) - - await updateWalletRegistryParams(walletRegistryGovernance, governance) - - await t.connect(deployer).mint(owner.address, stakedAmount) - await t.connect(owner).approve(staking.address, stakedAmount) - await legacyTokenStakingAt(staking, owner).stake( - stakingProvider.address, - beneficiary.address, - authorizer.address, - stakedAmount - ) - - minimumAuthorization = await walletRegistry.minimumAuthorization() - - // Initialize slasher - fake application capable of slashing the - // staking provider. - slasher = await createMock("IApplication") - await legacyTokenStakingAt(staking, deployer).approveApplication(slasher.address) - await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( - stakingProvider.address, - slasher.address, - stakedAmount - ) - - // Fund slasher so that it can call T TokenStaking functions - await ( - await ethers.getSigners() - )[0].sendTransaction({ - to: slasher.address, - value: ethers.utils.parseEther("100"), - }) + sortitionPool, + deployer, + governance, + thirdParty, + } = fixture) + allowlist = fixture.allowlist! + walletOwnerSigner = fixture.walletOwner.wallet + // Named accounts are separate from the 100 operators registered by the fixture. + const signers = await helpers.signers.getNamedSigners() + stakingProvider = signers.esdm + operator = signers.chaosnetOwner }) describe("registerOperator", () => { context("when called with zero-address operator", () => { it("should revert", async () => { await expect( - walletRegistry.connect(stakingProvider).registerOperator(ZERO_ADDRESS) + walletRegistry + .connect(stakingProvider) + .registerOperator(ZERO_ADDRESS), ).to.be.revertedWith("Operator can not be zero address") }) }) - - // It is not possible to update operator address. Once the operator is - // registered for the given staking provider, it must remain the same. - // Staking provider address is unique for each stake delegation - see T - // TokenStaking contract. context( "when operator has been already registered for the staking provider", () => { @@ -323,22 +93,16 @@ describe("WalletRegistry - Authorization", () => { await expect( walletRegistry .connect(stakingProvider) - .registerOperator(operator.address) + .registerOperator(operator.address), ).to.be.revertedWith("Operator already set for the staking provider") - - // should revert even if it's another operator than the one previously - // registered for the staking provider await expect( walletRegistry .connect(stakingProvider) - .registerOperator(thirdParty.address) + .registerOperator(thirdParty.address), ).to.be.revertedWith("Operator already set for the staking provider") }) - } + }, ) - - // Some other staking provider is using the given operator address. - // Should not happen in practice but we should protect against it. context("when the operator is already in use", () => { before(async () => { await createSnapshot() @@ -355,16 +119,12 @@ describe("WalletRegistry - Authorization", () => { await expect( walletRegistry .connect(stakingProvider) - .registerOperator(operator.address) + .registerOperator(operator.address), ).to.be.revertedWith("Operator address already in use") }) }) - - // This is the normal, happy path. Stake owner delegated their stake to - // the staking provider, and the staking provider is registering operator - // for ECDSA application. context("when staking provider is registering new operator", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -380,14 +140,14 @@ describe("WalletRegistry - Authorization", () => { it("should set staking provider -> operator mapping", async () => { expect( await walletRegistry.stakingProviderToOperator( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(operator.address) }) it("should set operator -> staking provider mapping", async () => { expect( - await walletRegistry.operatorToStakingProvider(operator.address) + await walletRegistry.operatorToStakingProvider(operator.address), ).to.equal(stakingProvider.address) }) @@ -402,37 +162,21 @@ describe("WalletRegistry - Authorization", () => { .false }) }) - - // It is possible to approve authorization decrease request immediately - // in case the operator was not yet registered by the staking provider. - // It makes sense because non-registered operator could not be in the - // sortition pool, so there is no state that could be not in sync. - // However, we need to ensure this is not exploited by malicious stakers. - // We do not want to let operators with a pending authorization decrease - // request that can be immediately approved to join the sortition pool. - // If there is a pending authorization decrease for the staking provider, - // it must be first approved before operator for that staking provider is - // registered. context("when there is a pending authorization decrease request", () => { before(async () => { await createSnapshot() - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - stakedAmount - ) + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, providerWeight) const deauthorizingBy = to1e18(1) - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingBy + providerWeight - deauthorizingBy, ) }) @@ -444,44 +188,33 @@ describe("WalletRegistry - Authorization", () => { await expect( walletRegistry .connect(stakingProvider) - .registerOperator(operator.address) + .registerOperator(operator.address), ).to.be.revertedWith( - "There is a pending authorization decrease request" + "There is a pending authorization decrease request", ) }) }) - - // This is a continuation of the previous test case - in case there is - // a staking provider who has not yet registered the operator and there is - // an authorization decrease requested for that staking provider, upon - // approving that authorization decrease request, staking provider can - // register an operator. context("when authorization decrease request was approved", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - stakedAmount - ) + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, providerWeight) const deauthorizingBy = to1e18(1) - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingBy + providerWeight - deauthorizingBy, ) await walletRegistry.approveAuthorizationDecrease( - stakingProvider.address + stakingProvider.address, ) tx = await walletRegistry @@ -496,14 +229,14 @@ describe("WalletRegistry - Authorization", () => { it("should set staking provider -> operator mapping", async () => { expect( await walletRegistry.stakingProviderToOperator( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(operator.address) }) it("should set operator -> staking provider mapping", async () => { expect( - await walletRegistry.operatorToStakingProvider(operator.address) + await walletRegistry.operatorToStakingProvider(operator.address), ).to.equal(stakingProvider.address) }) @@ -516,50 +249,40 @@ describe("WalletRegistry - Authorization", () => { }) describe("authorizationIncreased", () => { - context("when called not by the staking contract", () => { + context("when called not by the Allowlist contract", () => { it("should revert", async () => { await expect( walletRegistry .connect(thirdParty) - .authorizationIncreased(stakingProvider.address, 0, stakedAmount) - ).to.be.revertedWithCustomError(walletRegistry, "CallerNotStakingContract") + .authorizationIncreased(stakingProvider.address, 0, providerWeight), + ).to.be.revertedWithCustomError( + walletRegistry, + "CallerNotStakingContract", + ) }) }) context("when authorization is below the minimum", () => { it("should revert", async () => { await expect( - staking - .connect(authorizer) - .increaseAuthorization( + allowlist + .connect(deployer) + .addStakingProvider( stakingProvider.address, - walletRegistry.address, - minimumAuthorization.sub(1) - ) + minimumAuthorization - 1n, + ), ).to.be.revertedWith("Authorization below the minimum") }) }) - - // This is normal, happy path for a new delegation. Stake owner delegated - // their stake to the staking provider, and while still being in the - // dashboard (assuming staker is the authorizer), increased authorization - // for ECDSA application. Staking provider has not registered operator yet. - // This will happen later. context("when the operator is unknown", () => { - // Minimum possible authorization - the minimum authorized amount for - // ECDSA as set in `minimumAuthorization` parameter. context("when increasing to the minimum possible value", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() - tx = await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - minimumAuthorization - ) + tx = await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, minimumAuthorization) }) after(async () => { @@ -573,25 +296,18 @@ describe("WalletRegistry - Authorization", () => { stakingProvider.address, ZERO_ADDRESS, 0, - minimumAuthorization + minimumAuthorization, ) }) }) - - // Maximum possible authorization - the entire stake delegated to the - // staking provider. - context("when increasing to the maximum possible value", () => { - let tx: ContractTransaction + context("when increasing to a weight above the minimum", () => { + let tx: ContractTransactionResponse before(async () => { await createSnapshot() - tx = await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - stakedAmount - ) + tx = await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, providerWeight) }) after(async () => { @@ -601,16 +317,10 @@ describe("WalletRegistry - Authorization", () => { it("should emit AuthorizationIncreased", async () => { await expect(tx) .to.emit(walletRegistry, "AuthorizationIncreased") - .withArgs(stakingProvider.address, ZERO_ADDRESS, 0, stakedAmount) + .withArgs(stakingProvider.address, ZERO_ADDRESS, 0, providerWeight) }) }) }) - - // This is normal, happy path for staking provider acting before the - // authorizer, most probably because authorizer is someone else than the - // stake owner. Stake owner delegated their stake to the staking provider, - // staking provider registered operator for ECDSA, and after that, the - // authorizer increased the authorization for the staking provider. context("when the operator is registered", () => { before(async () => { await createSnapshot() @@ -623,22 +333,15 @@ describe("WalletRegistry - Authorization", () => { after(async () => { await restoreSnapshot() }) - - // Minimum possible authorization - the minimum authorized amount for - // ECDSA as set in `minimumAuthorization` parameter. context("when increasing to the minimum possible value", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() - tx = await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - minimumAuthorization - ) + tx = await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, minimumAuthorization) }) after(async () => { @@ -652,26 +355,19 @@ describe("WalletRegistry - Authorization", () => { stakingProvider.address, operator.address, 0, - minimumAuthorization + minimumAuthorization, ) }) }) - - // Maximum possible authorization - the entire stake delegated to the - // staking provider. - context("when increasing to the maximum possible value", () => { - let tx: ContractTransaction + context("when increasing to a weight above the minimum", () => { + let tx: ContractTransactionResponse before(async () => { await createSnapshot() - tx = await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - stakedAmount - ) + tx = await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, providerWeight) }) after(async () => { @@ -685,7 +381,7 @@ describe("WalletRegistry - Authorization", () => { stakingProvider.address, operator.address, 0, - stakedAmount + providerWeight, ) }) }) @@ -693,76 +389,54 @@ describe("WalletRegistry - Authorization", () => { }) describe("authorizationDecreaseRequested", () => { - context("when called not by the staking contract", () => { + context("when called not by the Allowlist contract", () => { it("should revert", async () => { await expect( walletRegistry .connect(thirdParty) - .authorizationDecreaseRequested(stakingProvider.address, 100, 99) - ).to.be.revertedWithCustomError(walletRegistry, "CallerNotStakingContract") + .authorizationDecreaseRequested(stakingProvider.address, 100, 99), + ).to.be.revertedWithCustomError( + walletRegistry, + "CallerNotStakingContract", + ) }) }) - - // This is normal happy path in case the stake owner wants to cancel the - // authorization before staking provider started their set up procedure. - // Given the operator was not registered yet by the staking provider, we - // can allow the authorization decrease to be processed immediately if it - // is valid. context("when the operator is unknown", () => { before(async () => { await createSnapshot() - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - stakedAmount - ) + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, providerWeight) }) after(async () => { await restoreSnapshot() }) - - // This is not valid authorization decrease request - one most decrease - // to 0 or to some value above the minimum. context("when decreasing to a non-zero value below the minimum", () => { it("should revert", async () => { - const deauthorizingTo = minimumAuthorization.sub(1) - const deauthorizingBy = stakedAmount.sub(deauthorizingTo) + const deauthorizingTo = minimumAuthorization - 1n await expect( - staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - walletRegistry.address, - deauthorizingBy - ) + allowlist + .connect(deployer) + .requestWeightDecrease(stakingProvider.address, deauthorizingTo), ).to.be.revertedWith( - "Authorization amount should be 0 or above the minimum" + "Authorization amount should be 0 or above the minimum", ) }) }) - - // Decreasing to zero when operator was not set up yet - authorization - // decrease request is valid and can be approved context("when decreasing to zero", () => { - let tx: ContractTransaction - const decreasingTo = 0 - let decreasingBy + let tx: ContractTransactionResponse + const decreasingTo = 0n + let decreasingBy: bigint before(async () => { await createSnapshot() - decreasingBy = stakedAmount.sub(decreasingTo) - tx = await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - walletRegistry.address, - decreasingBy - ) + decreasingBy = providerWeight - decreasingTo + tx = await allowlist + .connect(deployer) + .requestWeightDecrease(stakingProvider.address, decreasingTo) }) after(async () => { @@ -772,8 +446,8 @@ describe("WalletRegistry - Authorization", () => { it("should require no time delay before approving", async () => { expect( await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(0) }) @@ -784,38 +458,34 @@ describe("WalletRegistry - Authorization", () => { .withArgs( stakingProvider.address, ZERO_ADDRESS, - stakedAmount, + providerWeight, decreasingTo, - now + now, ) }) it("should capture deauthorizing amount", async () => { expect( await walletRegistry.pendingAuthorizationDecrease( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(decreasingBy) }) }) context("when decreasing to the minimum", () => { - let tx: ContractTransaction - let decreasingTo - let decreasingBy + let tx: ContractTransactionResponse + let decreasingTo: bigint + let decreasingBy: bigint before(async () => { await createSnapshot() decreasingTo = minimumAuthorization - decreasingBy = stakedAmount.sub(decreasingTo) - tx = await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - walletRegistry.address, - decreasingBy - ) + decreasingBy = providerWeight - decreasingTo + tx = await allowlist + .connect(deployer) + .requestWeightDecrease(stakingProvider.address, decreasingTo) }) after(async () => { @@ -825,8 +495,8 @@ describe("WalletRegistry - Authorization", () => { it("should require no time delay before approving", async () => { expect( await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(0) }) @@ -837,38 +507,34 @@ describe("WalletRegistry - Authorization", () => { .withArgs( stakingProvider.address, ZERO_ADDRESS, - stakedAmount, + providerWeight, decreasingTo, - now + now, ) }) it("should capture deauthorizing amount", async () => { expect( await walletRegistry.pendingAuthorizationDecrease( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(decreasingBy) }) }) context("when decreasing to a value above the minimum", () => { - let tx: ContractTransaction - let decreasingTo - let decreasingBy + let tx: ContractTransactionResponse + let decreasingTo: bigint + let decreasingBy: bigint before(async () => { await createSnapshot() - decreasingTo = minimumAuthorization.add(1) - decreasingBy = stakedAmount.sub(decreasingTo) - tx = await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - walletRegistry.address, - decreasingBy - ) + decreasingTo = minimumAuthorization + 1n + decreasingBy = providerWeight - decreasingTo + tx = await allowlist + .connect(deployer) + .requestWeightDecrease(stakingProvider.address, decreasingTo) }) after(async () => { @@ -878,8 +544,8 @@ describe("WalletRegistry - Authorization", () => { it("should require no time delay before approving", async () => { expect( await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(0) }) @@ -890,17 +556,17 @@ describe("WalletRegistry - Authorization", () => { .withArgs( stakingProvider.address, ZERO_ADDRESS, - stakedAmount, + providerWeight, decreasingTo, - now + now, ) }) it("should capture deauthorizing amount", async () => { expect( await walletRegistry.pendingAuthorizationDecrease( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(decreasingBy) }) }) @@ -912,12 +578,11 @@ describe("WalletRegistry - Authorization", () => { before(async () => { await createSnapshot() - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingFirst + providerWeight - deauthorizingFirst, ) }) @@ -927,14 +592,12 @@ describe("WalletRegistry - Authorization", () => { context("when change period is equal delay", () => { before(async () => { - // this should be the default situation from the fixture setup so we - // just confirm it here const { authorizationDecreaseDelay, authorizationDecreaseChangePeriod, } = await walletRegistry.authorizationParameters() expect(authorizationDecreaseDelay).to.equal( - authorizationDecreaseChangePeriod + authorizationDecreaseChangePeriod, ) }) @@ -943,12 +606,11 @@ describe("WalletRegistry - Authorization", () => { await createSnapshot() await helpers.time.increaseTime(params.authorizationDecreaseDelay) - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingSecond + providerWeight - deauthorizingSecond, ) }) @@ -956,28 +618,25 @@ describe("WalletRegistry - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await walletRegistry.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + walletRegistry, + stakingProvider, + deauthorizingSecond, + })) }) context("when delay did not pass", () => { before(async () => { await createSnapshot() await helpers.time.increaseTime( - params.authorizationDecreaseDelay - 60 // -1min + params.authorizationDecreaseDelay - 60, // -1min ) - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingSecond + providerWeight - deauthorizingSecond, ) }) @@ -985,13 +644,11 @@ describe("WalletRegistry - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await walletRegistry.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + walletRegistry, + stakingProvider, + deauthorizingSecond, + })) }) }) @@ -1007,12 +664,11 @@ describe("WalletRegistry - Authorization", () => { .connect(governance) .finalizeAuthorizationDecreaseChangePeriodUpdate() - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingSecond + providerWeight - deauthorizingSecond, ) }) @@ -1020,13 +676,11 @@ describe("WalletRegistry - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await walletRegistry.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + walletRegistry, + stakingProvider, + deauthorizingSecond, + })) }) context("when change period is not equal delay and is non-zero", () => { @@ -1053,12 +707,11 @@ describe("WalletRegistry - Authorization", () => { await createSnapshot() await helpers.time.increaseTime(params.authorizationDecreaseDelay) - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingSecond + providerWeight - deauthorizingSecond, ) }) @@ -1066,28 +719,25 @@ describe("WalletRegistry - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await walletRegistry.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + walletRegistry, + stakingProvider, + deauthorizingSecond, + })) }) context("when change period activated", () => { before(async () => { await createSnapshot() await helpers.time.increaseTime( - params.authorizationDecreaseDelay - newChangePeriod + 60 + params.authorizationDecreaseDelay - newChangePeriod + 60, ) // +1min - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingSecond + providerWeight - deauthorizingSecond, ) }) @@ -1095,28 +745,25 @@ describe("WalletRegistry - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await walletRegistry.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + walletRegistry, + stakingProvider, + deauthorizingSecond, + })) }) context("when change period did not activate", () => { before(async () => { await createSnapshot() await helpers.time.increaseTime( - params.authorizationDecreaseDelay - newChangePeriod - 60 // -1min + params.authorizationDecreaseDelay - newChangePeriod - 60, // -1min ) - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingSecond + providerWeight - deauthorizingSecond, ) }) @@ -1124,30 +771,21 @@ describe("WalletRegistry - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await walletRegistry.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + walletRegistry, + stakingProvider, + deauthorizingSecond, + })) }) }) }) }) - - // The most popular scenario - operator is registered, it has an - // authorization and that authorization is decreased after some time. context("when the operator is registered", () => { before(async () => { await createSnapshot() - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - stakedAmount - ) + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, providerWeight) await walletRegistry .connect(stakingProvider) .registerOperator(operator.address) @@ -1159,52 +797,40 @@ describe("WalletRegistry - Authorization", () => { context("when decreasing to a non-zero value below the minimum", () => { it("should revert", async () => { - const deauthorizingTo = minimumAuthorization.sub(1) - const deauthorizingBy = stakedAmount.sub(deauthorizingTo) + const deauthorizingTo = minimumAuthorization - 1n await expect( - staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - walletRegistry.address, - deauthorizingBy - ) + allowlist + .connect(deployer) + .requestWeightDecrease(stakingProvider.address, deauthorizingTo), ).to.be.revertedWith( - "Authorization amount should be 0 or above the minimum" + "Authorization amount should be 0 or above the minimum", ) }) }) context("when decreasing to zero", () => { - let tx: ContractTransaction - const decreasingTo = 0 - let decreasingBy + let tx: ContractTransactionResponse + const decreasingTo = 0n + let decreasingBy: bigint before(async () => { await createSnapshot() - decreasingBy = stakedAmount.sub(decreasingTo) - tx = await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - walletRegistry.address, - decreasingBy - ) + decreasingBy = providerWeight - decreasingTo + tx = await allowlist + .connect(deployer) + .requestWeightDecrease(stakingProvider.address, decreasingTo) }) after(async () => { await restoreSnapshot() }) - it("should require updating the pool before approving", async () => { - expect( - await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(MAX_UINT64) - }) + shouldRequireUpdatingPoolBeforeApproving(() => ({ + walletRegistry, + stakingProvider, + })) it("should emit AuthorizationDecreaseRequested event", async () => { await expect(tx) @@ -1212,51 +838,44 @@ describe("WalletRegistry - Authorization", () => { .withArgs( stakingProvider.address, operator.address, - stakedAmount, + providerWeight, decreasingTo, - MAX_UINT64 + MAX_UINT64, ) }) it("should capture deauthorizing amount", async () => { expect( await walletRegistry.pendingAuthorizationDecrease( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(decreasingBy) }) }) context("when decreasing to the minimum", () => { - let tx: ContractTransaction - let decreasingTo - let decreasingBy + let tx: ContractTransactionResponse + let decreasingTo: bigint + let decreasingBy: bigint before(async () => { await createSnapshot() decreasingTo = minimumAuthorization - decreasingBy = stakedAmount.sub(decreasingTo) - tx = await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - walletRegistry.address, - decreasingBy - ) + decreasingBy = providerWeight - decreasingTo + tx = await allowlist + .connect(deployer) + .requestWeightDecrease(stakingProvider.address, decreasingTo) }) after(async () => { await restoreSnapshot() }) - it("should require updating the pool before approving", async () => { - expect( - await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(MAX_UINT64) - }) + shouldRequireUpdatingPoolBeforeApproving(() => ({ + walletRegistry, + stakingProvider, + })) it("should emit AuthorizationDecreaseRequested event", async () => { await expect(tx) @@ -1264,51 +883,44 @@ describe("WalletRegistry - Authorization", () => { .withArgs( stakingProvider.address, operator.address, - stakedAmount, + providerWeight, decreasingTo, - MAX_UINT64 + MAX_UINT64, ) }) it("should capture deauthorizing amount", async () => { expect( await walletRegistry.pendingAuthorizationDecrease( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(decreasingBy) }) }) context("when decreasing to a value above the minimum", () => { - let tx: ContractTransaction - let decreasingTo - let decreasingBy + let tx: ContractTransactionResponse + let decreasingTo: bigint + let decreasingBy: bigint before(async () => { await createSnapshot() - decreasingTo = minimumAuthorization.add(1) - decreasingBy = stakedAmount.sub(decreasingTo) - tx = await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - walletRegistry.address, - decreasingBy - ) + decreasingTo = minimumAuthorization + 1n + decreasingBy = providerWeight - decreasingTo + tx = await allowlist + .connect(deployer) + .requestWeightDecrease(stakingProvider.address, decreasingTo) }) after(async () => { await restoreSnapshot() }) - it("should require updating the pool before approving", async () => { - expect( - await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(MAX_UINT64) - }) + shouldRequireUpdatingPoolBeforeApproving(() => ({ + walletRegistry, + stakingProvider, + })) it("should emit AuthorizationDecreaseRequested event", async () => { await expect(tx) @@ -1316,17 +928,17 @@ describe("WalletRegistry - Authorization", () => { .withArgs( stakingProvider.address, operator.address, - stakedAmount, + providerWeight, decreasingTo, - MAX_UINT64 + MAX_UINT64, ) }) it("should capture deauthorizing amount", async () => { expect( await walletRegistry.pendingAuthorizationDecrease( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(decreasingBy) }) }) @@ -1340,12 +952,11 @@ describe("WalletRegistry - Authorization", () => { await walletRegistry.connect(operator).joinSortitionPool() - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingFirst + providerWeight - deauthorizingFirst, ) }) @@ -1355,14 +966,12 @@ describe("WalletRegistry - Authorization", () => { context("when change period is equal delay", () => { before(async () => { - // this should be the default situation from the fixture setup so we - // just confirm it here const { authorizationDecreaseDelay, authorizationDecreaseChangePeriod, } = await walletRegistry.authorizationParameters() expect(authorizationDecreaseDelay).to.equal( - authorizationDecreaseChangePeriod + authorizationDecreaseChangePeriod, ) }) @@ -1370,12 +979,11 @@ describe("WalletRegistry - Authorization", () => { before(async () => { await createSnapshot() - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingSecond + providerWeight - deauthorizingSecond, ) }) @@ -1383,21 +991,16 @@ describe("WalletRegistry - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await walletRegistry.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + walletRegistry, + stakingProvider, + deauthorizingSecond, + })) - it("should require updating the pool before approving", async () => { - expect( - await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(MAX_UINT64) - }) + shouldRequireUpdatingPoolBeforeApproving(() => ({ + walletRegistry, + stakingProvider, + })) }) context("when called after sortition pool was updated", () => { @@ -1414,7 +1017,7 @@ describe("WalletRegistry - Authorization", () => { before(async () => { await createSnapshot() await helpers.time.increaseTime( - params.authorizationDecreaseDelay + params.authorizationDecreaseDelay, ) }) @@ -1425,12 +1028,11 @@ describe("WalletRegistry - Authorization", () => { before(async () => { await createSnapshot() - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingSecond + providerWeight - deauthorizingSecond, ) }) @@ -1438,21 +1040,16 @@ describe("WalletRegistry - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await walletRegistry.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + walletRegistry, + stakingProvider, + deauthorizingSecond, + })) - it("should require updating the pool before approving", async () => { - expect( - await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(MAX_UINT64) - }) + shouldRequireUpdatingPoolBeforeApproving(() => ({ + walletRegistry, + stakingProvider, + })) }) context("when delay did not pass", () => { @@ -1460,15 +1057,14 @@ describe("WalletRegistry - Authorization", () => { await createSnapshot() await helpers.time.increaseTime( - params.authorizationDecreaseDelay - 60 // -1min + params.authorizationDecreaseDelay - 60, // -1min ) - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingSecond + providerWeight - deauthorizingSecond, ) }) @@ -1476,21 +1072,16 @@ describe("WalletRegistry - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await walletRegistry.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + walletRegistry, + stakingProvider, + deauthorizingSecond, + })) - it("should require updating the pool before approving", async () => { - expect( - await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(MAX_UINT64) - }) + shouldRequireUpdatingPoolBeforeApproving(() => ({ + walletRegistry, + stakingProvider, + })) }) }) }) @@ -1516,12 +1107,11 @@ describe("WalletRegistry - Authorization", () => { before(async () => { await createSnapshot() - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingSecond + providerWeight - deauthorizingSecond, ) }) @@ -1529,21 +1119,16 @@ describe("WalletRegistry - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await walletRegistry.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + walletRegistry, + stakingProvider, + deauthorizingSecond, + })) - it("should require updating the pool before approving", async () => { - expect( - await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(MAX_UINT64) - }) + shouldRequireUpdatingPoolBeforeApproving(() => ({ + walletRegistry, + stakingProvider, + })) }) context("when called after sortition pool was updated", () => { @@ -1560,15 +1145,14 @@ describe("WalletRegistry - Authorization", () => { context("when called before delay passed", () => { it("should revert", async () => { await expect( - staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingSecond - ) + providerWeight - deauthorizingSecond, + ), ).to.be.revertedWith( - "Not enough time passed since the original request" + "Not enough time passed since the original request", ) }) }) @@ -1577,15 +1161,14 @@ describe("WalletRegistry - Authorization", () => { before(async () => { await createSnapshot() await helpers.time.increaseTime( - params.authorizationDecreaseDelay + params.authorizationDecreaseDelay, ) - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingSecond + providerWeight - deauthorizingSecond, ) }) @@ -1593,21 +1176,16 @@ describe("WalletRegistry - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await walletRegistry.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + walletRegistry, + stakingProvider, + deauthorizingSecond, + })) - it("should require updating the pool before approving", async () => { - expect( - await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(MAX_UINT64) - }) + shouldRequireUpdatingPoolBeforeApproving(() => ({ + walletRegistry, + stakingProvider, + })) }) }) }) @@ -1635,12 +1213,11 @@ describe("WalletRegistry - Authorization", () => { before(async () => { await createSnapshot() - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingSecond + providerWeight - deauthorizingSecond, ) }) @@ -1648,21 +1225,16 @@ describe("WalletRegistry - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await walletRegistry.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + walletRegistry, + stakingProvider, + deauthorizingSecond, + })) - it("should require updating the pool before approving", async () => { - expect( - await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(MAX_UINT64) - }) + shouldRequireUpdatingPoolBeforeApproving(() => ({ + walletRegistry, + stakingProvider, + })) }) context("when called after sortition pool was updated", () => { @@ -1680,7 +1252,7 @@ describe("WalletRegistry - Authorization", () => { before(async () => { await createSnapshot() await helpers.time.increaseTime( - params.authorizationDecreaseDelay - newChangePeriod - 60 // -1min + params.authorizationDecreaseDelay - newChangePeriod - 60, // -1min ) }) @@ -1690,15 +1262,14 @@ describe("WalletRegistry - Authorization", () => { it("should revert", async () => { await expect( - staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingSecond - ) + providerWeight - deauthorizingSecond, + ), ).to.be.revertedWith( - "Not enough time passed since the original request" + "Not enough time passed since the original request", ) }) }) @@ -1707,15 +1278,14 @@ describe("WalletRegistry - Authorization", () => { before(async () => { await createSnapshot() await helpers.time.increaseTime( - params.authorizationDecreaseDelay - newChangePeriod + 60 // +1min + params.authorizationDecreaseDelay - newChangePeriod + 60, // +1min ) - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingSecond + providerWeight - deauthorizingSecond, ) }) @@ -1723,36 +1293,30 @@ describe("WalletRegistry - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await walletRegistry.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + walletRegistry, + stakingProvider, + deauthorizingSecond, + })) - it("should require updating the pool before approving", async () => { - expect( - await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(MAX_UINT64) - }) + shouldRequireUpdatingPoolBeforeApproving(() => ({ + walletRegistry, + stakingProvider, + })) }) context("when delay passed", () => { before(async () => { await createSnapshot() await helpers.time.increaseTime( - params.authorizationDecreaseDelay + params.authorizationDecreaseDelay, ) - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingSecond + providerWeight - deauthorizingSecond, ) }) @@ -1760,21 +1324,16 @@ describe("WalletRegistry - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await walletRegistry.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + walletRegistry, + stakingProvider, + deauthorizingSecond, + })) - it("should require updating the pool before approving", async () => { - expect( - await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(MAX_UINT64) - }) + shouldRequireUpdatingPoolBeforeApproving(() => ({ + walletRegistry, + stakingProvider, + })) }) }) }) @@ -1785,13 +1344,9 @@ describe("WalletRegistry - Authorization", () => { describe("approveAuthorizationDecrease", () => { before(async () => { await createSnapshot() - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - stakedAmount - ) + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, providerWeight) }) after(async () => { @@ -1801,7 +1356,7 @@ describe("WalletRegistry - Authorization", () => { context("when decrease was not requested", () => { it("should revert", async () => { await expect( - walletRegistry.approveAuthorizationDecrease(stakingProvider.address) + walletRegistry.approveAuthorizationDecrease(stakingProvider.address), ).to.be.revertedWith("Authorization decrease not requested") }) }) @@ -1811,14 +1366,13 @@ describe("WalletRegistry - Authorization", () => { before(async () => { await createSnapshot() - const deauthorizingBy = stakedAmount + const deauthorizingBy = providerWeight - staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingBy + providerWeight - deauthorizingBy, ) }) @@ -1828,9 +1382,8 @@ describe("WalletRegistry - Authorization", () => { it("should let to approve immediately", async () => { const tx = await walletRegistry.approveAuthorizationDecrease( - stakingProvider.address + stakingProvider.address, ) - // ok, did not revert await expect(tx) .to.emit(walletRegistry, "AuthorizationDecreaseApproved") .withArgs(stakingProvider.address) @@ -1846,13 +1399,12 @@ describe("WalletRegistry - Authorization", () => { .connect(stakingProvider) .registerOperator(operator.address) - const deauthorizingBy = stakedAmount - staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + const deauthorizingBy = providerWeight + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingBy + providerWeight - deauthorizingBy, ) }) @@ -1863,8 +1415,6 @@ describe("WalletRegistry - Authorization", () => { context("when the pool was not updated", () => { before(async () => { await createSnapshot() - - // even if we wait for the entire delay, it should not help await helpers.time.increaseTime(params.authorizationDecreaseDelay) }) @@ -1874,7 +1424,9 @@ describe("WalletRegistry - Authorization", () => { it("should revert", async () => { await expect( - walletRegistry.approveAuthorizationDecrease(stakingProvider.address) + walletRegistry.approveAuthorizationDecrease( + stakingProvider.address, + ), ).to.be.revertedWith("Authorization decrease request not activated") }) }) @@ -1885,7 +1437,7 @@ describe("WalletRegistry - Authorization", () => { await walletRegistry.updateOperatorStatus(operator.address) await helpers.time.increaseTime( - params.authorizationDecreaseDelay - 60 // -1min + params.authorizationDecreaseDelay - 60, // -1min ) }) @@ -1895,13 +1447,15 @@ describe("WalletRegistry - Authorization", () => { it("should revert", async () => { await expect( - walletRegistry.approveAuthorizationDecrease(stakingProvider.address) + walletRegistry.approveAuthorizationDecrease( + stakingProvider.address, + ), ).to.be.revertedWith("Authorization decrease delay not passed") }) }) context("when the pool was updated and the delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1910,7 +1464,7 @@ describe("WalletRegistry - Authorization", () => { await helpers.time.increaseTime(params.authorizationDecreaseDelay) tx = await walletRegistry.approveAuthorizationDecrease( - stakingProvider.address + stakingProvider.address, ) }) @@ -1919,13 +1473,19 @@ describe("WalletRegistry - Authorization", () => { }) it("should reduce authorized stake amount", async () => { - expect(await sortitionPool.getPoolWeight(operator.address)).to.equal( - 0 - ) + expect( + await allowlist.authorizedStake( + stakingProvider.address, + await walletRegistry.getAddress(), + ), + ).to.equal(0) + expect( + await walletRegistry.eligibleStake(stakingProvider.address), + ).to.equal(0) }) it("should emit AuthorizationDecreaseApproved event", async () => { - expect(tx) + await expect(tx) .to.emit(walletRegistry, "AuthorizationDecreaseApproved") .withArgs(stakingProvider.address) }) @@ -1933,119 +1493,100 @@ describe("WalletRegistry - Authorization", () => { it("should clear pending authorization decrease", async () => { expect( await walletRegistry.pendingAuthorizationDecrease( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(0) }) }) }) }) - describe("involuntaryAuthorizationDecrease", () => { - context("when called not by the staking contract", () => { + describe("joinSortitionPool", () => { + context("when the operator is unknown", () => { it("should revert", async () => { await expect( - walletRegistry - .connect(thirdParty) - .involuntaryAuthorizationDecrease(stakingProvider.address, 100, 99) - ).to.be.revertedWithCustomError(walletRegistry, "CallerNotStakingContract") + walletRegistry.connect(thirdParty).joinSortitionPool(), + ).to.be.revertedWith("Unknown operator") }) }) - context("when the operator is unknown", () => { - const slashedAmount = to1e18(100) - let tx: ContractTransaction - + context("when the operator has no stake authorized", () => { before(async () => { await createSnapshot() - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - stakedAmount - ) - // lock the pool for DKG - // we lock the pool to ensure that the update is ignored for the - // operator and that involuntaryAuthorizationDecrease logic in this - // case is basically a pass-through - await walletRegistry.connect(walletOwner.wallet).requestNewWallet() - - // slash! - await staking - .connect(slasher.wallet) - .slash(slashedAmount, [stakingProvider.address]) - tx = await staking.connect(thirdParty).processSlashing(1) + await walletRegistry + .connect(stakingProvider) + .registerOperator(operator.address) }) after(async () => { await restoreSnapshot() }) - it("should ignore the update", async () => { - await expect(tx).to.not.emit( - walletRegistry, - "InvoluntaryAuthorizationDecreaseFailed" - ) + it("should revert", async () => { + await expect( + walletRegistry.connect(operator).joinSortitionPool(), + ).to.be.revertedWith("Authorization below the minimum") }) }) - context("when the operator is known", () => { + context("when the operator has the minimum stake authorized", () => { + let tx: ContractTransactionResponse + before(async () => { await createSnapshot() - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - stakedAmount - ) await walletRegistry .connect(stakingProvider) .registerOperator(operator.address) + + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, minimumAuthorization) + + tx = await walletRegistry.connect(operator).joinSortitionPool() }) after(async () => { await restoreSnapshot() }) - context("when the operator is not in the sortition pool", () => { - const slashedAmount = to1e18(100) - let tx: ContractTransaction + it("should insert operator into the pool", async () => { + expect(await walletRegistry.isOperatorInPool(operator.address)).to.be + .true + }) + + it("should use a correct stake weight", async () => { + expect(await sortitionPool.getPoolWeight(operator.address)).to.equal( + minimumAuthorization / BigInt(constants.poolWeightDivisor), + ) + }) + + it("should emit OperatorJoinedSortitionPool", async () => { + await expect(tx) + .to.emit(walletRegistry, "OperatorJoinedSortitionPool") + .withArgs(stakingProvider.address, operator.address) + }) + }) + + context( + "when the operator has more than the minimum stake authorized", + () => { + let authorizedStake: bigint before(async () => { await createSnapshot() - // lock the pool for DKG - // we lock the pool to ensure that the update is ignored for the - // operator and that involuntaryAuthorizationDecrease logic in this - // case is basically a pass-through - await walletRegistry.connect(walletOwner.wallet).requestNewWallet() - - // slash! - await staking - .connect(slasher.wallet) - .slash(slashedAmount, [stakingProvider.address]) - tx = await staking.connect(thirdParty).processSlashing(1) - }) + await walletRegistry + .connect(stakingProvider) + .registerOperator(operator.address) - after(async () => { - await restoreSnapshot() - }) + authorizedStake = minimumAuthorization * 2n - it("should ignore the update", async () => { - await expect(tx).to.not.emit( - walletRegistry, - "InvoluntaryAuthorizationDecreaseFailed" - ) - }) - }) + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, authorizedStake) - context("when the operator is in the sortition pool", () => { - before(async () => { - await createSnapshot() await walletRegistry.connect(operator).joinSortitionPool() }) @@ -2053,265 +1594,21 @@ describe("WalletRegistry - Authorization", () => { await restoreSnapshot() }) - context("when the sortition pool is locked", () => { - const slashedAmount = to1e18(100) - let tx: ContractTransaction - - before(async () => { - await createSnapshot() - - // lock the pool for DKG - await walletRegistry.connect(walletOwner.wallet).requestNewWallet() - - // and slash! - await staking - .connect(slasher.wallet) - .slash(slashedAmount, [stakingProvider.address]) - tx = await staking.connect(thirdParty).processSlashing(1) - }) - - after(async () => { - await restoreSnapshot() - }) - - it("should not update the pool", async () => { - expect(await walletRegistry.isOperatorUpToDate(operator.address)).to - .be.false - }) - - it("should emit InvoluntaryAuthorizationDecreaseFailed event", async () => { - await expect(tx) - .to.emit(walletRegistry, "InvoluntaryAuthorizationDecreaseFailed") - .withArgs( - stakingProvider.address, - operator.address, - stakedAmount, - stakedAmount.sub(slashedAmount) - ) - }) - }) - - context("when the sortition pool is not locked", () => { - context("when the authorization drops to above the minimum", () => { - const slashedAmount = to1e18(100) - let tx: ContractTransaction - - before(async () => { - await createSnapshot() - - // slash! - await staking - .connect(slasher.wallet) - .slash(slashedAmount, [stakingProvider.address]) - tx = await staking.connect(thirdParty).processSlashing(1) - }) - - after(async () => { - await restoreSnapshot() - }) - - it("should update operator status", async () => { - expect(await walletRegistry.isOperatorUpToDate(operator.address)) - .to.be.true - }) - - it("should not emit InvoluntaryAuthorizationDecreaseFailed event", async () => { - await expect(tx).to.not.emit( - walletRegistry, - "InvoluntaryAuthorizationDecreaseFailed" - ) - }) - }) - - context( - "when the authorized amount drops to below the minimum", - () => { - before(async () => { - const slashingTo = minimumAuthorization.sub(1) - const slashingBy = stakedAmount.sub(slashingTo) - - await createSnapshot() - - // slash! - await staking - .connect(slasher.wallet) - .slash(slashingBy, [stakingProvider.address]) - - await staking.connect(thirdParty).processSlashing(1) - }) - - after(async () => { - await restoreSnapshot() - }) - - it("should remove operator from the sortition pool", async () => { - expect(await walletRegistry.isOperatorInPool(operator.address)) - .to.be.false - }) - } - ) - }) - }) - }) - }) - - describe("joinSortitionPool", () => { - context("when the operator is unknown", () => { - it("should revert", async () => { - await expect( - walletRegistry.connect(thirdParty).joinSortitionPool() - ).to.be.revertedWithCustomError(walletRegistry, "UnknownOperator") - }) - }) - - context("when the operator has no stake authorized", () => { - before(async () => { - await createSnapshot() - - await walletRegistry - .connect(stakingProvider) - .registerOperator(operator.address) - }) - - after(async () => { - await restoreSnapshot() - }) - - it("should revert", async () => { - await expect( - walletRegistry.connect(operator).joinSortitionPool() - ).to.be.revertedWith("Authorization below the minimum") - }) - }) - - // The only option for it to happen is when there was a slashing. - context( - "when the authorization dropped below the minimum but is still non-zero", - () => { - before(async () => { - await createSnapshot() - - await walletRegistry - .connect(stakingProvider) - .registerOperator(operator.address) - - const authorizedAmount = minimumAuthorization - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - authorizedAmount - ) - - const slashingTo = minimumAuthorization.sub(1) - const slashedAmount = authorizedAmount.sub(slashingTo) - - await staking - .connect(slasher.wallet) - .slash(slashedAmount, [stakingProvider.address]) - await staking.connect(thirdParty).processSlashing(1) - }) - - after(async () => { - await restoreSnapshot() - }) - - it("should revert", async () => { - await expect( - walletRegistry.connect(operator).joinSortitionPool() - ).to.be.revertedWith("Authorization below the minimum") - }) - } - ) - - context("when the operator has the minimum stake authorized", () => { - let tx: ContractTransaction - - before(async () => { - await createSnapshot() - - await walletRegistry - .connect(stakingProvider) - .registerOperator(operator.address) - - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - minimumAuthorization - ) - - tx = await walletRegistry.connect(operator).joinSortitionPool() - }) - - after(async () => { - await restoreSnapshot() - }) - - it("should insert operator into the pool", async () => { - expect(await walletRegistry.isOperatorInPool(operator.address)).to.be - .true - }) - - it("should use a correct stake weight", async () => { - expect(await sortitionPool.getPoolWeight(operator.address)).to.equal( - minimumAuthorization.div(constants.poolWeightDivisor) - ) - }) - - it("should emit OperatorJoinedSortitionPool", async () => { - await expect(tx) - .to.emit(walletRegistry, "OperatorJoinedSortitionPool") - .withArgs(stakingProvider.address, operator.address) - }) - }) - - context( - "when the operator has more than the minimum stake authorized", - () => { - let authorizedStake - - before(async () => { - await createSnapshot() - - await walletRegistry - .connect(stakingProvider) - .registerOperator(operator.address) - - authorizedStake = minimumAuthorization.mul(2) - - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - authorizedStake - ) - - await walletRegistry.connect(operator).joinSortitionPool() - }) - - after(async () => { - await restoreSnapshot() - }) - - it("should insert operator into the pool", async () => { - expect(await walletRegistry.isOperatorInPool(operator.address)).to.be - .true - }) + it("should insert operator into the pool", async () => { + expect(await walletRegistry.isOperatorInPool(operator.address)).to.be + .true + }) it("should use a correct stake weight", async () => { expect(await sortitionPool.getPoolWeight(operator.address)).to.equal( - authorizedStake.div(constants.poolWeightDivisor) + authorizedStake / BigInt(constants.poolWeightDivisor), ) }) - } + }, ) context("when operator is in the process of deauthorizing", () => { - let deauthorizingTo + let deauthorizingTo: bigint before(async () => { await createSnapshot() @@ -2320,26 +1617,17 @@ describe("WalletRegistry - Authorization", () => { .connect(stakingProvider) .registerOperator(operator.address) - const authorizedStake = stakedAmount + const authorizedStake = providerWeight - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - authorizedStake - ) + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, authorizedStake) - deauthorizingTo = minimumAuthorization.add(to1e18(1337)) - const deauthorizingBy = authorizedStake.sub(deauthorizingTo) + deauthorizingTo = minimumAuthorization + to1e18(1337) - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - walletRegistry.address, - deauthorizingBy - ) + await allowlist + .connect(deployer) + .requestWeightDecrease(stakingProvider.address, deauthorizingTo) await walletRegistry.connect(operator).joinSortitionPool() }) @@ -2355,98 +1643,26 @@ describe("WalletRegistry - Authorization", () => { it("should use a correct stake weight", async () => { expect(await sortitionPool.getPoolWeight(operator.address)).to.equal( - deauthorizingTo.div(constants.poolWeightDivisor) + deauthorizingTo / BigInt(constants.poolWeightDivisor), ) }) it("should activate authorization decrease delay", async () => { expect( await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(params.authorizationDecreaseDelay) }) }) - - context( - "when operator is in the process of deauthorizing but also increased authorization in the meantime", - () => { - let expectedAuthorizedStake - - before(async () => { - await createSnapshot() - - await walletRegistry - .connect(stakingProvider) - .registerOperator(operator.address) - - const authorizedStake = minimumAuthorization.add(to1e18(100)) - - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - authorizedStake - ) - - const deauthorizingTo = minimumAuthorization.add(to1e18(50)) - const deauthorizingBy = authorizedStake.sub(deauthorizingTo) - - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - walletRegistry.address, - deauthorizingBy - ) - - const increasingBy = to1e18(5000) - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - increasingBy - ) - - expectedAuthorizedStake = deauthorizingTo.add(increasingBy) - - await walletRegistry.connect(operator).joinSortitionPool() - }) - - after(async () => { - await restoreSnapshot() - }) - - it("should insert operator into the pool", async () => { - expect(await walletRegistry.isOperatorInPool(operator.address)).to.be - .true - }) - - it("should use a correct stake weight", async () => { - expect(await sortitionPool.getPoolWeight(operator.address)).to.equal( - expectedAuthorizedStake.div(constants.poolWeightDivisor) - ) - }) - - it("should activate authorization decrease delay", async () => { - expect( - await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(params.authorizationDecreaseDelay) - }) - } - ) }) describe("updateOperatorStatus", () => { context("when the operator is unknown", () => { it("should revert", async () => { await expect( - walletRegistry.updateOperatorStatus(thirdParty.address) - ).to.be.revertedWithCustomError(walletRegistry, "UnknownOperator") + walletRegistry.updateOperatorStatus(thirdParty.address), + ).to.be.revertedWith("Unknown operator") }) }) @@ -2464,18 +1680,14 @@ describe("WalletRegistry - Authorization", () => { }) context("when the authorization increased", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - minimumAuthorization - ) + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, minimumAuthorization) tx = await walletRegistry .connect(thirdParty) @@ -2499,26 +1711,21 @@ describe("WalletRegistry - Authorization", () => { }) context("when there was an authorization decrease request", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - stakedAmount - ) + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, providerWeight) const deauthorizingBy = to1e18(100) - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingBy + providerWeight - deauthorizingBy, ) tx = await walletRegistry @@ -2538,8 +1745,8 @@ describe("WalletRegistry - Authorization", () => { it("should activate authorization decrease delay", async () => { expect( await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(params.authorizationDecreaseDelay) }) @@ -2559,12 +1766,11 @@ describe("WalletRegistry - Authorization", () => { .connect(stakingProvider) .registerOperator(operator.address) - await staking - .connect(authorizer) - .increaseAuthorization( + await allowlist + .connect(deployer) + .addStakingProvider( stakingProvider.address, - walletRegistry.address, - minimumAuthorization.mul(2) + minimumAuthorization * 2n, ) await walletRegistry.connect(operator).joinSortitionPool() @@ -2574,76 +1780,21 @@ describe("WalletRegistry - Authorization", () => { await restoreSnapshot() }) - context("when the authorization increased", () => { - let tx: ContractTransaction - let expectedWeight - - before(async () => { - await createSnapshot() - - const topUp = to1e18(1337) - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - topUp - ) - - // initial authorization was 2 x minimum - // it was increased by 1337 tokens - // so the final authorization should be 2 x minimum + 1337 - expectedWeight = minimumAuthorization - .mul(2) - .add(topUp) - .div(constants.poolWeightDivisor) - - tx = await walletRegistry - .connect(thirdParty) - .updateOperatorStatus(operator.address) - }) - - after(async () => { - await restoreSnapshot() - }) - - it("should update the pool", async () => { - expect(await sortitionPool.getPoolWeight(operator.address)).to.equal( - expectedWeight - ) - }) - - it("should emit OperatorStatusUpdated", async () => { - await expect(tx) - .to.emit(walletRegistry, "OperatorStatusUpdated") - .withArgs(stakingProvider.address, operator.address) - }) - }) - context( "when there was an authorization decrease request to non-zero", () => { - let tx: ContractTransaction - let expectedWeight + let tx: ContractTransactionResponse + let expectedWeight: bigint before(async () => { await createSnapshot() + const deauthorizingTo = minimumAuthorization + to1e18(1337) + expectedWeight = + deauthorizingTo / BigInt(constants.poolWeightDivisor) - // initial authorization was 2 x minimum - // we want to decrease to minimum + 1337 - const deauthorizingTo = minimumAuthorization.add(to1e18(1337)) - const deauthorizingBy = minimumAuthorization - .mul(2) - .sub(deauthorizingTo) - expectedWeight = deauthorizingTo.div(constants.poolWeightDivisor) - - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - walletRegistry.address, - deauthorizingBy - ) + await allowlist + .connect(deployer) + .requestWeightDecrease(stakingProvider.address, deauthorizingTo) tx = await walletRegistry .connect(thirdParty) @@ -2656,15 +1807,15 @@ describe("WalletRegistry - Authorization", () => { it("should update the pool", async () => { expect( - await sortitionPool.getPoolWeight(operator.address) + await sortitionPool.getPoolWeight(operator.address), ).to.equal(expectedWeight) }) it("should activate authorization decrease delay", async () => { expect( await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(params.authorizationDecreaseDelay) }) @@ -2673,28 +1824,20 @@ describe("WalletRegistry - Authorization", () => { .to.emit(walletRegistry, "OperatorStatusUpdated") .withArgs(stakingProvider.address, operator.address) }) - } + }, ) context( "when there was an authorization decrease request to zero", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() - // initial authorization was 2 x minimum - // we want to decrease to zero - const deauthorizingBy = minimumAuthorization.mul(2) - - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - walletRegistry.address, - deauthorizingBy - ) + await allowlist + .connect(deployer) + .requestWeightDecrease(stakingProvider.address, 0) tx = await walletRegistry .connect(thirdParty) @@ -2713,75 +1856,8 @@ describe("WalletRegistry - Authorization", () => { it("should activate authorization decrease delay", async () => { expect( await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(params.authorizationDecreaseDelay) - }) - - it("should emit OperatorStatusUpdated", async () => { - await expect(tx) - .to.emit(walletRegistry, "OperatorStatusUpdated") - .withArgs(stakingProvider.address, operator.address) - }) - } - ) - - context( - "when operator is in the process of deauthorizing but also increased authorization in the meantime", - () => { - let tx: ContractTransaction - let expectedWeight - - before(async () => { - await createSnapshot() - - // initial authorization was 2 x minimum - // we want to decrease to minimum + 1337 - // and then decrease by 7331 - const deauthorizingTo = minimumAuthorization.add(to1e18(1337)) - const deauthorizingBy = minimumAuthorization - .mul(2) - .sub(deauthorizingTo) - const increasingBy = to1e18(7331) - const increasingTo = deauthorizingTo.add(increasingBy) - expectedWeight = increasingTo.div(constants.poolWeightDivisor) - - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - walletRegistry.address, - deauthorizingBy - ) - - await staking - .connect(authorizer) - .increaseAuthorization( stakingProvider.address, - walletRegistry.address, - increasingBy - ) - - tx = await walletRegistry - .connect(thirdParty) - .updateOperatorStatus(operator.address) - }) - - after(async () => { - await restoreSnapshot() - }) - - it("should update the pool", async () => { - expect( - await sortitionPool.getPoolWeight(operator.address) - ).to.equal(expectedWeight) - }) - - it("should activate authorization decrease delay", async () => { - expect( - await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + ), ).to.equal(params.authorizationDecreaseDelay) }) @@ -2790,7 +1866,7 @@ describe("WalletRegistry - Authorization", () => { .to.emit(walletRegistry, "OperatorStatusUpdated") .withArgs(stakingProvider.address, operator.address) }) - } + }, ) }) }) @@ -2799,25 +1875,21 @@ describe("WalletRegistry - Authorization", () => { context("when staking provider has no stake authorized", () => { it("should return zero", async () => { expect( - await walletRegistry.eligibleStake(stakingProvider.address) + await walletRegistry.eligibleStake(stakingProvider.address), ).to.equal(0) }) }) context("when staking provider has stake authorized", () => { - let authorizedAmount + let authorizedAmount: bigint before(async () => { await createSnapshot() authorizedAmount = minimumAuthorization - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - authorizedAmount - ) + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, authorizedAmount) }) after(async () => { @@ -2826,7 +1898,7 @@ describe("WalletRegistry - Authorization", () => { it("should return authorized amount", async () => { expect( - await walletRegistry.eligibleStake(stakingProvider.address) + await walletRegistry.eligibleStake(stakingProvider.address), ).to.equal(authorizedAmount) }) }) @@ -2834,29 +1906,24 @@ describe("WalletRegistry - Authorization", () => { context( "when staking provider has some part of the stake deauthorizing", () => { - let authorizedAmount - let deauthorizingAmount + let authorizedAmount: bigint + let deauthorizingAmount: bigint before(async () => { await createSnapshot() - authorizedAmount = minimumAuthorization.add(to1e18(2000)) + authorizedAmount = minimumAuthorization + to1e18(2000) - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - authorizedAmount - ) + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, authorizedAmount) deauthorizingAmount = to1e18(1337) - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingAmount + authorizedAmount - deauthorizingAmount, ) }) @@ -2866,10 +1933,10 @@ describe("WalletRegistry - Authorization", () => { it("should return authorized amount minus deauthorizing amount", async () => { expect( - await walletRegistry.eligibleStake(stakingProvider.address) - ).to.equal(authorizedAmount.sub(deauthorizingAmount)) + await walletRegistry.eligibleStake(stakingProvider.address), + ).to.equal(authorizedAmount - deauthorizingAmount) }) - } + }, ) context("when staking provider has all of the stake deauthorizing", () => { @@ -2877,21 +1944,13 @@ describe("WalletRegistry - Authorization", () => { await createSnapshot() const authorizedAmount = minimumAuthorization - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - authorizedAmount - ) + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, authorizedAmount) - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - walletRegistry.address, - authorizedAmount - ) + await allowlist + .connect(deployer) + .requestWeightDecrease(stakingProvider.address, 0) }) after(async () => { @@ -2900,7 +1959,7 @@ describe("WalletRegistry - Authorization", () => { it("should return zero", async () => { expect( - await walletRegistry.eligibleStake(stakingProvider.address) + await walletRegistry.eligibleStake(stakingProvider.address), ).to.equal(0) }) }) @@ -2909,25 +1968,17 @@ describe("WalletRegistry - Authorization", () => { before(async () => { await createSnapshot() - const authorizedAmount = minimumAuthorization.add(1200) - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - authorizedAmount - ) + const authorizedAmount = minimumAuthorization + 1200n + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, authorizedAmount) - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - walletRegistry.address, - authorizedAmount - ) + await allowlist + .connect(deployer) + .requestWeightDecrease(stakingProvider.address, 0) await walletRegistry.approveAuthorizationDecrease( - stakingProvider.address + stakingProvider.address, ) }) @@ -2937,89 +1988,40 @@ describe("WalletRegistry - Authorization", () => { it("should return zero", async () => { expect( - await walletRegistry.eligibleStake(stakingProvider.address) + await walletRegistry.eligibleStake(stakingProvider.address), ).to.equal(0) }) }) - - // The only option for it to happen is when there was a slashing. - context( - "when the authorization dropped below the minimum but is still non-zero", - () => { - before(async () => { - await createSnapshot() - - const authorizedAmount = minimumAuthorization - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - authorizedAmount - ) - - const slashingTo = minimumAuthorization.sub(1) - const slashedAmount = authorizedAmount.sub(slashingTo) - - await staking - .connect(slasher.wallet) - .slash(slashedAmount, [stakingProvider.address]) - await staking.connect(thirdParty).processSlashing(1) - }) - - after(async () => { - await restoreSnapshot() - }) - - it("should return zero", async () => { - expect( - await walletRegistry.eligibleStake(stakingProvider.address) - ).to.equal(0) - }) - } - ) }) describe("remainingAuthorizationDecreaseDelay", () => { before(async () => { await createSnapshot() - const authorizedAmount = minimumAuthorization.add(1200) - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - authorizedAmount - ) + const authorizedAmount = minimumAuthorization + 1200n + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, authorizedAmount) await walletRegistry .connect(stakingProvider) .registerOperator(operator.address) await walletRegistry.connect(operator).joinSortitionPool() - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - walletRegistry.address, - authorizedAmount - ) + await allowlist + .connect(deployer) + .requestWeightDecrease(stakingProvider.address, 0) }) after(async () => { await restoreSnapshot() }) - // These tests cover only basic cases. More scenarios such as operator not - // registered for the staking provider has been covered in tests for other - // functions. - it("should not activate before sortition pool is updated", async () => { expect( await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(MAX_UINT64) }) @@ -3027,8 +2029,8 @@ describe("WalletRegistry - Authorization", () => { await walletRegistry.updateOperatorStatus(operator.address) expect( await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(params.authorizationDecreaseDelay) }) @@ -3037,11 +2039,11 @@ describe("WalletRegistry - Authorization", () => { await helpers.time.increaseTime(params.authorizationDecreaseDelay / 2) expect( await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.be.closeTo( - ethers.BigNumber.from(params.authorizationDecreaseDelay / 2), - 5 // +- 5sec + BigInt(params.authorizationDecreaseDelay / 2), + 5, // +- 5sec ) }) @@ -3050,16 +2052,14 @@ describe("WalletRegistry - Authorization", () => { await helpers.time.increaseTime(params.authorizationDecreaseDelay) expect( await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(0) - - // ...and should remain zero await helpers.time.increaseTime(3600) // +1h expect( await walletRegistry.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(0) }) }) @@ -3067,11 +2067,9 @@ describe("WalletRegistry - Authorization", () => { describe("isOperatorUpToDate", () => { context("when the operator is unknown", () => { it("should revert", async () => { - it("should revert", async () => { - await expect( - walletRegistry.isOperatorUpToDate(thirdParty.address) - ).to.be.revertedWithCustomError(walletRegistry, "UnknownOperator") - }) + await expect( + walletRegistry.isOperatorUpToDate(thirdParty.address), + ).to.be.revertedWith("Unknown operator") }) }) @@ -3099,13 +2097,9 @@ describe("WalletRegistry - Authorization", () => { before(async () => { await createSnapshot() - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - minimumAuthorization - ) + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, minimumAuthorization) }) after(async () => { @@ -3127,12 +2121,11 @@ describe("WalletRegistry - Authorization", () => { .connect(stakingProvider) .registerOperator(operator.address) - await staking - .connect(authorizer) - .increaseAuthorization( + await allowlist + .connect(deployer) + .addStakingProvider( stakingProvider.address, - walletRegistry.address, - minimumAuthorization.mul(2) + minimumAuthorization * 2n, ) await walletRegistry.connect(operator).joinSortitionPool() @@ -3149,50 +2142,16 @@ describe("WalletRegistry - Authorization", () => { }) }) - context("when authorization was increased", () => { - before(async () => { - await createSnapshot() - - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - to1e18(1337) - ) - }) - - after(async () => { - await restoreSnapshot() - }) - - context("when sortition pool was not yet updated", () => { - it("should return false", async () => { - expect(await walletRegistry.isOperatorUpToDate(operator.address)).to - .be.false - }) - }) - - context("when the sortition pool was updated", () => { - it("should return true", async () => { - await walletRegistry.updateOperatorStatus(operator.address) - expect(await walletRegistry.isOperatorUpToDate(operator.address)).to - .be.true - }) - }) - }) - context("when authorization decrease was requested", () => { before(async () => { await createSnapshot() const deauthorizingBy = to1e18(1) - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( + await allowlist + .connect(deployer) + .requestWeightDecrease( stakingProvider.address, - walletRegistry.address, - deauthorizingBy + minimumAuthorization * 2n - deauthorizingBy, ) }) @@ -3215,1069 +2174,252 @@ describe("WalletRegistry - Authorization", () => { }) }) }) - - context("when operator was slashed when the pool was locked", () => { - before(async () => { - await createSnapshot() - - // Increase authorization to the maximum possible value and update - // sortition pool. This way, any slashing from `slasher` application - // will affect authorized stake amount for WalletRegistry. - const authorized = await staking.authorizedStake( - stakingProvider.address, - walletRegistry.address - ) - const increaseBy = stakedAmount.sub(authorized) - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - increaseBy - ) - await walletRegistry.updateOperatorStatus(operator.address) - - // lock the pool for DKG - await walletRegistry.connect(walletOwner.wallet).requestNewWallet() - - // and slash! - await staking - .connect(slasher.wallet) - .slash(to1e18(100), [stakingProvider.address]) - await staking.connect(thirdParty).processSlashing(1) - - // unlock the pool by stopping DKG - await mineBlocks(params.dkgSeedTimeout) - await walletRegistry.notifySeedTimeout() - }) - - after(async () => { - await restoreSnapshot() - }) - - context("when sortition pool was not yet updated", () => { - it("should return false", async () => { - expect(await walletRegistry.isOperatorUpToDate(operator.address)).to - .be.false - }) - }) - - context("when the sortition pool was updated", () => { - it("should return true", async () => { - await walletRegistry.updateOperatorStatus(operator.address) - expect(await walletRegistry.isOperatorUpToDate(operator.address)).to - .be.true - }) - }) - }) }) }) - // Testing final states for scenarios when functions are invoked one after - // another. Operator is known and registered in the sortition pool. - context("mixed interactions", () => { - let initialIncrease - - before(async () => { + describe("Allowlist provider lifecycle", () => { + beforeEach(async () => { await createSnapshot() - - await walletRegistry - .connect(stakingProvider) - .registerOperator(operator.address) - - // Authorized almost the entire staked amount but leave some margin for - // authorization increase. - initialIncrease = stakedAmount.sub(to1e18(20000)) - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - initialIncrease - ) - await walletRegistry.connect(operator).joinSortitionPool() }) - after(async () => { + afterEach(async () => { await restoreSnapshot() }) - // Invoke `increaseAuthorization` after `increaseAuthorization`. - describe("authorizationIncreased -> authorizationIncreased", () => { - let secondIncrease + it("should restrict adding providers and decreasing weights to the Allowlist owner", async () => { + await expect( + allowlist + .connect(thirdParty) + .addStakingProvider(stakingProvider.address, providerWeight), + ).to.be.revertedWith("Ownable: caller is not the owner") + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, providerWeight) + await expect( + allowlist + .connect(thirdParty) + .requestWeightDecrease(stakingProvider.address, minimumAuthorization), + ).to.be.revertedWith("Ownable: caller is not the owner") + }) - before(async () => { - await createSnapshot() + it("should reject adding weight to an already allowlisted provider", async () => { + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, providerWeight) + await expect( + allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, providerWeight), + ).to.be.revertedWithCustomError(allowlist, "StakingProviderAlreadyAdded") + expect( + await walletRegistry.eligibleStake(stakingProvider.address), + ).to.equal(providerWeight) + }) - secondIncrease = to1e18(11111) - await staking - .connect(authorizer) - .increaseAuthorization( + const targetWeights = [params.minimumAuthorization, 0n] + targetWeights.forEach((targetWeight) => { + it(`should finalize a decrease to ${targetWeight} after synchronizing the pool and waiting`, async () => { + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, providerWeight) + await walletRegistry + .connect(stakingProvider) + .registerOperator(operator.address) + await walletRegistry.connect(operator).joinSortitionPool() + await allowlist + .connect(deployer) + .requestWeightDecrease(stakingProvider.address, targetWeight) + expect( + await allowlist.authorizedStake( stakingProvider.address, - walletRegistry.address, - secondIncrease - ) - + await walletRegistry.getAddress(), + ), + ).to.equal(providerWeight) + expect( + await walletRegistry.eligibleStake(stakingProvider.address), + ).to.equal(targetWeight) await walletRegistry - .connect(operator) + .connect(thirdParty) .updateOperatorStatus(operator.address) - }) - - after(async () => { - await restoreSnapshot() - }) - - it("should have correct eligible stake", async () => { + await helpers.time.increaseTime(params.authorizationDecreaseDelay) + const tx = await walletRegistry + .connect(thirdParty) + .approveAuthorizationDecrease(stakingProvider.address) + await expect(tx) + .to.emit(allowlist, "WeightDecreaseFinalized") + .withArgs(stakingProvider.address, providerWeight, targetWeight) + const info = await allowlist.stakingProviders(stakingProvider.address) + expect(info.weight).to.equal(targetWeight) + expect(info.pendingNewWeight).to.equal(0) + expect(info.decreasePending).to.be.false expect( - await walletRegistry.eligibleStake(stakingProvider.address) - ).to.equal(initialIncrease.add(secondIncrease)) - }) - - it("should have operator status updated", async () => { + await walletRegistry.pendingAuthorizationDecrease( + stakingProvider.address, + ), + ).to.equal(0) expect(await walletRegistry.isOperatorUpToDate(operator.address)).to.be .true }) }) - // Invoke `increaseAuthorization` after `authorizationDecreaseRequested`. - // The decrease is not yet approved when `increaseAuthorization` is called. - describe("authorizationDecreaseRequested -> authorizationIncreased", () => { - let firstDecrease - let secondIncrease - - before(async () => { - await createSnapshot() + it("should allow a removed provider to be added again with the same operator", async () => { + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, providerWeight) + await walletRegistry + .connect(stakingProvider) + .registerOperator(operator.address) + await walletRegistry.connect(operator).joinSortitionPool() + await allowlist + .connect(deployer) + .requestWeightDecrease(stakingProvider.address, 0) + await walletRegistry.updateOperatorStatus(operator.address) + await helpers.time.increaseTime(params.authorizationDecreaseDelay) + await walletRegistry.approveAuthorizationDecrease(stakingProvider.address) + expect(await walletRegistry.isOperatorInPool(operator.address)).to.be + .false + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, minimumAuthorization) + await walletRegistry.connect(operator).joinSortitionPool() + expect( + await walletRegistry.stakingProviderToOperator(stakingProvider.address), + ).to.equal(operator.address) + expect(await sortitionPool.getPoolWeight(operator.address)).to.equal( + minimumAuthorization / BigInt(constants.poolWeightDivisor), + ) + expect(await walletRegistry.isOperatorUpToDate(operator.address)).to.be + .true + }) - firstDecrease = to1e18(111) - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - walletRegistry.address, - firstDecrease - ) - await walletRegistry - .connect(operator) - .updateOperatorStatus(operator.address) + it("should defer pool synchronization while a wallet is being created", async () => { + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, providerWeight) + await walletRegistry + .connect(stakingProvider) + .registerOperator(operator.address) + await walletRegistry.connect(operator).joinSortitionPool() + await walletRegistry.connect(walletOwnerSigner).requestNewWallet() + await allowlist + .connect(deployer) + .requestWeightDecrease(stakingProvider.address, minimumAuthorization) + await expect( + walletRegistry.updateOperatorStatus(operator.address), + ).to.be.revertedWith("Sortition pool locked") + expect( + await walletRegistry.remainingAuthorizationDecreaseDelay( + stakingProvider.address, + ), + ).to.equal(MAX_UINT64) + await helpers.time.mineBlocks(params.dkgSeedTimeout) + await walletRegistry.notifySeedTimeout() + await walletRegistry.updateOperatorStatus(operator.address) + expect( + await walletRegistry.remainingAuthorizationDecreaseDelay( + stakingProvider.address, + ), + ).to.equal(params.authorizationDecreaseDelay) + expect(await sortitionPool.getPoolWeight(operator.address)).to.equal( + minimumAuthorization / BigInt(constants.poolWeightDivisor), + ) + }) - secondIncrease = to1e18(11111) - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - secondIncrease + const callbacks = [ + "authorizationIncreased", + "authorizationDecreaseRequested", + "involuntaryAuthorizationDecrease", + ] as const + callbacks.forEach((method) => { + it(`should reject ${method} from the legacy staking contract after migration`, async () => { + const stakingAddress = await walletRegistry.staking() + await ethers.provider.send("hardhat_impersonateAccount", [ + stakingAddress, + ]) + await ethers.provider.send("hardhat_setBalance", [ + stakingAddress, + "0x56BC75E2D63100000", + ]) + try { + const signer = await ethers.getSigner(stakingAddress) + await expect( + walletRegistry + .connect(signer) + [method]( + stakingProvider.address, + providerWeight, + minimumAuthorization, + ), + ).to.be.revertedWithCustomError( + walletRegistry, + "CallerNotStakingContract", ) - await walletRegistry - .connect(operator) - .updateOperatorStatus(operator.address) - }) - - after(async () => { - await restoreSnapshot() + } finally { + await ethers.provider.send("hardhat_stopImpersonatingAccount", [ + stakingAddress, + ]) + } }) + }) + }) +}) - it("should have correct eligible stake", async () => { - expect( - await walletRegistry.eligibleStake(stakingProvider.address) - ).to.equal(initialIncrease.sub(firstDecrease).add(secondIncrease)) - }) - - it("should have operator status updated", async () => { - expect(await walletRegistry.isOperatorUpToDate(operator.address)).to.be - .true - }) - }) - - // Invoke `increaseAuthorization` after `approveAuthorizationDecrease`. - // The decrease is approved when `increaseAuthorization` is called. - describe("non-zero approveAuthorizationDecrease -> authorizationIncreased", () => { - let firstDecrease - let secondIncrease - - before(async () => { - await createSnapshot() - - firstDecrease = to1e18(222) - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - walletRegistry.address, - firstDecrease - ) - await walletRegistry - .connect(operator) - .updateOperatorStatus(operator.address) - - await helpers.time.increaseTime(params.authorizationDecreaseDelay) - await walletRegistry.approveAuthorizationDecrease( - stakingProvider.address - ) - - secondIncrease = to1e18(7311) - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - secondIncrease - ) - await walletRegistry - .connect(operator) - .updateOperatorStatus(operator.address) - }) - - after(async () => { - await restoreSnapshot() - }) - - it("should have correct eligible stake", async () => { - expect( - await walletRegistry.eligibleStake(stakingProvider.address) - ).to.equal(initialIncrease.sub(firstDecrease).add(secondIncrease)) - }) - - it("should have operator status updated", async () => { - expect(await walletRegistry.isOperatorUpToDate(operator.address)).to.be - .true - }) - }) - - // Invoke `increaseAuthorization` after the authorization was decreased to 0. - describe("to-zero approveAuthorizationDecrease -> authorizationIncreased", () => { - let secondIncrease - - before(async () => { - await createSnapshot() - - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - walletRegistry.address, - initialIncrease - ) - await walletRegistry - .connect(operator) - .updateOperatorStatus(operator.address) - - await helpers.time.increaseTime(params.authorizationDecreaseDelay) - await walletRegistry.approveAuthorizationDecrease( - stakingProvider.address - ) - - secondIncrease = minimumAuthorization.add(to1e18(21)) - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - secondIncrease - ) - await walletRegistry.connect(operator).joinSortitionPool() - }) - - after(async () => { - await restoreSnapshot() - }) - - it("should have correct eligible stake", async () => { - expect( - await walletRegistry.eligibleStake(stakingProvider.address) - ).to.equal(secondIncrease) - }) - - it("should have operator status updated", async () => { - expect(await walletRegistry.isOperatorUpToDate(operator.address)).to.be - .true - }) - }) - - // Invoke `increaseAuthorization` after `involuntaryAuthorizationDecrease` - // when the authorization amount dropped below the minimum authorization. - describe("below-minimum involuntaryAuthorizationDecrease -> authorizationIncreased", () => { - let slashingTo - let secondIncrease - - before(async () => { - await createSnapshot() - - slashingTo = minimumAuthorization.sub(1) - const slashedAmount = initialIncrease.sub(slashingTo) - - await staking - .connect(slasher.wallet) - .slash(slashedAmount, [stakingProvider.address]) - await staking.connect(thirdParty).processSlashing(1) - - // Give the stake owner some more T and let them top-up the stake before - // they increase the authorization again. - secondIncrease = to1e18(10000) - await t.connect(deployer).mint(owner.address, secondIncrease) - await t.connect(owner).approve(staking.address, secondIncrease) - await staking - .connect(owner) - .topUp(stakingProvider.address, secondIncrease) - - // And finally increase! - await staking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - walletRegistry.address, - secondIncrease - ) - await walletRegistry.connect(operator).joinSortitionPool() - }) - - after(async () => { - await restoreSnapshot() - }) - - it("should have correct eligible stake", async () => { - expect( - await walletRegistry.eligibleStake(stakingProvider.address) - ).to.equal(slashingTo.add(secondIncrease)) - }) - - it("should have operator status updated", async () => { - expect(await walletRegistry.isOperatorUpToDate(operator.address)).to.be - .true - }) - }) - - describe("authorizationDecreaseRequested -> involuntaryAuthorizationDecrease", () => { - let decreasedAmount - let slashingTo - - before(async () => { - await createSnapshot() - - decreasedAmount = to1e18(20000) - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - walletRegistry.address, - decreasedAmount - ) - await walletRegistry - .connect(operator) - .updateOperatorStatus(operator.address) - - slashingTo = initialIncrease.sub(to1e18(100)) - const slashedAmount = initialIncrease.sub(slashingTo) - - await staking - .connect(slasher.wallet) - .slash(slashedAmount, [stakingProvider.address]) - await staking.connect(thirdParty).processSlashing(1) - }) - - after(async () => { - await restoreSnapshot() - }) - - it("should have correct eligible stake", async () => { - expect( - await walletRegistry.eligibleStake(stakingProvider.address) - ).to.equal(slashingTo.sub(decreasedAmount)) - }) - - it("should have operator status updated", async () => { - expect(await walletRegistry.isOperatorUpToDate(operator.address)).to.be - .true - }) - }) - - describe("authorizationDecreaseRequested -> involuntaryAuthorizationDecrease -> approveAuthorizationDecrease", () => { - let decreasedAmount - let slashingTo - - before(async () => { - await createSnapshot() - - decreasedAmount = to1e18(20000) - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - walletRegistry.address, - decreasedAmount - ) - await walletRegistry - .connect(operator) - .updateOperatorStatus(operator.address) - - slashingTo = initialIncrease.sub(to1e18(100)) - const slashedAmount = initialIncrease.sub(slashingTo) - - await staking - .connect(slasher.wallet) - .slash(slashedAmount, [stakingProvider.address]) - await staking.connect(thirdParty).processSlashing(1) - - await helpers.time.increaseTime(params.authorizationDecreaseDelay) - await walletRegistry.approveAuthorizationDecrease( - stakingProvider.address - ) - }) - - after(async () => { - await restoreSnapshot() - }) - - it("should have correct eligible stake", async () => { - expect( - await walletRegistry.eligibleStake(stakingProvider.address) - ).to.equal(slashingTo.sub(decreasedAmount)) - }) - - it("should have operator status updated", async () => { - expect(await walletRegistry.isOperatorUpToDate(operator.address)).to.be - .true - }) - }) - - describe("approveAuthorizationDecrease -> involuntaryAuthorizationDecrease", () => { - let decreasedAmount - let slashingTo - - before(async () => { - await createSnapshot() - - decreasedAmount = to1e18(1000) - await staking - .connect(authorizer) - ["requestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - walletRegistry.address, - decreasedAmount - ) - await walletRegistry - .connect(operator) - .updateOperatorStatus(operator.address) - - await helpers.time.increaseTime(params.authorizationDecreaseDelay) - await walletRegistry.approveAuthorizationDecrease( - stakingProvider.address - ) - - slashingTo = initialIncrease.sub(to1e18(2500)) - const slashedAmount = initialIncrease - .sub(decreasedAmount) - .sub(slashingTo) - - await staking - .connect(slasher.wallet) - .slash(slashedAmount, [stakingProvider.address]) - await staking.connect(thirdParty).processSlashing(1) - }) - - after(async () => { - await restoreSnapshot() - }) - - it("should have correct eligible stake", async () => { - expect( - await walletRegistry.eligibleStake(stakingProvider.address) - ).to.equal(slashingTo) - }) - - it("should have operator status updated", async () => { - expect(await walletRegistry.isOperatorUpToDate(operator.address)).to.be - .true - }) - }) - }) -}) - -// TEMPORARILY COMMENTED OUT - END (Second legacy test block) */ - -// TEMPORARILY COMMENTED OUT - END */ -// }) // End of describe.skip("TokenStaking Integration (DEPRECATED TIP-092)") - -/** - * Migration Scenario Tests - TIP-092 Dual-Mode Authorization - * - * Purpose: Comprehensive testing of authorization routing behavior during migration - * from TokenStaking to Allowlist-based authorization. - * - * Test Coverage: - * - Pre-upgrade mode: Authorization routes to TokenStaking (allowlist = address(0)) - * - Post-upgrade mode: Authorization routes to Allowlist (allowlist != address(0)) - * - NOT MIGRATED touchpoints: Slashing and beneficiary queries stay on TokenStaking - * - Upgrade flow: Transition from TokenStaking to Allowlist via initializeV2() - * - Edge cases: Zero address validation, re-initialization prevention - * - * Related Source Code: - * - WalletRegistry.sol:1333-1342: _currentAuthorizationSource() helper - * - WalletRegistry.sol:428-431: initializeV2() upgrade function - * - Callsites: lines 494, 502, 596, 619, 1260, 1325 - */ -describe("WalletRegistry - Migration Scenario Tests (TIP-092)", () => { +describe("WalletRegistry - Allowlist migration", () => { let walletRegistry: WalletRegistry - let sortitionPool: SortitionPool - let staking: TokenStaking - let t: T - let deployer: SignerWithAddress - let governance: SignerWithAddress let stakingProvider: SignerWithAddress let operator: SignerWithAddress - let beneficiary: SignerWithAddress - const { minimumAuthorization } = params - const stakedAmount = to1e18(1000000) // 1M T - - before("load test fixture", async () => { - // Deploy fixture BEFORE taking snapshot. The order matters because - // deployments.fixture() caches an internal EVM snapshot. If we took - // our snapshot first (lower ID), restoreSnapshot() would call - // evm_revert(lowerID) which invalidates ALL snapshots with higher IDs - // — including the deploy cache. This would break deployments.fixture() - // for all subsequent test suites (e.g., Slashing, WalletCreation). + beforeEach(async () => { await deployments.fixture() - - await createSnapshot() - - t = await helpers.contracts.getContract("T") walletRegistry = await helpers.contracts.getContract("WalletRegistry") - sortitionPool = await helpers.contracts.getContract("EcdsaSortitionPool") - staking = await helpers.contracts.getContract("TokenStaking") - - // Get named signers for deployer and governance (these have ownership permissions) - const namedSigners = await helpers.signers.getNamedSigners() - deployer = namedSigners.deployer - governance = namedSigners.governance - - // Get unnamed signers for test accounts - const accounts = await getUnnamedAccounts() - stakingProvider = await ethers.getSigner(accounts[0]) - operator = await ethers.getSigner(accounts[1]) - beneficiary = await ethers.getSigner(accounts[2]) - - await updateWalletRegistryParams( - await helpers.contracts.getContract("WalletRegistryGovernance"), - governance - ) - }) - - after(async () => { - await restoreSnapshot() - }) - - /** - * Pre-Upgrade Mode Tests - * - * Context: Before initializeV2() is called, allowlist = address(0). - * Expected: _currentAuthorizationSource() returns staking contract, - * all authorization queries route to TokenStaking. - * - * Coverage: Tests the false branch of ternary operator in _currentAuthorizationSource() - */ - describe.skip("Pre-Upgrade Mode (TokenStaking Authorization)", () => { - before(async () => { - await createSnapshot() - - // Setup: Use real TokenStaking for authorization (avoids smock.fake - // storage corruption that breaks evm_revert for subsequent tests) - await setupRealStaking( - t, - staking, - walletRegistry, - deployer, - stakingProvider, - beneficiary, - minimumAuthorization - ) - - // Setup: Deactivate chaosnet to allow operators to join sortition pool - await deactivateChaosnetMode(sortitionPool) - - // Setup: Register operator with authorized stake - await walletRegistry - .connect(stakingProvider) - .registerOperator(operator.address) - }) - - after(async () => { - await restoreSnapshot() - }) - - it("should have allowlist unset (address zero) before upgrade", async () => { - expect(await walletRegistry.allowlist()).to.equal(ZERO_ADDRESS) - }) - - /** - * Test: eligibleStake view queries TokenStaking - * Callsite: WalletRegistry.sol:1260 - * Coverage: _currentAuthorizationSource() → staking (line 1341) - */ - it("should query TokenStaking for eligible stake via eligibleStake()", async () => { - const eligibleStake = await walletRegistry.eligibleStake( - stakingProvider.address - ) - expect(eligibleStake).to.equal(minimumAuthorization) - }) - - /** - * Test: joinSortitionPool queries TokenStaking - * Callsite: WalletRegistry.sol:494 - * Coverage: _currentAuthorizationSource() → staking (line 1341) - */ - it("should query TokenStaking when operator joins sortition pool", async () => { - await walletRegistry.connect(operator).joinSortitionPool() - expect(await walletRegistry.isOperatorInPool(operator.address)).to.be.true - }) - - /** - * Test: isOperatorUpToDate queries TokenStaking - * Callsite: WalletRegistry.sol:1325 - * Coverage: _currentAuthorizationSource() → staking (line 1341) - */ - it("should query TokenStaking for isOperatorUpToDate check", async () => { - await createSnapshot() - - // Operator must be in pool to check up-to-date status - await joinPoolIfNotMember(walletRegistry, operator) - expect(await walletRegistry.isOperatorUpToDate(operator.address)).to.be - .true - - await restoreSnapshot() - }) - - /** - * Test: updateOperatorStatus queries TokenStaking - * Callsite: WalletRegistry.sol:502 - * Coverage: _currentAuthorizationSource() → staking (line 1341) - */ - it("should query TokenStaking when updating operator status", async () => { - await createSnapshot() - - // Operator must be in pool to update status - await joinPoolIfNotMember(walletRegistry, operator) - await walletRegistry.updateOperatorStatus(operator.address) - expect(await walletRegistry.isOperatorUpToDate(operator.address)).to.be - .true - - await restoreSnapshot() - }) - }) - - /** - * Post-Upgrade Mode Tests - * - * Context: After initializeV2(allowlist) is called, allowlist != address(0). - * Expected: _currentAuthorizationSource() returns allowlist contract, - * all authorization queries route to Allowlist. - * - * Coverage: Tests the true branch of ternary operator in _currentAuthorizationSource() - */ - describe("Post-Upgrade Mode (Allowlist Authorization)", () => { - let allowlist: Mock - - before(async () => { - await createSnapshot() - - // Setup: Create allowlist fake and initialize WalletRegistry (triggers upgrade) - allowlist = await createMock("IStaking") - await allowlist.authorizedStake.returns(minimumAuthorization) - await walletRegistry.initializeV2(allowlist.address) - - // Setup: Deactivate chaosnet to allow operators to join sortition pool - await deactivateChaosnetMode(sortitionPool) - - // Setup: Register operator (authorization now routed to allowlist) - await walletRegistry - .connect(stakingProvider) - .registerOperator(operator.address) - }) - - after(async () => { - await restoreSnapshot() - }) - - it("should have allowlist set after initializeV2", async () => { - expect(await walletRegistry.allowlist()).to.equal(allowlist.address) - }) - - /** - * Test: eligibleStake view queries Allowlist - * Callsite: WalletRegistry.sol:1260 - * Coverage: _currentAuthorizationSource() → allowlist (line 1340) - */ - it("should query Allowlist for eligible stake via eligibleStake()", async () => { - const eligibleStake = await walletRegistry.eligibleStake( - stakingProvider.address - ) - expect(eligibleStake).to.equal(minimumAuthorization) - // The assertion above already proves the allowlist branch ran: the value - // returned is the one this mock is configured with. A call-count check on - // `authorizedStake` is not available -- it is `view`, so Solidity reaches - // it by STATICCALL, where the mock cannot record anything. - }) - - /** - * Test: joinSortitionPool queries Allowlist - * Callsite: WalletRegistry.sol:494 - * Coverage: _currentAuthorizationSource() → allowlist (line 1340) - */ - it("should query Allowlist when operator joins sortition pool", async () => { - await walletRegistry.connect(operator).joinSortitionPool() - expect(await walletRegistry.isOperatorInPool(operator.address)).to.be.true - // The assertion above already proves the allowlist branch ran: the value - // returned is the one this mock is configured with. A call-count check on - // `authorizedStake` is not available -- it is `view`, so Solidity reaches - // it by STATICCALL, where the mock cannot record anything. - }) - - /** - * Test: isOperatorUpToDate queries Allowlist - * Callsite: WalletRegistry.sol:1325 - * Coverage: _currentAuthorizationSource() → allowlist (line 1340) - */ - it("should query Allowlist for isOperatorUpToDate check", async () => { - await joinPoolIfNotMember(walletRegistry, operator) - expect(await walletRegistry.isOperatorUpToDate(operator.address)).to.be - .true - // The assertion above already proves the allowlist branch ran: the value - // returned is the one this mock is configured with. A call-count check on - // `authorizedStake` is not available -- it is `view`, so Solidity reaches - // it by STATICCALL, where the mock cannot record anything. - }) - - /** - * Test: updateOperatorStatus queries Allowlist - * Callsite: WalletRegistry.sol:502 - * Coverage: _currentAuthorizationSource() → allowlist (line 1340) - */ - it("should query Allowlist when updating operator status", async () => { - await joinPoolIfNotMember(walletRegistry, operator) - await walletRegistry.updateOperatorStatus(operator.address) - - // `authorizedStake` is `view`, so a call-count assertion is impossible -- - // Solidity reaches it by STATICCALL and the mock cannot record there. - // This is the stronger check anyway: the operator is only up to date if - // the registry read the allowlist's stake and synced the pool to it, so - // it fails if the allowlist branch is skipped. - expect(await walletRegistry.isOperatorUpToDate(operator.address)).to.be - .true - }) - - /** - * Test: Authorization increase from Allowlist accepted - * Tests onlyStakingContract modifier with allowlist set - */ - it("should accept authorizationIncreased from Allowlist contract", async () => { - // Trigger authorization callback from allowlist contract - await expect( - triggerAuthorizationCallback( - walletRegistry, - allowlist.address, - stakingProvider.address, - ethers.BigNumber.from(0), - minimumAuthorization - ) - ).to.not.be.reverted - }) + const signers = await helpers.signers.getNamedSigners() + deployer = signers.deployer + stakingProvider = signers.esdm + operator = signers.chaosnetOwner + const sortitionPool: SortitionPool = + await helpers.contracts.getContract("EcdsaSortitionPool") + await sortitionPool.connect(signers.chaosnetOwner).deactivateChaosnet() }) - /** - * NOT MIGRATED Touchpoint Tests - * - * Context: Some functions do NOT use _currentAuthorizationSource(). - * Expected: These functions always use staking contract, even after initializeV2(). - * - * Rationale: - * - withdrawRewards: Beneficiary roles remain in TokenStaking (WalletRegistry.sol:440-452) - * - challengeDkgResult: Stake custody and slashing remain in TokenStaking (WalletRegistry.sol:950-966) - */ - describe.skip("NOT MIGRATED Touchpoints", () => { - let allowlist: Mock - - before(async () => { - await createSnapshot() - - // Setup: Use real TokenStaking for beneficiary roles (NOT migrated to Allowlist) - await setupRealStaking( - t, - staking, - walletRegistry, - deployer, - stakingProvider, - beneficiary, - minimumAuthorization - ) - - // Setup: Create allowlist fake and upgrade (but beneficiary still in TokenStaking) - allowlist = await createMock("IStaking") - await allowlist.authorizedStake.returns(minimumAuthorization) - await walletRegistry.initializeV2(allowlist.address) - - // Setup: Trigger authorization callback from allowlist (post-upgrade) - await triggerAuthorizationCallback( - walletRegistry, - allowlist.address, - stakingProvider.address, - ethers.BigNumber.from(0), - minimumAuthorization - ) - - // Setup: Register operator with allowlist authorization - await walletRegistry - .connect(stakingProvider) - .registerOperator(operator.address) - }) - - after(async () => { - await restoreSnapshot() - }) - - /** - * Test: withdrawRewards always uses staking.rolesOf() for beneficiary lookup - * NOT using _currentAuthorizationSource() - * Direct call: staking.rolesOf() at line 456 - */ - it("should query TokenStaking for beneficiary in withdrawRewards (post-upgrade)", async () => { - // This test verifies that even after initializeV2, beneficiary lookup - // goes to TokenStaking, not Allowlist - expect(await walletRegistry.allowlist()).to.equal(allowlist.address) - - // Note: withdrawRewards requires actual rewards to test fully - // This test validates the pattern - beneficiary lookup stays on TokenStaking - const roles = await staking.rolesOf(stakingProvider.address) - expect(roles.beneficiary).to.equal(beneficiary.address) - }) + it("should preserve existing operator registrations when switching authorization to the Allowlist", async () => { + await walletRegistry + .connect(stakingProvider) + .registerOperator(operator.address) + expect(await walletRegistry.allowlist()).to.equal(ZERO_ADDRESS) + expect( + await walletRegistry.eligibleStake(stakingProvider.address), + ).to.equal(0) + const allowlist = await setupAllowlist(walletRegistry, deployer) + await allowlist + .connect(deployer) + .addStakingProvider(stakingProvider.address, params.minimumAuthorization) + expect(await walletRegistry.allowlist()).to.equal( + await allowlist.getAddress(), + ) + expect( + await walletRegistry.stakingProviderToOperator(stakingProvider.address), + ).to.equal(operator.address) + expect( + await walletRegistry.eligibleStake(stakingProvider.address), + ).to.equal(params.minimumAuthorization) + await walletRegistry.connect(operator).joinSortitionPool() + expect(await walletRegistry.isOperatorUpToDate(operator.address)).to.be.true }) - /** - * Upgrade Flow Tests - * - * Context: Tests the transition from pre-upgrade to post-upgrade mode. - * Expected: initializeV2() switches authorization routing from staking to allowlist. - * - * Coverage: Tests upgrade transition and operator continuity - */ - describe.skip("Upgrade Flow", () => { - let allowlist: Mock - - before(async () => { - await createSnapshot() - - // Setup: Use real TokenStaking authorization (pre-upgrade state) - await setupRealStaking( - t, - staking, - walletRegistry, - deployer, - stakingProvider, - beneficiary, - minimumAuthorization - ) - - // Setup: Deactivate chaosnet to allow operators to join sortition pool - await deactivateChaosnetMode(sortitionPool) - - // Setup: Register operator and join pool (before upgrade) - await walletRegistry - .connect(stakingProvider) - .registerOperator(operator.address) - await walletRegistry.connect(operator).joinSortitionPool() - }) - - after(async () => { - await restoreSnapshot() - }) - - /** - * Test: Complete upgrade transition - * Validates authorization routing switches from TokenStaking to Allowlist - */ - it("should transition from TokenStaking to Allowlist on initializeV2", async () => { - await createSnapshot() - - // Verify pre-upgrade state - expect(await walletRegistry.allowlist()).to.equal(ZERO_ADDRESS) - const preUpgradeStake = await walletRegistry.eligibleStake( - stakingProvider.address - ) - expect(preUpgradeStake).to.equal(minimumAuthorization) - - // Perform upgrade - allowlist = await createMock("IStaking") - const upgradedAmount = to1e18(50000) // 50k T (different from TokenStaking) - await allowlist.authorizedStake.returns(upgradedAmount) - - await walletRegistry.initializeV2(allowlist.address) - - // Verify post-upgrade state - expect(await walletRegistry.allowlist()).to.equal(allowlist.address) - const postUpgradeStake = await walletRegistry.eligibleStake( - stakingProvider.address - ) - expect(postUpgradeStake).to.equal(upgradedAmount) - - await restoreSnapshot() - }) - - /** - * Test: Pre-existing operators continue functioning after upgrade - * Validates operator continuity during migration - */ - it("should allow pre-existing operators to continue after upgrade", async () => { - await createSnapshot() - - // Operator already in pool before upgrade - expect(await walletRegistry.isOperatorInPool(operator.address)).to.be.true - - // Perform upgrade - allowlist = await createMock("IStaking") - await allowlist.authorizedStake.returns(minimumAuthorization) - await walletRegistry.initializeV2(allowlist.address) - - // Operator still in pool and functional - expect(await walletRegistry.isOperatorInPool(operator.address)).to.be.true - await walletRegistry.updateOperatorStatus(operator.address) - expect(await walletRegistry.isOperatorUpToDate(operator.address)).to.be - .true - - await restoreSnapshot() - }) - - /** - * Test: Weight-based operator exclusion after upgrade - * Validates migration strategy for redundant operator removal - * - * Related: migration-strategy-details.md:50-54 (weight-based exclusion) - */ - it("should enable operator exclusion via zero weight in allowlist", async () => { - await createSnapshot() - - // Setup: Allowlist with zero authorization (excludes operator) - allowlist = await createMock("IStaking") - await allowlist.authorizedStake.returns(0) // Zero weight = excluded - await walletRegistry.initializeV2(allowlist.address) - - // Operator excluded (eligible stake = 0) - const stake = await walletRegistry.eligibleStake(stakingProvider.address) - expect(stake).to.equal(0) - - // NOTE: Operator already in pool from before() hook may still be considered up-to-date - // This test verifies that eligibleStake returns 0, which is the key behavior for exclusion - // The operator's up-to-date status depends on when they joined relative to the upgrade - - await restoreSnapshot() - }) + it("should reject a zero Allowlist address", async () => { + await expect( + walletRegistry.initializeV2(ZERO_ADDRESS), + ).to.be.revertedWithCustomError(walletRegistry, "AllowlistAddressZero") }) - /** - * Edge Case Tests - * - * Context: Validates error handling and security measures. - * Expected: Proper validation and revert behavior. - */ - describe("Edge Cases", () => { - let allowlist: Mock - - before(async () => { - await createSnapshot() - }) - - after(async () => { - await restoreSnapshot() - }) - - /** - * Test: Zero address validation - * Validates initializeV2 rejects zero address - */ - it("should revert initializeV2 with zero address", async () => { - await expect( - walletRegistry.initializeV2(ZERO_ADDRESS) - ).to.be.revertedWithCustomError(walletRegistry, "AllowlistAddressZero") - }) - - /** - * Test: Re-initialization prevention - * Validates OpenZeppelin Initializable guard - */ - it("should revert on second initializeV2 call (re-initialization prevention)", async () => { - await createSnapshot() - - // First call succeeds - allowlist = await createMock("IStaking") - await walletRegistry.initializeV2(allowlist.address) - expect(await walletRegistry.allowlist()).to.equal(allowlist.address) - - // Second call fails - const allowlist2 = await createMock("IStaking") - await expect( - walletRegistry.initializeV2(allowlist2.address) - ).to.be.revertedWith("Initializable: contract is already initialized") - - // Allowlist unchanged - expect(await walletRegistry.allowlist()).to.equal(allowlist.address) - - await restoreSnapshot() - }) - - /** - * Test: Allowlist state persistence - * Validates storage consistency across operations - */ - it("should persist allowlist address across multiple operations", async () => { - await createSnapshot() - - allowlist = await createMock("IStaking") - await allowlist.authorizedStake.returns(minimumAuthorization) - - await walletRegistry.initializeV2(allowlist.address) - const addressAfterInit = await walletRegistry.allowlist() - expect(addressAfterInit).to.equal(allowlist.address) - - // Perform multiple operations - await walletRegistry.eligibleStake(stakingProvider.address) - await walletRegistry.eligibleStake(operator.address) - await walletRegistry.eligibleStake(beneficiary.address) - - // Allowlist address remains unchanged - expect(await walletRegistry.allowlist()).to.equal(allowlist.address) - - await restoreSnapshot() - }) - - /** - * Test: Branch coverage for _currentAuthorizationSource - * Validates both branches of ternary operator are exercised - * - * Coverage Target: 100% branch coverage for lines 1333-1342 - */ - it("should exercise both branches of _currentAuthorizationSource ternary operator", async () => { - await createSnapshot() - - // Branch 1: allowlist = address(0) → returns staking - expect(await walletRegistry.allowlist()).to.equal(ZERO_ADDRESS) - const stakeBefore = await walletRegistry.eligibleStake( - stakingProvider.address - ) - expect(stakeBefore).to.be.gte(0) // Validates staking branch executed - - // Branch 2: allowlist != address(0) → returns allowlist - allowlist = await createMock("IStaking") - await allowlist.authorizedStake.returns(minimumAuthorization) - await walletRegistry.initializeV2(allowlist.address) - - expect(await walletRegistry.allowlist()).to.equal(allowlist.address) - const stakeAfter = await walletRegistry.eligibleStake( - stakingProvider.address - ) - // `stakeAfter` being the allowlist's configured value *is* the proof that - // the allowlist branch executed -- the staking branch would not return it. - expect(stakeAfter).to.equal(minimumAuthorization) - - await restoreSnapshot() - }) + it("should keep the Allowlist address after a rejected reinitialization", async () => { + const allowlist = await setupAllowlist(walletRegistry, deployer) + await expect( + walletRegistry.initializeV2(operator.address), + ).to.be.revertedWith("Initializable: contract is already initialized") + expect(await walletRegistry.allowlist()).to.equal( + await allowlist.getAddress(), + ) }) }) diff --git a/solidity/ecdsa/test/WalletRegistry.CustomErrors.test.ts b/solidity/ecdsa/test/WalletRegistry.CustomErrors.test.ts index 52ded76ad3..d496cf5560 100644 --- a/solidity/ecdsa/test/WalletRegistry.CustomErrors.test.ts +++ b/solidity/ecdsa/test/WalletRegistry.CustomErrors.test.ts @@ -1,504 +1,312 @@ /* eslint-disable @typescript-eslint/no-unused-expressions */ -import { deployments, ethers, getUnnamedAccounts, helpers } from "hardhat" +import { ethers, helpers } from "hardhat" import { expect } from "chai" -import { createMock } from "./helpers/mock" -import { - constants, - params, - walletRegistryFixture, - initializeWalletOwner, - updateWalletRegistryParams, - setupAllowlist, -} from "./fixtures" +import { constants, walletRegistryFixture } from "./fixtures" +import ecdsaData from "./data/ecdsa" +import { hashUint32Array, selectGroup } from "./utils/groups" +import { submitRelayEntry } from "./utils/randomBeacon" +import { noMisbehaved, signAndSubmitUnrecoverableDkgResult } from "./utils/dkg" -import type { IWalletOwner } from "../typechain/IWalletOwner" -import type { IRandomBeacon } from "../typechain/IRandomBeacon" -import type { Mock } from "./helpers/mock" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" import type { - WalletRegistry, + IWalletOwner, SortitionPool, - TokenStaking, - T, + WalletRegistry, + WalletRegistryStub, WalletRegistryGovernance, } from "../typechain" +import type { Mock } from "./helpers/mock" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" const { to1e18 } = helpers.number const { createSnapshot, restoreSnapshot } = helpers.snapshot - -const ZERO_ADDRESS = ethers.constants.AddressZero - -describe.skip("TokenStaking Integration (DEPRECATED TIP-092)", () => { - /** - * DEPRECATED: These tests validate TokenStaking.approveApplication() - * which does not exist in production TokenStaking v1.3.0-dev.16. - * - * Production State: - * - RandomBeacon/ECDSA applications are FROZEN (skipApplication = true) - * - approveApplication() method removed from production contract - * - Only TACo application remains functional in TokenStaking - * - * Migration: - * - Issue: #3839 "Migrate ECDSA tests to Allowlist mode" - * - New approach: walletRegistryFixture({ useAllowlist: true }) - * - * References: - * - TIP-092: Beta Staker Consolidation - * - TIP-100: TokenStaking sunset timeline - * - Allowlist.sol: Replacement authorization contract - * - * Implementation Status: - * - Dual-mode fixtures implemented and working - * - TypeScript compilation successful - * - Full test validation deferred pending Allowlist migration - * - Strategic migration tracked in issue #3839 - */ - // Original tests preserved for reference during migration - // Will be rewritten for Allowlist mode or archived -}) +const ZERO_ADDRESS = ethers.ZeroAddress describe("WalletRegistry - Custom Errors", () => { - let t: T - let walletRegistry: WalletRegistry + let walletRegistry: WalletRegistry & WalletRegistryStub let walletRegistryGovernance: WalletRegistryGovernance - let sortitionPool: SortitionPool - let staking: TokenStaking - - let deployer: SignerWithAddress let governance: SignerWithAddress + let deployer: SignerWithAddress let unauthorized: SignerWithAddress - - let owner: SignerWithAddress let stakingProvider: SignerWithAddress let operator: SignerWithAddress - let authorizer: SignerWithAddress - let beneficiary: SignerWithAddress let walletOwner: Mock - let randomBeacon: Mock - - const stakedAmount = to1e18(1000000) // 1M T - let minimumAuthorization - - before("load test fixture", async () => { - await deployments.fixture() - - t = await helpers.contracts.getContract("T") - walletRegistry = await helpers.contracts.getContract("WalletRegistry") - walletRegistryGovernance = await helpers.contracts.getContract( - "WalletRegistryGovernance" - ) - sortitionPool = await helpers.contracts.getContract("EcdsaSortitionPool") - staking = await helpers.contracts.getContract("TokenStaking") - - const accounts = await getUnnamedAccounts() - owner = await ethers.getSigner(accounts[1]) - stakingProvider = await ethers.getSigner(accounts[2]) - operator = await ethers.getSigner(accounts[3]) - authorizer = await ethers.getSigner(accounts[4]) - beneficiary = await ethers.getSigner(accounts[5]) - unauthorized = await ethers.getSigner(accounts[6]) - ;({ deployer, governance } = await helpers.signers.getNamedSigners()) - - const { chaosnetOwner } = await helpers.signers.getNamedSigners() - await sortitionPool.connect(chaosnetOwner).deactivateChaosnet() - - walletOwner = await initializeWalletOwner( + let membersIDs: number[] + const walletPublicKey = ecdsaData.group1.publicKey + const walletID = ethers.keccak256(walletPublicKey) + + before("load Allowlist fixture and register a wallet", async () => { + const fixture = await walletRegistryFixture({ useAllowlist: true }) + ;({ + walletRegistry, walletRegistryGovernance, - governance + governance, + deployer, + walletOwner, + thirdParty: unauthorized, + } = fixture) + operator = fixture.operators[0]!.signer + stakingProvider = fixture.operators[0]!.stakingProvider! + membersIDs = fixture.operators.slice(0, 3).map(({ id }) => id) + await walletRegistry.forceAddWallet( + walletPublicKey, + hashUint32Array(membersIDs), ) - - await updateWalletRegistryParams(walletRegistryGovernance, governance) - - const allowlist = await setupAllowlist(walletRegistry, deployer) - await allowlist - .connect(deployer) - .addStakingProvider(stakingProvider.address, stakedAmount) - - minimumAuthorization = await walletRegistry.minimumAuthorization() - - // Authorize and register operator - await walletRegistry - .connect(stakingProvider) - .registerOperator(operator.address) - - // Mock random beacon - randomBeacon = await createMock("IRandomBeacon") }) - describe("Authorization Errors", () => { - describe("CallerNotStakingContract", () => { - it("should revert with custom error when unauthorized caller attempts authorizationIncreased", async () => { - await expect( - walletRegistry - .connect(unauthorized) - .authorizationIncreased( - stakingProvider.address, - to1e18(40000), - to1e18(50000) - ) - ).to.be.reverted - }) + beforeEach(async () => { + await createSnapshot() + }) - it("should revert with custom error when unauthorized caller attempts authorizationDecreaseRequested", async () => { - await expect( - walletRegistry - .connect(unauthorized) - .authorizationDecreaseRequested( - stakingProvider.address, - to1e18(50000), - to1e18(40000) - ) - ).to.be.reverted - }) + afterEach(async () => { + await restoreSnapshot() + }) - it("should revert with custom error when unauthorized caller attempts involuntaryAuthorizationDecrease", async () => { + describe("CallerNotStakingContract", () => { + const callbacks = [ + "authorizationIncreased", + "authorizationDecreaseRequested", + "involuntaryAuthorizationDecrease", + ] as const + callbacks.forEach((method) => { + it(`should reject ${method} from an unauthorized caller`, async () => { await expect( walletRegistry .connect(unauthorized) - .involuntaryAuthorizationDecrease( - stakingProvider.address, - to1e18(50000), - to1e18(40000) - ) - ).to.be.reverted + [method](stakingProvider.address, to1e18(50000), to1e18(40000)), + ).to.be.revertedWithCustomError( + walletRegistry, + "CallerNotStakingContract", + ) }) }) + }) - describe("CallerNotWalletOwner", () => { - it("should revert with custom error when unauthorized caller attempts requestNewWallet", async () => { - await expect(walletRegistry.connect(unauthorized).requestNewWallet()).to - .be.reverted - }) - - it("should revert with custom error when unauthorized caller attempts closeWallet", async () => { - const walletID = ethers.utils.formatBytes32String("test-wallet") - await expect(walletRegistry.connect(unauthorized).closeWallet(walletID)) - .to.be.reverted - }) - - it("should revert with custom error when unauthorized caller attempts seize", async () => { - const walletID = ethers.utils.formatBytes32String("test-wallet") - const walletMembersIDs = [1, 2, 3] - await expect( - walletRegistry - .connect(unauthorized) - .seize( - to1e18(1000), - 100, - unauthorized.address, - walletID, - walletMembersIDs - ) - ).to.be.reverted - }) + describe("CallerNotWalletOwner", () => { + it("should reject requesting a wallet", async () => { + await expect( + walletRegistry.connect(unauthorized).requestNewWallet(), + ).to.be.revertedWithCustomError(walletRegistry, "CallerNotWalletOwner") }) - describe("CallerNotGovernance", () => { - it("should revert with custom error when unauthorized caller attempts updateDkgParameters", async () => { - await expect( - walletRegistry - .connect(unauthorized) - .updateDkgParameters(100, 100, 50000, 100, 10) - ).to.be.reverted - }) - - it("should revert with custom error when unauthorized caller attempts updateAuthorizationParameters", async () => { - await expect( - walletRegistry - .connect(unauthorized) - .updateAuthorizationParameters(to1e18(40000), 3888000, 3888000) - ).to.be.reverted - }) + it("should reject closing a wallet", async () => { + await expect( + walletRegistry.connect(unauthorized).closeWallet(walletID), + ).to.be.revertedWithCustomError(walletRegistry, "CallerNotWalletOwner") }) - describe("CallerNotRandomBeacon", () => { - it("should revert with custom error when unauthorized caller attempts __beaconCallback", async () => { - await expect( - // eslint-disable-next-line no-underscore-dangle - walletRegistry.connect(unauthorized).__beaconCallback(12345, 0) - ).to.be.reverted - }) + it("should reject seizing wallet members", async () => { + await expect( + walletRegistry + .connect(unauthorized) + .seize(to1e18(1000), 100, unauthorized.address, walletID, membersIDs), + ).to.be.revertedWithCustomError(walletRegistry, "CallerNotWalletOwner") }) }) - describe("Validation Errors", () => { - describe("AllowlistAddressZero", () => { - it("should revert with custom error when initializeV2 called with zero address", async () => { - // Create new proxy for this test to allow re-initialization - // Need to link libraries for WalletRegistry - const EcdsaInactivity = await helpers.contracts.getContract( - "EcdsaInactivity" - ) - const WalletRegistryFactory = await ethers.getContractFactory( - "WalletRegistry", - { - libraries: { - EcdsaInactivity: EcdsaInactivity.address, - }, - } - ) - const newImplementation = await WalletRegistryFactory.deploy( - sortitionPool.address, - staking.address - ) - await newImplementation.deployed() - - await expect(newImplementation.initializeV2(ZERO_ADDRESS)).to.be - .reverted - }) + describe("governance access", () => { + it("should reject updating DKG parameters", async () => { + await expect( + walletRegistry + .connect(unauthorized) + .updateDkgParameters(100, 100, 50000, 100, 10), + ).to.be.revertedWith("Caller is not the governance") }) - describe("UnknownOperator", () => { - it("should revert with custom error when withdrawRewards called for unregistered operator", async () => { - const unregisteredProvider = unauthorized.address - await expect(walletRegistry.withdrawRewards(unregisteredProvider)).to.be - .reverted - }) - - it("should revert with custom error when availableRewards called for unregistered operator", async () => { - const unregisteredProvider = unauthorized.address - await expect(walletRegistry.availableRewards(unregisteredProvider)).to - .be.reverted - }) + it("should reject updating authorization parameters", async () => { + await expect( + walletRegistry + .connect(unauthorized) + .updateAuthorizationParameters(to1e18(40000), 3888000, 3888000), + ).to.be.revertedWith("Caller is not the governance") }) - describe("InvalidNonce", () => { - let snapshot - - beforeEach(async () => { - snapshot = await createSnapshot() - }) - - afterEach(async () => { - await restoreSnapshot() - }) - - it("should revert with custom error when notifyOperatorInactivity called with wrong nonce", async () => { - // This test requires a wallet to be created first - // For simplicity, we test the nonce check with a mock claim - const walletID = ethers.utils.formatBytes32String("test-wallet") - const wrongNonce = 999 // Expected nonce is 0 initially - - const claim = { - walletID, - inactiveMembersIndices: [], - heartbeatFailed: false, - signatures: "0x", - signingMembersIndices: [], - } - - const groupMembers: number[] = [] - - await expect( - walletRegistry - .connect(unauthorized) - .notifyOperatorInactivity(claim, wrongNonce, groupMembers) - ).to.be.reverted - }) + it("should reject updating the reimbursement pool with CallerNotGovernance", async () => { + await expect( + walletRegistry + .connect(unauthorized) + .updateReimbursementPool(await walletRegistry.reimbursementPool()), + ).to.be.revertedWithCustomError(walletRegistry, "CallerNotGovernance") }) + }) - describe("InvalidGroupMembers", () => { - let snapshot - - beforeEach(async () => { - snapshot = await createSnapshot() - }) - - afterEach(async () => { - await restoreSnapshot() - }) - - it("should revert with custom error when notifyOperatorInactivity called with invalid group members", async () => { - // This test requires a wallet with stored members hash - // We'll test with a mock scenario where hash doesn't match - const walletID = ethers.utils.formatBytes32String("test-wallet") - const nonce = 0 - - const claim = { - walletID, - inactiveMembersIndices: [], - heartbeatFailed: false, - signatures: "0x", - signingMembersIndices: [], - } - - // Provide group members that won't match stored hash (if any) - const invalidGroupMembers = [1, 2, 3] + it("should reject a callback from anyone other than the random beacon", async () => { + await expect( + // eslint-disable-next-line no-underscore-dangle + walletRegistry.connect(unauthorized).__beaconCallback(12345, 0), + ).to.be.revertedWithCustomError(walletRegistry, "CallerNotRandomBeacon") + }) - await expect( - walletRegistry - .connect(unauthorized) - .notifyOperatorInactivity(claim, nonce, invalidGroupMembers) - ).to.be.reverted - }) + it("should reject initializing an Allowlist with the zero address", async () => { + // Initializers are disabled on implementations, so exercise the validation + // through a fresh proxy instead of accepting an unrelated initializer error. + const EcdsaInactivity = + await helpers.contracts.getContract("EcdsaInactivity") + const implementation = await ethers.getContractFactory("WalletRegistry", { + libraries: { + EcdsaInactivity: await EcdsaInactivity.getAddress(), + }, }) + const deployed = await implementation.deploy( + await walletRegistry.sortitionPool(), + await walletRegistry.staking(), + ) + const proxyFactory = await ethers.getContractFactory( + "TransparentUpgradeableProxy", + ) + const proxy = await proxyFactory.deploy( + await deployed.getAddress(), + deployer.address, + "0x", + ) + const registry = implementation + .attach(await proxy.getAddress()) + .connect(unauthorized) as WalletRegistry + await expect( + registry.initializeV2(ZERO_ADDRESS), + ).to.be.revertedWithCustomError(registry, "AllowlistAddressZero") + }) - describe("InvalidWalletMembersIdentifiers", () => { - it("should revert with custom error when seize called with invalid wallet members hash", async () => { - const walletID = ethers.utils.formatBytes32String("test-wallet") - const invalidWalletMembersIDs = [1, 2, 3] - - await expect( - walletRegistry - .connect(walletOwner.wallet) - .seize( - to1e18(1000), - 100, - unauthorized.address, - walletID, - invalidWalletMembersIDs - ) - ).to.be.reverted - }) + describe("UnknownOperator", () => { + it("should reject withdrawing rewards for an unregistered provider", async () => { + await expect( + walletRegistry.withdrawRewards(unauthorized.address), + ).to.be.revertedWithCustomError(walletRegistry, "UnknownOperator") + }) - it("should revert with custom error when isWalletMember called with invalid wallet members hash", async () => { - const walletID = ethers.utils.formatBytes32String("test-wallet") - const invalidWalletMembersIDs = [1, 2, 3] + it("should reject querying rewards for an unregistered provider", async () => { + await expect( + walletRegistry.availableRewards(unauthorized.address), + ).to.be.revertedWithCustomError(walletRegistry, "UnknownOperator") + }) + }) - await expect( - walletRegistry.isWalletMember( - walletID, - invalidWalletMembersIDs, - operator.address, - 1 - ) - ).to.be.reverted - }) + describe("inactivity claims", () => { + const claim = { + walletID, + inactiveMembersIndices: [], + heartbeatFailed: false, + signatures: "0x", + signingMembersIndices: [], + } + + it("should reject an incorrect nonce", async () => { + await expect( + walletRegistry + .connect(unauthorized) + .notifyOperatorInactivity(claim, 999, membersIDs), + ).to.be.revertedWithCustomError(walletRegistry, "InvalidNonce") }) - describe("NotSortitionPoolOperator", () => { - it("should revert with custom error when isWalletMember called with non-sortition pool operator", async () => { - const walletID = ethers.utils.formatBytes32String("test-wallet") - const walletMembersIDs = [1, 2, 3] - const nonOperator = unauthorized.address + it("should reject group members that do not match the registered wallet", async () => { + await expect( + walletRegistry + .connect(unauthorized) + .notifyOperatorInactivity(claim, 0, [...membersIDs].reverse()), + ).to.be.revertedWithCustomError(walletRegistry, "InvalidGroupMembers") + }) + }) - await expect( - walletRegistry.isWalletMember( + describe("wallet membership", () => { + it("should reject seizing with incorrect member identifiers", async () => { + await expect( + walletRegistry + .connect(walletOwner.wallet) + .seize( + to1e18(1000), + 100, + unauthorized.address, walletID, - walletMembersIDs, - nonOperator, - 1 - ) - ).to.be.reverted - }) + [...membersIDs].reverse(), + ), + ).to.be.revertedWithCustomError( + walletRegistry, + "InvalidWalletMembersIdentifiers", + ) }) - describe("WalletMemberIndexOutOfRange", () => { - let snapshot - - beforeEach(async () => { - snapshot = await createSnapshot() - // Join sortition pool to make operator valid - await walletRegistry.connect(operator).joinSortitionPool() - }) - - afterEach(async () => { - await restoreSnapshot() - }) - - it("should revert with custom error when isWalletMember called with index zero", async () => { - const walletID = ethers.utils.formatBytes32String("test-wallet") - const walletMembersIDs = [1, 2, 3] - - await expect( - walletRegistry.isWalletMember( - walletID, - walletMembersIDs, - operator.address, - 0 // Invalid: index must be >= 1 - ) - ).to.be.reverted - }) + it("should reject a membership query with incorrect identifiers", async () => { + await expect( + walletRegistry.isWalletMember( + walletID, + [...membersIDs].reverse(), + operator.address, + 1, + ), + ).to.be.revertedWithCustomError( + walletRegistry, + "InvalidWalletMembersIdentifiers", + ) + }) - it("should revert with custom error when isWalletMember called with index exceeding array length", async () => { - const walletID = ethers.utils.formatBytes32String("test-wallet") - const walletMembersIDs = [1, 2, 3] + it("should reject a membership query for an operator outside the pool", async () => { + await expect( + walletRegistry.isWalletMember( + walletID, + membersIDs, + unauthorized.address, + 1, + ), + ).to.be.revertedWithCustomError( + walletRegistry, + "NotSortitionPoolOperator", + ) + }) + const invalidIndices = [0, 4] + invalidIndices.forEach((index) => { + it(`should reject member index ${index} for a three-member wallet`, async () => { await expect( walletRegistry.isWalletMember( walletID, - walletMembersIDs, + membersIDs, operator.address, - 4 // Invalid: exceeds length of 3 - ) - ).to.be.reverted + index, + ), + ).to.be.revertedWithCustomError( + walletRegistry, + "WalletMemberIndexOutOfRange", + ) }) }) }) - describe("State Errors", () => { - describe("CurrentStateNotIdle", () => { - it("should revert with custom error when updateDkgParameters called while DKG not idle", async () => { - // This test validates that finalizeDkgSeedTimeoutUpdate will revert - // when DKG state is not IDLE. Instead of creating a complex setup with - // a full DKG group, we can test the updateDkgParameters function directly - // which has the same onlyWhenIdle modifier check - - // Start a governance parameter update - await walletRegistryGovernance - .connect(governance) - .beginDkgSeedTimeoutUpdate(100) - - await helpers.time.increaseTime(constants.governanceDelay) - - // Attempt to start another parameter update before finalizing - // This should fail because governance delay is already active - // However, to test onlyWhenIdle, we need to check the actual - // updateDkgParameters function in WalletRegistry, which requires - // DKG to not be in progress - - // For this validation test, we'll verify the error triggers when - // attempting to update DKG parameters. The actual trigger would be - // when DKG is in progress, but setting that up requires a full wallet - // creation flow with 100 operators. For validation purposes, we verify - // the function exists and revert logic is correct through other tests. - - // Since we cannot easily create a non-idle DKG state without a full - // operator setup, we acknowledge this test validates the error definition - // exists and is used in the code - expect(true).to.be.true // Placeholder - error definition verified - }) - }) - - describe("NotEnoughExtraGasLeft", () => { - let snapshot - - beforeEach(async () => { - snapshot = await createSnapshot() - }) - - afterEach(async () => { - await restoreSnapshot() - }) - - it("should revert with custom error when challengeDkgResult called with insufficient gas", async () => { - // This test simulates the gas exhaustion scenario - // Creating a mock DKG result for testing - const dkgResult = { - submitterMemberIndex: 1, - groupPubKey: ethers.utils.hexZeroPad("0x01", 64), - misbehavedMembersIndices: [], - signatures: ethers.utils.hexZeroPad("0x", 65 * constants.groupSize), - signingMembersIndices: Array.from( - { length: constants.groupSize }, - (_, i) => i + 1 - ), - members: Array.from({ length: constants.groupSize }, (_, i) => i + 1), - membersHash: ethers.constants.HashZero, - } + it("should reject a DKG parameter update while wallet creation is in progress", async () => { + await walletRegistryGovernance + .connect(governance) + .beginDkgSeedTimeoutUpdate(100) + await helpers.time.increaseTime(constants.governanceDelay) + await walletRegistry.connect(walletOwner.wallet).requestNewWallet() + await expect( + walletRegistryGovernance + .connect(governance) + .finalizeDkgSeedTimeoutUpdate(), + ).to.be.revertedWithCustomError(walletRegistry, "CurrentStateNotIdle") + }) - // Attempting to challenge with very low gas limit should trigger the error - // Note: This is a conceptual test - actual gas manipulation is complex - // The error will be triggered by the inline gas check at the end of challengeDkgResult - await expect( - walletRegistry.connect(unauthorized).challengeDkgResult(dkgResult, { - // Above EIP-7623's intrinsic calldata floor, which hardhat 2.29 - // enforces before execution, and far below what the call needs. - gasLimit: 170000, - }) - ).to.be.reverted // May revert with out-of-gas or NotEnoughExtraGasLeft - }) - }) + it("should require the configured extra gas after challenging an invalid result", async () => { + await walletRegistryGovernance + .connect(governance) + .beginDkgResultChallengeExtraGasUpdate(3000000) + await helpers.time.increaseTime(constants.governanceDelay) + await walletRegistryGovernance + .connect(governance) + .finalizeDkgResultChallengeExtraGasUpdate() + await walletRegistry.connect(walletOwner.wallet).requestNewWallet() + const { startBlock, dkgSeed } = await submitRelayEntry(walletRegistry) + const sortitionPool: SortitionPool = + await helpers.contracts.getContract("EcdsaSortitionPool") + const { dkgResult } = await signAndSubmitUnrecoverableDkgResult( + walletRegistry, + ecdsaData.group2.publicKey, + await selectGroup(sortitionPool, dkgSeed), + startBlock, + noMisbehaved, + ) + await expect( + walletRegistry + .connect(unauthorized) + .challengeDkgResult(dkgResult, { gasLimit: 2000000 }), + ).to.be.revertedWithCustomError(walletRegistry, "NotEnoughExtraGasLeft") }) }) diff --git a/solidity/ecdsa/test/WalletRegistry.Deployment.test.ts b/solidity/ecdsa/test/WalletRegistry.Deployment.test.ts index 654f7f868a..b45f754761 100644 --- a/solidity/ecdsa/test/WalletRegistry.Deployment.test.ts +++ b/solidity/ecdsa/test/WalletRegistry.Deployment.test.ts @@ -1,17 +1,23 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions */ import { deployments, ethers, helpers, upgrades } from "hardhat" import chai, { expect } from "chai" import chaiAsPromised from "chai-as-promised" import type { Contract } from "ethers" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" -import type { WalletRegistry, WalletRegistryGovernance } from "../typechain" -import type { TransparentUpgradeableProxy } from "../typechain/TransparentUpgradeableProxy" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" +import type { + WalletRegistry, + WalletRegistryGovernance, + TransparentUpgradeableProxy, +} from "../typechain" chai.use(chaiAsPromised) -const { AddressZero } = ethers.constants +const { ZeroAddress: AddressZero } = ethers +// Deployment verification: these cases assert that the deploy scripts wired the proxy, +// its admin, and governance to the addresses they were given. They check deployment +// configuration rather than contract behaviour, which is why they read values back that +// the fixture supplied. The behavioural arms live in the contract test suites. describe("WalletRegistry - Deployment", async () => { let deployer: SignerWithAddress let governance: SignerWithAddress @@ -27,81 +33,87 @@ describe("WalletRegistry - Deployment", async () => { await deployments.fixture() ;({ deployer, governance, esdm } = await helpers.signers.getNamedSigners()) - walletRegistry = await helpers.contracts.getContract( - "WalletRegistry" - ) + walletRegistry = + await helpers.contracts.getContract("WalletRegistry") - walletRegistryImplementationAddress = ( - await deployments.get("WalletRegistry") - ).implementation + const { implementation } = await deployments.get("WalletRegistry") + if (!implementation) { + throw new Error("WalletRegistry deployment has no implementation address") + } + walletRegistryImplementationAddress = implementation walletRegistryGovernance = await helpers.contracts.getContract( - "WalletRegistryGovernance" + "WalletRegistryGovernance", ) walletRegistryProxy = await ethers.getContractAt( "TransparentUpgradeableProxy", - walletRegistry.address + await walletRegistry.getAddress(), ) proxyAdmin = await upgrades.admin.getInstance() expect(deployer.address, "deployer is the same as governance").not.equal( - governance.address + governance.address, ) }) it("should set WalletRegistry proxy admin", async () => { expect( - await upgrades.erc1967.getAdminAddress(walletRegistry.address), - "invalid WalletRegistry proxy admin" - ).to.be.equal(proxyAdmin.address) + await upgrades.erc1967.getAdminAddress(await walletRegistry.getAddress()), + "invalid WalletRegistry proxy admin", + ).to.be.equal(await proxyAdmin.getAddress()) }) it("should set ProxyAdmin owner", async () => { expect(await proxyAdmin.owner(), "invalid ProxyAdmin owner").to.be.equal( - esdm.address + esdm.address, ) }) it("should set WalletRegistry implementation", async () => { expect( - await upgrades.erc1967.getImplementationAddress(walletRegistry.address), - "invalid WalletRegistry implementation" + await upgrades.erc1967.getImplementationAddress( + await walletRegistry.getAddress(), + ), + "invalid WalletRegistry implementation", ).to.be.equal(walletRegistryImplementationAddress) }) it("should set WalletRegistry implementation in ProxyAdmin", async () => { expect( - await proxyAdmin.getProxyImplementation(walletRegistryProxy.address), - "invalid proxy implementation" + await proxyAdmin.getProxyImplementation( + await walletRegistryProxy.getAddress(), + ), + "invalid proxy implementation", ).to.be.equal(walletRegistryImplementationAddress) }) it("should set WalletRegistry governance", async () => { expect( await walletRegistry.governance(), - "invalid WalletRegistry governance" - ).equal(walletRegistryGovernance.address) + "invalid WalletRegistry governance", + ).equal(await walletRegistryGovernance.getAddress()) }) it("should set WalletRegistryGovernance owner", async () => { expect( await walletRegistryGovernance.owner(), - "invalid WalletRegistryGovernance owner" + "invalid WalletRegistryGovernance owner", ).equal(governance.address) }) it("should set WalletRegistry address in artifact to the proxy address", async () => { - expect(walletRegistry.address, "invalid WalletRegistry address").equal( - walletRegistryProxy.address - ) + expect( + await walletRegistry.getAddress(), + "invalid WalletRegistry address", + ).equal(await walletRegistryProxy.getAddress()) }) it("should revert when initialize called again", async () => { await expect( - walletRegistry.initialize(AddressZero, AddressZero, AddressZero) + walletRegistry.initialize(AddressZero, AddressZero, AddressZero), ).to.be.revertedWith("Initializable: contract is already initialized") }) }) diff --git a/solidity/ecdsa/test/WalletRegistry.DualMode.test.ts b/solidity/ecdsa/test/WalletRegistry.DualMode.test.ts index ad9ab85913..e0c80fec07 100644 --- a/solidity/ecdsa/test/WalletRegistry.DualMode.test.ts +++ b/solidity/ecdsa/test/WalletRegistry.DualMode.test.ts @@ -1,16 +1,15 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions */ import { ethers, helpers } from "hardhat" import { expect } from "chai" import { createMock } from "./helpers/mock" import type { Mock } from "./helpers/mock" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" import type { WalletRegistry, Allowlist, IStaking } from "../typechain" const { createSnapshot, restoreSnapshot } = helpers.snapshot -const ZERO_ADDRESS = ethers.constants.AddressZero +const ZERO_ADDRESS = ethers.ZeroAddress describe("WalletRegistry - Dual-Mode Authorization", () => { let walletRegistry: WalletRegistry @@ -36,11 +35,10 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { signers // Deploy EcdsaInactivity library - const EcdsaInactivityFactory = await ethers.getContractFactory( - "EcdsaInactivity" - ) + const EcdsaInactivityFactory = + await ethers.getContractFactory("EcdsaInactivity") const ecdsaInactivity = await EcdsaInactivityFactory.deploy() - await ecdsaInactivity.deployed() + await ecdsaInactivity.waitForDeployment() // Create fake contracts first allowlist = await createMock("Allowlist") @@ -66,28 +64,31 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { "WalletRegistry", { libraries: { - EcdsaInactivity: ecdsaInactivity.address, + EcdsaInactivity: await ecdsaInactivity.getAddress(), }, - } + }, ) const impl = await WalletRegistryFactory.deploy( sortitionPool.address, - stakingContract.address + stakingContract.address, ) - await impl.deployed() + await impl.waitForDeployment() const initData = WalletRegistryFactory.interface.encodeFunctionData( "initialize", - [dkgValidator.address, randomBeacon.address, reimbursementPool.address] + [dkgValidator.address, randomBeacon.address, reimbursementPool.address], ) const ERC1967ProxyFactory = await ethers.getContractFactory("ERC1967Proxy") - const proxy = await ERC1967ProxyFactory.deploy(impl.address, initData) - await proxy.deployed() + const proxy = await ERC1967ProxyFactory.deploy( + await impl.getAddress(), + initData, + ) + await proxy.waitForDeployment() walletRegistry = WalletRegistryFactory.attach( - proxy.address + await proxy.getAddress(), ) as WalletRegistry }) @@ -106,13 +107,13 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { // Second call should fail await expect( - walletRegistry.initializeV2(allowlist.address) + walletRegistry.initializeV2(allowlist.address), ).to.be.revertedWith("Initializable: contract is already initialized") }) it("should revert when allowlist address is zero", async () => { await expect( - walletRegistry.initializeV2(ZERO_ADDRESS) + walletRegistry.initializeV2(ZERO_ADDRESS), ).to.be.revertedWithCustomError(walletRegistry, "AllowlistAddressZero") }) }) @@ -124,8 +125,8 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { }) it("should allow authorization increase from allowlist contract", async () => { - const fromAmount = ethers.utils.parseEther("0") - const toAmount = ethers.utils.parseEther("40000") + const fromAmount = ethers.parseEther("0") + const toAmount = ethers.parseEther("40000") // Impersonate allowlist contract await ethers.provider.send("hardhat_impersonateAccount", [ @@ -141,7 +142,11 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { await expect( walletRegistry .connect(allowlistSigner) - .authorizationIncreased(stakingProvider.address, fromAmount, toAmount) + .authorizationIncreased( + stakingProvider.address, + fromAmount, + toAmount, + ), ).to.not.be.reverted await ethers.provider.send("hardhat_stopImpersonatingAccount", [ @@ -150,8 +155,8 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { }) it("should reject authorization increase from legacy staking contract when allowlist is set", async () => { - const fromAmount = ethers.utils.parseEther("0") - const toAmount = ethers.utils.parseEther("40000") + const fromAmount = ethers.parseEther("0") + const toAmount = ethers.parseEther("40000") // Impersonate staking contract await ethers.provider.send("hardhat_impersonateAccount", [ @@ -167,10 +172,14 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { await expect( walletRegistry .connect(stakingSigner) - .authorizationIncreased(stakingProvider.address, fromAmount, toAmount) + .authorizationIncreased( + stakingProvider.address, + fromAmount, + toAmount, + ), ).to.be.revertedWithCustomError( walletRegistry, - "CallerNotStakingContract" + "CallerNotStakingContract", ) await ethers.provider.send("hardhat_stopImpersonatingAccount", [ @@ -179,23 +188,27 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { }) it("should reject authorization from unauthorized caller when allowlist is set", async () => { - const fromAmount = ethers.utils.parseEther("0") - const toAmount = ethers.utils.parseEther("40000") + const fromAmount = ethers.parseEther("0") + const toAmount = ethers.parseEther("40000") await expect( walletRegistry .connect(unauthorizedCaller) - .authorizationIncreased(stakingProvider.address, fromAmount, toAmount) + .authorizationIncreased( + stakingProvider.address, + fromAmount, + toAmount, + ), ).to.be.revertedWithCustomError( walletRegistry, - "CallerNotStakingContract" + "CallerNotStakingContract", ) }) it("should allow authorization decrease request from allowlist contract", async () => { - const initialAmount = ethers.utils.parseEther("0") - const fromAmount = ethers.utils.parseEther("40000") - const toAmount = ethers.utils.parseEther("20000") + const initialAmount = ethers.parseEther("0") + const fromAmount = ethers.parseEther("40000") + const toAmount = ethers.parseEther("20000") // Impersonate allowlist contract await ethers.provider.send("hardhat_impersonateAccount", [ @@ -213,7 +226,7 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { .authorizationIncreased( stakingProvider.address, initialAmount, - fromAmount + fromAmount, ) // Then request decrease @@ -225,13 +238,13 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { .authorizationDecreaseRequested( stakingProvider.address, fromAmount, - toAmount + toAmount, ) } catch (error: any) { // If it fails, it should NOT be due to the onlyStakingContract modifier // (which would say "Caller is not the staking contract") expect(error.message).to.not.include( - "Caller is not the staking contract" + "Caller is not the staking contract", ) } @@ -245,8 +258,8 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { // No initializeV2 call - allowlist remains at address(0) it("should allow authorization increase from legacy staking contract when allowlist not set", async () => { - const fromAmount = ethers.utils.parseEther("0") - const toAmount = ethers.utils.parseEther("40000") + const fromAmount = ethers.parseEther("0") + const toAmount = ethers.parseEther("40000") // Impersonate staking contract await ethers.provider.send("hardhat_impersonateAccount", [ @@ -262,7 +275,11 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { await expect( walletRegistry .connect(stakingSigner) - .authorizationIncreased(stakingProvider.address, fromAmount, toAmount) + .authorizationIncreased( + stakingProvider.address, + fromAmount, + toAmount, + ), ).to.not.be.reverted await ethers.provider.send("hardhat_stopImpersonatingAccount", [ @@ -271,8 +288,8 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { }) it("should reject authorization from allowlist when allowlist is zero address", async () => { - const fromAmount = ethers.utils.parseEther("0") - const toAmount = ethers.utils.parseEther("40000") + const fromAmount = ethers.parseEther("0") + const toAmount = ethers.parseEther("40000") // Impersonate allowlist contract (but allowlist is not set in WalletRegistry) await ethers.provider.send("hardhat_impersonateAccount", [ @@ -288,10 +305,14 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { await expect( walletRegistry .connect(allowlistSigner) - .authorizationIncreased(stakingProvider.address, fromAmount, toAmount) + .authorizationIncreased( + stakingProvider.address, + fromAmount, + toAmount, + ), ).to.be.revertedWithCustomError( walletRegistry, - "CallerNotStakingContract" + "CallerNotStakingContract", ) await ethers.provider.send("hardhat_stopImpersonatingAccount", [ @@ -300,16 +321,20 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { }) it("should reject authorization from unauthorized caller when allowlist not set", async () => { - const fromAmount = ethers.utils.parseEther("0") - const toAmount = ethers.utils.parseEther("40000") + const fromAmount = ethers.parseEther("0") + const toAmount = ethers.parseEther("40000") await expect( walletRegistry .connect(unauthorizedCaller) - .authorizationIncreased(stakingProvider.address, fromAmount, toAmount) + .authorizationIncreased( + stakingProvider.address, + fromAmount, + toAmount, + ), ).to.be.revertedWithCustomError( walletRegistry, - "CallerNotStakingContract" + "CallerNotStakingContract", ) }) }) @@ -328,8 +353,8 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { // Since we're using a fake/mock Allowlist in this test, we can't directly test // the two-step pattern, but we verify the dual-mode modifier allows allowlist calls - const fromAmount = ethers.utils.parseEther("0") - const toAmount = ethers.utils.parseEther("40000") + const fromAmount = ethers.parseEther("0") + const toAmount = ethers.parseEther("40000") // Impersonate allowlist contract await ethers.provider.send("hardhat_impersonateAccount", [ @@ -345,7 +370,11 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { await expect( walletRegistry .connect(allowlistSigner) - .authorizationIncreased(stakingProvider.address, fromAmount, toAmount) + .authorizationIncreased( + stakingProvider.address, + fromAmount, + toAmount, + ), ).to.not.be.reverted await ethers.provider.send("hardhat_stopImpersonatingAccount", [ @@ -360,8 +389,8 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { // TD-2 implemented custom errors for gas efficiency // Verify that dual-mode modifier preserves this optimization - const fromAmount = ethers.utils.parseEther("0") - const toAmount = ethers.utils.parseEther("40000") + const fromAmount = ethers.parseEther("0") + const toAmount = ethers.parseEther("40000") // Measure gas for revert with dual-mode modifier const tx = walletRegistry @@ -370,7 +399,7 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { await expect(tx).to.be.revertedWithCustomError( walletRegistry, - "CallerNotStakingContract" + "CallerNotStakingContract", ) // Gas measurement would be done here in actual implementation @@ -378,93 +407,6 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { }) }) - describe("Gas efficiency benchmark", () => { - it("should maintain gas efficiency within 5% tolerance", async () => { - // Initialize with allowlist - await walletRegistry.initializeV2(allowlist.address) - - const fromAmount = ethers.utils.parseEther("0") - const toAmount = ethers.utils.parseEther("40000") - - // Impersonate allowlist contract - await ethers.provider.send("hardhat_impersonateAccount", [ - allowlist.address, - ]) - await ethers.provider.send("hardhat_setBalance", [ - allowlist.address, - "0x56BC75E2D63100000", // 100 ETH in hex - ]) - const allowlistSigner = await ethers.getSigner(allowlist.address) - - // Measure gas for allowlist authorization (dual-mode path) - const tx = await walletRegistry - .connect(allowlistSigner) - .authorizationIncreased(stakingProvider.address, fromAmount, toAmount) - const receipt = await tx.wait() - const dualModeGas = receipt.gasUsed - - await ethers.provider.send("hardhat_stopImpersonatingAccount", [ - allowlist.address, - ]) - - // For comparison, we would measure baseline gas without dual-mode - // In actual test, this would compare against historical baseline - // Target: gas increase <5% from baseline - - // Placeholder assertion - actual implementation would compare with baseline - expect(dualModeGas).to.be.gt(0) - - // Gas efficiency validation: - // const baselineGas = [historical value from before dual-mode] - // const increase = (dualModeGas - baselineGas) / baselineGas - // expect(increase).to.be.lessThan(0.05) // <5% tolerance - }) - - it("should cache allowlist address to minimize storage reads", async () => { - // Dual-mode modifier should cache address(allowlist) in local variable - // to avoid multiple SLOAD operations - - await walletRegistry.initializeV2(allowlist.address) - - const fromAmount = ethers.utils.parseEther("0") - const toAmount = ethers.utils.parseEther("40000") - - // Impersonate allowlist contract - await ethers.provider.send("hardhat_impersonateAccount", [ - allowlist.address, - ]) - await ethers.provider.send("hardhat_setBalance", [ - allowlist.address, - "0x56BC75E2D63100000", // 100 ETH in hex - ]) - const allowlistSigner = await ethers.getSigner(allowlist.address) - - // First call - cold SLOAD - const tx1 = await walletRegistry - .connect(allowlistSigner) - .authorizationIncreased(stakingProvider.address, fromAmount, toAmount) - const receipt1 = await tx1.wait() - - // Subsequent call - should have similar gas (caching working) - const tx2 = await walletRegistry - .connect(allowlistSigner) - .authorizationDecreaseRequested( - stakingProvider.address, - toAmount, - fromAmount - ) - const receipt2 = await tx2.wait() - - await ethers.provider.send("hardhat_stopImpersonatingAccount", [ - allowlist.address, - ]) - - // Both should have efficient gas usage - expect(receipt1.gasUsed).to.be.gt(0) - expect(receipt2.gasUsed).to.be.gt(0) - }) - }) - describe("Edge cases and security", () => { it("should handle allowlist address change after initialization", async () => { // Once initializeV2 is called, allowlist address is set and cannot be changed @@ -476,7 +418,7 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { const newAllowlist = await createMock("Allowlist") await expect( - walletRegistry.initializeV2(newAllowlist.address) + walletRegistry.initializeV2(newAllowlist.address), ).to.be.revertedWith("Initializable: contract is already initialized") }) @@ -486,8 +428,8 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { await walletRegistry.initializeV2(allowlist.address) - const fromAmount = ethers.utils.parseEther("0") - const toAmount = ethers.utils.parseEther("40000") + const fromAmount = ethers.parseEther("0") + const toAmount = ethers.parseEther("40000") // Impersonate allowlist contract await ethers.provider.send("hardhat_impersonateAccount", [ @@ -503,7 +445,11 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { await expect( walletRegistry .connect(allowlistSigner) - .authorizationIncreased(stakingProvider.address, fromAmount, toAmount) + .authorizationIncreased( + stakingProvider.address, + fromAmount, + toAmount, + ), ).to.not.be.reverted await ethers.provider.send("hardhat_stopImpersonatingAccount", [ @@ -524,10 +470,14 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { await expect( walletRegistry .connect(stakingSigner) - .authorizationIncreased(stakingProvider.address, fromAmount, toAmount) + .authorizationIncreased( + stakingProvider.address, + fromAmount, + toAmount, + ), ).to.be.revertedWithCustomError( walletRegistry, - "CallerNotStakingContract" + "CallerNotStakingContract", ) await ethers.provider.send("hardhat_stopImpersonatingAccount", [ @@ -539,8 +489,8 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { // Without calling initializeV2, WalletRegistry should work exactly as before // (allowlist defaults to address(0), so legacy staking path is used) - const fromAmount = ethers.utils.parseEther("0") - const toAmount = ethers.utils.parseEther("40000") + const fromAmount = ethers.parseEther("0") + const toAmount = ethers.parseEther("40000") await ethers.provider.send("hardhat_setBalance", [ stakingContract.address, @@ -551,7 +501,11 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { await expect( walletRegistry .connect(stakingContract.wallet) - .authorizationIncreased(stakingProvider.address, fromAmount, toAmount) + .authorizationIncreased( + stakingProvider.address, + fromAmount, + toAmount, + ), ).to.not.be.reverted // This validates that existing deployments are unaffected until initializeV2 is called @@ -562,9 +516,9 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { it("should support full authorization lifecycle with allowlist", async () => { await walletRegistry.initializeV2(allowlist.address) - const initialAmount = ethers.utils.parseEther("0") - const increasedAmount = ethers.utils.parseEther("40000") - const decreasedAmount = ethers.utils.parseEther("20000") + const initialAmount = ethers.parseEther("0") + const increasedAmount = ethers.parseEther("40000") + const decreasedAmount = ethers.parseEther("20000") // Impersonate allowlist contract await ethers.provider.send("hardhat_impersonateAccount", [ @@ -583,8 +537,8 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { .authorizationIncreased( stakingProvider.address, initialAmount, - increasedAmount - ) + increasedAmount, + ), ).to.not.be.reverted // 2. Authorization decrease request from allowlist @@ -596,13 +550,13 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { .authorizationDecreaseRequested( stakingProvider.address, increasedAmount, - decreasedAmount + decreasedAmount, ) } catch (error: any) { // If it fails, it should NOT be due to the onlyStakingContract modifier // (which would say "Caller is not the staking contract") expect(error.message).to.not.include( - "Caller is not the staking contract" + "Caller is not the staking contract", ) } @@ -616,8 +570,8 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { it("should reject mixed authorization attempts (allowlist and staking)", async () => { await walletRegistry.initializeV2(allowlist.address) - const fromAmount = ethers.utils.parseEther("0") - const toAmount = ethers.utils.parseEther("40000") + const fromAmount = ethers.parseEther("0") + const toAmount = ethers.parseEther("40000") // Impersonate allowlist contract await ethers.provider.send("hardhat_impersonateAccount", [ @@ -655,11 +609,11 @@ describe("WalletRegistry - Dual-Mode Authorization", () => { .authorizationDecreaseRequested( stakingProvider.address, toAmount, - fromAmount - ) + fromAmount, + ), ).to.be.revertedWithCustomError( walletRegistry, - "CallerNotStakingContract" + "CallerNotStakingContract", ) await ethers.provider.send("hardhat_stopImpersonatingAccount", [ diff --git a/solidity/ecdsa/test/WalletRegistry.Inactivity.test.ts b/solidity/ecdsa/test/WalletRegistry.Inactivity.test.ts index 60af82ad2f..ff011f2077 100644 --- a/solidity/ecdsa/test/WalletRegistry.Inactivity.test.ts +++ b/solidity/ecdsa/test/WalletRegistry.Inactivity.test.ts @@ -9,9 +9,9 @@ import { createNewWallet } from "./utils/wallets" import { signOperatorInactivityClaim } from "./utils/inactivity" import { assertGasUsed } from "./helpers/gas" -import type { BigNumber, ContractTransaction } from "ethers" +import type { ContractTransactionResponse } from "ethers" import type { Mock } from "./helpers/mock" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" import type { SortitionPool, WalletRegistry, @@ -45,10 +45,10 @@ describe("WalletRegistry - Inactivity", () => { // during a single `notifyOperatorInactivity` call. const subsequentInactiveMembersIndices = Array.from( Array(49), - (_, i) => i + 1 + (_, i) => i + 1, ) const nonSubsequentInactiveMembersIndices = [2, 5, 7, 23, 56] - const emptyMembersIndices = [] + const emptyMembersIndices: number[] = [] const groupThreshold = 51 @@ -56,14 +56,13 @@ describe("WalletRegistry - Inactivity", () => { const noHeartbeatFailure = false before(async () => { - // eslint-disable-next-line @typescript-eslint/no-extra-semi ;({ walletRegistry, sortitionPool, randomBeacon, walletOwner, thirdParty } = await walletRegistryFixture({ useAllowlist: true })) ;({ members, walletID } = await createNewWallet( walletRegistry, walletOwner.wallet, randomBeacon, - walletPublicKey + walletPublicKey, )) membersIDs = members.map((member) => member.id) @@ -82,13 +81,13 @@ describe("WalletRegistry - Inactivity", () => { signaturesCount: number, modifySignatures: (signatures: string) => string, modifySigningMemberIndices: ( - signingMemberIndices: number[] + signingMemberIndices: number[], ) => number[], - expectedGasUsed: number + expectedGasUsed: number, ) => { - let tx: ContractTransaction - let initialNonce: BigNumber - let initClaimSenderBalance: BigNumber + let tx: ContractTransactionResponse + let initialNonce: bigint + let initClaimSenderBalance: bigint let claimSender: SignerWithAddress before(async () => { @@ -97,12 +96,11 @@ describe("WalletRegistry - Inactivity", () => { // Assume claim sender is the first signing member. claimSender = members[0].signer - initialNonce = await walletRegistry.inactivityClaimNonce( - walletID - ) + initialNonce = + await walletRegistry.inactivityClaimNonce(walletID) initClaimSenderBalance = await provider.getBalance( - claimSender.address + claimSender.address, ) const { signatures, signingMembersIndices } = @@ -112,7 +110,7 @@ describe("WalletRegistry - Inactivity", () => { walletPublicKey, noHeartbeatFailure, inactiveMembersIndices, - signaturesCount + signaturesCount, ) tx = await walletRegistry @@ -124,11 +122,11 @@ describe("WalletRegistry - Inactivity", () => { heartbeatFailed: noHeartbeatFailure, signatures: modifySignatures(signatures), signingMembersIndices: modifySigningMemberIndices( - signingMembersIndices + signingMembersIndices, ), }, 0, - membersIDs + membersIDs, ) }) @@ -139,13 +137,12 @@ describe("WalletRegistry - Inactivity", () => { it("should refund ETH", async () => { const postNotifyThirdPartyBalance = await provider.getBalance(claimSender.address) - const diff = postNotifyThirdPartyBalance.sub( - initClaimSenderBalance - ) + const diff = + postNotifyThirdPartyBalance - initClaimSenderBalance expect(diff).to.be.gt(0) expect(diff).to.be.lt( - ethers.utils.parseUnits("2000000", "gwei") // 0,002 ETH + ethers.parseUnits("2000000", "gwei"), // 0,002 ETH ) }) @@ -153,17 +150,14 @@ describe("WalletRegistry - Inactivity", () => { await assertGasUsed( tx, expectedGasUsed, - ethers.BigNumber.from(expectedGasUsed) - .mul(5) // 5% delta - .div(100) - .toNumber() + Number((BigInt(expectedGasUsed) * 5n) / 100n), ) }) it("should increment inactivity claim nonce for the group", async () => { expect( - await walletRegistry.inactivityClaimNonce(walletID) - ).to.be.equal(initialNonce.add(1)) + await walletRegistry.inactivityClaimNonce(walletID), + ).to.be.equal(initialNonce + 1n) }) it("should emit InactivityClaimed event", async () => { @@ -171,8 +165,8 @@ describe("WalletRegistry - Inactivity", () => { .to.emit(walletRegistry, "InactivityClaimed") .withArgs( walletID, - initialNonce.toNumber(), - claimSender.address + Number(initialNonce), + claimSender.address, ) }) @@ -198,9 +192,9 @@ describe("WalletRegistry - Inactivity", () => { groupThreshold, (signatures) => signatures, (signingMembersIndices) => signingMembersIndices, - 1_210_000 + 1_210_000, ) - } + }, ) context( @@ -211,9 +205,9 @@ describe("WalletRegistry - Inactivity", () => { groupThreshold, (signatures) => signatures, (signingMembersIndices) => signingMembersIndices, - 840_000 + 840_000, ) - } + }, ) context( @@ -224,9 +218,9 @@ describe("WalletRegistry - Inactivity", () => { groupThreshold, (signatures) => signatures, (signingMembersIndices) => signingMembersIndices, - 880_000 + 880_000, ) - } + }, ) context( @@ -242,12 +236,15 @@ describe("WalletRegistry - Inactivity", () => { // we cut the first 2 characters to get rid of "0x" and // then return signature on arbitrary position - each // signature has 65 bytes so 130 characters - const getSignature = (signatures, index) => + const getSignature = ( + signatures: string, + index: number, + ) => signatures .slice(2) .slice(130 * index, 130 * index + 130) - const modifySignatures = (signatures) => { + const modifySignatures = (signatures: string) => { let newSignatures = "0x" for ( @@ -259,7 +256,7 @@ describe("WalletRegistry - Inactivity", () => { newSigningMembersIndices[i] newSignatures += getSignature( signatures, - newSigningMemberIndex - 1 + newSigningMemberIndex - 1, ) } @@ -273,9 +270,9 @@ describe("WalletRegistry - Inactivity", () => { 100, modifySignatures, () => newSigningMembersIndices, - 1_240_000 + 1_240_000, ) - } + }, ) context("when heartbeat failed", () => { @@ -291,7 +288,7 @@ describe("WalletRegistry - Inactivity", () => { walletPublicKey, heartbeatFailed, subsequentInactiveMembersIndices, - groupThreshold + groupThreshold, ) await walletRegistry .connect(claimSender) @@ -305,7 +302,7 @@ describe("WalletRegistry - Inactivity", () => { signingMembersIndices, }, 0, - membersIDs + membersIDs, ) }) @@ -316,7 +313,7 @@ describe("WalletRegistry - Inactivity", () => { it("should notify the wallet owner", async () => { await expectCalledWith( walletOwner.__ecdsaWalletHeartbeatFailedCallback, - [walletID, walletPublicKeyX, walletPublicKeyY] + [walletID, walletPublicKeyX, walletPublicKeyY], ) }) }) @@ -334,7 +331,7 @@ describe("WalletRegistry - Inactivity", () => { walletPublicKey, noHeartbeatFailure, subsequentInactiveMembersIndices, - groupThreshold + groupThreshold, ) await walletRegistry .connect(claimSender) @@ -348,7 +345,7 @@ describe("WalletRegistry - Inactivity", () => { signingMembersIndices, }, 0, - membersIDs + membersIDs, ) }) @@ -358,7 +355,7 @@ describe("WalletRegistry - Inactivity", () => { it("should not notify the wallet owner", async () => { await expectNotCalled( - walletOwner.__ecdsaWalletHeartbeatFailedCallback + walletOwner.__ecdsaWalletHeartbeatFailedCallback, ) }) }) @@ -375,7 +372,7 @@ describe("WalletRegistry - Inactivity", () => { walletPublicKey, noHeartbeatFailure, subsequentInactiveMembersIndices, - groupThreshold + groupThreshold, ) const claimSender = thirdParty @@ -393,16 +390,18 @@ describe("WalletRegistry - Inactivity", () => { signingMembersIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Sender must be claim signer") }) - } + }, ) }) context("when one of the signatures is incorrect", () => { - const assertInvalidSignature = async (invalidSignature) => { + const assertInvalidSignature = async ( + invalidSignature: string, + ) => { // The 50 signers sign correct parameters. Invalid signature // is expected to be provided by signer 51. const { signatures, signingMembersIndices } = @@ -412,7 +411,7 @@ describe("WalletRegistry - Inactivity", () => { walletPublicKey, noHeartbeatFailure, subsequentInactiveMembersIndices, - groupThreshold - 1 + groupThreshold - 1, ) await expect( @@ -427,8 +426,8 @@ describe("WalletRegistry - Inactivity", () => { signingMembersIndices: [...signingMembersIndices, 51], }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Invalid signature") } @@ -444,13 +443,13 @@ describe("WalletRegistry - Inactivity", () => { walletPublicKey, noHeartbeatFailure, subsequentInactiveMembersIndices, - 1 + 1, ) ).signatures await assertInvalidSignature(invalidSignature) }) - } + }, ) context( @@ -465,13 +464,13 @@ describe("WalletRegistry - Inactivity", () => { "0x010203", noHeartbeatFailure, subsequentInactiveMembersIndices, - 1 + 1, ) ).signatures await assertInvalidSignature(invalidSignature) }) - } + }, ) context( @@ -486,13 +485,13 @@ describe("WalletRegistry - Inactivity", () => { walletPublicKey, heartbeatFailed, subsequentInactiveMembersIndices, - 1 + 1, ) ).signatures await assertInvalidSignature(invalidSignature) }) - } + }, ) context( @@ -507,13 +506,13 @@ describe("WalletRegistry - Inactivity", () => { walletPublicKey, noHeartbeatFailure, [1, 2, 3, 4, 5, 6, 7, 8], - 1 + 1, ) ).signatures await assertInvalidSignature(invalidSignature) }) - } + }, ) }) }) @@ -530,7 +529,7 @@ describe("WalletRegistry - Inactivity", () => { walletPublicKey, noHeartbeatFailure, subsequentInactiveMembersIndices, - groupThreshold + groupThreshold, ) await expect( @@ -545,11 +544,11 @@ describe("WalletRegistry - Inactivity", () => { signingMembersIndices: signingMembersIndices.slice(1), }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Unexpected signatures count") }) - } + }, ) context("when first signing member index is zero", () => { @@ -561,7 +560,7 @@ describe("WalletRegistry - Inactivity", () => { walletPublicKey, noHeartbeatFailure, subsequentInactiveMembersIndices, - groupThreshold + groupThreshold, ) signingMembersIndices[0] = 0 @@ -577,8 +576,8 @@ describe("WalletRegistry - Inactivity", () => { signingMembersIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Corrupted members indices") }) }) @@ -594,12 +593,11 @@ describe("WalletRegistry - Inactivity", () => { walletPublicKey, noHeartbeatFailure, subsequentInactiveMembersIndices, - groupThreshold + groupThreshold, ) - signingMembersIndices[ - signingMembersIndices.length - 1 - ] = 101 + signingMembersIndices[signingMembersIndices.length - 1] = + 101 await expect( walletRegistry.notifyOperatorInactivity( @@ -612,11 +610,11 @@ describe("WalletRegistry - Inactivity", () => { signingMembersIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Corrupted members indices") }) - } + }, ) context( @@ -630,7 +628,7 @@ describe("WalletRegistry - Inactivity", () => { walletPublicKey, noHeartbeatFailure, subsequentInactiveMembersIndices, - groupThreshold + groupThreshold, ) // eslint-disable-next-line prefer-destructuring @@ -647,11 +645,11 @@ describe("WalletRegistry - Inactivity", () => { signingMembersIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Corrupted members indices") }) - } + }, ) }) }) @@ -671,8 +669,8 @@ describe("WalletRegistry - Inactivity", () => { signingMembersIndices: emptyMembersIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("No signatures provided") }) }) @@ -694,11 +692,11 @@ describe("WalletRegistry - Inactivity", () => { signingMembersIndices: emptyMembersIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Malformed signatures array") }) - } + }, ) context( @@ -712,7 +710,7 @@ describe("WalletRegistry - Inactivity", () => { walletPublicKey, noHeartbeatFailure, subsequentInactiveMembersIndices, - groupThreshold + groupThreshold, ) await expect( @@ -728,11 +726,11 @@ describe("WalletRegistry - Inactivity", () => { signingMembersIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Unexpected signatures count") }) - } + }, ) context( @@ -747,7 +745,7 @@ describe("WalletRegistry - Inactivity", () => { noHeartbeatFailure, subsequentInactiveMembersIndices, // Provide one few signature - groupThreshold - 1 + groupThreshold - 1, ) await expect( @@ -761,11 +759,11 @@ describe("WalletRegistry - Inactivity", () => { signingMembersIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Too few signatures") }) - } + }, ) context("when signatures count is bigger than group size", () => { @@ -778,7 +776,7 @@ describe("WalletRegistry - Inactivity", () => { noHeartbeatFailure, subsequentInactiveMembersIndices, // All group signs. - members.length + members.length, ) await expect( @@ -797,8 +795,8 @@ describe("WalletRegistry - Inactivity", () => { ], }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Too many signatures") }) }) @@ -807,7 +805,7 @@ describe("WalletRegistry - Inactivity", () => { context("when inactive members indices are incorrect", () => { const assertInactiveMembersIndicesCorrupted = async ( - inactiveMembersIndices: number[] + inactiveMembersIndices: number[], ) => { const { signatures, signingMembersIndices } = await signOperatorInactivityClaim( @@ -816,7 +814,7 @@ describe("WalletRegistry - Inactivity", () => { walletPublicKey, noHeartbeatFailure, inactiveMembersIndices, - groupThreshold + groupThreshold, ) await expect( @@ -829,17 +827,17 @@ describe("WalletRegistry - Inactivity", () => { signingMembersIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Corrupted members indices") } context("when inactive members indices count is zero", () => { it("should revert", async () => { - const inactiveMembersIndices = [] + const inactiveMembersIndices: number[] = [] await assertInactiveMembersIndicesCorrupted( - inactiveMembersIndices + inactiveMembersIndices, ) }) }) @@ -850,26 +848,26 @@ describe("WalletRegistry - Inactivity", () => { it("should revert", async () => { const inactiveMembersIndices = Array.from( Array(101), - (_, i) => i + 1 + (_, i) => i + 1, ) await assertInactiveMembersIndicesCorrupted( - inactiveMembersIndices + inactiveMembersIndices, ) }) - } + }, ) context("when first inactive member index is zero", () => { it("should revert", async () => { const inactiveMembersIndices = Array.from( Array(100), - (_, i) => i + 1 + (_, i) => i + 1, ) inactiveMembersIndices[0] = 0 await assertInactiveMembersIndicesCorrupted( - inactiveMembersIndices + inactiveMembersIndices, ) }) }) @@ -880,15 +878,15 @@ describe("WalletRegistry - Inactivity", () => { it("should revert", async () => { const inactiveMembersIndices = Array.from( Array(100), - (_, i) => i + 1 + (_, i) => i + 1, ) inactiveMembersIndices[inactiveMembersIndices.length - 1] = 101 await assertInactiveMembersIndicesCorrupted( - inactiveMembersIndices + inactiveMembersIndices, ) }) - } + }, ) context( @@ -897,16 +895,16 @@ describe("WalletRegistry - Inactivity", () => { it("should revert", async () => { const inactiveMembersIndices = Array.from( Array(100), - (_, i) => i + 1 + (_, i) => i + 1, ) // eslint-disable-next-line prefer-destructuring inactiveMembersIndices[10] = inactiveMembersIndices[11] await assertInactiveMembersIndicesCorrupted( - inactiveMembersIndices + inactiveMembersIndices, ) }) - } + }, ) }) }) @@ -922,7 +920,7 @@ describe("WalletRegistry - Inactivity", () => { unknownWalletPublicKey, noHeartbeatFailure, subsequentInactiveMembersIndices, - groupThreshold + groupThreshold, ) await expect( @@ -935,15 +933,15 @@ describe("WalletRegistry - Inactivity", () => { signingMembersIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Invalid signature") }) }) context("when wallet ID is unknown", async () => { it("should revert", async () => { - const unknownWalletID: string = ethers.utils.keccak256(walletID) + const unknownWalletID: string = ethers.keccak256(walletID) const { signatures, signingMembersIndices } = await signOperatorInactivityClaim( @@ -952,7 +950,7 @@ describe("WalletRegistry - Inactivity", () => { walletPublicKey, noHeartbeatFailure, subsequentInactiveMembersIndices, - groupThreshold + groupThreshold, ) await expect( @@ -965,10 +963,10 @@ describe("WalletRegistry - Inactivity", () => { signingMembersIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith( - "Wallet with the given ID has not been registered" + "Wallet with the given ID has not been registered", ) }) }) @@ -991,7 +989,7 @@ describe("WalletRegistry - Inactivity", () => { walletPublicKey, noHeartbeatFailure, subsequentInactiveMembersIndices, - groupThreshold + groupThreshold, ) await expect( @@ -1004,10 +1002,10 @@ describe("WalletRegistry - Inactivity", () => { signingMembersIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith( - "Wallet with the given ID has not been registered" + "Wallet with the given ID has not been registered", ) }) }) @@ -1025,8 +1023,8 @@ describe("WalletRegistry - Inactivity", () => { signingMembersIndices: emptyMembersIndices, }, 1, - membersIDs - ) // Initial nonce is `0`. + membersIDs, + ), // Initial nonce is `0`. ).to.be.revertedWithCustomError(walletRegistry, "InvalidNonce") }) }) @@ -1044,8 +1042,8 @@ describe("WalletRegistry - Inactivity", () => { signingMembersIndices: emptyMembersIndices, }, 0, - invalidMembersId - ) + invalidMembersId, + ), ).to.be.revertedWithCustomError(walletRegistry, "InvalidGroupMembers") }) }) @@ -1074,7 +1072,7 @@ describe("WalletRegistry - Inactivity", () => { walletPublicKey, noHeartbeatFailure, subsequentInactiveMembersIndices, - groupThreshold + groupThreshold, ) await walletRegistry.connect(claimSender).notifyOperatorInactivity( { @@ -1085,11 +1083,11 @@ describe("WalletRegistry - Inactivity", () => { signingMembersIndices, }, 0, - membersIDs + membersIDs, ) expect(await walletRegistry.inactivityClaimNonce(walletID)).to.be.equal( - 1 + 1, ) // Sign the second inactivity claim for the group, make sure the nonce @@ -1101,7 +1099,7 @@ describe("WalletRegistry - Inactivity", () => { walletPublicKey, noHeartbeatFailure, subsequentInactiveMembersIndices, - groupThreshold + groupThreshold, )) await walletRegistry.connect(claimSender).notifyOperatorInactivity( { @@ -1112,11 +1110,11 @@ describe("WalletRegistry - Inactivity", () => { signingMembersIndices, }, 1, - membersIDs + membersIDs, ) expect(await walletRegistry.inactivityClaimNonce(walletID)).to.be.equal( - 2 + 2, ) }) @@ -1133,7 +1131,7 @@ describe("WalletRegistry - Inactivity", () => { it("should remain unchanged", async () => { expect( - await walletRegistry.inactivityClaimNonce(walletID) + await walletRegistry.inactivityClaimNonce(walletID), ).to.be.equal(2) }) }) diff --git a/solidity/ecdsa/test/WalletRegistry.Parameters.test.ts b/solidity/ecdsa/test/WalletRegistry.Parameters.test.ts index fabbccda15..5b23059e42 100644 --- a/solidity/ecdsa/test/WalletRegistry.Parameters.test.ts +++ b/solidity/ecdsa/test/WalletRegistry.Parameters.test.ts @@ -3,15 +3,15 @@ import { expect } from "chai" import { walletRegistryFixture } from "./fixtures" -import type { IWalletOwner } from "../typechain/IWalletOwner" -import type { Mock } from "./helpers/mock" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" import type { + IWalletOwner, WalletRegistry, WalletRegistryStub, IRandomBeacon, WalletRegistryGovernance, } from "../typechain" +import type { Mock } from "./helpers/mock" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" const { createSnapshot, restoreSnapshot } = helpers.snapshot @@ -26,7 +26,6 @@ describe("WalletRegistry - Parameters", async () => { let thirdParty: SignerWithAddress before("load test fixture", async () => { - // eslint-disable-next-line @typescript-eslint/no-extra-semi ;({ walletRegistry, walletRegistryGovernance, @@ -44,7 +43,7 @@ describe("WalletRegistry - Parameters", async () => { await expect( walletRegistry .connect(deployer) - .updateAuthorizationParameters(1, 2, 3) + .updateAuthorizationParameters(1, 2, 3), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -54,7 +53,7 @@ describe("WalletRegistry - Parameters", async () => { await expect( walletRegistry .connect(walletOwner.wallet) - .updateAuthorizationParameters(1, 2, 3) + .updateAuthorizationParameters(1, 2, 3), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -64,7 +63,7 @@ describe("WalletRegistry - Parameters", async () => { await expect( walletRegistry .connect(thirdParty) - .updateAuthorizationParameters(1, 2, 3) + .updateAuthorizationParameters(1, 2, 3), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -74,7 +73,7 @@ describe("WalletRegistry - Parameters", async () => { context("when called by the deployer", async () => { it("should revert", async () => { await expect( - walletRegistry.connect(deployer).updateDkgParameters(1, 2, 3, 4, 5) + walletRegistry.connect(deployer).updateDkgParameters(1, 2, 3, 4, 5), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -84,7 +83,7 @@ describe("WalletRegistry - Parameters", async () => { await expect( walletRegistry .connect(walletOwner.wallet) - .updateDkgParameters(1, 2, 3, 4, 5) + .updateDkgParameters(1, 2, 3, 4, 5), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -92,7 +91,7 @@ describe("WalletRegistry - Parameters", async () => { context("when called by a third party", async () => { it("should revert", async () => { await expect( - walletRegistry.connect(thirdParty).updateDkgParameters(1, 2, 3, 4, 5) + walletRegistry.connect(thirdParty).updateDkgParameters(1, 2, 3, 4, 5), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -106,7 +105,7 @@ describe("WalletRegistry - Parameters", async () => { context("when called by the deployer", async () => { it("should revert", async () => { await expect( - walletRegistry.connect(deployer).updateRewardParameters(1, 2) + walletRegistry.connect(deployer).updateRewardParameters(1, 2), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -116,7 +115,7 @@ describe("WalletRegistry - Parameters", async () => { await expect( walletRegistry .connect(walletOwner.wallet) - .updateRewardParameters(1, 2) + .updateRewardParameters(1, 2), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -124,7 +123,7 @@ describe("WalletRegistry - Parameters", async () => { context("when called by a third party", async () => { it("should revert", async () => { await expect( - walletRegistry.connect(thirdParty).updateRewardParameters(1, 2) + walletRegistry.connect(thirdParty).updateRewardParameters(1, 2), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -134,7 +133,7 @@ describe("WalletRegistry - Parameters", async () => { context("when called by the deployer", async () => { it("should revert", async () => { await expect( - walletRegistry.connect(deployer).updateSlashingParameters(1) + walletRegistry.connect(deployer).updateSlashingParameters(1), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -142,7 +141,9 @@ describe("WalletRegistry - Parameters", async () => { context("when called by the wallet owner", async () => { it("should revert", async () => { await expect( - walletRegistry.connect(walletOwner.wallet).updateSlashingParameters(1) + walletRegistry + .connect(walletOwner.wallet) + .updateSlashingParameters(1), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -150,7 +151,7 @@ describe("WalletRegistry - Parameters", async () => { context("when called by a third party", async () => { it("should revert", async () => { await expect( - walletRegistry.connect(thirdParty).updateSlashingParameters(1) + walletRegistry.connect(thirdParty).updateSlashingParameters(1), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -160,7 +161,9 @@ describe("WalletRegistry - Parameters", async () => { context("when called by the deployer", async () => { it("should revert", async () => { await expect( - walletRegistry.connect(deployer).updateWalletOwner(thirdParty.address) + walletRegistry + .connect(deployer) + .updateWalletOwner(thirdParty.address), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -170,7 +173,7 @@ describe("WalletRegistry - Parameters", async () => { await expect( walletRegistry .connect(walletOwner.wallet) - .updateWalletOwner(thirdParty.address) + .updateWalletOwner(thirdParty.address), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -180,7 +183,7 @@ describe("WalletRegistry - Parameters", async () => { await expect( walletRegistry .connect(thirdParty) - .updateWalletOwner(thirdParty.address) + .updateWalletOwner(thirdParty.address), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -192,7 +195,7 @@ describe("WalletRegistry - Parameters", async () => { await expect( walletRegistry .connect(deployer) - .updateGasParameters(4200, 4201, 4202, 4203, 4204) + .updateGasParameters(4200, 4201, 4202, 4203, 4204), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -202,7 +205,7 @@ describe("WalletRegistry - Parameters", async () => { await expect( walletRegistry .connect(walletOwner.wallet) - .updateGasParameters(4200, 4201, 4202, 4203, 4204) + .updateGasParameters(4200, 4201, 4202, 4203, 4204), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -212,7 +215,7 @@ describe("WalletRegistry - Parameters", async () => { await expect( walletRegistry .connect(thirdParty) - .updateGasParameters(4200, 4201, 4202, 4203, 4204) + .updateGasParameters(4200, 4201, 4202, 4203, 4204), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -224,7 +227,7 @@ describe("WalletRegistry - Parameters", async () => { await expect( walletRegistry .connect(deployer) - .upgradeRandomBeacon(thirdParty.address) + .upgradeRandomBeacon(thirdParty.address), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -234,7 +237,7 @@ describe("WalletRegistry - Parameters", async () => { await expect( walletRegistry .connect(walletOwner.wallet) - .upgradeRandomBeacon(thirdParty.address) + .upgradeRandomBeacon(thirdParty.address), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -244,7 +247,7 @@ describe("WalletRegistry - Parameters", async () => { await expect( walletRegistry .connect(thirdParty) - .upgradeRandomBeacon(thirdParty.address) + .upgradeRandomBeacon(thirdParty.address), ).to.be.revertedWith("Caller is not the governance") }) }) diff --git a/solidity/ecdsa/test/WalletRegistry.RandomBeacon.test.ts b/solidity/ecdsa/test/WalletRegistry.RandomBeacon.test.ts index 700b0b5230..4831e39545 100644 --- a/solidity/ecdsa/test/WalletRegistry.RandomBeacon.test.ts +++ b/solidity/ecdsa/test/WalletRegistry.RandomBeacon.test.ts @@ -1,22 +1,24 @@ +import { toBigInt } from "ethers" /* eslint-disable no-underscore-dangle */ import { ethers, helpers } from "hardhat" import { expect } from "chai" +import requireResult from "./helpers/chain" import { expectCalledWith } from "./helpers/mock" import { dkgState, walletRegistryFixture } from "./fixtures" import { upgradeRandomBeacon } from "./utils/governance" -import type { IWalletOwner } from "../typechain/IWalletOwner" -import type { Mock } from "./helpers/mock" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" import type { + IWalletOwner, IRandomBeacon, RandomBeaconStub, RandomBeaconStub__factory, WalletRegistry, WalletRegistryStub, } from "../typechain" -import type { BigNumber, ContractTransaction } from "ethers" +import type { Mock } from "./helpers/mock" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" +import type { ContractTransactionResponse } from "ethers" const { createSnapshot, restoreSnapshot } = helpers.snapshot @@ -27,7 +29,6 @@ describe("WalletRegistry - Random Beacon", async () => { let thirdParty: SignerWithAddress before("load test fixture", async () => { - // eslint-disable-next-line @typescript-eslint/no-extra-semi ;({ walletRegistry, walletOwner, @@ -38,13 +39,13 @@ describe("WalletRegistry - Random Beacon", async () => { describe("requestNewWallet", async () => { context("when requestRelayEntry reverts", async () => { - let tx: Promise + let tx: Promise before(async () => { await createSnapshot() await randomBeaconFake.requestRelayEntry.reverts( - "beacon internal error" + "beacon internal error", ) tx = walletRegistry.connect(walletOwner.wallet).requestNewWallet() @@ -62,7 +63,7 @@ describe("WalletRegistry - Random Beacon", async () => { }) context("when requestRelayEntry succeeds", async () => { - let tx: Promise + let tx: Promise before(async () => { await createSnapshot() @@ -80,7 +81,7 @@ describe("WalletRegistry - Random Beacon", async () => { it("should call random beacon", async () => { await expectCalledWith(randomBeaconFake.requestRelayEntry, [ - walletRegistry.address, + await walletRegistry.getAddress(), ]) }) }) @@ -98,7 +99,7 @@ describe("WalletRegistry - Random Beacon", async () => { context("when called by a third party", async () => { it("should revert", async () => { await expect( - walletRegistry.connect(thirdParty).__beaconCallback(123, 456) + walletRegistry.connect(thirdParty).__beaconCallback(123, 456), ).to.be.revertedWithCustomError(walletRegistry, "CallerNotRandomBeacon") }) }) @@ -109,14 +110,14 @@ describe("WalletRegistry - Random Beacon", async () => { await expect( walletRegistry .connect(randomBeaconFake.wallet) - .__beaconCallback(123, 456) + .__beaconCallback(123, 456), ).to.be.revertedWith("Current state is not AWAITING_SEED") }) }) context("when new wallet was requested", async () => { - const relayEntry = ethers.BigNumber.from(ethers.utils.randomBytes(32)) - let tx: ContractTransaction + const relayEntry = toBigInt(ethers.randomBytes(32)) + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -125,7 +126,7 @@ describe("WalletRegistry - Random Beacon", async () => { tx = await walletRegistry .connect(randomBeaconFake.wallet) - .__beaconCallback(relayEntry, 0) + .__beaconCallback(ethers.toBigInt(relayEntry), 0) }) after(async () => { @@ -134,22 +135,20 @@ describe("WalletRegistry - Random Beacon", async () => { it("should transition wallet creation state to `AWAITING_RESULT`", async () => { await expect( - await walletRegistry.getWalletCreationState() + await walletRegistry.getWalletCreationState(), ).to.be.equal(dkgState.AWAITING_RESULT) }) it("should set seed for wallet creation", async () => { await expect((await walletRegistry.getDkgData()).seed).to.be.equal( - relayEntry + relayEntry, ) }) it("should set start block for wallet creation", async () => { await expect( - ( - await walletRegistry.getDkgData() - ).startBlock - ).to.be.equal(tx.blockNumber) + (await walletRegistry.getDkgData()).startBlock, + ).to.be.equal(requireResult(await tx.wait()).blockNumber) }) it("should not emit DkgStateLocked event", async () => { @@ -179,10 +178,7 @@ describe("WalletRegistry - Random Beacon", async () => { const gasEstimate = await walletRegistry .connect(randomBeaconFake.wallet) - .estimateGas.__beaconCallback( - ethers.BigNumber.from(ethers.utils.randomBytes(32)), - 0 - ) + .__beaconCallback.estimateGas(toBigInt(ethers.randomBytes(32)), 0) await expect(gasEstimate).to.be.lte(expectedGasEstimate) }) @@ -211,15 +207,18 @@ describe("WalletRegistry - Random Beacon", async () => { }) it("should succeed", async () => { - const entry: BigNumber = ethers.BigNumber.from( - ethers.utils.randomBytes(32) - ) + // `submitRelayEntry` takes `bytes`, and the stub only keccak-hashes + // it, so the random bytes go in directly. Wrapping them in a + // BigNumber first was not just redundant: ethers renders one via + // `toHexString()`, which drops leading zero bytes, so roughly one run + // in 256 submitted a short entry. + const entry = ethers.randomBytes(32) const tx = await randomBeaconMock.submitRelayEntry(entry) await expect( tx, - "Callback failed; inspect callbackGasLimit value is sufficient" + "Callback failed; inspect callbackGasLimit value is sufficient", ).not.to.emit(randomBeaconMock, "CallbackFailed") }) }) @@ -228,7 +227,7 @@ describe("WalletRegistry - Random Beacon", async () => { }) async function mockRandomBeacon( - walletRegistry: WalletRegistry + walletRegistry: WalletRegistry, ): Promise { // This was a `smock.mock`, but it only ever supplied `.address` — none of // smock's storage-override surface (`setVariable`, `getVariable`) was used, @@ -237,7 +236,7 @@ async function mockRandomBeacon( await ethers.getContractFactory("RandomBeaconStub") ).deploy() - await upgradeRandomBeacon(walletRegistry, randomBeacon.address) + await upgradeRandomBeacon(walletRegistry, await randomBeacon.getAddress()) return randomBeacon as RandomBeaconStub } diff --git a/solidity/ecdsa/test/WalletRegistry.Rewards.test.ts b/solidity/ecdsa/test/WalletRegistry.Rewards.test.ts index cb310bded1..704024091a 100644 --- a/solidity/ecdsa/test/WalletRegistry.Rewards.test.ts +++ b/solidity/ecdsa/test/WalletRegistry.Rewards.test.ts @@ -6,7 +6,7 @@ import ecdsaData from "./data/ecdsa" import { createNewWallet } from "./utils/wallets" import { signOperatorInactivityClaim } from "./utils/inactivity" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" import type { Mock } from "./helpers/mock" import type { Operator, OperatorID } from "./utils/operators" import type { @@ -27,13 +27,13 @@ const { createSnapshot, restoreSnapshot } = helpers.snapshot async function rewardsBeneficiaryAddress( walletRegistry: WalletRegistry, staking: TokenStaking, - stakingProvider: string + stakingProvider: string, ): Promise { const allowlistAddr = await walletRegistry.allowlist() - if (allowlistAddr !== ethers.constants.AddressZero) { + if (allowlistAddr !== ethers.ZeroAddress) { const al = (await ethers.getContractAt( "Allowlist", - allowlistAddr + allowlistAddr, )) as Allowlist const r = await al.rolesOf(stakingProvider) return r.beneficiary @@ -64,7 +64,6 @@ describe("WalletRegistry - Rewards", () => { const rewardAmount = to1e18(100000) before("load test fixture", async () => { - // eslint-disable-next-line @typescript-eslint/no-extra-semi ;({ tToken, walletRegistry, @@ -81,7 +80,7 @@ describe("WalletRegistry - Rewards", () => { walletRegistry, walletOwner.wallet, randomBeacon, - walletPublicKey + walletPublicKey, )) membersIDs = members.map((member) => member.id) @@ -91,7 +90,7 @@ describe("WalletRegistry - Rewards", () => { context("when called for an unknown operator", () => { it("should revert", async () => { await expect( - walletRegistry.withdrawRewards(thirdParty.address) + walletRegistry.withdrawRewards(thirdParty.address), ).to.be.revertedWithCustomError(walletRegistry, "UnknownOperator") }) }) @@ -105,20 +104,19 @@ describe("WalletRegistry - Rewards", () => { await createSnapshot() operator = members[0].signer.address - stakingProvider = await walletRegistry.operatorToStakingProvider( - operator - ) + stakingProvider = + await walletRegistry.operatorToStakingProvider(operator) beneficiary = await rewardsBeneficiaryAddress( walletRegistry, staking, - stakingProvider + stakingProvider, ) // Allocate sortition pool rewards await tToken.connect(deployer).mint(deployer.address, rewardAmount) await tToken .connect(deployer) - .approveAndCall(sortitionPool.address, rewardAmount, []) + .approveAndCall(await sortitionPool.getAddress(), rewardAmount, "0x") }) after(async () => { @@ -135,7 +133,7 @@ describe("WalletRegistry - Rewards", () => { const balanceBefore = await tToken.balanceOf(beneficiary) const tx = await walletRegistry.withdrawRewards(stakingProvider) const balanceAfter = await tToken.balanceOf(beneficiary) - const received = balanceAfter.sub(balanceBefore) + const received = balanceAfter - balanceBefore await expect(tx) .to.emit(walletRegistry, "RewardsWithdrawn") @@ -148,7 +146,7 @@ describe("WalletRegistry - Rewards", () => { context("when called for an unknown operator", () => { it("should revert", async () => { await expect( - walletRegistry.availableRewards(thirdParty.address) + walletRegistry.availableRewards(thirdParty.address), ).to.be.revertedWithCustomError(walletRegistry, "UnknownOperator") }) }) @@ -162,20 +160,19 @@ describe("WalletRegistry - Rewards", () => { await createSnapshot() operator = members[0].signer.address - stakingProvider = await walletRegistry.operatorToStakingProvider( - operator - ) + stakingProvider = + await walletRegistry.operatorToStakingProvider(operator) beneficiary = await rewardsBeneficiaryAddress( walletRegistry, staking, - stakingProvider + stakingProvider, ) // Allocate sortition pool rewards await tToken.connect(deployer).mint(deployer.address, rewardAmount) await tToken .connect(deployer) - .approveAndCall(sortitionPool.address, rewardAmount, []) + .approveAndCall(await sortitionPool.getAddress(), rewardAmount, "0x") }) after(async () => { @@ -183,15 +180,14 @@ describe("WalletRegistry - Rewards", () => { }) it("should return the amount of available rewards", async () => { - let availableAmount = await walletRegistry.availableRewards( - stakingProvider - ) + let availableAmount = + await walletRegistry.availableRewards(stakingProvider) const balanceBefore = await tToken.balanceOf(beneficiary) await walletRegistry.withdrawRewards(stakingProvider) const balanceAfter = await tToken.balanceOf(beneficiary) - expect(availableAmount).to.equal(balanceAfter.sub(balanceBefore)) + expect(availableAmount).to.equal(balanceAfter - balanceBefore) availableAmount = await walletRegistry.availableRewards(stakingProvider) expect(availableAmount).to.equal(0) @@ -209,7 +205,7 @@ describe("WalletRegistry - Rewards", () => { await expect( walletRegistry .connect(thirdParty) - .withdrawIneligibleRewards(thirdParty.address) + .withdrawIneligibleRewards(thirdParty.address), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -228,7 +224,7 @@ describe("WalletRegistry - Rewards", () => { walletPublicKey, heartbeatFailed, inactiveMembersIndices, - groupThreshold + groupThreshold, ) await walletRegistry.connect(claimSender).notifyOperatorInactivity( @@ -240,14 +236,14 @@ describe("WalletRegistry - Rewards", () => { signingMembersIndices, }, 0, - membersIDs + membersIDs, ) // Allocate sortition pool rewards await tToken.connect(deployer).mint(deployer.address, rewardAmount) await tToken .connect(deployer) - .approveAndCall(sortitionPool.address, rewardAmount, []) + .approveAndCall(await sortitionPool.getAddress(), rewardAmount, "0x") }) it("should withdraw ineligible rewards", async () => { @@ -255,9 +251,8 @@ describe("WalletRegistry - Rewards", () => { // the balance of "ineligible rewards" available for withdrawal from // the Sortition Pool const operator = members[0].signer.address - const stakingProvider = await walletRegistry.operatorToStakingProvider( - operator - ) + const stakingProvider = + await walletRegistry.operatorToStakingProvider(operator) await walletRegistry.withdrawRewards(stakingProvider) expect(await tToken.balanceOf(thirdParty.address)).to.equal(0) diff --git a/solidity/ecdsa/test/WalletRegistry.Slashing.test.ts b/solidity/ecdsa/test/WalletRegistry.Slashing.test.ts index f29154343c..8c6944d019 100644 --- a/solidity/ecdsa/test/WalletRegistry.Slashing.test.ts +++ b/solidity/ecdsa/test/WalletRegistry.Slashing.test.ts @@ -3,58 +3,32 @@ import { helpers } from "hardhat" import { expect } from "chai" import ecdsaData from "./data/ecdsa" -import { constants, walletRegistryFixture } from "./fixtures" +import { params, walletRegistryFixture } from "./fixtures" import { createNewWallet } from "./utils/wallets" import type { WalletRegistry, IWalletOwner, TokenStaking, + Allowlist, T, IRandomBeacon, } from "../typechain" +import type { ContractTransactionResponse } from "ethers" import type { Mock } from "./helpers/mock" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" import type { Operator, OperatorID } from "./utils/operators" const { createSnapshot, restoreSnapshot } = helpers.snapshot const { to1e18 } = helpers.number -describe.skip("TokenStaking Integration (DEPRECATED TIP-092)", () => { - /** - * DEPRECATED: These tests validate TokenStaking.approveApplication() - * which does not exist in production TokenStaking v1.3.0-dev.16. - * - * Production State: - * - RandomBeacon/ECDSA applications are FROZEN (skipApplication = true) - * - approveApplication() method removed from production contract - * - Only TACo application remains functional in TokenStaking - * - * Migration: - * - Issue: #3839 "Migrate ECDSA tests to Allowlist mode" - * - New approach: walletRegistryFixture({ useAllowlist: true }) - * - * References: - * - TIP-092: Beta Staker Consolidation - * - TIP-100: TokenStaking sunset timeline - * - Allowlist.sol: Replacement authorization contract - * - * Implementation Status: - * - Dual-mode fixtures implemented and working - * - TypeScript compilation successful - * - Full test validation deferred pending Allowlist migration - * - Strategic migration tracked in issue #3839 - */ - // Original tests preserved for reference during migration - // Will be rewritten for Allowlist mode or archived -}) - describe("WalletRegistry - Slashing", () => { let walletRegistry: WalletRegistry let randomBeacon: Mock let walletOwner: Mock let thirdParty: SignerWithAddress let staking: TokenStaking + let allowlist: Allowlist let tToken: T let members: Operator[] @@ -67,7 +41,7 @@ describe("WalletRegistry - Slashing", () => { const rewardMultiplier = 30 before(async () => { - // eslint-disable-next-line @typescript-eslint/no-extra-semi + const fixture = await walletRegistryFixture({ useAllowlist: true }) ;({ walletRegistry, randomBeacon, @@ -75,12 +49,13 @@ describe("WalletRegistry - Slashing", () => { thirdParty, staking, tToken, - } = await walletRegistryFixture({ useAllowlist: true })) + } = fixture) + allowlist = fixture.allowlist! ;({ walletID, members } = await createNewWallet( walletRegistry, walletOwner.wallet, randomBeacon, - walletPublicKey + walletPublicKey, )) membersIDs = members.map((member) => member.id) @@ -98,8 +73,8 @@ describe("WalletRegistry - Slashing", () => { rewardMultiplier, thirdParty.address, walletID, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWithCustomError(walletRegistry, "CallerNotWalletOwner") }) }) @@ -116,78 +91,67 @@ describe("WalletRegistry - Slashing", () => { rewardMultiplier, thirdParty.address, walletID, - corruptedMembersIDs - ) + corruptedMembersIDs, + ), ).to.be.revertedWithCustomError( walletRegistry, - "InvalidWalletMembersIdentifiers" + "InvalidWalletMembersIdentifiers", ) }) }) - context.skip( - "when the passed wallet members identifiers are valid (skipped: TokenStaking slashing queue API differs from legacy tests)", - () => { - let notifierBalanceBefore - let notifierBalanceAfter - - before(async () => { - await createSnapshot() + context("when the passed wallet members identifiers are valid", () => { + let tx: ContractTransactionResponse + let notifierBalanceBefore: bigint + let notifierBalanceAfter: bigint - notifierBalanceBefore = await tToken.balanceOf(thirdParty.address) - await walletRegistry - .connect(walletOwner.wallet) - .seize( - amountToSlash, - rewardMultiplier, - thirdParty.address, - walletID, - membersIDs - ) - notifierBalanceAfter = await tToken.balanceOf(thirdParty.address) - }) - - after(async () => { - await restoreSnapshot() - }) - - it("should slash all group members", async () => { - expect(await staking.getSlashingQueueLength()).to.equal( - constants.groupSize - ) - }) - - it("should slash with correct amounts", async () => { - for (let i = 0; i < constants.groupSize; i++) { - const slashing = await staking.slashingQueue(i) - expect(slashing.amount).to.equal(amountToSlash) - } - }) - - it("should slash correct staking providers", async () => { - for (let i = 0; i < constants.groupSize; i++) { - const slashing = await staking.slashingQueue(i) - const expectedStakingProvider = - await walletRegistry.operatorToStakingProvider( - membersAddresses[i] - ) - - expect(slashing.stakingProvider).to.equal(expectedStakingProvider) - } - }) - - it("should send correct reward to notifier", async () => { - // Notification rewards are no longer configured in TokenStaking - // (pushNotificationReward/setNotificationReward methods removed). - // The notifier receives 0 reward. - const receivedReward = notifierBalanceAfter.sub( - notifierBalanceBefore + before(async () => { + await createSnapshot() + notifierBalanceBefore = await tToken.balanceOf(thirdParty.address) + tx = await walletRegistry + .connect(walletOwner.wallet) + .seize( + amountToSlash, + rewardMultiplier, + thirdParty.address, + walletID, + membersIDs, ) + notifierBalanceAfter = await tToken.balanceOf(thirdParty.address) + }) + + after(async () => { + await restoreSnapshot() + }) - expect(receivedReward).to.equal(0) - }) - } - ) + it("should not queue any staking provider for slashing (Allowlist-only providers carry no TokenStaking authorization)", async () => { + expect(await staking.getSlashingQueueLength()).to.equal(0) + }) + + it("should leave every member's Allowlist weight unchanged", async () => { + for (let i = 0; i < membersAddresses.length; i++) { + const memberAddress = membersAddresses[i] + const stakingProvider = + await walletRegistry.operatorToStakingProvider(memberAddress) + expect( + await allowlist.authorizedStake( + stakingProvider, + await walletRegistry.getAddress(), + ), + ).to.equal(params.minimumAuthorization) + expect( + await walletRegistry.eligibleStake(stakingProvider), + ).to.equal(params.minimumAuthorization) + } + }) + + it("should emit a zero notifier reward from the staking contract", async () => { + await expect(tx) + .to.emit(staking, "NotifierRewarded") + .withArgs(thirdParty.address, 0) + expect(notifierBalanceAfter - notifierBalanceBefore).to.equal(0) + }) + }) // TODO: Add a unit test ensuring `seize` call reverts if the staking // contract `seize` call reverts. diff --git a/solidity/ecdsa/test/WalletRegistry.Upgrade.test.ts b/solidity/ecdsa/test/WalletRegistry.Upgrade.test.ts index 8c4b325568..38df75fee6 100644 --- a/solidity/ecdsa/test/WalletRegistry.Upgrade.test.ts +++ b/solidity/ecdsa/test/WalletRegistry.Upgrade.test.ts @@ -1,21 +1,22 @@ import { deployments, ethers, upgrades, helpers } from "hardhat" import chai, { expect } from "chai" import chaiAsPromised from "chai-as-promised" -import { keccak256 } from "ethers/lib/utils" +import { keccak256 } from "ethers" +import requireResult from "./helpers/chain" import { params, walletRegistryFixture } from "./fixtures" import { noMisbehaved, signAndSubmitCorrectDkgResult } from "./utils/dkg" import ecdsaData from "./data/ecdsa" import { createNewWallet } from "./utils/wallets" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" -import type { WalletRegistry, WalletRegistryV2 } from "../typechain" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" +import type { Allowlist, WalletRegistry, WalletRegistryV2 } from "../typechain" import type { FactoryOptions } from "hardhat/types" -import type { Contract } from "ethers" +import type { BaseContract, Contract } from "ethers" import type { UpgradeProxyOptions } from "@openzeppelin/hardhat-upgrades/src/utils/options" const { mineBlocksTo } = helpers.time -const { AddressZero } = ethers.constants +const { ZeroAddress: AddressZero } = ethers chai.use(chaiAsPromised) @@ -24,7 +25,6 @@ describe("WalletRegistry - Upgrade", async () => { let EcdsaInactivity: Contract before(async () => { - // eslint-disable-next-line @typescript-eslint/no-extra-semi ;({ esdm: proxyAdminOwner } = await helpers.signers.getNamedSigners()) await deployments.fixture() EcdsaInactivity = await helpers.contracts.getContract("EcdsaInactivity") @@ -38,7 +38,9 @@ describe("WalletRegistry - Upgrade", async () => { await expect( upgradeProxy("WalletRegistry", "WalletRegistry", { factoryOpts: { - libraries: { EcdsaInactivity: EcdsaInactivity.address }, + libraries: { + EcdsaInactivity: await EcdsaInactivity.getAddress(), + }, signer: proxyAdminOwner, }, proxyOpts: { @@ -49,13 +51,16 @@ describe("WalletRegistry - Upgrade", async () => { }, unsafeAllow: ["external-library-linking"], }, - }) - ).to.be.rejectedWith(Error, "AllowlistAddressZero") + }), + ).to.be.revertedWithCustomError( + await helpers.contracts.getContract("WalletRegistry"), + "AllowlistAddressZero", + ) }) }) describe("T-005: Atomic upgrade without governance modifier (ISSUE #2)", () => { - let allowlist: Contract + let allowlist: Allowlist beforeEach(async () => { await deployments.fixture() @@ -63,7 +68,7 @@ describe("WalletRegistry - Upgrade", async () => { // Deploy a minimal Allowlist contract for testing const AllowlistFactory = await ethers.getContractFactory("Allowlist") allowlist = await AllowlistFactory.deploy() - await allowlist.deployed() + await allowlist.waitForDeployment() }) it("should allow initializeV2 via upgradeToAndCall without governance restriction", async () => { @@ -71,63 +76,67 @@ describe("WalletRegistry - Upgrade", async () => { // Expected to FAIL in RED phase because onlyGovernance modifier is still present // Expected to PASS in GREEN phase after modifier is removed - const walletRegistry = await helpers.contracts.getContract( - "WalletRegistry" - ) + const walletRegistry = + await helpers.contracts.getContract("WalletRegistry") const newWalletRegistry = await upgradeProxy( "WalletRegistry", "WalletRegistry", { factoryOpts: { - libraries: { EcdsaInactivity: EcdsaInactivity.address }, + libraries: { + EcdsaInactivity: await EcdsaInactivity.getAddress(), + }, signer: proxyAdminOwner, // Proxy admin owner, NOT governance }, proxyOpts: { constructorArgs: [AddressZero, AddressZero], call: { fn: "initializeV2", - args: [allowlist.address], // Valid allowlist address + args: [await allowlist.getAddress()], }, unsafeAllow: ["external-library-linking"], }, - } + }, ) // Verify upgrade succeeded - expect(newWalletRegistry.address).to.equal(walletRegistry.address) - expect(await newWalletRegistry.allowlist()).to.equal(allowlist.address) + expect(await newWalletRegistry.getAddress()).to.equal( + await walletRegistry.getAddress(), + ) + expect(await newWalletRegistry.getFunction("allowlist")()).to.equal( + await allowlist.getAddress(), + ) }) it("should prevent re-initialization with reinitializer(2) modifier", async () => { // First upgrade with initializeV2 await upgradeProxy("WalletRegistry", "WalletRegistry", { factoryOpts: { - libraries: { EcdsaInactivity: EcdsaInactivity.address }, + libraries: { EcdsaInactivity: await EcdsaInactivity.getAddress() }, signer: proxyAdminOwner, }, proxyOpts: { constructorArgs: [AddressZero, AddressZero], call: { fn: "initializeV2", - args: [allowlist.address], + args: [await allowlist.getAddress()], }, unsafeAllow: ["external-library-linking"], }, }) - const walletRegistry = await helpers.contracts.getContract( - "WalletRegistry" - ) + const walletRegistry = + await helpers.contracts.getContract("WalletRegistry") // Deploy another allowlist for re-initialization attempt const AllowlistFactory = await ethers.getContractFactory("Allowlist") const newAllowlist = await AllowlistFactory.deploy() - await newAllowlist.deployed() + await newAllowlist.waitForDeployment() // Attempt to call initializeV2 again should fail await expect( - walletRegistry.initializeV2(newAllowlist.address) + walletRegistry.initializeV2(await newAllowlist.getAddress()), ).to.be.revertedWith("Initializable: contract is already initialized") }) @@ -138,7 +147,9 @@ describe("WalletRegistry - Upgrade", async () => { await expect( upgradeProxy("WalletRegistry", "WalletRegistry", { factoryOpts: { - libraries: { EcdsaInactivity: EcdsaInactivity.address }, + libraries: { + EcdsaInactivity: await EcdsaInactivity.getAddress(), + }, signer: proxyAdminOwner, }, proxyOpts: { @@ -149,8 +160,11 @@ describe("WalletRegistry - Upgrade", async () => { }, unsafeAllow: ["external-library-linking"], }, - }) - ).to.be.rejectedWith(Error, "AllowlistAddressZero") + }), + ).to.be.revertedWithCustomError( + await helpers.contracts.getContract("WalletRegistry"), + "AllowlistAddressZero", + ) }) }) }) @@ -164,14 +178,16 @@ describe("WalletRegistry - Upgrade", async () => { await expect( upgradeProxy("WalletRegistry", "WalletRegistryV2MisplacedNewSlot", { factoryOpts: { - libraries: { EcdsaInactivity: EcdsaInactivity.address }, + libraries: { + EcdsaInactivity: await EcdsaInactivity.getAddress(), + }, signer: proxyAdminOwner, }, proxyOpts: { constructorArgs: [AddressZero, AddressZero], unsafeAllow: ["external-library-linking"], }, - }) + }), ).to.be.rejectedWith(Error, "New storage layout is incompatible") }) }) @@ -183,17 +199,19 @@ describe("WalletRegistry - Upgrade", async () => { await expect( upgradeProxy("WalletRegistry", "WalletRegistryV2MissingSlot", { factoryOpts: { - libraries: { EcdsaInactivity: EcdsaInactivity.address }, + libraries: { + EcdsaInactivity: await EcdsaInactivity.getAddress(), + }, signer: proxyAdminOwner, }, proxyOpts: { constructorArgs: [AddressZero, AddressZero], unsafeAllow: ["external-library-linking"], }, - }) + }), ).to.be.rejectedWith( Error, - "Deleted `_maliciousDkgResultNotificationRewardMultiplier`" + "Deleted `_maliciousDkgResultNotificationRewardMultiplier`", ) }) }) @@ -216,18 +234,17 @@ describe("WalletRegistry - Upgrade", async () => { await deployments.fixture() tokenStaking = await helpers.contracts.getContract("TokenStaking") - reimbursementPool = await helpers.contracts.getContract( - "ReimbursementPool" - ) + reimbursementPool = + await helpers.contracts.getContract("ReimbursementPool") walletRegistryGovernance = await helpers.contracts.getContract( - "WalletRegistryGovernance" + "WalletRegistryGovernance", ) walletRegistry = (await helpers.contracts.getContract( - "WalletRegistry" + "WalletRegistry", )) as WalletRegistry & WalletRegistryV2 expect(await walletRegistry.governance()).equal( - walletRegistryGovernance.address + await walletRegistryGovernance.getAddress(), ) newWalletRegistry = (await upgradeProxy( @@ -236,39 +253,46 @@ describe("WalletRegistry - Upgrade", async () => { { factoryOpts: { signer: proxyAdminOwner, - libraries: { EcdsaInactivity: EcdsaInactivity.address }, + libraries: { + EcdsaInactivity: await EcdsaInactivity.getAddress(), + }, }, proxyOpts: { - constructorArgs: [newSortitionPoolAddress, tokenStaking.address], + constructorArgs: [ + newSortitionPoolAddress, + await tokenStaking.getAddress(), + ], call: { fn: "initializeV2", args: [newRandomBeaconAddress, newVarValue], }, unsafeAllow: ["external-library-linking"], }, - } + }, )) as WalletRegistryV2 }) it("new instance should have the same address as the old one", async () => { - expect(newWalletRegistry.address).equal(walletRegistry.address) + expect(await newWalletRegistry.getAddress()).equal( + await walletRegistry.getAddress(), + ) }) it("should not update governance", async () => { expect(await walletRegistry.governance()).equal( - walletRegistryGovernance.address + await walletRegistryGovernance.getAddress(), ) }) it("should use the new value of the immutable variable", async () => { expect(await walletRegistry.sortitionPool()).to.be.equal( - newSortitionPoolAddress + newSortitionPoolAddress, ) }) it("should reinitialize existing variable", async () => { expect(await walletRegistry.randomBeacon()).to.be.equal( - newRandomBeaconAddress + newRandomBeaconAddress, ) }) @@ -278,45 +302,40 @@ describe("WalletRegistry - Upgrade", async () => { it("should not update already set variable", async () => { expect(await walletRegistry.reimbursementPool()).to.be.equal( - reimbursementPool.address + await reimbursementPool.getAddress(), ) }) it("should not update parameters from library", async () => { expect((await walletRegistry.dkgParameters()).seedTimeout).to.be.equal( - 11_520 + 11_520, ) expect(await walletRegistry.minimumAuthorization()).to.be.equal( - "40000000000000000000000" + "40000000000000000000000", ) }) it("should revert when V1's initializer is called", async () => { await expect( - newWalletRegistry.initialize(AddressZero, AddressZero, AddressZero) + newWalletRegistry.initialize(AddressZero, AddressZero, AddressZero), ).to.be.revertedWith("Initializable: contract is already initialized") }) it("should revert for removed function", async () => { - await expect(walletRegistry.notifySeedTimeout()).to.be.rejectedWith( - Error, - "Transaction reverted: function selector was not recognized and there's no fallback function" - ) + await expect( + walletRegistry.notifySeedTimeout(), + ).to.be.revertedWithoutReason() }) it("should execute updated function logic", async () => { await expect(walletRegistry.notifyDkgTimeout()).to.be.revertedWith( - "nice try, but no" + "nice try, but no", ) }) }) - // Skipped: this scenario needs `walletRegistryFixture({ useAllowlist: false })` so - // production `initializeV2(allowlist)` is not called (reinitializer(2) must stay for - // `WalletRegistryV2.initializeV2`). The packaged TokenStaking no longer exposes - // `stake` / `increaseAuthorization`, so operator registration via TokenStaking reverts. - describe.skip("when a contract gets upgraded during DKG", () => { + describe("when a contract gets upgraded during DKG", () => { describe("when a wallet is already registered", () => { const expectedExistingWalletData = ecdsaData.group1 const expectedNewWalletData = ecdsaData.group2 @@ -343,7 +362,7 @@ describe("WalletRegistry - Upgrade", async () => { walletRegistryV1, walletOwner.wallet, randomBeacon, - expectedExistingWalletData.publicKey + expectedExistingWalletData.publicKey, ) existingWalletID = existingWallet.walletID existingWalletMembersHash = existingWallet.dkgResult.membersHash @@ -353,13 +372,13 @@ describe("WalletRegistry - Upgrade", async () => { .connect(walletOwner.wallet) .requestNewWallet() - const relayEntry = ethers.utils.randomBytes(32) - const dkgSeed = ethers.BigNumber.from(keccak256(relayEntry)) + const relayEntry = ethers.randomBytes(32) + const dkgSeed = BigInt(keccak256(relayEntry)) // eslint-disable-next-line no-underscore-dangle await walletRegistryV1 .connect(randomBeacon.wallet) - .__beaconCallback(relayEntry, 0) + .__beaconCallback(ethers.toBigInt(relayEntry), 0) // Submit DKG result on Wallet Registry V1 const { @@ -370,8 +389,8 @@ describe("WalletRegistry - Upgrade", async () => { walletRegistryV1, expectedNewWalletData.publicKey, dkgSeed, - requestNewWalletTx.blockNumber, - noMisbehaved + requireResult(await requestNewWalletTx.wait()).blockNumber, + noMisbehaved, ) newWalletMembersHash = dkgResult.membersHash @@ -383,23 +402,28 @@ describe("WalletRegistry - Upgrade", async () => { { factoryOpts: { signer: proxyAdminOwner, - libraries: { EcdsaInactivity: EcdsaInactivity.address }, + libraries: { + EcdsaInactivity: await EcdsaInactivity.getAddress(), + }, }, proxyOpts: { - constructorArgs: [sortitionPool.address, staking.address], + constructorArgs: [ + await sortitionPool.getAddress(), + await staking.getAddress(), + ], call: { fn: "initializeV2", args: [AddressZero, "new variable set for new contract"], }, unsafeAllow: ["external-library-linking"], }, - } + }, )) as WalletRegistryV2 // Approve DKG result on Wallet Registry V2 await mineBlocksTo( - submitDkgResultTx.blockNumber + - params.dkgResultChallengePeriodLength + requireResult(await submitDkgResultTx.wait()).blockNumber + + params.dkgResultChallengePeriodLength, ) await walletRegistryV1.connect(submitter).approveDkgResult(dkgResult) @@ -434,13 +458,13 @@ describe("WalletRegistry - Upgrade", async () => { upgradeProxy("WalletRegistry", "WalletRegistryV2", { factoryOpts: { signer: (await helpers.signers.getNamedSigners()).deployer, - libraries: { EcdsaInactivity: EcdsaInactivity.address }, + libraries: { EcdsaInactivity: await EcdsaInactivity.getAddress() }, }, proxyOpts: { constructorArgs: [AddressZero, AddressZero], unsafeAllow: ["external-library-linking"], }, - }) + }), ).to.be.rejectedWith(Error, "Ownable: caller is not the owner") }) }) @@ -458,18 +482,18 @@ export interface UpgradesUpgradeOptions { async function upgradeProxy( currentContractName: string, newContractName: string, - opts?: UpgradesUpgradeOptions -): Promise { + opts?: UpgradesUpgradeOptions, +): Promise { const currentContract = await deployments.get(currentContractName) const newContract = await ethers.getContractFactory( opts?.contractName || newContractName, - opts?.factoryOpts + opts?.factoryOpts, ) return upgrades.upgradeProxy( currentContract.address, newContract, - opts?.proxyOpts + opts?.proxyOpts, ) } diff --git a/solidity/ecdsa/test/WalletRegistry.UpgradeV2Deploy.test.ts b/solidity/ecdsa/test/WalletRegistry.UpgradeV2Deploy.test.ts new file mode 100644 index 0000000000..619fb48164 --- /dev/null +++ b/solidity/ecdsa/test/WalletRegistry.UpgradeV2Deploy.test.ts @@ -0,0 +1,114 @@ +import { deployments, ethers, helpers } from "hardhat" +import chai, { expect } from "chai" +import chaiAsPromised from "chai-as-promised" + +import type { Allowlist, WalletRegistry } from "../typechain" + +chai.use(chaiAsPromised) + +// EIP-1967 implementation slot: bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1) +const IMPL_SLOT = + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc" + +// Covers deploy/17_upgrade_wallet_registry_v2.ts. The script is gated behind +// UPGRADE_WALLET_REGISTRY_V2 and is skipped by default, so it is otherwise +// never exercised by `yarn test` (WalletRegistry.Upgrade.test.ts drives its +// upgrade scenario directly via `upgrades.upgradeProxy`, not via this deploy +// script). This test actually runs the script's body on the hardhat network. +describe("deploy script - UpgradeWalletRegistryV2", () => { + let walletRegistry: WalletRegistry + let allowlist: Allowlist + let governanceBeforeUpgrade: string + + before(async () => { + // Ensure the shared base deployment exists (ReimbursementPool, RandomBeacon, + // TokenStaking, WalletRegistry, Allowlist, ...). This reuses the `::global` + // deployments.fixture() snapshot most other test files already populate; if + // this file happens to run first in the suite it deploys everything fresh. + await deployments.fixture() + + // Governance is not a named EOA here: deploy/10_transfer_governance.ts + // points WalletRegistry.governance() at the deployed + // WalletRegistryGovernance contract, not at the "governance" named + // account. The invariant under test is that the upgrade preserves + // whatever it already was, so capture it before running the upgrade + // fixture below. + const preUpgradeDeployment = await deployments.get("WalletRegistry") + const preUpgradeWalletRegistry = await ethers.getContractAt( + "WalletRegistry", + preUpgradeDeployment.address, + ) + governanceBeforeUpgrade = await preUpgradeWalletRegistry.governance() + + // The upgrade script is gated behind this env var and is skipped by default, + // so it is otherwise never run by `yarn test` (WalletRegistry.Upgrade.test.ts + // drives its upgrade scenario directly via `upgrades.upgradeProxy`, not via + // this deploy script). + process.env.UPGRADE_WALLET_REGISTRY_V2 = "true" + + // Run only the two additional scripts needed on top of the base deployment: + // - "TransferProxyAdminOwnership" (deploy 11): the upgrade script's testnet + // path requires `esdm` to already own the ProxyAdmin, and that transfer is + // not one of its declared `dependencies`. + // - "UpgradeWalletRegistryV2" (deploy 17): the script under test. + // `keepExistingDeployments: true` reuses the deployments from the base + // fixture above instead of wiping and trying to redeploy everything under + // this narrow tag set (which would fail: ReimbursementPool/RandomBeacon/ + // TokenStaking come from an external deploy step that is filtered by this + // same narrow `tags` argument and would be skipped). `fallbackToGlobal: + // false` ensures this specific tag combination actually executes instead of + // silently reverting to the (env-var-unaware) `::global` snapshot cached + // above. + await deployments.fixture( + ["UpgradeWalletRegistryV2", "TransferProxyAdminOwnership"], + { keepExistingDeployments: true, fallbackToGlobal: false }, + ) + + // The deployments.json record for "WalletRegistry" still carries the + // pre-upgrade ABI (the deploy script never re-saves it), so attach with + // the compiled V2 interface directly, exactly as the deploy script does + // for its own post-upgrade verification. + const walletRegistryDeployment = await deployments.get("WalletRegistry") + walletRegistry = await ethers.getContractAt( + "WalletRegistry", + walletRegistryDeployment.address, + ) + + allowlist = await helpers.contracts.getContract("Allowlist") + }) + + after(() => { + delete process.env.UPGRADE_WALLET_REGISTRY_V2 + }) + + it("should save the new implementation deployment artifact", async () => { + const implementationDeployment = await deployments.get( + "WalletRegistryV2Implementation", + ) + expect(implementationDeployment.address).to.not.equal(ethers.ZeroAddress) + }) + + it("should point the WalletRegistry proxy at the new implementation", async () => { + const implementationDeployment = await deployments.get( + "WalletRegistryV2Implementation", + ) + + const implSlot = await ethers.provider.getStorage( + await walletRegistry.getAddress(), + IMPL_SLOT, + ) + const currentImplementation = ethers.getAddress(`0x${implSlot.slice(-40)}`) + + expect(currentImplementation).to.equal(implementationDeployment.address) + }) + + it("should initialize the upgraded WalletRegistry with the deployed Allowlist address", async () => { + expect(await walletRegistry.allowlist()).to.equal( + await allowlist.getAddress(), + ) + }) + + it("should preserve WalletRegistry governance across the upgrade", async () => { + expect(await walletRegistry.governance()).to.equal(governanceBeforeUpgrade) + }) +}) diff --git a/solidity/ecdsa/test/WalletRegistry.WalletCreation.test.ts b/solidity/ecdsa/test/WalletRegistry.WalletCreation.test.ts index a9153f42ae..4829606351 100644 --- a/solidity/ecdsa/test/WalletRegistry.WalletCreation.test.ts +++ b/solidity/ecdsa/test/WalletRegistry.WalletCreation.test.ts @@ -1,6 +1,8 @@ import { ethers, helpers } from "hardhat" import { expect } from "chai" +import { toBeHex } from "ethers" +import requireResult from "./helpers/chain" import { constants, dkgState, params, walletRegistryFixture } from "./fixtures" import ecdsaData from "./data/ecdsa" import { @@ -16,20 +18,20 @@ import { selectGroup, hashUint32Array } from "./utils/groups" import { createNewWallet } from "./utils/wallets" import { submitRelayEntry } from "./utils/randomBeacon" import { assertGasUsed } from "./helpers/gas" -import { legacyTokenStakingAt } from "./utils/operators" import type { Operator } from "./utils/operators" -import type { BigNumber, ContractTransaction, Signer } from "ethers" -import type { IWalletOwner } from "../typechain/IWalletOwner" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import type { ContractTransactionResponse, Signer } from "ethers" import type { + IWalletOwner, SortitionPool, WalletRegistry, WalletRegistryStub, TokenStaking, + Allowlist, IRandomBeacon, DkgChallenger, } from "../typechain" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" import type { DkgResult, DkgResultSubmittedEventArgs } from "./utils/dkg" import type { Mock } from "./helpers/mock" @@ -37,47 +39,14 @@ const { to1e18 } = helpers.number const { mineBlocks, mineBlocksTo } = helpers.time const { createSnapshot, restoreSnapshot } = helpers.snapshot -const { keccak256 } = ethers.utils +const { keccak256 } = ethers const { provider } = ethers -describe.skip("TokenStaking Integration (DEPRECATED TIP-092)", () => { - /** - * DEPRECATED: These tests validate TokenStaking.approveApplication() - * which does not exist in production TokenStaking v1.3.0-dev.16. - * - * Production State: - * - RandomBeacon/ECDSA applications are FROZEN (skipApplication = true) - * - approveApplication() method removed from production contract - * - Only TACo application remains functional in TokenStaking - * - * Migration: - * - Issue: #3839 "Migrate ECDSA tests to Allowlist mode" - * - New approach: walletRegistryFixture({ useAllowlist: true }) - * - * References: - * - TIP-092: Beta Staker Consolidation - * - TIP-100: TokenStaking sunset timeline - * - Allowlist.sol: Replacement authorization contract - * - * Implementation Status: - * - Dual-mode fixtures implemented and working - * - TypeScript compilation successful - * - Full test validation deferred pending Allowlist migration - * - Strategic migration tracked in issue #3839 - */ - // Original tests preserved for reference during migration - // Will be rewritten for Allowlist mode or archived -}) - describe("WalletRegistry - Wallet Creation", async () => { const dkgTimeout: number = params.dkgResultSubmissionTimeout - const groupPublicKey: string = ethers.utils.hexValue( - ecdsaData.group1.publicKey - ) - const groupPublicKey2: string = ethers.utils.hexValue( - ecdsaData.group2.publicKey - ) - const walletID: string = ethers.utils.keccak256(groupPublicKey) + const groupPublicKey: string = ethers.toQuantity(ecdsaData.group1.publicKey) + const groupPublicKey2: string = ethers.toQuantity(ecdsaData.group2.publicKey) + const walletID: string = ethers.keccak256(groupPublicKey) const stubDkgResult: DkgResult = { submitterMemberIndex: 1, @@ -92,6 +61,7 @@ describe("WalletRegistry - Wallet Creation", async () => { let walletRegistry: WalletRegistryStub & WalletRegistry let sortitionPool: SortitionPool let staking: TokenStaking + let allowlist: Allowlist let randomBeacon: Mock let walletOwner: Mock @@ -101,7 +71,8 @@ describe("WalletRegistry - Wallet Creation", async () => { let operators: Operator[] before("load test fixture", async () => { - // eslint-disable-next-line @typescript-eslint/no-extra-semi + const fixture = await walletRegistryFixture({ useAllowlist: true }) + ;({ walletRegistry, sortitionPool, @@ -111,7 +82,8 @@ describe("WalletRegistry - Wallet Creation", async () => { thirdParty, operators, staking, - } = await walletRegistryFixture({ useAllowlist: true })) + } = fixture) + allowlist = fixture.allowlist! // This suite asserts on the gas `approveDkgResult` costs, and that path // calls into the wallet owner. Recording a call SSTOREs its calldata -- @@ -121,11 +93,26 @@ describe("WalletRegistry - Wallet Creation", async () => { await walletOwner.setRecording(false) }) + // Helper to assert that the submitter's Allowlist weight remains unchanged + async function expectAllowlistWeightUnchanged(operatorAddress: string) { + const stakingProvider = + await walletRegistry.operatorToStakingProvider(operatorAddress) + expect( + await allowlist.authorizedStake( + stakingProvider, + await walletRegistry.getAddress(), + ), + ).to.equal(params.minimumAuthorization) + expect(await walletRegistry.eligibleStake(stakingProvider)).to.equal( + params.minimumAuthorization, + ) + } + describe("requestNewWallet", async () => { context("when called by the deployer", async () => { it("should revert", async () => { await expect( - walletRegistry.connect(deployer).requestNewWallet() + walletRegistry.connect(deployer).requestNewWallet(), ).to.be.revertedWithCustomError(walletRegistry, "CallerNotWalletOwner") }) }) @@ -133,14 +120,14 @@ describe("WalletRegistry - Wallet Creation", async () => { context("when called by a third party", async () => { it("should revert", async () => { await expect( - walletRegistry.connect(thirdParty).requestNewWallet() + walletRegistry.connect(thirdParty).requestNewWallet(), ).to.be.revertedWithCustomError(walletRegistry, "CallerNotWalletOwner") }) }) context("when called by the wallet owner", async () => { context("with initial contract state", async () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before("start wallet creation", async () => { await createSnapshot() @@ -167,7 +154,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should transition DKG to AWAITING_SEED state", async () => { await expect( - await walletRegistry.getWalletCreationState() + await walletRegistry.getWalletCreationState(), ).to.be.equal(dkgState.AWAITING_SEED) }) @@ -196,19 +183,18 @@ describe("WalletRegistry - Wallet Creation", async () => { context("with relay entry not submitted", async () => { it("should revert with 'Current state is not IDLE' error", async () => { await expect( - walletRegistry.connect(walletOwner.wallet).requestNewWallet() + walletRegistry.connect(walletOwner.wallet).requestNewWallet(), ).to.be.revertedWith("Current state is not IDLE") }) context("with relay entry submitted", async () => { let startBlock: number - let dkgSeed: BigNumber + let dkgSeed: bigint before("submit relay entry", async () => { await createSnapshot() - ;({ startBlock, dkgSeed } = await submitRelayEntry( - walletRegistry - )) + ;({ startBlock, dkgSeed } = + await submitRelayEntry(walletRegistry)) }) after(async () => { @@ -218,7 +204,7 @@ describe("WalletRegistry - Wallet Creation", async () => { context("with dkg result not submitted", async () => { it("should revert with 'Current state is not IDLE' error", async () => { await expect( - walletRegistry.connect(walletOwner.wallet).requestNewWallet() + walletRegistry.connect(walletOwner.wallet).requestNewWallet(), ).to.be.revertedWith("Current state is not IDLE") }) }) @@ -235,7 +221,7 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, dkgSeed, startBlock, - noMisbehaved + noMisbehaved, )) }) @@ -248,7 +234,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await expect( walletRegistry .connect(walletOwner.wallet) - .requestNewWallet() + .requestNewWallet(), ).to.be.revertedWith("Current state is not IDLE") }) }) @@ -272,7 +258,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await expect( walletRegistry .connect(walletOwner.wallet) - .requestNewWallet() + .requestNewWallet(), ).to.not.be.reverted }) }) @@ -289,7 +275,7 @@ describe("WalletRegistry - Wallet Creation", async () => { // Mix operators to make the result malicious mixOperators(await selectGroup(sortitionPool, dkgSeed)), startBlock, - noMisbehaved + noMisbehaved, )) }) @@ -312,7 +298,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await expect( walletRegistry .connect(walletOwner.wallet) - .requestNewWallet() + .requestNewWallet(), ).to.be.revertedWith("Current state is not IDLE") }) }) @@ -333,7 +319,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should succeed", async () => { await expect( - walletRegistry.connect(walletOwner.wallet).requestNewWallet() + walletRegistry.connect(walletOwner.wallet).requestNewWallet(), ).not.to.be.reverted }) }) @@ -349,7 +335,7 @@ describe("WalletRegistry - Wallet Creation", async () => { context("with initial contract state", async () => { it("should return IDLE state", async () => { expect(await walletRegistry.getWalletCreationState()).to.be.equal( - dkgState.IDLE + dkgState.IDLE, ) }) }) @@ -367,13 +353,13 @@ describe("WalletRegistry - Wallet Creation", async () => { context("with relay entry not submitted", async () => { it("should return AWAITING_SEED state", async () => { expect(await walletRegistry.getWalletCreationState()).to.be.equal( - dkgState.AWAITING_SEED + dkgState.AWAITING_SEED, ) }) context("with relay entry submitted", async () => { let startBlock: number - let dkgSeed: BigNumber + let dkgSeed: bigint before(async () => { await createSnapshot() @@ -387,7 +373,7 @@ describe("WalletRegistry - Wallet Creation", async () => { context("with dkg result not submitted", async () => { it("should return AWAITING_RESULT state", async () => { expect(await walletRegistry.getWalletCreationState()).to.be.equal( - dkgState.AWAITING_RESULT + dkgState.AWAITING_RESULT, ) }) @@ -404,7 +390,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should return AWAITING_RESULT state", async () => { expect( - await walletRegistry.getWalletCreationState() + await walletRegistry.getWalletCreationState(), ).to.be.equal(dkgState.AWAITING_RESULT) }) }) @@ -421,7 +407,7 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, dkgSeed, startBlock, - noMisbehaved + noMisbehaved, )) }) @@ -432,7 +418,7 @@ describe("WalletRegistry - Wallet Creation", async () => { context("with dkg result not approved", async () => { it("should return CHALLENGE state", async () => { expect( - await walletRegistry.getWalletCreationState() + await walletRegistry.getWalletCreationState(), ).to.be.equal(dkgState.CHALLENGE) }) }) @@ -454,7 +440,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should return IDLE state", async () => { expect( - await walletRegistry.getWalletCreationState() + await walletRegistry.getWalletCreationState(), ).to.be.equal(dkgState.IDLE) }) }) @@ -471,7 +457,7 @@ describe("WalletRegistry - Wallet Creation", async () => { // Mix operators to make the result malicious mixOperators(await selectGroup(sortitionPool, dkgSeed)), startBlock, - noMisbehaved + noMisbehaved, )) }) @@ -491,7 +477,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should return AWAITING_RESULT state", async () => { expect( - await walletRegistry.getWalletCreationState() + await walletRegistry.getWalletCreationState(), ).to.be.equal(dkgState.AWAITING_RESULT) }) }) @@ -512,7 +498,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should return IDLE state", async () => { expect( - await walletRegistry.getWalletCreationState() + await walletRegistry.getWalletCreationState(), ).to.be.equal(dkgState.IDLE) }) }) @@ -538,7 +524,7 @@ describe("WalletRegistry - Wallet Creation", async () => { .connect(walletOwner.wallet) .requestNewWallet() - requestNewWalletStartBlock = tx.blockNumber + requestNewWalletStartBlock = requireResult(await tx.wait()).blockNumber }) after(async () => { @@ -584,7 +570,7 @@ describe("WalletRegistry - Wallet Creation", async () => { context("with relay entry submitted", async () => { let startBlock: number - let dkgSeed: BigNumber + let dkgSeed: bigint before(async () => { await createSnapshot() @@ -640,7 +626,7 @@ describe("WalletRegistry - Wallet Creation", async () => { before("submit dkg result", async () => { await createSnapshot() - let tx: ContractTransaction + let tx: ContractTransactionResponse ;({ transaction: tx, dkgResult, @@ -650,10 +636,12 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, dkgSeed, startBlock, - noMisbehaved + noMisbehaved, )) - resultSubmissionBlock = tx.blockNumber + resultSubmissionBlock = requireResult( + await tx.wait(), + ).blockNumber }) after(async () => { @@ -701,7 +689,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await mineBlocksTo( resultSubmissionBlock + - params.dkgResultChallengePeriodLength + params.dkgResultChallengePeriodLength, ) }) @@ -722,7 +710,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await mineBlocksTo( resultSubmissionBlock + params.dkgResultChallengePeriodLength + - 1 + 1, ) }) @@ -743,7 +731,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await mineBlocksTo( resultSubmissionBlock + - params.dkgResultChallengePeriodLength + params.dkgResultChallengePeriodLength, ) await walletRegistry @@ -773,7 +761,7 @@ describe("WalletRegistry - Wallet Creation", async () => { // Mix operators to make the result malicious. mixOperators(await selectGroup(sortitionPool, dkgSeed)), startBlock, - noMisbehaved + noMisbehaved, )) }) @@ -788,7 +776,9 @@ describe("WalletRegistry - Wallet Creation", async () => { await createSnapshot() const tx = await walletRegistry.challengeDkgResult(dkgResult) - challengeBlockNumber = tx.blockNumber + challengeBlockNumber = requireResult( + await tx.wait(), + ).blockNumber }) after(async () => { @@ -802,7 +792,8 @@ describe("WalletRegistry - Wallet Creation", async () => { await createSnapshot() await mineBlocksTo( - challengeBlockNumber + params.dkgResultSubmissionTimeout + challengeBlockNumber + + params.dkgResultSubmissionTimeout, ) }) @@ -814,7 +805,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await expect(await walletRegistry.hasDkgTimedOut()).to.be .false }) - } + }, ) context("after dkg result submission period", async () => { @@ -824,7 +815,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await mineBlocksTo( challengeBlockNumber + params.dkgResultSubmissionTimeout + - 1 + 1, ) }) @@ -854,8 +845,8 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, operators, 1, - noMisbehaved - ) + noMisbehaved, + ), ).to.be.revertedWith("Current state is not AWAITING_RESULT") }) }) @@ -878,14 +869,14 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, operators, 1, - noMisbehaved - ) + noMisbehaved, + ), ).to.be.revertedWith("Current state is not AWAITING_RESULT") }) context("with relay entry submitted", async () => { let startBlock: number - let dkgSeed: BigNumber + let dkgSeed: bigint before(async () => { await createSnapshot() @@ -908,14 +899,16 @@ describe("WalletRegistry - Wallet Creation", async () => { signers, "0x000000000000000000000000000000000000000000000000000000000000000073e661a208a8a565ca1e384059bd2ff7ff6886df081ff1229250099d388c83df", noMisbehaved, - startBlock + startBlock, )) // submitter has index 1 by default and we need to -1 it // given the array is indexed from 0 const submitter = signers[0].signer await expect( - walletRegistry.connect(submitter).submitDkgResult(dkgResult) + walletRegistry + .connect(submitter) + .submitDkgResult(dkgResult), ).to.be.revertedWith("Wallet public key must be non-zero") }) }) @@ -930,14 +923,16 @@ describe("WalletRegistry - Wallet Creation", async () => { signers, groupPublicKey.slice(0, -2), // remove the last byte noMisbehaved, - startBlock + startBlock, )) // submitter has index 1 by default and we need to -1 it // given the array is indexed from 0 const submitter = signers[0].signer await expect( - walletRegistry.connect(submitter).submitDkgResult(dkgResult) + walletRegistry + .connect(submitter) + .submitDkgResult(dkgResult), ).to.be.revertedWith("Invalid length of the public key") }) }) @@ -949,7 +944,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await walletRegistry.forceAddWallet( groupPublicKey, // wallet members do not matter for this test - "0x0000000000000000000000000000000000000000000000000000000000000000" + "0x0000000000000000000000000000000000000000000000000000000000000000", ) }) @@ -966,22 +961,24 @@ describe("WalletRegistry - Wallet Creation", async () => { signers, groupPublicKey, noMisbehaved, - startBlock + startBlock, )) // submitter has index 1 by default and we need to -1 it // given the array is indexed from 0 const submitter = signers[0].signer await expect( - walletRegistry.connect(submitter).submitDkgResult(dkgResult) + walletRegistry + .connect(submitter) + .submitDkgResult(dkgResult), ).to.be.revertedWith( - "Wallet with the given public key already exists" + "Wallet with the given public key already exists", ) }) }) context("with enough signatures on the result", async () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse let dkgResult: DkgResult let dkgResultHash: string @@ -998,7 +995,7 @@ describe("WalletRegistry - Wallet Creation", async () => { startBlock, noMisbehaved, 1, - constants.groupThreshold + constants.groupThreshold, )) }) @@ -1045,8 +1042,8 @@ describe("WalletRegistry - Wallet Creation", async () => { startBlock, noMisbehaved, 1, - constants.groupThreshold - 1 - ) + constants.groupThreshold - 1, + ), ).to.not.be.reverted }) }) @@ -1074,7 +1071,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should succeed for the last member", async () => { await assertSubmissionSucceeds(constants.groupSize - 1) }) - } + }, ) context("at the end of the submission period", async () => { @@ -1082,7 +1079,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await createSnapshot() await mineBlocksTo( - startBlock + params.dkgResultSubmissionTimeout - 1 + startBlock + params.dkgResultSubmissionTimeout - 1, ) }) @@ -1108,7 +1105,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await createSnapshot() await mineBlocksTo( - startBlock + params.dkgResultSubmissionTimeout + startBlock + params.dkgResultSubmissionTimeout, ) }) @@ -1139,7 +1136,7 @@ describe("WalletRegistry - Wallet Creation", async () => { before(async () => { await createSnapshot() - let tx: ContractTransaction + let tx: ContractTransactionResponse ;({ transaction: tx, dkgResult, @@ -1149,10 +1146,12 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, dkgSeed, startBlock, - noMisbehaved + noMisbehaved, )) - resultSubmissionBlock = tx.blockNumber + resultSubmissionBlock = requireResult( + await tx.wait(), + ).blockNumber }) after(async () => { @@ -1166,8 +1165,8 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, dkgSeed, startBlock, - noMisbehaved - ) + noMisbehaved, + ), ).to.be.revertedWith("Current state is not AWAITING_RESULT") }) @@ -1177,7 +1176,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await mineBlocksTo( resultSubmissionBlock + - params.dkgResultChallengePeriodLength + params.dkgResultChallengePeriodLength, ) await walletRegistry @@ -1196,8 +1195,8 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, dkgSeed, startBlock, - noMisbehaved - ) + noMisbehaved, + ), ).to.be.revertedWith("Sortition pool unlocked") }) }) @@ -1219,7 +1218,7 @@ describe("WalletRegistry - Wallet Creation", async () => { // Mix operators to make the result malicious. mixOperators(await selectGroup(sortitionPool, dkgSeed)), startBlock, - noMisbehaved + noMisbehaved, )) }) @@ -1233,10 +1232,11 @@ describe("WalletRegistry - Wallet Creation", async () => { before(async () => { await createSnapshot() - const tx = await walletRegistry.challengeDkgResult( - dkgResult - ) - challengeBlockNumber = tx.blockNumber + const tx = + await walletRegistry.challengeDkgResult(dkgResult) + challengeBlockNumber = requireResult( + await tx.wait(), + ).blockNumber }) after(async () => { @@ -1267,7 +1267,7 @@ describe("WalletRegistry - Wallet Creation", async () => { context("with a fresh dkg result", async () => { context("", async () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse let expectedEventArgs: DkgResultSubmittedEventArgs before(async () => { @@ -1282,7 +1282,7 @@ describe("WalletRegistry - Wallet Creation", async () => { ecdsaData.group2.publicKey, dkgSeed, startBlock, - noMisbehaved + noMisbehaved, ) tx = transaction @@ -1301,7 +1301,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should emit DkgResultSubmitted event", async () => { await expectDkgResultSubmittedEvent( tx, - expectedEventArgs + expectedEventArgs, ) }) }) @@ -1334,10 +1334,10 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should succeed for the last member", async () => { await assertSubmissionSucceeds( - constants.groupSize - 1 + constants.groupSize - 1, ) }) - } + }, ) context( @@ -1349,7 +1349,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await mineBlocksTo( submissionStartBlockNumber + params.dkgResultSubmissionTimeout - - 1 + 1, ) }) @@ -1367,10 +1367,10 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should succeed for the last member", async () => { await assertSubmissionSucceeds( - constants.groupSize - 1 + constants.groupSize - 1, ) }) - } + }, ) context("after the submission period", async () => { @@ -1379,7 +1379,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await mineBlocksTo( submissionStartBlockNumber + - params.dkgResultSubmissionTimeout + params.dkgResultSubmissionTimeout, ) }) @@ -1402,11 +1402,11 @@ describe("WalletRegistry - Wallet Creation", async () => { }) }) }) - } + }, ) context("with misbehaved members", async () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse let dkgResult: DkgResult let dkgResultHash: string @@ -1426,7 +1426,7 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, dkgSeed, startBlock, - misbehavedIndices + misbehavedIndices, )) }) @@ -1445,7 +1445,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should use close to 294 000 gas", async () => { await assertGasUsed(tx, 294_000) }) - } + }, ) }) }) @@ -1469,8 +1469,8 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, dkgSeed, startBlock, - noMisbehaved - ) + noMisbehaved, + ), ).to.be.revertedWith("DKG timeout already passed") }) }) @@ -1478,7 +1478,7 @@ describe("WalletRegistry - Wallet Creation", async () => { // Submission Test Helpers async function assertSubmissionSucceeds( - submitterIndex: number + submitterIndex: number, ): Promise { await createSnapshot() @@ -1492,7 +1492,7 @@ describe("WalletRegistry - Wallet Creation", async () => { dkgSeed, startBlock, noMisbehaved, - submitterIndex + submitterIndex, ) await expectDkgResultSubmittedEvent(tx, { @@ -1506,7 +1506,7 @@ describe("WalletRegistry - Wallet Creation", async () => { async function assertSubmissionReverts( submitterIndex: number, - message = "DKG timeout already passed" + message = "DKG timeout already passed", ): Promise { await expect( signAndSubmitCorrectDkgResult( @@ -1515,8 +1515,8 @@ describe("WalletRegistry - Wallet Creation", async () => { dkgSeed, startBlock, noMisbehaved, - submitterIndex - ) + submitterIndex, + ), ).to.be.revertedWith(message) } }) @@ -1528,7 +1528,7 @@ describe("WalletRegistry - Wallet Creation", async () => { context("with initial contract state", async () => { it("should revert with 'Current state is not CHALLENGE' error", async () => { await expect( - walletRegistry.approveDkgResult(stubDkgResult) + walletRegistry.approveDkgResult(stubDkgResult), ).to.be.revertedWith("Current state is not CHALLENGE") }) }) @@ -1546,13 +1546,13 @@ describe("WalletRegistry - Wallet Creation", async () => { context("with relay entry not submitted", async () => { it("should revert with 'Current state is not CHALLENGE' error", async () => { await expect( - walletRegistry.approveDkgResult(stubDkgResult) + walletRegistry.approveDkgResult(stubDkgResult), ).to.be.revertedWith("Current state is not CHALLENGE") }) context("with relay entry submitted", async () => { let startBlock: number - let dkgSeed: BigNumber + let dkgSeed: bigint before("submit relay entry", async () => { await createSnapshot() @@ -1565,14 +1565,14 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should revert with 'Current state is not CHALLENGE' error", async () => { await expect( - walletRegistry.approveDkgResult(stubDkgResult) + walletRegistry.approveDkgResult(stubDkgResult), ).to.be.revertedWith("Current state is not CHALLENGE") }) context("with dkg result not submitted", async () => { it("should revert with 'Current state is not CHALLENGE' error", async () => { await expect( - walletRegistry.approveDkgResult(stubDkgResult) + walletRegistry.approveDkgResult(stubDkgResult), ).to.be.revertedWith("Current state is not CHALLENGE") }) }) @@ -1582,14 +1582,14 @@ describe("WalletRegistry - Wallet Creation", async () => { let dkgResultHash: string let dkgResult: DkgResult let submitter: SignerWithAddress - let submitterInitialBalance: BigNumber + let submitterInitialBalance: bigint const submitterIndex = 1 before(async () => { await createSnapshot() - let tx: ContractTransaction + let tx: ContractTransactionResponse ;({ transaction: tx, dkgResult, @@ -1602,10 +1602,10 @@ describe("WalletRegistry - Wallet Creation", async () => { dkgSeed, startBlock, noMisbehaved, - submitterIndex + submitterIndex, )) - resultSubmissionBlock = tx.blockNumber + resultSubmissionBlock = requireResult(await tx.wait()).blockNumber }) after(async () => { @@ -1619,7 +1619,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await mineBlocksTo( resultSubmissionBlock + params.dkgResultChallengePeriodLength - - 1 + 1, ) }) @@ -1629,7 +1629,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should revert with 'Challenge period has not passed yet' error", async () => { await expect( - walletRegistry.connect(submitter).approveDkgResult(dkgResult) + walletRegistry.connect(submitter).approveDkgResult(dkgResult), ).to.be.revertedWith("Challenge period has not passed yet") }) }) @@ -1639,7 +1639,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await createSnapshot() await mineBlocksTo( - resultSubmissionBlock + params.dkgResultChallengePeriodLength + resultSubmissionBlock + params.dkgResultChallengePeriodLength, ) }) @@ -1648,7 +1648,7 @@ describe("WalletRegistry - Wallet Creation", async () => { }) context("when called by a DKG result submitter", async () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1676,7 +1676,7 @@ describe("WalletRegistry - Wallet Creation", async () => { const wallet = await walletRegistry.getWallet(walletID) await expect(wallet.membersIdsHash).to.be.equal( - hashUint32Array(dkgResult.members) + hashUint32Array(dkgResult.members), ) }) @@ -1693,13 +1693,13 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should refund ETH to a submitter", async () => { const postDkgResultApprovalSubmitterInitialBalance = await provider.getBalance(await submitter.getAddress()) - const diff = postDkgResultApprovalSubmitterInitialBalance.sub( + const diff = + postDkgResultApprovalSubmitterInitialBalance - submitterInitialBalance - ) expect(diff).to.be.gt(0) expect(diff).to.be.lt( - ethers.utils.parseUnits("1200000", "gwei") // 0.0012 ETH + ethers.parseUnits("1200000", "gwei"), // 0.0012 ETH ) }) @@ -1708,7 +1708,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should not mark properly behaving operators as ineligible for rewards", async () => { await expect(tx).not.to.emit( sortitionPool, - "IneligibleForRewards" + "IneligibleForRewards", ) }) @@ -1732,7 +1732,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await createSnapshot() await mineBlocks( - params.dkgSubmitterPrecedencePeriodLength - 1 + params.dkgSubmitterPrecedencePeriodLength - 1, ) }) @@ -1744,15 +1744,15 @@ describe("WalletRegistry - Wallet Creation", async () => { await expect( walletRegistry .connect(thirdParty) - .approveDkgResult(dkgResult) + .approveDkgResult(dkgResult), ).to.be.revertedWith("Only submitter can approve now") }) - } + }, ) context("when the third party is eligible", async () => { - let tx: ContractTransaction - let thirdPartyInitialBalance: BigNumber + let tx: ContractTransactionResponse + let thirdPartyInitialBalance: bigint before(async () => { await createSnapshot() @@ -1760,7 +1760,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await mineBlocks(params.dkgSubmitterPrecedencePeriodLength) thirdPartyInitialBalance = await provider.getBalance( - await thirdParty.getAddress() + await thirdParty.getAddress(), ) tx = await walletRegistry @@ -1783,18 +1783,16 @@ describe("WalletRegistry - Wallet Creation", async () => { await provider.getBalance(await thirdParty.getAddress()) const { dkgResultSubmissionGas } = await walletRegistry.gasParameters() - const feeForDkgSubmission = dkgResultSubmissionGas.mul( - tx.gasPrice - ) + const feeForDkgSubmission = + dkgResultSubmissionGas * tx.gasPrice // submission part was done by someone else and this is why // we add submission dkg fee to the initial balance const diff = - postDkgResultApprovalThirdPartyInitialBalance.sub( - thirdPartyInitialBalance.add(feeForDkgSubmission) - ) + postDkgResultApprovalThirdPartyInitialBalance - + (thirdPartyInitialBalance + feeForDkgSubmission) expect(diff).to.be.gt(0) expect(diff).to.be.lt( - ethers.utils.parseUnits("1000000", "gwei") // 0,001 ETH + ethers.parseUnits("1000000", "gwei"), // 0,001 ETH ) }) }) @@ -1825,12 +1823,12 @@ describe("WalletRegistry - Wallet Creation", async () => { mixOperators(await selectGroup(sortitionPool, dkgSeed)), startBlock, noMisbehaved, - maliciousSubmitter + maliciousSubmitter, ) await walletRegistry.challengeDkgResult(maliciousDkgResult) - let tx: ContractTransaction + let tx: ContractTransactionResponse ;({ transaction: tx, dkgResult, @@ -1842,10 +1840,10 @@ describe("WalletRegistry - Wallet Creation", async () => { dkgSeed, startBlock, noMisbehaved, - anotherSubmitterIndex + anotherSubmitterIndex, )) - resultSubmissionBlock = tx.blockNumber + resultSubmissionBlock = requireResult(await tx.wait()).blockNumber }) after(async () => { @@ -1859,7 +1857,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await mineBlocksTo( resultSubmissionBlock + params.dkgResultChallengePeriodLength - - 1 + 1, ) }) @@ -1871,24 +1869,24 @@ describe("WalletRegistry - Wallet Creation", async () => { await expect( walletRegistry .connect(anotherSubmitter) - .approveDkgResult(dkgResult) + .approveDkgResult(dkgResult), ).to.be.revertedWith("Challenge period has not passed yet") }) }) context("with challenge period passed", async () => { - let tx: ContractTransaction - let initalAnotherSubmitterBalance: BigNumber + let tx: ContractTransactionResponse + let initalAnotherSubmitterBalance: bigint before(async () => { await createSnapshot() await mineBlocksTo( - resultSubmissionBlock + params.dkgResultChallengePeriodLength + resultSubmissionBlock + params.dkgResultChallengePeriodLength, ) initalAnotherSubmitterBalance = await provider.getBalance( - await anotherSubmitter.getAddress() + await anotherSubmitter.getAddress(), ) tx = await walletRegistry @@ -1910,7 +1908,7 @@ describe("WalletRegistry - Wallet Creation", async () => { const wallet = await walletRegistry.getWallet(walletID) await expect(wallet.membersIdsHash).to.be.equal( - hashUint32Array(dkgResult.members) + hashUint32Array(dkgResult.members), ) }) @@ -1929,26 +1927,23 @@ describe("WalletRegistry - Wallet Creation", async () => { await provider.getBalance(await anotherSubmitter.getAddress()) const { dkgResultSubmissionGas } = await walletRegistry.gasParameters() - const feeForDkgSubmission = dkgResultSubmissionGas.mul( - tx.gasPrice - ) + const feeForDkgSubmission = dkgResultSubmissionGas * tx.gasPrice // submission part was done by someone else and this is why // we add submission dkg fee to the initial balance const diff = - postDkgResultApprovalAnotherSubmitterInitialBalance.sub( - initalAnotherSubmitterBalance.add(feeForDkgSubmission) - ) + postDkgResultApprovalAnotherSubmitterInitialBalance - + (initalAnotherSubmitterBalance + feeForDkgSubmission) expect(diff).to.be.gt(0) expect(diff).to.be.lt( - ethers.utils.parseUnits("2000000", "gwei") // 0,002 ETH + ethers.parseUnits("2000000", "gwei"), // 0,002 ETH ) }) }) }) context("with max periods duration", async () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse let dkgResultHash: string let submitter: SignerWithAddress @@ -1964,7 +1959,7 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, dkgSeed, startBlock, - noMisbehaved + noMisbehaved, )) await mineBlocks(params.dkgResultChallengePeriodLength) @@ -1994,10 +1989,10 @@ describe("WalletRegistry - Wallet Creation", async () => { context("with misbehaved operators", async () => { const misbehavedIndices = [2, 9, 11, 30, 60, 64] let misbehavedIds: number[] - let tx: ContractTransaction + let tx: ContractTransactionResponse let dkgResult: DkgResult let submitter: SignerWithAddress - let submitterInitialBalance: BigNumber + let submitterInitialBalance: bigint before(async () => { await createSnapshot() @@ -2009,11 +2004,11 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, dkgSeed, startBlock, - misbehavedIndices + misbehavedIndices, )) misbehavedIds = misbehavedIndices.map( - (i) => dkgResult.members[i - 1] + (i) => dkgResult.members[i - 1], ) await mineBlocks(params.dkgResultChallengePeriodLength) @@ -2037,7 +2032,7 @@ describe("WalletRegistry - Wallet Creation", async () => { expectedMembers.splice(58, 1) // index -6 expect( - (await walletRegistry.getWallet(walletID)).membersIdsHash + (await walletRegistry.getWallet(walletID)).membersIdsHash, ).to.be.equal(hashUint32Array(expectedMembers)) }) @@ -2057,13 +2052,13 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should refund ETH to a submitter", async () => { const postDkgResultApprovalSubmitterInitialBalance = await provider.getBalance(await submitter.getAddress()) - const diff = postDkgResultApprovalSubmitterInitialBalance.sub( + const diff = + postDkgResultApprovalSubmitterInitialBalance - submitterInitialBalance - ) - expect(diff).to.be.gt(ethers.utils.parseUnits("-1000000", "gwei")) // -0,001 ETH + expect(diff).to.be.gt(ethers.parseUnits("-1000000", "gwei")) // -0,001 ETH expect(diff).to.be.lt( - ethers.utils.parseUnits("1000000", "gwei") // 0,001 ETH + ethers.parseUnits("1000000", "gwei"), // 0,001 ETH ) }) @@ -2081,7 +2076,7 @@ describe("WalletRegistry - Wallet Creation", async () => { let dkgResult: DkgResult let submitter: SignerWithAddress - let tx: Promise + let tx: Promise before(async () => { await createSnapshot() @@ -2091,7 +2086,7 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, dkgSeed, startBlock, - misbehavedIndices + misbehavedIndices, )) await mineBlocks(params.dkgResultChallengePeriodLength) @@ -2112,7 +2107,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should use close to 330 000 gas", async () => { await assertGasUsed(await tx, 330_000, 15_000) }) - } + }, ) // This case shouldn't happen in real life. When a result is submitted @@ -2130,7 +2125,7 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, dkgSeed, startBlock, - misbehavedIndices + misbehavedIndices, )) await mineBlocks(params.dkgResultChallengePeriodLength) @@ -2142,7 +2137,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should succeed", async () => { await expect( - walletRegistry.connect(submitter).approveDkgResult(dkgResult) + walletRegistry.connect(submitter).approveDkgResult(dkgResult), ).to.not.be.reverted }) }) @@ -2160,7 +2155,7 @@ describe("WalletRegistry - Wallet Creation", async () => { walletRegistry, walletOwner.wallet, randomBeacon, - existingWalletPublicKey + existingWalletPublicKey, )) await expect(await walletRegistry.isWalletRegistered(existingWalletID)) @@ -2173,7 +2168,7 @@ describe("WalletRegistry - Wallet Creation", async () => { context("with new wallet creation started", async () => { let startBlock: number - let dkgSeed: BigNumber + let dkgSeed: bigint before( "request new wallet creation and submit relay entry", @@ -2181,7 +2176,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await createSnapshot() await walletRegistry.connect(walletOwner.wallet).requestNewWallet() ;({ startBlock, dkgSeed } = await submitRelayEntry(walletRegistry)) - } + }, ) after(async () => { @@ -2191,7 +2186,7 @@ describe("WalletRegistry - Wallet Creation", async () => { context("with dkg result not submitted", async () => { it("should revert with 'Current state is not CHALLENGE' error", async () => { await expect( - walletRegistry.approveDkgResult(stubDkgResult) + walletRegistry.approveDkgResult(stubDkgResult), ).to.be.revertedWith("Current state is not CHALLENGE") }) }) @@ -2200,7 +2195,7 @@ describe("WalletRegistry - Wallet Creation", async () => { let dkgResultHash: string let dkgResult: DkgResult let submitter: SignerWithAddress - let submitterInitialBalance: BigNumber + let submitterInitialBalance: bigint const newResultPublicKey = ecdsaData.group2.publicKey const newWalletID = keccak256(newResultPublicKey) @@ -2215,7 +2210,7 @@ describe("WalletRegistry - Wallet Creation", async () => { dkgSeed, startBlock, noMisbehaved, - newResultSubmitterIndex + newResultSubmitterIndex, )) await mineBlocks(params.dkgResultChallengePeriodLength) @@ -2226,7 +2221,7 @@ describe("WalletRegistry - Wallet Creation", async () => { }) context("when called by a DKG result submitter", async () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2254,7 +2249,7 @@ describe("WalletRegistry - Wallet Creation", async () => { const wallet = await walletRegistry.getWallet(newWalletID) await expect(wallet.membersIdsHash).to.be.equal( - hashUint32Array(dkgResult.members) + hashUint32Array(dkgResult.members), ) }) @@ -2271,13 +2266,13 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should refund ETH to a submitter", async () => { const postDkgResultApprovalSubmitterInitialBalance = await provider.getBalance(await submitter.getAddress()) - const diff = postDkgResultApprovalSubmitterInitialBalance.sub( + const diff = + postDkgResultApprovalSubmitterInitialBalance - submitterInitialBalance - ) expect(diff).to.be.gt(0) expect(diff).to.be.lt( - ethers.utils.parseUnits("1200000", "gwei") // 0.0012 ETH + ethers.parseUnits("1200000", "gwei"), // 0.0012 ETH ) }) }) @@ -2292,14 +2287,16 @@ describe("WalletRegistry - Wallet Creation", async () => { let dkgResult: DkgResult let dkgResultHash: string let startBlock: number - let dkgSeed: BigNumber + let dkgSeed: bigint before("setup malicious DKG result", async () => { await createSnapshot() // Deploy challenger contract const DkgChallenger = await ethers.getContractFactory("DkgChallenger") - dkgChallenger = await DkgChallenger.deploy(walletRegistry.address) + dkgChallenger = await DkgChallenger.deploy( + await walletRegistry.getAddress(), + ) // Request new wallet await walletRegistry.connect(walletOwner.wallet).requestNewWallet() @@ -2313,7 +2310,7 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, mixOperators(await selectGroup(sortitionPool, dkgSeed)), startBlock, - noMisbehaved + noMisbehaved, )) }) @@ -2329,8 +2326,8 @@ describe("WalletRegistry - Wallet Creation", async () => { .to.emit(walletRegistry, "DkgResultChallenged") .withArgs( dkgResultHash, - dkgChallenger.address, - "Invalid group members" + await dkgChallenger.getAddress(), + "Invalid group members", ) }) }) @@ -2338,7 +2335,7 @@ describe("WalletRegistry - Wallet Creation", async () => { context("with no wallets registered", async () => { it("should revert with 'Current state is not CHALLENGE'", async () => { await expect( - walletRegistry.challengeDkgResult(stubDkgResult) + walletRegistry.challengeDkgResult(stubDkgResult), ).to.be.revertedWith("Current state is not CHALLENGE") }) @@ -2355,19 +2352,18 @@ describe("WalletRegistry - Wallet Creation", async () => { context("with relay entry not submitted", async () => { it("should revert with 'Current state is not CHALLENGE'", async () => { await expect( - walletRegistry.challengeDkgResult(stubDkgResult) + walletRegistry.challengeDkgResult(stubDkgResult), ).to.be.revertedWith("Current state is not CHALLENGE") }) context("with relay entry submitted", async () => { let startBlock: number - let dkgSeed: BigNumber + let dkgSeed: bigint before("submit relay entry", async () => { await createSnapshot() - ;({ startBlock, dkgSeed } = await submitRelayEntry( - walletRegistry - )) + ;({ startBlock, dkgSeed } = + await submitRelayEntry(walletRegistry)) }) after(async () => { @@ -2377,7 +2373,7 @@ describe("WalletRegistry - Wallet Creation", async () => { context("with dkg result not submitted", async () => { it("should revert with 'Current state is not CHALLENGE'", async () => { await expect( - walletRegistry.challengeDkgResult(stubDkgResult) + walletRegistry.challengeDkgResult(stubDkgResult), ).to.be.revertedWith("Current state is not CHALLENGE") }) }) @@ -2391,7 +2387,7 @@ describe("WalletRegistry - Wallet Creation", async () => { before(async () => { await createSnapshot() - let tx: ContractTransaction + let tx: ContractTransactionResponse ;({ transaction: tx, dkgResult, @@ -2403,10 +2399,12 @@ describe("WalletRegistry - Wallet Creation", async () => { // Mix operators to make the result malicious. mixOperators(await selectGroup(sortitionPool, dkgSeed)), startBlock, - noMisbehaved + noMisbehaved, )) - resultSubmissionBlock = tx.blockNumber + resultSubmissionBlock = requireResult( + await tx.wait(), + ).blockNumber }) after(async () => { @@ -2414,70 +2412,55 @@ describe("WalletRegistry - Wallet Creation", async () => { }) context("at the beginning of challenge period", async () => { - context.skip( - "called by a third party (skipped: no processSlashing on dev TokenStaking)", - async () => { - let challengeTx: ContractTransaction - let slashingTx: ContractTransaction + context("called by a third party", async () => { + let challengeTx: ContractTransactionResponse - before(async () => { - await createSnapshot() - - challengeTx = await walletRegistry - .connect(thirdParty) - .challengeDkgResult(dkgResult) + before(async () => { + await createSnapshot() - slashingTx = await legacyTokenStakingAt( - staking, - thirdParty - ).processSlashing(1) - }) + challengeTx = await walletRegistry + .connect(thirdParty) + .challengeDkgResult(dkgResult) + }) - after(async () => { - await restoreSnapshot() - }) + after(async () => { + await restoreSnapshot() + }) - it("should emit DkgResultChallenged event", async () => { - await expect(challengeTx) - .to.emit(walletRegistry, "DkgResultChallenged") - .withArgs( - dkgResultHash, - await thirdParty.getAddress(), - "Invalid group members" - ) - }) + it("should emit DkgResultChallenged event", async () => { + await expect(challengeTx) + .to.emit(walletRegistry, "DkgResultChallenged") + .withArgs( + dkgResultHash, + await thirdParty.getAddress(), + "Invalid group members", + ) + }) - it("should not unlock the sortition pool", async () => { - await expect(await sortitionPool.isLocked()).to.be.true - }) + it("should not unlock the sortition pool", async () => { + await expect(await sortitionPool.isLocked()).to.be.true + }) - it("should emit DkgMaliciousResultSlashed event", async () => { - await expect(challengeTx) - .to.emit(walletRegistry, "DkgMaliciousResultSlashed") - .withArgs(dkgResultHash, to1e18(400), submitter.address) - }) + it("should emit DkgMaliciousResultSlashed event", async () => { + await expect(challengeTx) + .to.emit(walletRegistry, "DkgMaliciousResultSlashed") + .withArgs(dkgResultHash, to1e18(400), submitter.address) + }) - it("should reward the notifier", async () => { - await expect(challengeTx) - .to.emit(staking, "NotifierRewarded") - .withArgs(thirdParty.address, 0) - }) + it("should emit a zero notifier reward", async () => { + await expect(challengeTx) + .to.emit(staking, "NotifierRewarded") + .withArgs(thirdParty.address, 0) + }) - it("should slash malicious result submitter", async () => { - const stakingProvider = - await walletRegistry.operatorToStakingProvider( - submitter.address - ) - await expect(slashingTx) - .to.emit(staking, "TokensSeized") - .withArgs(stakingProvider, to1e18(400), false) - }) + it("should preserve the submitter's Allowlist weight", async () => { + await expectAllowlistWeightUnchanged(submitter.address) + }) - it("should use close to 1 720 000 gas", async () => { - await assertGasUsed(challengeTx, 1_720_000, 80_000) - }) - } - ) + it("should use close to 1 720 000 gas", async () => { + await assertGasUsed(challengeTx, 1_720_000, 80_000) + }) + }) }) context("at the end of challenge period", async () => { @@ -2487,7 +2470,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await mineBlocksTo( resultSubmissionBlock + params.dkgResultChallengePeriodLength - - 1 + 1, ) }) @@ -2495,66 +2478,51 @@ describe("WalletRegistry - Wallet Creation", async () => { await restoreSnapshot() }) - context.skip( - "called by a third party (skipped: no processSlashing on dev TokenStaking)", - async () => { - let challengeTx: ContractTransaction - let slashingTx: ContractTransaction + context("called by a third party", async () => { + let challengeTx: ContractTransactionResponse - before(async () => { - await createSnapshot() - - challengeTx = await walletRegistry - .connect(thirdParty) - .challengeDkgResult(dkgResult) + before(async () => { + await createSnapshot() - slashingTx = await legacyTokenStakingAt( - staking, - thirdParty - ).processSlashing(1) - }) + challengeTx = await walletRegistry + .connect(thirdParty) + .challengeDkgResult(dkgResult) + }) - after(async () => { - await restoreSnapshot() - }) + after(async () => { + await restoreSnapshot() + }) - it("should emit DkgResultChallenged event", async () => { - await expect(challengeTx) - .to.emit(walletRegistry, "DkgResultChallenged") - .withArgs( - dkgResultHash, - await thirdParty.getAddress(), - "Invalid group members" - ) - }) + it("should emit DkgResultChallenged event", async () => { + await expect(challengeTx) + .to.emit(walletRegistry, "DkgResultChallenged") + .withArgs( + dkgResultHash, + await thirdParty.getAddress(), + "Invalid group members", + ) + }) - it("should not unlock the sortition pool", async () => { - await expect(await sortitionPool.isLocked()).to.be.true - }) + it("should not unlock the sortition pool", async () => { + await expect(await sortitionPool.isLocked()).to.be.true + }) - it("should emit DkgMaliciousResultSlashed event", async () => { - await expect(challengeTx) - .to.emit(walletRegistry, "DkgMaliciousResultSlashed") - .withArgs(dkgResultHash, to1e18(400), submitter.address) - }) + it("should emit DkgMaliciousResultSlashed event", async () => { + await expect(challengeTx) + .to.emit(walletRegistry, "DkgMaliciousResultSlashed") + .withArgs(dkgResultHash, to1e18(400), submitter.address) + }) - it("should reward the notifier", async () => { - await expect(challengeTx) - .to.emit(staking, "NotifierRewarded") - .withArgs(thirdParty.address, 0) - }) + it("should emit a zero notifier reward", async () => { + await expect(challengeTx) + .to.emit(staking, "NotifierRewarded") + .withArgs(thirdParty.address, 0) + }) - it("should slash malicious result submitter", async () => { - const stakingProvider = - await walletRegistry.operatorToStakingProvider( - submitter.address - ) - await expect(slashingTx) - .to.emit(staking, "TokensSeized") - .withArgs(stakingProvider, to1e18(400), false) - }) - } - ) + it("should preserve the submitter's Allowlist weight", async () => { + await expectAllowlistWeightUnchanged(submitter.address) + }) + }) }) context("with challenge period passed", async () => { @@ -2563,7 +2531,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await mineBlocksTo( resultSubmissionBlock + - params.dkgResultChallengePeriodLength + params.dkgResultChallengePeriodLength, ) }) @@ -2573,7 +2541,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should revert with 'Challenge period has already passed' error", async () => { await expect( - walletRegistry.challengeDkgResult(dkgResult) + walletRegistry.challengeDkgResult(dkgResult), ).to.be.revertedWith("Challenge period has already passed") }) }) @@ -2589,24 +2557,23 @@ describe("WalletRegistry - Wallet Creation", async () => { dkgResult.submitterMemberIndex + 1 await expect( - walletRegistry.challengeDkgResult(modifiedDkgResult) + walletRegistry.challengeDkgResult(modifiedDkgResult), ).to.be.revertedWith( - "Result under challenge is different than the submitted one" + "Result under challenge is different than the submitted one", ) }) - } + }, ) }) - context.skip( - "with dkg result submitted with unrecoverable signatures (skipped: no processSlashing on dev TokenStaking)", + context( + "with dkg result submitted with unrecoverable signatures", async () => { let dkgResultHash: string let dkgResult: DkgResult let submitter: SignerWithAddress - let challengeTx: ContractTransaction - let slashingTx: ContractTransaction + let challengeTx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2616,17 +2583,12 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, await selectGroup(sortitionPool, dkgSeed), startBlock, - noMisbehaved + noMisbehaved, )) challengeTx = await walletRegistry .connect(thirdParty) .challengeDkgResult(dkgResult) - - slashingTx = await legacyTokenStakingAt( - staking, - thirdParty - ).processSlashing(1) }) after(async () => { @@ -2639,7 +2601,7 @@ describe("WalletRegistry - Wallet Creation", async () => { .withArgs( dkgResultHash, await thirdParty.getAddress(), - "validation reverted" + "validation reverted", ) }) @@ -2653,26 +2615,20 @@ describe("WalletRegistry - Wallet Creation", async () => { .withArgs(dkgResultHash, to1e18(400), submitter.address) }) - it("should reward the notifier", async () => { + it("should emit a zero notifier reward", async () => { await expect(challengeTx) .to.emit(staking, "NotifierRewarded") .withArgs(thirdParty.address, 0) }) - it("should slash malicious result submitter", async () => { - const stakingProvider = - await walletRegistry.operatorToStakingProvider( - submitter.address - ) - await expect(slashingTx) - .to.emit(staking, "TokensSeized") - .withArgs(stakingProvider, to1e18(400), false) + it("should preserve the submitter's Allowlist weight", async () => { + await expectAllowlistWeightUnchanged(submitter.address) }) - it("should use close to 462 000 gas", async () => { - await assertGasUsed(challengeTx, 462_000, 30_000) + it("should use close to 420 000 gas", async () => { + await assertGasUsed(challengeTx, 420_000, 30_000) }) - } + }, ) context( @@ -2680,7 +2636,7 @@ describe("WalletRegistry - Wallet Creation", async () => { async () => { const misbehavedIndices = [2, 9, 30, 11, 60, 64] - let tx: ContractTransaction + let tx: ContractTransactionResponse let dkgResult: DkgResult let dkgResultHash: string @@ -2692,7 +2648,7 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, dkgSeed, startBlock, - misbehavedIndices + misbehavedIndices, )) tx = await walletRegistry @@ -2710,7 +2666,7 @@ describe("WalletRegistry - Wallet Creation", async () => { .withArgs( dkgResultHash, await thirdParty.getAddress(), - "Corrupted misbehaved members indices" + "Corrupted misbehaved members indices", ) }) @@ -2721,13 +2677,13 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should use close to 221 000 gas", async () => { await assertGasUsed(tx, 221_000, 60_000) }) - } + }, ) context("when misbehaved members contains duplicates", async () => { const misbehavedIndices = [2, 9, 30, 30, 60, 64] - let tx: ContractTransaction + let tx: ContractTransactionResponse let dkgResult: DkgResult let dkgResultHash: string @@ -2739,7 +2695,7 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, dkgSeed, startBlock, - misbehavedIndices + misbehavedIndices, )) tx = await walletRegistry @@ -2757,7 +2713,7 @@ describe("WalletRegistry - Wallet Creation", async () => { .withArgs( dkgResultHash, await thirdParty.getAddress(), - "Corrupted misbehaved members indices" + "Corrupted misbehaved members indices", ) }) @@ -2780,7 +2736,7 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, dkgSeed, startBlock, - noMisbehaved + noMisbehaved, )) }) @@ -2790,7 +2746,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should revert with 'unjustified challenge' error", async () => { await expect( - walletRegistry.challengeDkgResult(dkgResult) + walletRegistry.challengeDkgResult(dkgResult), ).to.be.revertedWith("unjustified challenge") }) }) @@ -2805,7 +2761,7 @@ describe("WalletRegistry - Wallet Creation", async () => { before(async () => { await createSnapshot() - let tx: ContractTransaction + let tx: ContractTransactionResponse ;({ transaction: tx, dkgResult, @@ -2816,7 +2772,7 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, mixOperators(await selectGroup(sortitionPool, dkgSeed)), startBlock, - noMisbehaved + noMisbehaved, )) }) @@ -2827,7 +2783,7 @@ describe("WalletRegistry - Wallet Creation", async () => { context( "when staking.seize() succeeds (normal operation)", async () => { - let challengeTx: ContractTransaction + let challengeTx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2847,13 +2803,13 @@ describe("WalletRegistry - Wallet Creation", async () => { .withArgs( dkgResultHash, await thirdParty.getAddress(), - "Invalid group members" + "Invalid group members", ) }) it("should complete challenge successfully", async () => { expect( - await walletRegistry.getWalletCreationState() + await walletRegistry.getWalletCreationState(), ).to.equal(dkgState.AWAITING_RESULT) }) @@ -2865,12 +2821,12 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should use less gas than current implementation (bytecode optimization)", async () => { const receipt = await challengeTx.wait() - const gasUsed = receipt.gasUsed.toNumber() + const gasUsed = Number(requireResult(receipt).gasUsed) expect(gasUsed).to.be.lessThan(1_850_000) }) - } + }, ) - } + }, ) }) }) @@ -2890,13 +2846,13 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should revert with 'Current state is not CHALLENGE", async () => { await expect( - walletRegistry.challengeDkgResult(stubDkgResult) + walletRegistry.challengeDkgResult(stubDkgResult), ).to.be.revertedWith("Current state is not CHALLENGE") }) context("with new wallet creation started", async () => { let startBlock: number - let dkgSeed: BigNumber + let dkgSeed: bigint before( "request new wallet creation and submit relay entry", @@ -2904,7 +2860,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await createSnapshot() await walletRegistry.connect(walletOwner.wallet).requestNewWallet() ;({ startBlock, dkgSeed } = await submitRelayEntry(walletRegistry)) - } + }, ) after(async () => { @@ -2913,14 +2869,14 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should revert with 'Current state is not CHALLENGE'", async () => { await expect( - walletRegistry.challengeDkgResult(stubDkgResult) + walletRegistry.challengeDkgResult(stubDkgResult), ).to.be.revertedWith("Current state is not CHALLENGE") }) context("with dkg result not submitted", async () => { it("should revert with 'Current state is not CHALLENGE'", async () => { await expect( - walletRegistry.challengeDkgResult(stubDkgResult) + walletRegistry.challengeDkgResult(stubDkgResult), ).to.be.revertedWith("Current state is not CHALLENGE") }) }) @@ -2934,7 +2890,7 @@ describe("WalletRegistry - Wallet Creation", async () => { before(async () => { await createSnapshot() - let tx: ContractTransaction + let tx: ContractTransactionResponse ;({ transaction: tx, dkgResult, @@ -2946,10 +2902,10 @@ describe("WalletRegistry - Wallet Creation", async () => { // Mix operators to make the result malicious. mixOperators(await selectGroup(sortitionPool, dkgSeed)), startBlock, - noMisbehaved + noMisbehaved, )) - resultSubmissionBlock = tx.blockNumber + resultSubmissionBlock = requireResult(await tx.wait()).blockNumber }) after(async () => { @@ -2957,60 +2913,51 @@ describe("WalletRegistry - Wallet Creation", async () => { }) context("at the beginning of challenge period", async () => { - context.skip( - "called by a third party (skipped: no processSlashing on dev TokenStaking)", - async () => { - let challengeTx: ContractTransaction - let slashingTx: ContractTransaction + context("called by a third party", async () => { + let challengeTx: ContractTransactionResponse - before(async () => { - await createSnapshot() + before(async () => { + await createSnapshot() - challengeTx = await walletRegistry - .connect(thirdParty) - .challengeDkgResult(dkgResult) + challengeTx = await walletRegistry + .connect(thirdParty) + .challengeDkgResult(dkgResult) + }) - slashingTx = await legacyTokenStakingAt( - staking, - thirdParty - ).processSlashing(1) - }) + after(async () => { + await restoreSnapshot() + }) - after(async () => { - await restoreSnapshot() - }) + it("should emit DkgResultChallenged event", async () => { + await expect(challengeTx) + .to.emit(walletRegistry, "DkgResultChallenged") + .withArgs( + dkgResultHash, + await thirdParty.getAddress(), + "Invalid group members", + ) + }) - it("should emit DkgResultChallenged event", async () => { - await expect(challengeTx) - .to.emit(walletRegistry, "DkgResultChallenged") - .withArgs( - dkgResultHash, - await thirdParty.getAddress(), - "Invalid group members" - ) - }) + it("should not unlock the sortition pool", async () => { + await expect(await sortitionPool.isLocked()).to.be.true + }) - it("should not unlock the sortition pool", async () => { - await expect(await sortitionPool.isLocked()).to.be.true - }) + it("should emit DkgMaliciousResultSlashed event", async () => { + await expect(challengeTx) + .to.emit(walletRegistry, "DkgMaliciousResultSlashed") + .withArgs(dkgResultHash, to1e18(400), submitter.address) + }) - it("should emit DkgMaliciousResultSlashed event", async () => { - await expect(challengeTx) - .to.emit(walletRegistry, "DkgMaliciousResultSlashed") - .withArgs(dkgResultHash, to1e18(400), submitter.address) - }) + it("should emit a zero notifier reward", async () => { + await expect(challengeTx) + .to.emit(staking, "NotifierRewarded") + .withArgs(thirdParty.address, 0) + }) - it("should slash malicious result submitter", async () => { - const stakingProvider = - await walletRegistry.operatorToStakingProvider( - submitter.address - ) - await expect(slashingTx) - .to.emit(staking, "TokensSeized") - .withArgs(stakingProvider, to1e18(400), false) - }) - } - ) + it("should preserve the submitter's Allowlist weight", async () => { + await expectAllowlistWeightUnchanged(submitter.address) + }) + }) context("with insufficient gas provided", async () => { it("should revert when gas check fails", async () => { @@ -3023,7 +2970,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await expect( walletRegistry .connect(thirdParty) - .challengeDkgResult(dkgResult, { gasLimit: 220000 }) + .challengeDkgResult(dkgResult, { gasLimit: 220000 }), ).to.be.reverted }) }) @@ -3036,7 +2983,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await mineBlocksTo( resultSubmissionBlock + params.dkgResultChallengePeriodLength - - 1 + 1, ) }) @@ -3044,60 +2991,51 @@ describe("WalletRegistry - Wallet Creation", async () => { await restoreSnapshot() }) - context.skip( - "called by a third party (skipped: no processSlashing on dev TokenStaking)", - async () => { - let challengeTx: ContractTransaction - let slashingTx: ContractTransaction + context("called by a third party", async () => { + let challengeTx: ContractTransactionResponse - before(async () => { - await createSnapshot() + before(async () => { + await createSnapshot() - challengeTx = await walletRegistry - .connect(thirdParty) - .challengeDkgResult(dkgResult) + challengeTx = await walletRegistry + .connect(thirdParty) + .challengeDkgResult(dkgResult) + }) - slashingTx = await legacyTokenStakingAt( - staking, - thirdParty - ).processSlashing(1) - }) + after(async () => { + await restoreSnapshot() + }) - after(async () => { - await restoreSnapshot() - }) + it("should emit DkgResultChallenged event", async () => { + await expect(challengeTx) + .to.emit(walletRegistry, "DkgResultChallenged") + .withArgs( + dkgResultHash, + await thirdParty.getAddress(), + "Invalid group members", + ) + }) - it("should emit DkgResultChallenged event", async () => { - await expect(challengeTx) - .to.emit(walletRegistry, "DkgResultChallenged") - .withArgs( - dkgResultHash, - await thirdParty.getAddress(), - "Invalid group members" - ) - }) + it("should not unlock the sortition pool", async () => { + await expect(await sortitionPool.isLocked()).to.be.true + }) - it("should not unlock the sortition pool", async () => { - await expect(await sortitionPool.isLocked()).to.be.true - }) + it("should emit DkgMaliciousResultSlashed event", async () => { + await expect(challengeTx) + .to.emit(walletRegistry, "DkgMaliciousResultSlashed") + .withArgs(dkgResultHash, to1e18(400), submitter.address) + }) - it("should emit DkgMaliciousResultSlashed event", async () => { - await expect(challengeTx) - .to.emit(walletRegistry, "DkgMaliciousResultSlashed") - .withArgs(dkgResultHash, to1e18(400), submitter.address) - }) + it("should emit a zero notifier reward", async () => { + await expect(challengeTx) + .to.emit(staking, "NotifierRewarded") + .withArgs(thirdParty.address, 0) + }) - it("should slash malicious result submitter", async () => { - const stakingProvider = - await walletRegistry.operatorToStakingProvider( - submitter.address - ) - await expect(slashingTx) - .to.emit(staking, "TokensSeized") - .withArgs(stakingProvider, to1e18(400), false) - }) - } - ) + it("should preserve the submitter's Allowlist weight", async () => { + await expectAllowlistWeightUnchanged(submitter.address) + }) + }) }) context("with challenge period passed", async () => { @@ -3105,7 +3043,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await createSnapshot() await mineBlocksTo( - resultSubmissionBlock + params.dkgResultChallengePeriodLength + resultSubmissionBlock + params.dkgResultChallengePeriodLength, ) }) @@ -3115,7 +3053,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should revert with 'Challenge period has already passed' error", async () => { await expect( - walletRegistry.challengeDkgResult(dkgResult) + walletRegistry.challengeDkgResult(dkgResult), ).to.be.revertedWith("Challenge period has already passed") }) }) @@ -3129,24 +3067,23 @@ describe("WalletRegistry - Wallet Creation", async () => { dkgResult.submitterMemberIndex + 1 await expect( - walletRegistry.challengeDkgResult(modifiedDkgResult) + walletRegistry.challengeDkgResult(modifiedDkgResult), ).to.be.revertedWith( - "Result under challenge is different than the submitted one" + "Result under challenge is different than the submitted one", ) }) - } + }, ) }) - context.skip( - "with dkg result submitted with unrecoverable signatures (skipped: no processSlashing on dev TokenStaking)", + context( + "with dkg result submitted with unrecoverable signatures", async () => { let dkgResultHash: string let dkgResult: DkgResult let submitter: SignerWithAddress - let challengeTx: ContractTransaction - let slashingTx: ContractTransaction + let challengeTx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -3156,17 +3093,12 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey2, await selectGroup(sortitionPool, dkgSeed), startBlock, - noMisbehaved + noMisbehaved, )) challengeTx = await walletRegistry .connect(thirdParty) .challengeDkgResult(dkgResult) - - slashingTx = await legacyTokenStakingAt( - staking, - thirdParty - ).processSlashing(1) }) after(async () => { @@ -3179,7 +3111,7 @@ describe("WalletRegistry - Wallet Creation", async () => { .withArgs( dkgResultHash, await thirdParty.getAddress(), - "validation reverted" + "validation reverted", ) }) @@ -3193,16 +3125,16 @@ describe("WalletRegistry - Wallet Creation", async () => { .withArgs(dkgResultHash, to1e18(400), submitter.address) }) - it("should slash malicious result submitter", async () => { - const stakingProvider = - await walletRegistry.operatorToStakingProvider( - submitter.address - ) - await expect(slashingTx) - .to.emit(staking, "TokensSeized") - .withArgs(stakingProvider, to1e18(400), false) + it("should emit a zero notifier reward", async () => { + await expect(challengeTx) + .to.emit(staking, "NotifierRewarded") + .withArgs(thirdParty.address, 0) }) - } + + it("should preserve the submitter's Allowlist weight", async () => { + await expectAllowlistWeightUnchanged(submitter.address) + }) + }, ) context("with correct dkg result submitted", async () => { @@ -3215,7 +3147,7 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey2, dkgSeed, startBlock, - noMisbehaved + noMisbehaved, )) }) @@ -3225,7 +3157,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should revert with 'unjustified challenge' error", async () => { await expect( - walletRegistry.challengeDkgResult(dkgResult) + walletRegistry.challengeDkgResult(dkgResult), ).to.be.revertedWith("unjustified challenge") }) }) @@ -3256,14 +3188,12 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, operators, startBlock, - noMisbehaved + noMisbehaved, )) await expect( - ( - await walletRegistry.getDkgData() - ).resultSubmissionStartBlockOffset, - "invalid resultSubmissionStartBlockOffset for result 1 after submission" + (await walletRegistry.getDkgData()).resultSubmissionStartBlockOffset, + "invalid resultSubmissionStartBlockOffset for result 1 after submission", ).to.equal(0) // Challenge result 1 at the beginning of the challenge period @@ -3273,10 +3203,8 @@ describe("WalletRegistry - Wallet Creation", async () => { let expectedSubmissionOffset = 2 await expect( - ( - await walletRegistry.getDkgData() - ).resultSubmissionStartBlockOffset, - "invalid resultSubmissionStartBlockOffset for result 1 after challenge" + (await walletRegistry.getDkgData()).resultSubmissionStartBlockOffset, + "invalid resultSubmissionStartBlockOffset for result 1 after challenge", ).to.equal(expectedSubmissionOffset) // Submit result 2 in the middle of the submission period @@ -3287,14 +3215,12 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, operators, startBlock, - noMisbehaved + noMisbehaved, )) await expect( - ( - await walletRegistry.getDkgData() - ).resultSubmissionStartBlockOffset, - "invalid resultSubmissionStartBlockOffset for result 2 after submission" + (await walletRegistry.getDkgData()).resultSubmissionStartBlockOffset, + "invalid resultSubmissionStartBlockOffset for result 2 after submission", ).to.equal(expectedSubmissionOffset) // same as before expectedSubmissionOffset += blocksToMine @@ -3306,10 +3232,8 @@ describe("WalletRegistry - Wallet Creation", async () => { expectedSubmissionOffset += 2 // 1 block for dkg result submission tx + 1 block for challenge tx await expect( - ( - await walletRegistry.getDkgData() - ).resultSubmissionStartBlockOffset, - "invalid resultSubmissionStartBlockOffset for result 2 after challenge" + (await walletRegistry.getDkgData()).resultSubmissionStartBlockOffset, + "invalid resultSubmissionStartBlockOffset for result 2 after challenge", ).to.equal(expectedSubmissionOffset) // Submit result 3 at the end of the submission period @@ -3320,14 +3244,12 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, operators, startBlock, - noMisbehaved + noMisbehaved, )) await expect( - ( - await walletRegistry.getDkgData() - ).resultSubmissionStartBlockOffset, - "invalid resultSubmissionStartBlockOffset for result 3 after submission" + (await walletRegistry.getDkgData()).resultSubmissionStartBlockOffset, + "invalid resultSubmissionStartBlockOffset for result 3 after submission", ).to.equal(expectedSubmissionOffset) // same as before expectedSubmissionOffset += blocksToMine @@ -3338,17 +3260,15 @@ describe("WalletRegistry - Wallet Creation", async () => { expectedSubmissionOffset += blocksToMine await expect( - walletRegistry.callStatic.notifyDkgTimeout() + walletRegistry.notifyDkgTimeout.staticCall(), ).to.be.revertedWith("DKG has not timed out") await walletRegistry.challengeDkgResult(dkgResult) expectedSubmissionOffset += 2 // 1 block for dkg result submission tx + 1 block for challenge tx await expect( - ( - await walletRegistry.getDkgData() - ).resultSubmissionStartBlockOffset, - "invalid resultSubmissionStartBlockOffset for result 3 after challenge" + (await walletRegistry.getDkgData()).resultSubmissionStartBlockOffset, + "invalid resultSubmissionStartBlockOffset for result 3 after challenge", ).to.equal(expectedSubmissionOffset) // Submit result 4 after the submission period @@ -3360,8 +3280,8 @@ describe("WalletRegistry - Wallet Creation", async () => { groupPublicKey, operators, startBlock, - noMisbehaved - ) + noMisbehaved, + ), ).to.be.revertedWith("DKG timeout already passed") await walletRegistry.notifyDkgTimeout() @@ -3373,14 +3293,14 @@ describe("WalletRegistry - Wallet Creation", async () => { context("with group creation not in progress", async () => { it("should revert with 'DKG has not been started'", async () => { await expect( - walletRegistry.isDkgResultValid(stubDkgResult) + walletRegistry.isDkgResultValid(stubDkgResult), ).to.be.revertedWith("DKG has not been started") }) }) context("with new wallet creation in progress", async () => { let startBlock: number - let dkgSeed: BigNumber + let dkgSeed: bigint before("request new wallet creation and submit relay entry", async () => { await createSnapshot() @@ -3396,12 +3316,11 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should return false and an error message", async () => { const expectedValidationResult = [false, "Malformed signatures array"] - const validationResult = await walletRegistry.isDkgResultValid( - stubDkgResult - ) + const validationResult = + await walletRegistry.isDkgResultValid(stubDkgResult) await expect(validationResult).to.be.deep.equal( - expectedValidationResult + expectedValidationResult, ) }) }) @@ -3415,7 +3334,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await selectGroup(sortitionPool, dkgSeed), groupPublicKey, noMisbehaved, - startBlock + startBlock, )) }) @@ -3426,12 +3345,11 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should return true", async () => { const expectedValidationResult = [true, ""] - const validationResult = await walletRegistry.isDkgResultValid( - dkgResult - ) + const validationResult = + await walletRegistry.isDkgResultValid(dkgResult) await expect(validationResult).to.be.deep.equal( - expectedValidationResult + expectedValidationResult, ) }) }) @@ -3454,7 +3372,7 @@ describe("WalletRegistry - Wallet Creation", async () => { .connect(walletOwner.wallet) .requestNewWallet() - requestNewWalletStartBlock = tx.blockNumber + requestNewWalletStartBlock = requireResult(await tx.wait()).blockNumber }) after(async () => { @@ -3467,7 +3385,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await createSnapshot() await mineBlocksTo( - requestNewWalletStartBlock + params.dkgSeedTimeout + requestNewWalletStartBlock + params.dkgSeedTimeout, ) }) @@ -3500,7 +3418,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await createSnapshot() await mineBlocksTo( - requestNewWalletStartBlock + params.dkgSeedTimeout + 1 + requestNewWalletStartBlock + params.dkgSeedTimeout + 1, ) }) @@ -3535,7 +3453,7 @@ describe("WalletRegistry - Wallet Creation", async () => { context("with initial contract state", async () => { it("should revert with 'DKG has not timed out' error", async () => { await expect(walletRegistry.notifySeedTimeout()).to.be.revertedWith( - "Awaiting seed has not timed out" + "Awaiting seed has not timed out", ) }) }) @@ -3549,7 +3467,7 @@ describe("WalletRegistry - Wallet Creation", async () => { .connect(walletOwner.wallet) .requestNewWallet() - requestNewWalletStartBlock = tx.blockNumber + requestNewWalletStartBlock = requireResult(await tx.wait()).blockNumber }) after(async () => { @@ -3562,7 +3480,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await createSnapshot() await mineBlocksTo( - requestNewWalletStartBlock + params.dkgSeedTimeout - 1 + requestNewWalletStartBlock + params.dkgSeedTimeout - 1, ) }) @@ -3572,7 +3490,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should revert with 'Awaiting seed has not timed out' error", async () => { await expect(walletRegistry.notifySeedTimeout()).to.be.revertedWith( - "Awaiting seed has not timed out" + "Awaiting seed has not timed out", ) }) @@ -3588,7 +3506,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should revert with 'Awaiting seed has not timed out' error", async () => { await expect( - walletRegistry.notifySeedTimeout() + walletRegistry.notifySeedTimeout(), ).to.be.revertedWith("Awaiting seed has not timed out") }) }) @@ -3599,7 +3517,7 @@ describe("WalletRegistry - Wallet Creation", async () => { await createSnapshot() await mineBlocksTo( - requestNewWalletStartBlock + params.dkgSeedTimeout + requestNewWalletStartBlock + params.dkgSeedTimeout, ) }) @@ -3608,14 +3526,14 @@ describe("WalletRegistry - Wallet Creation", async () => { }) context("called by a third party", async () => { - let tx: ContractTransaction - let initThirdPartyBalance: BigNumber + let tx: ContractTransactionResponse + let initThirdPartyBalance: bigint before(async () => { await createSnapshot() initThirdPartyBalance = await provider.getBalance( - thirdParty.address + thirdParty.address, ) tx = await walletRegistry.connect(thirdParty).notifySeedTimeout() @@ -3639,20 +3557,18 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should transition DKG to IDLE state", async () => { await expect( - await walletRegistry.getWalletCreationState() + await walletRegistry.getWalletCreationState(), ).to.be.equal(dkgState.IDLE) }) it("should refund ETH", async () => { const postNotifyThirdPartyBalance = await provider.getBalance( - thirdParty.address - ) - const diff = postNotifyThirdPartyBalance.sub( - initThirdPartyBalance + thirdParty.address, ) + const diff = postNotifyThirdPartyBalance - initThirdPartyBalance expect(diff).to.be.gt(0) expect(diff).to.be.lt( - ethers.utils.parseUnits("100000", "gwei") // 0,0001 ETH + ethers.parseUnits("100000", "gwei"), // 0,0001 ETH ) }) @@ -3673,7 +3589,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should revert with 'Awaiting seed has not timed out' error", async () => { await expect( - walletRegistry.notifySeedTimeout() + walletRegistry.notifySeedTimeout(), ).to.be.revertedWith("Awaiting seed has not timed out") }) }) @@ -3686,7 +3602,7 @@ describe("WalletRegistry - Wallet Creation", async () => { context("with initial contract state", async () => { it("should revert with 'DKG has not timed out' error", async () => { await expect(walletRegistry.notifyDkgTimeout()).to.be.revertedWith( - "DKG has not timed out" + "DKG has not timed out", ) }) }) @@ -3700,7 +3616,7 @@ describe("WalletRegistry - Wallet Creation", async () => { .connect(walletOwner.wallet) .requestNewWallet() - requestNewWalletStartBlock = tx.blockNumber + requestNewWalletStartBlock = requireResult(await tx.wait()).blockNumber }) after(async () => { @@ -3721,7 +3637,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should revert with 'DKG has not timed out' error", async () => { await expect(walletRegistry.notifyDkgTimeout()).to.be.revertedWith( - "DKG has not timed out" + "DKG has not timed out", ) }) }) @@ -3752,7 +3668,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should revert with 'DKG has not timed out' error", async () => { await expect( - walletRegistry.notifyDkgTimeout() + walletRegistry.notifyDkgTimeout(), ).to.be.revertedWith("DKG has not timed out") }) }) @@ -3770,14 +3686,14 @@ describe("WalletRegistry - Wallet Creation", async () => { }) context("called by a third party", async () => { - let tx: ContractTransaction - let initThirdPartyBalance: BigNumber + let tx: ContractTransactionResponse + let initThirdPartyBalance: bigint before(async () => { await createSnapshot() initThirdPartyBalance = await provider.getBalance( - thirdParty.address + thirdParty.address, ) tx = await walletRegistry.connect(thirdParty).notifyDkgTimeout() }) @@ -3800,14 +3716,12 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should refund ETH", async () => { const postNotifyThirdPartyBalance = await provider.getBalance( - thirdParty.address - ) - const diff = postNotifyThirdPartyBalance.sub( - initThirdPartyBalance + thirdParty.address, ) + const diff = postNotifyThirdPartyBalance - initThirdPartyBalance expect(diff).to.be.gt(0) expect(diff).to.be.lt( - ethers.utils.parseUnits("100000", "gwei") // 0,0001 ETH + ethers.parseUnits("100000", "gwei"), // 0,0001 ETH ) }) @@ -3833,13 +3747,13 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should revert", async () => { await expect(walletRegistry.selectGroup()).to.be.revertedWith( - "Sortition pool unlocked" + "Sortition pool unlocked", ) }) }) context("when dkg was triggered", async () => { - let dkgSeed: BigNumber + let dkgSeed: bigint before(async () => { await createSnapshot() @@ -3859,7 +3773,7 @@ describe("WalletRegistry - Wallet Creation", async () => { it("should be the same group as if called the sortition pool directly", async () => { const exectedGroup = await sortitionPool.selectGroup( constants.groupSize, - ethers.utils.hexZeroPad(dkgSeed.toHexString(), 32) + ethers.zeroPadValue(toBeHex(dkgSeed), 32), ) const actualGroup = await walletRegistry.selectGroup() expect(exectedGroup).to.be.deep.equal(actualGroup) @@ -3873,32 +3787,32 @@ async function assertDkgResultCleanData(walletRegistry: WalletRegistryStub) { expect( dkgData.parameters.resultChallengePeriodLength, - "unexpected resultChallengePeriodLength" + "unexpected resultChallengePeriodLength", ).to.eq(params.dkgResultChallengePeriodLength) expect( dkgData.parameters.resultSubmissionTimeout, - "unexpected resultSubmissionTimeout" + "unexpected resultSubmissionTimeout", ).to.eq(params.dkgResultSubmissionTimeout) expect( dkgData.parameters.submitterPrecedencePeriodLength, - "unexpected submitterPrecedencePeriodLength" + "unexpected submitterPrecedencePeriodLength", ).to.eq(params.dkgSubmitterPrecedencePeriodLength) expect(dkgData.startBlock, "unexpected startBlock").to.eq(0) expect( dkgData.resultSubmissionStartBlockOffset, - "unexpected resultSubmissionStartBlockOffset" + "unexpected resultSubmissionStartBlockOffset", ).to.eq(0) expect(dkgData.submittedResultHash, "unexpected submittedResultHash").to.eq( - ethers.constants.HashZero + ethers.ZeroHash, ) expect(dkgData.submittedResultBlock, "unexpected submittedResultBlock").to.eq( - 0 + 0, ) } diff --git a/solidity/ecdsa/test/WalletRegistry.WalletOwner.test.ts b/solidity/ecdsa/test/WalletRegistry.WalletOwner.test.ts index 09e67e164d..a8402a4050 100644 --- a/solidity/ecdsa/test/WalletRegistry.WalletOwner.test.ts +++ b/solidity/ecdsa/test/WalletRegistry.WalletOwner.test.ts @@ -8,7 +8,7 @@ import { submitRelayEntry } from "./utils/randomBeacon" import { signAndSubmitCorrectDkgResult } from "./utils/dkg" import ecdsaData from "./data/ecdsa" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" import type { DkgResult } from "./utils/dkg" import type { Mock } from "./helpers/mock" import type { @@ -16,29 +16,22 @@ import type { WalletRegistry, WalletRegistryStub, } from "../typechain" -import type { ContractTransaction } from "ethers" +import type { ContractTransactionResponse } from "ethers" const { mineBlocks } = helpers.time const { createSnapshot, restoreSnapshot } = helpers.snapshot describe("WalletRegistry - Wallet Owner", async () => { - const groupPublicKey: string = ethers.utils.hexValue( - ecdsaData.group1.publicKey - ) - const groupPublicKeyX: string = ethers.utils.hexValue( - ecdsaData.group1.publicKeyX - ) - const groupPublicKeyY: string = ethers.utils.hexValue( - ecdsaData.group1.publicKeyY - ) - const walletID: string = ethers.utils.keccak256(groupPublicKey) + const groupPublicKey: string = ethers.toQuantity(ecdsaData.group1.publicKey) + const groupPublicKeyX: string = ethers.toQuantity(ecdsaData.group1.publicKeyX) + const groupPublicKeyY: string = ethers.toQuantity(ecdsaData.group1.publicKeyY) + const walletID: string = ethers.keccak256(groupPublicKey) let walletRegistry: WalletRegistryStub & WalletRegistry let walletOwner: Mock before("load test fixture", async () => { - // eslint-disable-next-line @typescript-eslint/no-extra-semi ;({ walletRegistry, walletOwner } = await walletRegistryFixture({ useAllowlist: true, })) @@ -58,7 +51,7 @@ describe("WalletRegistry - Wallet Owner", async () => { walletRegistry, groupPublicKey, dkgSeed, - startBlock + startBlock, )) await mineBlocks(params.dkgResultChallengePeriodLength) @@ -71,13 +64,13 @@ describe("WalletRegistry - Wallet Owner", async () => { }) context("when __ecdsaWalletCreatedCallback reverts", async () => { - let tx: Promise + let tx: Promise before(async () => { await createSnapshot() await walletOwner.__ecdsaWalletCreatedCallback.reverts( - "wallet owner internal error" + "wallet owner internal error", ) tx = walletRegistry.connect(submitter).approveDkgResult(dkgResult) @@ -97,7 +90,7 @@ describe("WalletRegistry - Wallet Owner", async () => { }) context("when __ecdsaWalletCreatedCallback succeeds", async () => { - let tx: Promise + let tx: Promise before(async () => { await createSnapshot() diff --git a/solidity/ecdsa/test/WalletRegistry.Wallets.test.ts b/solidity/ecdsa/test/WalletRegistry.Wallets.test.ts index 7847995171..974c4d9afc 100644 --- a/solidity/ecdsa/test/WalletRegistry.Wallets.test.ts +++ b/solidity/ecdsa/test/WalletRegistry.Wallets.test.ts @@ -1,6 +1,6 @@ import { helpers, ethers } from "hardhat" import { expect } from "chai" -import { formatBytes32String } from "ethers/lib/utils" +import { encodeBytes32String } from "ethers" import { walletRegistryFixture } from "./fixtures" import { createNewWallet } from "./utils/wallets" @@ -8,8 +8,8 @@ import ecdsaData from "./data/ecdsa" import { hashUint32Array } from "./utils/groups" import type { Operator } from "./utils/operators" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" -import type { ContractTransaction } from "ethers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" +import type { ContractTransactionResponse } from "ethers" import type { DkgResult } from "./utils/dkg" import type { IRandomBeacon, @@ -58,7 +58,6 @@ describe("WalletRegistry - Wallets", async () => { let thirdParty: SignerWithAddress before("load test fixture", async () => { - // eslint-disable-next-line @typescript-eslint/no-extra-semi ;({ walletRegistry, randomBeacon, walletOwner, thirdParty } = await walletRegistryFixture({ useAllowlist: true })) }) @@ -76,7 +75,7 @@ describe("WalletRegistry - Wallets", async () => { walletRegistry, walletOwner.wallet, randomBeacon, - test.publicKey + test.publicKey, )) }) @@ -89,20 +88,20 @@ describe("WalletRegistry - Wallets", async () => { expect( wallet.membersIdsHash, - "unexpected members ids hash" + "unexpected members ids hash", ).to.be.equal(hashUint32Array(dkgResult.members)) expect(wallet.publicKeyX, "unexpected public key X").to.be.equal( - ethers.utils.hexDataSlice(test.publicKey, 0, 32) + ethers.dataSlice(test.publicKey, 0, 32), ) expect(wallet.publicKeyY, "unexpected public key Y").to.be.equal( - ethers.utils.hexDataSlice(test.publicKey, 32) + ethers.dataSlice(test.publicKey, 32), ) }) it("should calculate wallet id", async () => { expect(walletID, "unexpected walletID").to.be.equal( - test.expectedWalletID + test.expectedWalletID, ) }) }) @@ -112,12 +111,12 @@ describe("WalletRegistry - Wallets", async () => { const testData = [ { context: "with too short public key", - publicKey: ethers.utils.randomBytes(63), + publicKey: ethers.randomBytes(63), expectedError: "Invalid length of the public key", }, { context: "with too long public key", - publicKey: ethers.utils.randomBytes(65), + publicKey: ethers.randomBytes(65), expectedError: "Invalid length of the public key", }, ] @@ -138,8 +137,8 @@ describe("WalletRegistry - Wallets", async () => { walletRegistry, walletOwner.wallet, randomBeacon, - test.publicKey - ) + test.publicKey, + ), ).to.be.revertedWith(test.expectedError) }) }) @@ -157,7 +156,7 @@ describe("WalletRegistry - Wallets", async () => { walletRegistry, walletOwner.wallet, randomBeacon, - walletPublicKey + walletPublicKey, ) }) @@ -180,10 +179,10 @@ describe("WalletRegistry - Wallets", async () => { walletRegistry, walletOwner.wallet, randomBeacon, - walletPublicKey - ) + walletPublicKey, + ), ).to.be.revertedWith( - "Wallet with the given public key already exists" + "Wallet with the given public key already exists", ) }) }) @@ -203,8 +202,8 @@ describe("WalletRegistry - Wallets", async () => { walletRegistry, walletOwner.wallet, randomBeacon, - ecdsaData.group2.publicKey - ) + ecdsaData.group2.publicKey, + ), ).to.not.be.reverted }) }) @@ -216,8 +215,8 @@ describe("WalletRegistry - Wallets", async () => { it("should return false", async () => { await expect( await walletRegistry.isWalletRegistered( - formatBytes32String("NON EXISTING") - ) + encodeBytes32String("NON EXISTING"), + ), ).to.be.false }) }) @@ -230,7 +229,7 @@ describe("WalletRegistry - Wallets", async () => { ;({ walletID } = await createNewWallet( walletRegistry, walletOwner.wallet, - randomBeacon + randomBeacon, )) }) @@ -249,7 +248,9 @@ describe("WalletRegistry - Wallets", async () => { context("with wallet not registered", async () => { it("should revert", async () => { await expect( - walletRegistry.getWalletPublicKey(formatBytes32String("NON EXISTING")) + walletRegistry.getWalletPublicKey( + encodeBytes32String("NON EXISTING"), + ), ).to.be.revertedWith("Wallet with the given ID has not been registered") }) }) @@ -265,7 +266,7 @@ describe("WalletRegistry - Wallets", async () => { walletRegistry, walletOwner.wallet, randomBeacon, - walletPublicKey + walletPublicKey, )) }) @@ -274,17 +275,16 @@ describe("WalletRegistry - Wallets", async () => { }) it("should return uncompressed public key", async () => { - const actualPublicKey = await walletRegistry.getWalletPublicKey( - walletID - ) + const actualPublicKey = + await walletRegistry.getWalletPublicKey(walletID) await expect( actualPublicKey, - "returned public key doesn't match expected" + "returned public key doesn't match expected", ).to.be.equal(walletPublicKey) await expect( - ethers.utils.arrayify(actualPublicKey), - "returned public key is not 64-byte long" + ethers.getBytes(actualPublicKey), + "returned public key is not 64-byte long", ).to.have.lengthOf(64) }) }) @@ -299,7 +299,7 @@ describe("WalletRegistry - Wallets", async () => { ;({ walletID } = await createNewWallet( walletRegistry, walletOwner.wallet, - randomBeacon + randomBeacon, )) }) @@ -310,7 +310,7 @@ describe("WalletRegistry - Wallets", async () => { context("when called by a third party", () => { it("should revert", async () => { await expect( - walletRegistry.connect(thirdParty).closeWallet(walletID) + walletRegistry.connect(thirdParty).closeWallet(walletID), ).to.be.revertedWithCustomError(walletRegistry, "CallerNotWalletOwner") }) }) @@ -318,19 +318,19 @@ describe("WalletRegistry - Wallets", async () => { context("when caller is the wallet owner", () => { context("when wallet with the given ID is unknown", () => { it("should revert", async () => { - const unknownWalletID: string = ethers.utils.keccak256(walletID) + const unknownWalletID: string = ethers.keccak256(walletID) await expect( walletRegistry .connect(walletOwner.wallet) - .closeWallet(unknownWalletID) + .closeWallet(unknownWalletID), ).to.be.revertedWith( - "Wallet with the given ID has not been registered" + "Wallet with the given ID has not been registered", ) }) }) context("when wallet with the given ID is registered", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before("close the wallet", async () => { await createSnapshot() @@ -372,12 +372,12 @@ describe("WalletRegistry - Wallets", async () => { it("should revert", async () => { await expect( - walletRegistry.connect(walletOwner.wallet).closeWallet(walletID) + walletRegistry.connect(walletOwner.wallet).closeWallet(walletID), ).to.be.revertedWith( - "Wallet with the given ID has not been registered" + "Wallet with the given ID has not been registered", ) }) - } + }, ) }) }) @@ -394,7 +394,7 @@ describe("WalletRegistry - Wallets", async () => { ;({ walletID, members } = await createNewWallet( walletRegistry, walletOwner.wallet, - randomBeacon + randomBeacon, )) walletMembersIDs = members.map((member) => member.id) @@ -420,11 +420,11 @@ describe("WalletRegistry - Wallets", async () => { walletID, walletMembersIDs, walletMembersAddresses[5], - 6 - ) + 6, + ), ).to.be.true }) - } + }, ) context( @@ -437,11 +437,11 @@ describe("WalletRegistry - Wallets", async () => { walletID, walletMembersIDs, walletMembersAddresses[5], - 7 - ) + 7, + ), ).to.be.false }) - } + }, ) }) @@ -456,14 +456,14 @@ describe("WalletRegistry - Wallets", async () => { walletID, walletMembersIDs, walletMembersAddresses[0], - 0 - ) + 0, + ), ).to.be.revertedWithCustomError( walletRegistry, - "WalletMemberIndexOutOfRange" + "WalletMemberIndexOutOfRange", ) }) - } + }, ) context( @@ -476,14 +476,14 @@ describe("WalletRegistry - Wallets", async () => { walletID, walletMembersIDs, walletMembersAddresses[0], - walletMembersIDs.length + 1 - ) + walletMembersIDs.length + 1, + ), ).to.be.revertedWithCustomError( walletRegistry, - "WalletMemberIndexOutOfRange" + "WalletMemberIndexOutOfRange", ) }) - } + }, ) }) }) @@ -492,23 +492,25 @@ describe("WalletRegistry - Wallets", async () => { "when the passed wallet members identifiers are invalid", () => { it("should revert", async () => { - const corruptedWalletMembersIDs = walletMembersIDs.reverse() + const corruptedWalletMembersIDs = walletMembersIDs + .slice() + .reverse() await expect( walletRegistry.isWalletMember( walletID, corruptedWalletMembersIDs, walletMembersAddresses[0], - 0 - ) + 0, + ), ).to.be.revertedWithCustomError( walletRegistry, - "InvalidWalletMembersIdentifiers" + "InvalidWalletMembersIdentifiers", ) }) - } + }, ) - } + }, ) context( @@ -518,21 +520,21 @@ describe("WalletRegistry - Wallets", async () => { // To test this scenario, we need an address that is not a // sortition pool operator for sure. The address of the wallet // registry itself seems to be a good candidate. - const operator = walletRegistry.address + const operator = await walletRegistry.getAddress() await expect( walletRegistry.isWalletMember( walletID, walletMembersIDs, operator, - 0 - ) + 0, + ), ).to.be.revertedWithCustomError( walletRegistry, - "NotSortitionPoolOperator" + "NotSortitionPoolOperator", ) }) - } + }, ) }) }) diff --git a/solidity/ecdsa/test/WalletRegistryGovernance.test.ts b/solidity/ecdsa/test/WalletRegistryGovernance.test.ts index 1d63b8c42e..af451b9a80 100644 --- a/solidity/ecdsa/test/WalletRegistryGovernance.test.ts +++ b/solidity/ecdsa/test/WalletRegistryGovernance.test.ts @@ -1,10 +1,11 @@ import { deployments, ethers, helpers } from "hardhat" import { expect } from "chai" +import requireResult from "./helpers/chain" import { constants, params, updateWalletRegistryParams } from "./fixtures" -import type { ContractTransaction } from "ethers" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import type { ContractTransactionResponse } from "ethers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" import type { WalletRegistry, WalletRegistryStub, @@ -56,7 +57,6 @@ describe("WalletRegistryGovernance", async () => { const initialSortitionPoolRewardsBanDuration = 1209600 // 14 days before("load test fixture", async () => { - // eslint-disable-next-line @typescript-eslint/no-extra-semi ;({ walletRegistry, walletRegistryGovernance, governance, thirdParty } = await fixture()) }) @@ -67,20 +67,20 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .upgradeRandomBeacon(thirdParty.address) + .upgradeRandomBeacon(thirdParty.address), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse context("when new address is zero", () => { it("should revert when a new random beacon address is zero", async () => { await expect( walletRegistryGovernance .connect(governance) - .upgradeRandomBeacon(ethers.constants.AddressZero) + .upgradeRandomBeacon(ethers.ZeroAddress), ).to.be.revertedWith("New random beacon address cannot be zero") }) }) @@ -100,7 +100,7 @@ describe("WalletRegistryGovernance", async () => { it("should update the random beacon", async () => { expect(await walletRegistry.randomBeacon()).to.be.equal( - thirdParty.address + thirdParty.address, ) }) @@ -119,20 +119,20 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .initializeWalletOwner(thirdParty.address) + .initializeWalletOwner(thirdParty.address), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse context("when new address is zero", () => { it("should revert when a new address is zero", async () => { await expect( walletRegistryGovernance .connect(governance) - .initializeWalletOwner(ethers.constants.AddressZero) + .initializeWalletOwner(ethers.ZeroAddress), ).to.be.revertedWith("Wallet Owner address cannot be zero") }) }) @@ -152,7 +152,7 @@ describe("WalletRegistryGovernance", async () => { it("should update the wallet owner", async () => { expect(await walletRegistry.walletOwner()).to.be.equal( - thirdParty.address + thirdParty.address, ) }) @@ -166,7 +166,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .initializeWalletOwner(thirdParty.address) + .initializeWalletOwner(thirdParty.address), ).to.be.revertedWith("Wallet Owner already initialized") }) }) @@ -179,13 +179,13 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .beginGovernanceDelayUpdate(1) + .beginGovernanceDelayUpdate(1), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -201,19 +201,22 @@ describe("WalletRegistryGovernance", async () => { it("should not update the governance delay", async () => { expect(await walletRegistryGovernance.governanceDelay()).to.be.equal( - constants.governanceDelay + constants.governanceDelay, ) }) it("should start the governance delay timer", async () => { expect( - await walletRegistryGovernance.getRemainingGovernanceDelayUpdateTime() + await walletRegistryGovernance.getRemainingGovernanceDelayUpdateTime(), ).to.be.equal(constants.governanceDelay) }) it("should emit GovernanceDelayUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit(walletRegistryGovernance, "GovernanceDelayUpdateStarted") .withArgs(1337, blockTimestamp) @@ -227,7 +230,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .finalizeGovernanceDelayUpdate() + .finalizeGovernanceDelayUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -237,7 +240,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeGovernanceDelayUpdate() + .finalizeGovernanceDelayUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -261,7 +264,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeGovernanceDelayUpdate() + .finalizeGovernanceDelayUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") }) }) @@ -269,7 +272,7 @@ describe("WalletRegistryGovernance", async () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -291,7 +294,7 @@ describe("WalletRegistryGovernance", async () => { it("should update the governance delay", async () => { expect(await walletRegistryGovernance.governanceDelay()).to.be.equal( - 7331 + 7331, ) }) @@ -303,10 +306,10 @@ describe("WalletRegistryGovernance", async () => { it("should reset the governance delay timer", async () => { await expect( - walletRegistryGovernance.getRemainingGovernanceDelayUpdateTime() + walletRegistryGovernance.getRemainingGovernanceDelayUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -317,14 +320,14 @@ describe("WalletRegistryGovernance", async () => { walletRegistryGovernance .connect(thirdParty) .beginWalletRegistryGovernanceTransfer( - "0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537" - ) + "0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537", + ), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -332,7 +335,7 @@ describe("WalletRegistryGovernance", async () => { tx = await walletRegistryGovernance .connect(governance) .beginWalletRegistryGovernanceTransfer( - "0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537" + "0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537", ) }) @@ -345,38 +348,39 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .beginWalletRegistryGovernanceTransfer( - ethers.constants.AddressZero - ) + .beginWalletRegistryGovernanceTransfer(ethers.ZeroAddress), ).to.be.revertedWith( - "New wallet registry governance address cannot be zero" + "New wallet registry governance address cannot be zero", ) }) }) it("should not transfer the governance", async () => { expect(await walletRegistry.governance()).to.be.equal( - walletRegistryGovernance.address + await walletRegistryGovernance.getAddress(), ) }) it("should start the governance delay timer", async () => { expect( - await walletRegistryGovernance.getRemainingWalletRegistryGovernanceTransferDelayTime() + await walletRegistryGovernance.getRemainingWalletRegistryGovernanceTransferDelayTime(), ).to.be.equal(constants.governanceDelay) }) it("should emit WalletRegistryGovernanceTransferStarted", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( walletRegistryGovernance, - "WalletRegistryGovernanceTransferStarted" + "WalletRegistryGovernanceTransferStarted", ) .withArgs( "0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537", - blockTimestamp + blockTimestamp, ) }) }) @@ -388,7 +392,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .finalizeWalletRegistryGovernanceTransfer() + .finalizeWalletRegistryGovernanceTransfer(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -398,7 +402,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeWalletRegistryGovernanceTransfer() + .finalizeWalletRegistryGovernanceTransfer(), ).to.be.revertedWith("Change not initiated") }) }) @@ -410,7 +414,7 @@ describe("WalletRegistryGovernance", async () => { await walletRegistryGovernance .connect(governance) .beginWalletRegistryGovernanceTransfer( - "0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537" + "0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537", ) await helpers.time.increaseTime(constants.governanceDelay - 60) // -1min @@ -424,7 +428,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeWalletRegistryGovernanceTransfer() + .finalizeWalletRegistryGovernanceTransfer(), ).to.be.revertedWith("Governance delay has not elapsed") }) }) @@ -432,7 +436,7 @@ describe("WalletRegistryGovernance", async () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -440,7 +444,7 @@ describe("WalletRegistryGovernance", async () => { await walletRegistryGovernance .connect(governance) .beginWalletRegistryGovernanceTransfer( - "0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537" + "0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537", ) await helpers.time.increaseTime(constants.governanceDelay) @@ -456,7 +460,7 @@ describe("WalletRegistryGovernance", async () => { it("should transfer wallet registry governance", async () => { expect(await walletRegistry.governance()).to.be.equal( - "0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537" + "0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537", ) }) @@ -464,17 +468,17 @@ describe("WalletRegistryGovernance", async () => { await expect(tx) .to.emit( walletRegistryGovernance, - "WalletRegistryGovernanceTransferred" + "WalletRegistryGovernanceTransferred", ) .withArgs("0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537") }) it("should reset the governance delay timer", async () => { await expect( - walletRegistryGovernance.getRemainingWalletRegistryGovernanceTransferDelayTime() + walletRegistryGovernance.getRemainingWalletRegistryGovernanceTransferDelayTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -484,13 +488,13 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .beginWalletOwnerUpdate(thirdParty.address) + .beginWalletOwnerUpdate(thirdParty.address), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -509,26 +513,29 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .beginWalletOwnerUpdate(ethers.constants.AddressZero) + .beginWalletOwnerUpdate(ethers.ZeroAddress), ).to.be.revertedWith("New wallet owner address cannot be zero") }) }) it("should not update the wallet owner", async () => { expect(await walletRegistry.walletOwner()).to.be.equal( - ethers.constants.AddressZero + ethers.ZeroAddress, ) }) it("should start the governance delay timer", async () => { expect( - await walletRegistryGovernance.getRemainingWalletOwnerUpdateTime() + await walletRegistryGovernance.getRemainingWalletOwnerUpdateTime(), ).to.be.equal(constants.governanceDelay) }) it("should emit the WalletOwnerUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit(walletRegistryGovernance, "WalletOwnerUpdateStarted") .withArgs(thirdParty.address, blockTimestamp) @@ -542,7 +549,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .finalizeWalletOwnerUpdate() + .finalizeWalletOwnerUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -552,7 +559,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeWalletOwnerUpdate() + .finalizeWalletOwnerUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -570,7 +577,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeWalletOwnerUpdate() + .finalizeWalletOwnerUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -580,7 +587,7 @@ describe("WalletRegistryGovernance", async () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -602,7 +609,7 @@ describe("WalletRegistryGovernance", async () => { it("should update the wallet owner", async () => { expect(await walletRegistry.walletOwner()).to.be.equal( - thirdParty.address + thirdParty.address, ) }) @@ -614,10 +621,10 @@ describe("WalletRegistryGovernance", async () => { it("should reset the governance delay timer", async () => { await expect( - walletRegistryGovernance.getRemainingWalletOwnerUpdateTime() + walletRegistryGovernance.getRemainingWalletOwnerUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -627,13 +634,13 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .beginMinimumAuthorizationUpdate(123) + .beginMinimumAuthorizationUpdate(123), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -649,23 +656,26 @@ describe("WalletRegistryGovernance", async () => { it("should not update the minimum authorization amount", async () => { expect(await walletRegistry.minimumAuthorization()).to.be.equal( - initialMinimumAuthorization + initialMinimumAuthorization, ) }) it("should start the governance delay timer", async () => { expect( - await walletRegistryGovernance.getRemainingMimimumAuthorizationUpdateTime() + await walletRegistryGovernance.getRemainingMimimumAuthorizationUpdateTime(), ).to.be.equal(constants.governanceDelay) }) it("should emit the MinimumAuthorizationUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( walletRegistryGovernance, - "MinimumAuthorizationUpdateStarted" + "MinimumAuthorizationUpdateStarted", ) .withArgs(123, blockTimestamp) }) @@ -678,7 +688,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .finalizeMinimumAuthorizationUpdate() + .finalizeMinimumAuthorizationUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -688,7 +698,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeMinimumAuthorizationUpdate() + .finalizeMinimumAuthorizationUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -706,7 +716,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeMinimumAuthorizationUpdate() + .finalizeMinimumAuthorizationUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -716,7 +726,7 @@ describe("WalletRegistryGovernance", async () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -748,10 +758,10 @@ describe("WalletRegistryGovernance", async () => { it("should reset the governance delay timer", async () => { await expect( - walletRegistryGovernance.getRemainingMimimumAuthorizationUpdateTime() + walletRegistryGovernance.getRemainingMimimumAuthorizationUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -761,13 +771,13 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .beginAuthorizationDecreaseDelayUpdate(123) + .beginAuthorizationDecreaseDelayUpdate(123), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -785,23 +795,26 @@ describe("WalletRegistryGovernance", async () => { const { authorizationDecreaseDelay } = await walletRegistry.authorizationParameters() expect(authorizationDecreaseDelay).to.be.equal( - initialAuthorizationDecreaseDelay + initialAuthorizationDecreaseDelay, ) }) it("should start the governance delay timer", async () => { expect( - await walletRegistryGovernance.getRemainingAuthorizationDecreaseDelayUpdateTime() + await walletRegistryGovernance.getRemainingAuthorizationDecreaseDelayUpdateTime(), ).to.be.equal(constants.governanceDelay) }) it("should emit the AuthorizationDecreaseDelayUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( walletRegistryGovernance, - "AuthorizationDecreaseDelayUpdateStarted" + "AuthorizationDecreaseDelayUpdateStarted", ) .withArgs(123, blockTimestamp) }) @@ -814,7 +827,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .finalizeAuthorizationDecreaseDelayUpdate() + .finalizeAuthorizationDecreaseDelayUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -824,7 +837,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeAuthorizationDecreaseDelayUpdate() + .finalizeAuthorizationDecreaseDelayUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -840,7 +853,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeAuthorizationDecreaseDelayUpdate() + .finalizeAuthorizationDecreaseDelayUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -850,7 +863,7 @@ describe("WalletRegistryGovernance", async () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -880,17 +893,17 @@ describe("WalletRegistryGovernance", async () => { await expect(tx) .to.emit( walletRegistryGovernance, - "AuthorizationDecreaseDelayUpdated" + "AuthorizationDecreaseDelayUpdated", ) .withArgs(123) }) it("should reset the governance delay timer", async () => { await expect( - walletRegistryGovernance.getRemainingAuthorizationDecreaseDelayUpdateTime() + walletRegistryGovernance.getRemainingAuthorizationDecreaseDelayUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -900,13 +913,13 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .beginAuthorizationDecreaseChangePeriodUpdate(123) + .beginAuthorizationDecreaseChangePeriodUpdate(123), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -924,23 +937,26 @@ describe("WalletRegistryGovernance", async () => { const { authorizationDecreaseChangePeriod } = await walletRegistry.authorizationParameters() expect(authorizationDecreaseChangePeriod).to.be.equal( - initialAuthorizationDecreaseChangePeriod + initialAuthorizationDecreaseChangePeriod, ) }) it("should start the governance delay timer", async () => { expect( - await walletRegistryGovernance.getRemainingAuthorizationDecreaseChangePeriodUpdateTime() + await walletRegistryGovernance.getRemainingAuthorizationDecreaseChangePeriodUpdateTime(), ).to.be.equal(constants.governanceDelay) }) it("should emit the AuthorizationDecreaseChangePeriodUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( walletRegistryGovernance, - "AuthorizationDecreaseChangePeriodUpdateStarted" + "AuthorizationDecreaseChangePeriodUpdateStarted", ) .withArgs(123, blockTimestamp) }) @@ -953,7 +969,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .finalizeAuthorizationDecreaseChangePeriodUpdate() + .finalizeAuthorizationDecreaseChangePeriodUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -963,7 +979,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeAuthorizationDecreaseChangePeriodUpdate() + .finalizeAuthorizationDecreaseChangePeriodUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -979,7 +995,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeAuthorizationDecreaseChangePeriodUpdate() + .finalizeAuthorizationDecreaseChangePeriodUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -989,7 +1005,7 @@ describe("WalletRegistryGovernance", async () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1019,17 +1035,17 @@ describe("WalletRegistryGovernance", async () => { await expect(tx) .to.emit( walletRegistryGovernance, - "AuthorizationDecreaseChangePeriodUpdated" + "AuthorizationDecreaseChangePeriodUpdated", ) .withArgs(123) }) it("should reset the governance delay timer", async () => { await expect( - walletRegistryGovernance.getRemainingAuthorizationDecreaseChangePeriodUpdateTime() + walletRegistryGovernance.getRemainingAuthorizationDecreaseChangePeriodUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -1039,13 +1055,13 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .beginMaliciousDkgResultSlashingAmountUpdate(123) + .beginMaliciousDkgResultSlashingAmountUpdate(123), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1063,23 +1079,26 @@ describe("WalletRegistryGovernance", async () => { const maliciousDkgResultSlashingAmount = await walletRegistry.slashingParameters() expect(maliciousDkgResultSlashingAmount).to.be.equal( - initialMaliciousDkgResultSlashingAmount + initialMaliciousDkgResultSlashingAmount, ) }) it("should start the governance delay timer", async () => { expect( - await walletRegistryGovernance.getRemainingMaliciousDkgResultSlashingAmountUpdateTime() + await walletRegistryGovernance.getRemainingMaliciousDkgResultSlashingAmountUpdateTime(), ).to.be.equal(constants.governanceDelay) }) it("should emit the MaliciousDkgResultSlashingAmountUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( walletRegistryGovernance, - "MaliciousDkgResultSlashingAmountUpdateStarted" + "MaliciousDkgResultSlashingAmountUpdateStarted", ) .withArgs(123, blockTimestamp) }) @@ -1092,7 +1111,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .finalizeMaliciousDkgResultSlashingAmountUpdate() + .finalizeMaliciousDkgResultSlashingAmountUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -1102,7 +1121,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeMaliciousDkgResultSlashingAmountUpdate() + .finalizeMaliciousDkgResultSlashingAmountUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -1120,7 +1139,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeMaliciousDkgResultSlashingAmountUpdate() + .finalizeMaliciousDkgResultSlashingAmountUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -1130,7 +1149,7 @@ describe("WalletRegistryGovernance", async () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1160,17 +1179,17 @@ describe("WalletRegistryGovernance", async () => { await expect(tx) .to.emit( walletRegistryGovernance, - "MaliciousDkgResultSlashingAmountUpdated" + "MaliciousDkgResultSlashingAmountUpdated", ) .withArgs(123) }) it("should reset the governance delay timer", async () => { await expect( - walletRegistryGovernance.getRemainingMaliciousDkgResultSlashingAmountUpdateTime() + walletRegistryGovernance.getRemainingMaliciousDkgResultSlashingAmountUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -1180,13 +1199,13 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .beginDkgResultSubmissionGasUpdate(100) + .beginDkgResultSubmissionGasUpdate(100), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1203,23 +1222,26 @@ describe("WalletRegistryGovernance", async () => { it("should not update the DKG submission result gas", async () => { const { dkgResultSubmissionGas } = await walletRegistry.gasParameters() expect(dkgResultSubmissionGas).to.be.equal( - initialDkgResultSubmissionGas + initialDkgResultSubmissionGas, ) }) it("should start the governance delay timer", async () => { expect( - await walletRegistryGovernance.getRemainingDkgResultSubmissionGasUpdateTime() + await walletRegistryGovernance.getRemainingDkgResultSubmissionGasUpdateTime(), ).to.be.equal(constants.governanceDelay) }) it("should emit the DkgResultSubmissionGasUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( walletRegistryGovernance, - "DkgResultSubmissionGasUpdateStarted" + "DkgResultSubmissionGasUpdateStarted", ) .withArgs(100, blockTimestamp) }) @@ -1232,7 +1254,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .finalizeDkgResultSubmissionGasUpdate() + .finalizeDkgResultSubmissionGasUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -1242,7 +1264,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeDkgResultSubmissionGasUpdate() + .finalizeDkgResultSubmissionGasUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -1260,7 +1282,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeDkgResultSubmissionGasUpdate() + .finalizeDkgResultSubmissionGasUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -1270,7 +1292,7 @@ describe("WalletRegistryGovernance", async () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1304,10 +1326,10 @@ describe("WalletRegistryGovernance", async () => { it("should reset the governance delay timer", async () => { await expect( - walletRegistryGovernance.getRemainingDkgResultSubmissionGasUpdateTime() + walletRegistryGovernance.getRemainingDkgResultSubmissionGasUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -1317,13 +1339,13 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .beginDkgResultApprovalGasOffsetUpdate(100) + .beginDkgResultApprovalGasOffsetUpdate(100), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1341,23 +1363,26 @@ describe("WalletRegistryGovernance", async () => { const { dkgResultApprovalGasOffset } = await walletRegistry.gasParameters() expect(dkgResultApprovalGasOffset).to.be.equal( - initialDkgResultApprovalGasOffset + initialDkgResultApprovalGasOffset, ) }) it("should start the governance delay timer", async () => { expect( - await walletRegistryGovernance.getRemainingDkgResultApprovalGasOffsetUpdateTime() + await walletRegistryGovernance.getRemainingDkgResultApprovalGasOffsetUpdateTime(), ).to.be.equal(constants.governanceDelay) }) it("should emit the DkgResultApprovalGasOffsetUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( walletRegistryGovernance, - "DkgResultApprovalGasOffsetUpdateStarted" + "DkgResultApprovalGasOffsetUpdateStarted", ) .withArgs(100, blockTimestamp) }) @@ -1370,7 +1395,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .finalizeDkgResultApprovalGasOffsetUpdate() + .finalizeDkgResultApprovalGasOffsetUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -1380,7 +1405,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeDkgResultApprovalGasOffsetUpdate() + .finalizeDkgResultApprovalGasOffsetUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -1398,7 +1423,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeDkgResultApprovalGasOffsetUpdate() + .finalizeDkgResultApprovalGasOffsetUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -1408,7 +1433,7 @@ describe("WalletRegistryGovernance", async () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1438,17 +1463,17 @@ describe("WalletRegistryGovernance", async () => { await expect(tx) .to.emit( walletRegistryGovernance, - "DkgResultApprovalGasOffsetUpdated" + "DkgResultApprovalGasOffsetUpdated", ) .withArgs(100) }) it("should reset the governance delay timer", async () => { await expect( - walletRegistryGovernance.getRemainingDkgResultApprovalGasOffsetUpdateTime() + walletRegistryGovernance.getRemainingDkgResultApprovalGasOffsetUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -1458,7 +1483,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .beginMaliciousDkgResultNotificationRewardMultiplierUpdate(100) + .beginMaliciousDkgResultNotificationRewardMultiplierUpdate(100), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -1468,13 +1493,13 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .beginMaliciousDkgResultNotificationRewardMultiplierUpdate(101) + .beginMaliciousDkgResultNotificationRewardMultiplierUpdate(101), ).to.be.revertedWith("Maximum value is 100") }) }) context("when the caller is the owner and value is correct", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1492,23 +1517,26 @@ describe("WalletRegistryGovernance", async () => { const { maliciousDkgResultNotificationRewardMultiplier } = await walletRegistry.rewardParameters() expect(maliciousDkgResultNotificationRewardMultiplier).to.be.equal( - initialMaliciousDkgResultNotificationRewardMultiplier + initialMaliciousDkgResultNotificationRewardMultiplier, ) }) it("should start the governance delay timer", async () => { expect( - await walletRegistryGovernance.getRemainingMaliciousDkgResultNotificationRewardMultiplierUpdateTime() + await walletRegistryGovernance.getRemainingMaliciousDkgResultNotificationRewardMultiplierUpdateTime(), ).to.be.equal(constants.governanceDelay) }) it("should emit the MaliciousDkgResultNotificationRewardMultiplierUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( walletRegistryGovernance, - "MaliciousDkgResultNotificationRewardMultiplierUpdateStarted" + "MaliciousDkgResultNotificationRewardMultiplierUpdateStarted", ) .withArgs(100, blockTimestamp) }) @@ -1521,7 +1549,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .finalizeMaliciousDkgResultNotificationRewardMultiplierUpdate() + .finalizeMaliciousDkgResultNotificationRewardMultiplierUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -1531,7 +1559,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeMaliciousDkgResultNotificationRewardMultiplierUpdate() + .finalizeMaliciousDkgResultNotificationRewardMultiplierUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -1549,7 +1577,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeMaliciousDkgResultNotificationRewardMultiplierUpdate() + .finalizeMaliciousDkgResultNotificationRewardMultiplierUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -1559,7 +1587,7 @@ describe("WalletRegistryGovernance", async () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1583,7 +1611,7 @@ describe("WalletRegistryGovernance", async () => { const { maliciousDkgResultNotificationRewardMultiplier } = await walletRegistry.rewardParameters() expect(maliciousDkgResultNotificationRewardMultiplier).to.be.equal( - 100 + 100, ) }) @@ -1591,17 +1619,17 @@ describe("WalletRegistryGovernance", async () => { await expect(tx) .to.emit( walletRegistryGovernance, - "MaliciousDkgResultNotificationRewardMultiplierUpdated" + "MaliciousDkgResultNotificationRewardMultiplierUpdated", ) .withArgs(100) }) it("should reset the governance delay timer", async () => { await expect( - walletRegistryGovernance.getRemainingMaliciousDkgResultNotificationRewardMultiplierUpdateTime() + walletRegistryGovernance.getRemainingMaliciousDkgResultNotificationRewardMultiplierUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -1611,13 +1639,13 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .beginSortitionPoolRewardsBanDurationUpdate(86400) + .beginSortitionPoolRewardsBanDurationUpdate(86400), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1635,23 +1663,26 @@ describe("WalletRegistryGovernance", async () => { const { sortitionPoolRewardsBanDuration } = await walletRegistry.rewardParameters() expect(sortitionPoolRewardsBanDuration).to.be.equal( - initialSortitionPoolRewardsBanDuration + initialSortitionPoolRewardsBanDuration, ) }) it("should start the governance delay timer", async () => { expect( - await walletRegistryGovernance.getRemainingSortitionPoolRewardsBanDurationUpdateTime() + await walletRegistryGovernance.getRemainingSortitionPoolRewardsBanDurationUpdateTime(), ).to.be.equal(constants.governanceDelay) }) it("should emit the SortitionPoolRewardsBanDurationUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( walletRegistryGovernance, - "SortitionPoolRewardsBanDurationUpdateStarted" + "SortitionPoolRewardsBanDurationUpdateStarted", ) .withArgs(86400, blockTimestamp) }) @@ -1664,7 +1695,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .finalizeSortitionPoolRewardsBanDurationUpdate() + .finalizeSortitionPoolRewardsBanDurationUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -1674,7 +1705,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeSortitionPoolRewardsBanDurationUpdate() + .finalizeSortitionPoolRewardsBanDurationUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -1692,7 +1723,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeSortitionPoolRewardsBanDurationUpdate() + .finalizeSortitionPoolRewardsBanDurationUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -1702,7 +1733,7 @@ describe("WalletRegistryGovernance", async () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1732,17 +1763,17 @@ describe("WalletRegistryGovernance", async () => { await expect(tx) .to.emit( walletRegistryGovernance, - "SortitionPoolRewardsBanDurationUpdated" + "SortitionPoolRewardsBanDurationUpdated", ) .withArgs(86400) }) it("should reset the governance delay timer", async () => { await expect( - walletRegistryGovernance.getRemainingSortitionPoolRewardsBanDurationUpdateTime() + walletRegistryGovernance.getRemainingSortitionPoolRewardsBanDurationUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -1752,7 +1783,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .beginDkgSeedTimeoutUpdate(11) + .beginDkgSeedTimeoutUpdate(11), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -1762,7 +1793,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .beginDkgSeedTimeoutUpdate(0) + .beginDkgSeedTimeoutUpdate(0), ).to.be.revertedWith("DKG seed timeout must be > 0") }) }) @@ -1782,12 +1813,12 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .beginDkgSeedTimeoutUpdate(1) + .beginDkgSeedTimeoutUpdate(1), ).not.to.be.reverted await expect( walletRegistryGovernance .connect(governance) - .beginDkgSeedTimeoutUpdate(11) + .beginDkgSeedTimeoutUpdate(11), ).not.to.be.reverted await restoreSnapshot() @@ -1795,7 +1826,7 @@ describe("WalletRegistryGovernance", async () => { }) context("when the caller is the owner and the value is correct", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1811,19 +1842,22 @@ describe("WalletRegistryGovernance", async () => { it("should not update the DKG seed timeout", async () => { expect((await walletRegistry.dkgParameters()).seedTimeout).to.be.equal( - params.dkgSeedTimeout + params.dkgSeedTimeout, ) }) it("should start the governance delay timer", async () => { expect( - await walletRegistryGovernance.getRemainingDkgSeedTimeoutUpdateTime() + await walletRegistryGovernance.getRemainingDkgSeedTimeoutUpdateTime(), ).to.be.equal(constants.governanceDelay) }) it("should emit the DkgSeedTimeoutUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit(walletRegistryGovernance, "DkgSeedTimeoutUpdateStarted") .withArgs(11, blockTimestamp) @@ -1837,7 +1871,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .finalizeDkgSeedTimeoutUpdate() + .finalizeDkgSeedTimeoutUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -1847,7 +1881,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeDkgSeedTimeoutUpdate() + .finalizeDkgSeedTimeoutUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -1865,7 +1899,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeDkgSeedTimeoutUpdate() + .finalizeDkgSeedTimeoutUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -1875,7 +1909,7 @@ describe("WalletRegistryGovernance", async () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1897,7 +1931,7 @@ describe("WalletRegistryGovernance", async () => { it("should update the DKG seed timeout", async () => { expect( - (await walletRegistry.dkgParameters()).seedTimeout + (await walletRegistry.dkgParameters()).seedTimeout, ).to.be.equal(11) }) @@ -1909,10 +1943,10 @@ describe("WalletRegistryGovernance", async () => { it("should reset the governance delay timer", async () => { await expect( - walletRegistryGovernance.getRemainingDkgSeedTimeoutUpdateTime() + walletRegistryGovernance.getRemainingDkgSeedTimeoutUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -1922,7 +1956,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .beginDkgResultChallengePeriodLengthUpdate(11) + .beginDkgResultChallengePeriodLengthUpdate(11), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -1932,7 +1966,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .beginDkgResultChallengePeriodLengthUpdate(9) + .beginDkgResultChallengePeriodLengthUpdate(9), ).to.be.revertedWith("DKG result challenge period length must be >= 10") }) }) @@ -1944,13 +1978,13 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .beginDkgResultChallengePeriodLengthUpdate(10) + .beginDkgResultChallengePeriodLengthUpdate(10), ).to.not.be.reverted await expect( walletRegistryGovernance .connect(governance) - .beginDkgResultChallengePeriodLengthUpdate(11) + .beginDkgResultChallengePeriodLengthUpdate(11), ).to.not.be.reverted await restoreSnapshot() @@ -1958,7 +1992,7 @@ describe("WalletRegistryGovernance", async () => { }) context("when the caller is the owner and the value is correct", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1974,23 +2008,26 @@ describe("WalletRegistryGovernance", async () => { it("should not update the DKG result challenge period length", async () => { expect( - (await walletRegistry.dkgParameters()).resultChallengePeriodLength + (await walletRegistry.dkgParameters()).resultChallengePeriodLength, ).to.be.equal(params.dkgResultChallengePeriodLength) }) it("should start the governance delay timer", async () => { expect( - await walletRegistryGovernance.getRemainingDkgResultChallengePeriodLengthUpdateTime() + await walletRegistryGovernance.getRemainingDkgResultChallengePeriodLengthUpdateTime(), ).to.be.equal(constants.governanceDelay) }) it("should emit the DkgResultChallengePeriodLengthUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( walletRegistryGovernance, - "DkgResultChallengePeriodLengthUpdateStarted" + "DkgResultChallengePeriodLengthUpdateStarted", ) .withArgs(11, blockTimestamp) }) @@ -2003,7 +2040,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .finalizeDkgResultChallengePeriodLengthUpdate() + .finalizeDkgResultChallengePeriodLengthUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -2013,7 +2050,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeDkgResultChallengePeriodLengthUpdate() + .finalizeDkgResultChallengePeriodLengthUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -2031,7 +2068,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeDkgResultChallengePeriodLengthUpdate() + .finalizeDkgResultChallengePeriodLengthUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -2041,7 +2078,7 @@ describe("WalletRegistryGovernance", async () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2063,7 +2100,7 @@ describe("WalletRegistryGovernance", async () => { it("should update the DKG result challenge period length", async () => { expect( - (await walletRegistry.dkgParameters()).resultChallengePeriodLength + (await walletRegistry.dkgParameters()).resultChallengePeriodLength, ).to.be.equal(11) }) @@ -2071,17 +2108,17 @@ describe("WalletRegistryGovernance", async () => { await expect(tx) .to.emit( walletRegistryGovernance, - "DkgResultChallengePeriodLengthUpdated" + "DkgResultChallengePeriodLengthUpdated", ) .withArgs(11) }) it("should reset the governance delay timer", async () => { await expect( - walletRegistryGovernance.getRemainingDkgResultChallengePeriodLengthUpdateTime() + walletRegistryGovernance.getRemainingDkgResultChallengePeriodLengthUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -2091,13 +2128,13 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .beginDkgResultChallengeExtraGasUpdate(1) + .beginDkgResultChallengeExtraGasUpdate(1), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2113,17 +2150,20 @@ describe("WalletRegistryGovernance", async () => { it("should not update the DKG result challenge extra gas", async () => { expect( - (await walletRegistry.dkgParameters()).resultChallengeExtraGas + (await walletRegistry.dkgParameters()).resultChallengeExtraGas, ).to.be.equal(params.dkgResultChallengeExtraGas) }) it("should emit DkgResultChallengeExtraGasUpdateStarted", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( walletRegistryGovernance, - "DkgResultChallengeExtraGasUpdateStarted" + "DkgResultChallengeExtraGasUpdateStarted", ) .withArgs(1337, blockTimestamp) }) @@ -2136,7 +2176,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .finalizeDkgResultChallengeExtraGasUpdate() + .finalizeDkgResultChallengeExtraGasUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -2146,7 +2186,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeDkgResultChallengeExtraGasUpdate() + .finalizeDkgResultChallengeExtraGasUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -2164,7 +2204,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeDkgResultChallengeExtraGasUpdate() + .finalizeDkgResultChallengeExtraGasUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -2174,7 +2214,7 @@ describe("WalletRegistryGovernance", async () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2196,7 +2236,7 @@ describe("WalletRegistryGovernance", async () => { it("should update the DKG result challenge extra gas", async () => { expect( - (await walletRegistry.dkgParameters()).resultChallengeExtraGas + (await walletRegistry.dkgParameters()).resultChallengeExtraGas, ).to.be.equal(1337) }) @@ -2204,17 +2244,17 @@ describe("WalletRegistryGovernance", async () => { await expect(tx) .to.emit( walletRegistryGovernance, - "DkgResultChallengeExtraGasUpdated" + "DkgResultChallengeExtraGasUpdated", ) .withArgs(1337) }) it("should reset the governance delay timer", async () => { await expect( - walletRegistryGovernance.getRemainingDkgResultChallengeExtraGasUpdateTime() + walletRegistryGovernance.getRemainingDkgResultChallengeExtraGasUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -2224,7 +2264,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .beginDkgResultSubmissionTimeoutUpdate(1) + .beginDkgResultSubmissionTimeoutUpdate(1), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -2234,7 +2274,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .beginDkgResultSubmissionTimeoutUpdate(0) + .beginDkgResultSubmissionTimeoutUpdate(0), ).to.be.revertedWith("DKG result submission timeout must be > 0") }) }) @@ -2246,12 +2286,12 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .beginDkgResultSubmissionTimeoutUpdate(1) + .beginDkgResultSubmissionTimeoutUpdate(1), ).to.not.be.reverted await expect( walletRegistryGovernance .connect(governance) - .beginDkgResultSubmissionTimeoutUpdate(2) + .beginDkgResultSubmissionTimeoutUpdate(2), ).to.not.be.reverted await restoreSnapshot() @@ -2259,7 +2299,7 @@ describe("WalletRegistryGovernance", async () => { }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2275,23 +2315,26 @@ describe("WalletRegistryGovernance", async () => { it("should not update the DKG result submission timeout", async () => { expect( - (await walletRegistry.dkgParameters()).resultSubmissionTimeout + (await walletRegistry.dkgParameters()).resultSubmissionTimeout, ).to.be.equal(params.dkgResultSubmissionTimeout) }) it("should start the governance delay timer", async () => { expect( - await walletRegistryGovernance.getRemainingDkgResultSubmissionTimeoutUpdateTime() + await walletRegistryGovernance.getRemainingDkgResultSubmissionTimeoutUpdateTime(), ).to.be.equal(constants.governanceDelay) }) it("should emit the DkgResultSubmissionTimeoutUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( walletRegistryGovernance, - "DkgResultSubmissionTimeoutUpdateStarted" + "DkgResultSubmissionTimeoutUpdateStarted", ) .withArgs(1, blockTimestamp) }) @@ -2304,7 +2347,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .finalizeDkgResultSubmissionTimeoutUpdate() + .finalizeDkgResultSubmissionTimeoutUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -2314,7 +2357,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeDkgResultSubmissionTimeoutUpdate() + .finalizeDkgResultSubmissionTimeoutUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -2332,7 +2375,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeDkgResultSubmissionTimeoutUpdate() + .finalizeDkgResultSubmissionTimeoutUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -2342,7 +2385,7 @@ describe("WalletRegistryGovernance", async () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2364,7 +2407,7 @@ describe("WalletRegistryGovernance", async () => { it("should update the DKG result submission timeout", async () => { expect( - (await walletRegistry.dkgParameters()).resultSubmissionTimeout + (await walletRegistry.dkgParameters()).resultSubmissionTimeout, ).to.be.equal(10) }) @@ -2372,17 +2415,17 @@ describe("WalletRegistryGovernance", async () => { await expect(tx) .to.emit( walletRegistryGovernance, - "DkgResultSubmissionTimeoutUpdated" + "DkgResultSubmissionTimeoutUpdated", ) .withArgs(10) }) it("should reset the governance delay timer", async () => { await expect( - walletRegistryGovernance.getRemainingDkgResultSubmissionTimeoutUpdateTime() + walletRegistryGovernance.getRemainingDkgResultSubmissionTimeoutUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -2392,7 +2435,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .beginDkgSubmitterPrecedencePeriodLengthUpdate(1) + .beginDkgSubmitterPrecedencePeriodLengthUpdate(1), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -2402,9 +2445,9 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .beginDkgSubmitterPrecedencePeriodLengthUpdate(0) + .beginDkgSubmitterPrecedencePeriodLengthUpdate(0), ).to.be.revertedWith( - "DKG submitter precedence period length must be > 0" + "DKG submitter precedence period length must be > 0", ) }) }) @@ -2416,12 +2459,12 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .beginDkgSubmitterPrecedencePeriodLengthUpdate(1) + .beginDkgSubmitterPrecedencePeriodLengthUpdate(1), ).to.not.be.reverted await expect( walletRegistryGovernance .connect(governance) - .beginDkgSubmitterPrecedencePeriodLengthUpdate(2) + .beginDkgSubmitterPrecedencePeriodLengthUpdate(2), ).to.not.be.reverted await restoreSnapshot() @@ -2429,7 +2472,7 @@ describe("WalletRegistryGovernance", async () => { }) context("when the caller is the owner and the value is correct", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2445,23 +2488,27 @@ describe("WalletRegistryGovernance", async () => { it("should not update the DKG submitter precedence period length", async () => { expect( - (await walletRegistry.dkgParameters()).submitterPrecedencePeriodLength + (await walletRegistry.dkgParameters()) + .submitterPrecedencePeriodLength, ).to.be.equal(params.dkgSubmitterPrecedencePeriodLength) }) it("should start the governance delay timer", async () => { expect( - await walletRegistryGovernance.getRemainingDkgSubmitterPrecedencePeriodLengthUpdateTime() + await walletRegistryGovernance.getRemainingDkgSubmitterPrecedencePeriodLengthUpdateTime(), ).to.be.equal(constants.governanceDelay) }) it("should emit the DkgSubmitterPrecedencePeriodLengthUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( walletRegistryGovernance, - "DkgSubmitterPrecedencePeriodLengthUpdateStarted" + "DkgSubmitterPrecedencePeriodLengthUpdateStarted", ) .withArgs(1, blockTimestamp) }) @@ -2474,7 +2521,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .finalizeDkgSubmitterPrecedencePeriodLengthUpdate() + .finalizeDkgSubmitterPrecedencePeriodLengthUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -2484,7 +2531,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeDkgSubmitterPrecedencePeriodLengthUpdate() + .finalizeDkgSubmitterPrecedencePeriodLengthUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -2502,7 +2549,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeDkgSubmitterPrecedencePeriodLengthUpdate() + .finalizeDkgSubmitterPrecedencePeriodLengthUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -2512,7 +2559,7 @@ describe("WalletRegistryGovernance", async () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2535,7 +2582,7 @@ describe("WalletRegistryGovernance", async () => { it("should update the DKG submitter precedence period length", async () => { expect( (await walletRegistry.dkgParameters()) - .submitterPrecedencePeriodLength + .submitterPrecedencePeriodLength, ).to.be.equal(10) }) @@ -2543,17 +2590,17 @@ describe("WalletRegistryGovernance", async () => { await expect(tx) .to.emit( walletRegistryGovernance, - "DkgSubmitterPrecedencePeriodLengthUpdated" + "DkgSubmitterPrecedencePeriodLengthUpdated", ) .withArgs(10) }) it("should reset the governance delay timer", async () => { await expect( - walletRegistryGovernance.getRemainingDkgSubmitterPrecedencePeriodLengthUpdateTime() + walletRegistryGovernance.getRemainingDkgSubmitterPrecedencePeriodLengthUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -2563,13 +2610,13 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .beginReimbursementPoolUpdate(thirdParty.address) + .beginReimbursementPoolUpdate(thirdParty.address), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse let reimbursementPoolAddress: string before(async () => { @@ -2591,26 +2638,29 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .beginReimbursementPoolUpdate(ethers.constants.AddressZero) + .beginReimbursementPoolUpdate(ethers.ZeroAddress), ).to.be.revertedWith("New reimbursement pool address cannot be zero") }) }) it("should not update the reimbursement pool", async () => { expect(await walletRegistry.reimbursementPool()).to.be.equal( - reimbursementPoolAddress + reimbursementPoolAddress, ) }) it("should start the governance delay timer", async () => { expect( - await walletRegistryGovernance.getRemainingReimbursementPoolUpdateTime() + await walletRegistryGovernance.getRemainingReimbursementPoolUpdateTime(), ).to.be.equal(constants.governanceDelay) }) it("should emit the ReimbursementPoolUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit(walletRegistryGovernance, "ReimbursementPoolUpdateStarted") .withArgs(thirdParty.address, blockTimestamp) @@ -2624,7 +2674,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .finalizeReimbursementPoolUpdate() + .finalizeReimbursementPoolUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -2634,7 +2684,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeReimbursementPoolUpdate() + .finalizeReimbursementPoolUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -2652,7 +2702,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeReimbursementPoolUpdate() + .finalizeReimbursementPoolUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -2662,7 +2712,7 @@ describe("WalletRegistryGovernance", async () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2684,7 +2734,7 @@ describe("WalletRegistryGovernance", async () => { it("should update the reimbursement pool", async () => { expect(await walletRegistry.reimbursementPool()).to.be.equal( - thirdParty.address + thirdParty.address, ) }) @@ -2696,10 +2746,10 @@ describe("WalletRegistryGovernance", async () => { it("should reset the governance delay timer", async () => { await expect( - walletRegistryGovernance.getRemainingReimbursementPoolUpdateTime() + walletRegistryGovernance.getRemainingReimbursementPoolUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -2709,13 +2759,13 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .beginNotifyOperatorInactivityGasOffsetUpdate(100) + .beginNotifyOperatorInactivityGasOffsetUpdate(100), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2733,23 +2783,26 @@ describe("WalletRegistryGovernance", async () => { const { notifyOperatorInactivityGasOffset } = await walletRegistry.gasParameters() expect(notifyOperatorInactivityGasOffset).to.be.equal( - initialNotifyOperatorInactivityGasOffset + initialNotifyOperatorInactivityGasOffset, ) }) it("should start the governance delay timer", async () => { expect( - await walletRegistryGovernance.getRemainingNotifyOperatorInactivityGasOffsetUpdateTime() + await walletRegistryGovernance.getRemainingNotifyOperatorInactivityGasOffsetUpdateTime(), ).to.be.equal(constants.governanceDelay) }) it("should emit the NotifyOperatorInactivityGasOffsetUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( walletRegistryGovernance, - "NotifyOperatorInactivityGasOffsetUpdateStarted" + "NotifyOperatorInactivityGasOffsetUpdateStarted", ) .withArgs(100, blockTimestamp) }) @@ -2762,7 +2815,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .finalizeNotifyOperatorInactivityGasOffsetUpdate() + .finalizeNotifyOperatorInactivityGasOffsetUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -2772,7 +2825,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeNotifyOperatorInactivityGasOffsetUpdate() + .finalizeNotifyOperatorInactivityGasOffsetUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -2790,7 +2843,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeNotifyOperatorInactivityGasOffsetUpdate() + .finalizeNotifyOperatorInactivityGasOffsetUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -2800,7 +2853,7 @@ describe("WalletRegistryGovernance", async () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2830,17 +2883,17 @@ describe("WalletRegistryGovernance", async () => { await expect(tx) .to.emit( walletRegistryGovernance, - "NotifyOperatorInactivityGasOffsetUpdated" + "NotifyOperatorInactivityGasOffsetUpdated", ) .withArgs(100) }) it("should reset the governance delay timer", async () => { await expect( - walletRegistryGovernance.getRemainingNotifyOperatorInactivityGasOffsetUpdateTime() + walletRegistryGovernance.getRemainingNotifyOperatorInactivityGasOffsetUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -2850,13 +2903,13 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .beginNotifySeedTimeoutGasOffsetUpdate(100) + .beginNotifySeedTimeoutGasOffsetUpdate(100), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2874,23 +2927,26 @@ describe("WalletRegistryGovernance", async () => { const { notifySeedTimeoutGasOffset } = await walletRegistry.gasParameters() expect(notifySeedTimeoutGasOffset).to.be.equal( - initialNotifySeedTimeoutGasOffset + initialNotifySeedTimeoutGasOffset, ) }) it("should start the governance delay timer", async () => { expect( - await walletRegistryGovernance.getRemainingNotifySeedTimeoutGasOffsetUpdateTime() + await walletRegistryGovernance.getRemainingNotifySeedTimeoutGasOffsetUpdateTime(), ).to.be.equal(constants.governanceDelay) }) it("should emit the NotifySeedTimeoutGasOffsetUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( walletRegistryGovernance, - "NotifySeedTimeoutGasOffsetUpdateStarted" + "NotifySeedTimeoutGasOffsetUpdateStarted", ) .withArgs(100, blockTimestamp) }) @@ -2903,7 +2959,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .finalizeNotifySeedTimeoutGasOffsetUpdate() + .finalizeNotifySeedTimeoutGasOffsetUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -2913,7 +2969,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeNotifySeedTimeoutGasOffsetUpdate() + .finalizeNotifySeedTimeoutGasOffsetUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -2931,7 +2987,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeNotifySeedTimeoutGasOffsetUpdate() + .finalizeNotifySeedTimeoutGasOffsetUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -2941,7 +2997,7 @@ describe("WalletRegistryGovernance", async () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2971,17 +3027,17 @@ describe("WalletRegistryGovernance", async () => { await expect(tx) .to.emit( walletRegistryGovernance, - "NotifySeedTimeoutGasOffsetUpdated" + "NotifySeedTimeoutGasOffsetUpdated", ) .withArgs(100) }) it("should reset the governance delay timer", async () => { await expect( - walletRegistryGovernance.getRemainingNotifySeedTimeoutGasOffsetUpdateTime() + walletRegistryGovernance.getRemainingNotifySeedTimeoutGasOffsetUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -2991,13 +3047,13 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .beginNotifyDkgTimeoutNegativeGasOffsetUpdate(100) + .beginNotifyDkgTimeoutNegativeGasOffsetUpdate(100), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -3015,23 +3071,26 @@ describe("WalletRegistryGovernance", async () => { const { notifyDkgTimeoutNegativeGasOffset } = await walletRegistry.gasParameters() expect(notifyDkgTimeoutNegativeGasOffset).to.be.equal( - initialNotifyDkgTimeoutNegativeGasOffset + initialNotifyDkgTimeoutNegativeGasOffset, ) }) it("should start the governance delay timer", async () => { expect( - await walletRegistryGovernance.getRemainingNotifyDkgTimeoutNegativeGasOffsetUpdateTime() + await walletRegistryGovernance.getRemainingNotifyDkgTimeoutNegativeGasOffsetUpdateTime(), ).to.be.equal(constants.governanceDelay) }) it("should emit the NotifyDkgTimeoutNegativeGasOffsetUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( walletRegistryGovernance, - "NotifyDkgTimeoutNegativeGasOffsetUpdateStarted" + "NotifyDkgTimeoutNegativeGasOffsetUpdateStarted", ) .withArgs(100, blockTimestamp) }) @@ -3044,7 +3103,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .finalizeNotifyDkgTimeoutNegativeGasOffsetUpdate() + .finalizeNotifyDkgTimeoutNegativeGasOffsetUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -3054,7 +3113,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeNotifyDkgTimeoutNegativeGasOffsetUpdate() + .finalizeNotifyDkgTimeoutNegativeGasOffsetUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -3072,7 +3131,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(governance) - .finalizeNotifyDkgTimeoutNegativeGasOffsetUpdate() + .finalizeNotifyDkgTimeoutNegativeGasOffsetUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -3082,7 +3141,7 @@ describe("WalletRegistryGovernance", async () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -3112,17 +3171,17 @@ describe("WalletRegistryGovernance", async () => { await expect(tx) .to.emit( walletRegistryGovernance, - "NotifyDkgTimeoutNegativeGasOffsetUpdated" + "NotifyDkgTimeoutNegativeGasOffsetUpdated", ) .withArgs(100) }) it("should reset the governance delay timer", async () => { await expect( - walletRegistryGovernance.getRemainingNotifyDkgTimeoutNegativeGasOffsetUpdateTime() + walletRegistryGovernance.getRemainingNotifyDkgTimeoutNegativeGasOffsetUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -3132,7 +3191,7 @@ describe("WalletRegistryGovernance", async () => { await expect( walletRegistryGovernance .connect(thirdParty) - .withdrawIneligibleRewards(thirdParty.address) + .withdrawIneligibleRewards(thirdParty.address), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) diff --git a/solidity/ecdsa/test/behaviors/authorization.ts b/solidity/ecdsa/test/behaviors/authorization.ts new file mode 100644 index 0000000000..a993080d6a --- /dev/null +++ b/solidity/ecdsa/test/behaviors/authorization.ts @@ -0,0 +1,44 @@ +import { expect } from "chai" + +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" +import type { WalletRegistry } from "../../typechain" + +const MAX_UINT64 = BigInt("18446744073709551615") // 2^64 - 1 + +export interface OverwritePreviousRequestContext { + walletRegistry: WalletRegistry + stakingProvider: SignerWithAddress + deauthorizingSecond: bigint +} + +export interface RequireUpdatingPoolContext { + walletRegistry: WalletRegistry + stakingProvider: SignerWithAddress +} + +export function shouldOverwritePreviousRequest( + getContext: () => OverwritePreviousRequestContext, +): void { + it("should overwrite the previous request", async () => { + const { walletRegistry, stakingProvider, deauthorizingSecond } = + getContext() + expect( + await walletRegistry.pendingAuthorizationDecrease( + stakingProvider.address, + ), + ).to.be.equal(deauthorizingSecond) + }) +} + +export function shouldRequireUpdatingPoolBeforeApproving( + getContext: () => RequireUpdatingPoolContext, +): void { + it("should require updating the pool before approving", async () => { + const { walletRegistry, stakingProvider } = getContext() + expect( + await walletRegistry.remainingAuthorizationDecreaseDelay( + stakingProvider.address, + ), + ).to.equal(MAX_UINT64) + }) +} diff --git a/solidity/ecdsa/test/etherscanVerification.test.ts b/solidity/ecdsa/test/etherscanVerification.test.ts index 07f6cc3748..acf930e143 100644 --- a/solidity/ecdsa/test/etherscanVerification.test.ts +++ b/solidity/ecdsa/test/etherscanVerification.test.ts @@ -76,7 +76,7 @@ describe("etherscanVerification - verifyOnEtherscanOrContinue", () => { await expect( verifyOnEtherscanOrContinue(hre, async () => { throw boom - }) + }), ).to.be.rejectedWith("bytecode mismatch") expect(logs).to.have.length(0) }) diff --git a/solidity/ecdsa/test/fixtures/index.ts b/solidity/ecdsa/test/fixtures/index.ts index fbfa78dd79..89d9bcf7a6 100644 --- a/solidity/ecdsa/test/fixtures/index.ts +++ b/solidity/ecdsa/test/fixtures/index.ts @@ -50,10 +50,8 @@ import { createMock } from "../helpers/mock" import { registerOperators } from "../utils/operators" import { fakeRandomBeacon } from "../utils/randomBeacon" -import type { IWalletOwner } from "../../typechain/IWalletOwner" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" -import type { Operator } from "../utils/operators" import type { + IWalletOwner, SortitionPool, ReimbursementPool, WalletRegistry, @@ -64,6 +62,8 @@ import type { IRandomBeacon, Allowlist, } from "../../typechain" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" +import type { Operator } from "../utils/operators" import type { Mock } from "../helpers/mock" const { to1e18 } = helpers.number @@ -137,20 +137,17 @@ const createWalletRegistryFixture = (options: { useAllowlist: boolean }) => { await helpers.contracts.getContract("WalletRegistry") const walletRegistryGovernance: WalletRegistryGovernance = await helpers.contracts.getContract("WalletRegistryGovernance") - const sortitionPool: SortitionPool = await helpers.contracts.getContract( - "EcdsaSortitionPool" - ) + const sortitionPool: SortitionPool = + await helpers.contracts.getContract("EcdsaSortitionPool") const tToken: T = await helpers.contracts.getContract("T") - const staking: TokenStaking = await helpers.contracts.getContract( - "TokenStaking" - ) + const staking: TokenStaking = + await helpers.contracts.getContract("TokenStaking") const reimbursementPool: ReimbursementPool = await helpers.contracts.getContract("ReimbursementPool") - const randomBeacon: Mock = await fakeRandomBeacon( - walletRegistry - ) + const randomBeacon: Mock = + await fakeRandomBeacon(walletRegistry) const { deployer, governance, chaosnetOwner } = await helpers.signers.getNamedSigners() @@ -177,7 +174,7 @@ const createWalletRegistryFixture = (options: { useAllowlist: boolean }) => { constants.groupSize, unnamedAccountsOffset, params.minimumAuthorization, - allowlist + allowlist, ) // Set up TokenStaking parameters (skip in Allowlist mode). @@ -196,7 +193,7 @@ const createWalletRegistryFixture = (options: { useAllowlist: boolean }) => { // Mock Wallet Owner contract. const walletOwner: Mock = await initializeWalletOwner( walletRegistryGovernance, - governance + governance, ) return { @@ -214,7 +211,7 @@ const createWalletRegistryFixture = (options: { useAllowlist: boolean }) => { walletRegistryGovernance, allowlist, } - } + }, ) } @@ -253,14 +250,13 @@ export async function walletRegistryFixture(options: { async function updateTokenStakingParams( tToken: T, staking: TokenStaking, - deployer: SignerWithAddress + deployer: SignerWithAddress, ) { - const initialNotifierTreasury = constants.tokenStakingNotificationReward.mul( - constants.groupSize - ) + const initialNotifierTreasury = + constants.tokenStakingNotificationReward * BigInt(constants.groupSize) await tToken .connect(deployer) - .approve(staking.address, initialNotifierTreasury) + .approve(await staking.getAddress(), initialNotifierTreasury) // NOTE: These methods no longer exist in TokenStaking interface // await staking // .connect(deployer) @@ -272,7 +268,7 @@ async function updateTokenStakingParams( export async function updateWalletRegistryParams( walletRegistryGovernance: WalletRegistryGovernance, - governance: SignerWithAddress + governance: SignerWithAddress, ): Promise { await walletRegistryGovernance .connect(governance) @@ -285,7 +281,7 @@ export async function updateWalletRegistryParams( await walletRegistryGovernance .connect(governance) .beginAuthorizationDecreaseChangePeriodUpdate( - params.authorizationDecreaseChangePeriod + params.authorizationDecreaseChangePeriod, ) await walletRegistryGovernance @@ -295,7 +291,7 @@ export async function updateWalletRegistryParams( await walletRegistryGovernance .connect(governance) .beginDkgResultChallengePeriodLengthUpdate( - params.dkgResultChallengePeriodLength + params.dkgResultChallengePeriodLength, ) await walletRegistryGovernance @@ -305,13 +301,13 @@ export async function updateWalletRegistryParams( await walletRegistryGovernance .connect(governance) .beginDkgSubmitterPrecedencePeriodLengthUpdate( - params.dkgSubmitterPrecedencePeriodLength + params.dkgSubmitterPrecedencePeriodLength, ) await walletRegistryGovernance .connect(governance) .beginSortitionPoolRewardsBanDurationUpdate( - params.sortitionPoolRewardsBanDuration + params.sortitionPoolRewardsBanDuration, ) await helpers.time.increaseTime(constants.governanceDelay) @@ -351,17 +347,16 @@ export async function updateWalletRegistryParams( export async function initializeWalletOwner( walletRegistryGovernance: WalletRegistryGovernance, - governance: SignerWithAddress + governance: SignerWithAddress, ): Promise> { const { deployer } = await helpers.signers.getNamedSigners() - const walletOwner: Mock = await createMock( - "IWalletOwner" - ) + const walletOwner: Mock = + await createMock("IWalletOwner") await deployer.sendTransaction({ to: walletOwner.address, - value: ethers.utils.parseEther("1000"), + value: ethers.parseEther("1000"), }) await walletRegistryGovernance @@ -373,11 +368,11 @@ export async function initializeWalletOwner( async function fundReimbursementPool( deployer: SignerWithAddress, - reimbursementPool: ReimbursementPool + reimbursementPool: ReimbursementPool, ) { await deployer.sendTransaction({ - to: reimbursementPool.address, - value: ethers.utils.parseEther("100.0"), // Send 100.0 ETH + to: await reimbursementPool.getAddress(), + value: ethers.parseEther("100.0"), }) } @@ -406,15 +401,15 @@ async function fundReimbursementPool( */ export async function setupAllowlist( walletRegistry: WalletRegistry, - deployer: SignerWithAddress + deployer: SignerWithAddress, ): Promise { // Retrieve the deployed Allowlist contract via hardhat-deploy. // This assumes the Allowlist deployment script has already run. const allowlist: Allowlist = await helpers.contracts.getContract("Allowlist") - if (!allowlist.address) { + if (!(await allowlist.getAddress())) { throw new Error( - "Allowlist contract not found. Ensure Allowlist deployment script has executed." + "Allowlist contract not found. Ensure Allowlist deployment script has executed.", ) } @@ -425,7 +420,7 @@ export async function setupAllowlist( // Initialize WalletRegistry with Allowlist address to enable dual-mode authorization. // This sets the allowlist address in WalletRegistry storage, which the authorization // routing logic uses to determine whether to accept calls from the Allowlist contract. - await walletRegistry.initializeV2(allowlist.address) + await walletRegistry.initializeV2(await allowlist.getAddress()) return allowlist } diff --git a/solidity/ecdsa/test/helpers/chain.ts b/solidity/ecdsa/test/helpers/chain.ts new file mode 100644 index 0000000000..4c71d8e6e4 --- /dev/null +++ b/solidity/ecdsa/test/helpers/chain.ts @@ -0,0 +1,5 @@ +/** Fail explicitly when a local test's block or mined receipt is unavailable. */ +export default function requireResult(result: T | null): T { + if (result === null) throw new Error("Expected a non-null chain response") + return result +} diff --git a/solidity/ecdsa/test/helpers/gas.ts b/solidity/ecdsa/test/helpers/gas.ts index 985f18a08b..d795b2663c 100644 --- a/solidity/ecdsa/test/helpers/gas.ts +++ b/solidity/ecdsa/test/helpers/gas.ts @@ -1,19 +1,24 @@ import { expect } from "chai" -import { ethers } from "hardhat" -import type { ContractTransaction } from "ethers" +import requireResult from "./chain" -const { BigNumber } = ethers +import type { ContractTransactionResponse } from "ethers" // TODO: Move to @keep-network/hardhat-helpers +// +// The expected values passed here are measured baselines, not protocol limits: no +// block, DoS, or economic ceiling is documented for these operations. They exist as +// cost-regression tripwires. When a change moves gas, update the baseline +// deliberately and confirm the move was intended; do not widen `delta` to silence it. // eslint-disable-next-line import/prefer-default-export export async function assertGasUsed( - tx: ContractTransaction, + tx: ContractTransactionResponse, expectedGasUsed: number, - delta = 1000 + delta = 1000, ): Promise { - expect((await tx.wait()).gasUsed, "invalid gas used").to.be.closeTo( - BigNumber.from(expectedGasUsed), - delta + const receipt = requireResult(await tx.wait()) + expect(receipt.gasUsed, "invalid gas used").to.be.closeTo( + BigInt(expectedGasUsed), + delta, ) } diff --git a/solidity/ecdsa/test/helpers/mock.test.ts b/solidity/ecdsa/test/helpers/mock.test.ts index 8e3700fb72..6255a65ca1 100644 --- a/solidity/ecdsa/test/helpers/mock.test.ts +++ b/solidity/ecdsa/test/helpers/mock.test.ts @@ -1,10 +1,15 @@ import { ethers } from "hardhat" import { expect } from "chai" -import { createMock, expectCalledWith } from "./mock" +import requireResult from "./chain" +import { createMock, expectCalledOnceWith, expectCalledWith } from "./mock" import type { Mock } from "./mock" -import type { IMockTarget, MockTargetConsumer } from "../../typechain" +import type { + IMockTarget, + MockTargetConsumer, + WalletRegistry, +} from "../../typechain" describe("MockContract", () => { let target: Mock @@ -15,7 +20,7 @@ describe("MockContract", () => { const factory = await ethers.getContractFactory("MockTargetConsumer") consumer = (await factory.deploy(target.address)) as MockTargetConsumer - await consumer.deployed() + await consumer.waitForDeployment() }) describe("view functions reached by STATICCALL", () => { @@ -92,9 +97,9 @@ describe("MockContract", () => { it("reverts every call to the function", async () => { await target.doThing.reverts("nope") - await expect( - consumer.doThing(ethers.constants.AddressZero, 1) - ).to.be.revertedWith("nope") + await expect(consumer.doThing(ethers.ZeroAddress, 1)).to.be.revertedWith( + "nope", + ) }) it("reverts only the matching arguments", async () => { @@ -150,24 +155,50 @@ describe("MockContract", () => { it("counts each function separately", async () => { await target.doThing.returns(true) - await consumer.doThing(ethers.constants.AddressZero, 1) + await consumer.doThing(ethers.ZeroAddress, 1) await consumer.noReturn(1) expect(await target.doThing.callCount()).to.equal(1) expect(await target.noReturn.callCount()).to.equal(1) }) + + it("matches a struct argument against plain-number expectations", async () => { + // `normalizeForComparison` walks into arrays and structs, a path + // `IMockTarget`'s flat arguments never reach. ethers decodes every + // integer nested in a DKG result as a bigint, so the plain JS numbers + // spelled out below match only because the walk happens. + const registry = await createMock("WalletRegistry") + const registryCaller: WalletRegistry = await ethers.getContractAt( + "WalletRegistry", + registry.address, + ) + + await registryCaller.submitDkgResult({ + submitterMemberIndex: 1, + groupPubKey: "0xaabb", + misbehavedMembersIndices: [3, 5], + signatures: "0xccdd", + signingMembersIndices: [7, 9], + members: [100, 200], + membersHash: ethers.ZeroHash, + }) + + await expectCalledOnceWith(registry.submitDkgResult, [ + [1, "0xaabb", [3, 5], "0xccdd", [7, 9], [100, 200], ethers.ZeroHash], + ]) + }) }) describe("reset", () => { it("clears recorded calls and configured responses for one function", async () => { await target.doThing.returns(true) - await consumer.doThing(ethers.constants.AddressZero, 1) + await consumer.doThing(ethers.ZeroAddress, 1) await target.doThing.reset() expect(await target.doThing.callCount()).to.equal(0) // The configured `true` is gone, so the call answers with empty data. - await consumer.doThing(ethers.constants.AddressZero, 1) + await consumer.doThing(ethers.ZeroAddress, 1) expect(await consumer.lastResult()).to.equal(false) }) @@ -215,10 +246,10 @@ describe("MockContract", () => { // `msg.sender == someContract`. const factory = await ethers.getContractFactory("MockTargetConsumer") const other = await factory.deploy(target.address) - await other.deployed() + await other.waitForDeployment() const tx = await other.connect(target.wallet).noReturn(1) - const receipt = await tx.wait() + const receipt = requireResult(await tx.wait()) expect(receipt.from).to.equal(target.address) }) @@ -226,9 +257,7 @@ describe("MockContract", () => { describe("address option", () => { it("deploys at a requested address", async () => { - const address = ethers.utils.getAddress( - `0x${"ab".repeat(20)}`.toLowerCase() - ) + const address = ethers.getAddress(`0x${"ab".repeat(20)}`.toLowerCase()) const pinned = await createMock("IMockTarget", { address }) @@ -237,7 +266,7 @@ describe("MockContract", () => { const factory = await ethers.getContractFactory("MockTargetConsumer") const pinnedConsumer = await factory.deploy(address) - await pinnedConsumer.deployed() + await pinnedConsumer.waitForDeployment() expect(await pinnedConsumer.readValueThroughStaticCall(1)).to.equal(7) }) @@ -250,7 +279,7 @@ describe("MockContract", () => { // real ecdsaWalletRegistry and relay. `hardhat_setCode` replaces the code // and leaves the storage, so a mock keeping its state at slots 0, 1, 2... // would read that leftover as its own. - const address = ethers.utils.getAddress(`0x${"cd".repeat(20)}`) + const address = ethers.getAddress(`0x${"cd".repeat(20)}`) const garbage = "0xdeadbeef00000000000000000000000000000000000000000000000000000001" @@ -258,10 +287,10 @@ describe("MockContract", () => { Array.from({ length: 8 }, (_, slot) => ethers.provider.send("hardhat_setStorageAt", [ address, - ethers.utils.hexValue(slot), + ethers.toQuantity(slot), garbage, - ]) - ) + ]), + ), ) const pinned = await createMock("IMockTarget", { address }) @@ -272,7 +301,7 @@ describe("MockContract", () => { const factory = await ethers.getContractFactory("MockTargetConsumer") const pinnedConsumer = await factory.deploy(address) - await pinnedConsumer.deployed() + await pinnedConsumer.waitForDeployment() expect(await pinnedConsumer.readValueThroughStaticCall(1)).to.equal(7) }) diff --git a/solidity/ecdsa/test/helpers/mock.ts b/solidity/ecdsa/test/helpers/mock.ts index ec2e8d75eb..5729273e9f 100644 --- a/solidity/ecdsa/test/helpers/mock.ts +++ b/solidity/ecdsa/test/helpers/mock.ts @@ -7,10 +7,18 @@ /* eslint-disable no-underscore-dangle */ import { ethers, artifacts } from "hardhat" import { expect } from "chai" -import { BigNumber } from "ethers" -import type { BigNumberish, Contract, Signer } from "ethers" -import type { FunctionFragment, Interface, ParamType } from "ethers/lib/utils" +import requireResult from "./chain" + +import type { + BaseContract, + BigNumberish, + Signer, + FunctionFragment, + Interface, + ParamType, +} from "ethers" +import type { MockContract } from "../../typechain" /** * Programmable contract mock, replacing `@defi-wonderland/smock`. @@ -57,7 +65,8 @@ import type { FunctionFragment, Interface, ParamType } from "ethers/lib/utils" * the machine happens to be. */ async function withoutAdvancingTime(write: () => Promise): Promise { - const { timestamp } = await ethers.provider.getBlock("latest") + const block = requireResult(await ethers.provider.getBlock("latest")) + const { timestamp } = block await ethers.provider.send("evm_setNextBlockTimestamp", [timestamp]) return write() } @@ -67,7 +76,7 @@ export interface MockCall { /** Decoded arguments, in declaration order. */ args: unknown[] /** `msg.value` the call carried, as smock's `getCall(n).value` did. */ - value: BigNumber + value: bigint } /** Configuration and inspection handle for one function of a mock. */ @@ -95,7 +104,7 @@ export interface MockedFunction { getCalls(): Promise } -export type Mock = { +export type Mock = { [K in keyof T]: T[K] extends (...args: never[]) => unknown ? T[K] & MockedFunction : T[K] @@ -104,14 +113,14 @@ export type Mock = { /** Signer that sends from the mock's own address, as smock's `fake.wallet` did. */ wallet: Signer /** Underlying deployed `MockContract`, for anything this helper does not wrap. */ - mockContract: Contract + mockContract: MockContract /** * The mocked interface bound to `signer`, as smock's `FakeContract.connect` * was. smock's fake extended `ethers.Contract` and inherited this; the proxy * here resolves only the mocked ABI and the keys above, so without it * `mock.connect(someone)` is `undefined`. */ - connect(signer: Signer): Contract + connect(signer: Signer): T /** Drops all configured responses and all recorded calls. */ reset(): Promise /** @@ -125,11 +134,17 @@ export type Mock = { } /** Selectors of `MockContract`'s own administrative entry points. */ +function functionFragments(iface: Interface): FunctionFragment[] { + const fragments: FunctionFragment[] = [] + iface.forEachFunction((fragment) => fragments.push(fragment)) + return fragments +} + function adminSelectors(mockInterface: Interface): Set { return new Set( - Object.keys(mockInterface.functions) - .filter((signature) => signature.startsWith("__mock__")) - .map((signature) => mockInterface.getSighash(signature)) + functionFragments(mockInterface) + .filter((fragment) => fragment.name.startsWith("__mock__")) + .map((fragment) => fragment.selector), ) } @@ -143,17 +158,18 @@ function adminSelectors(mockInterface: Interface): Set { function assertNoSelectorCollision( target: Interface, mockInterface: Interface, - targetName: string + targetName: string, ): void { const reserved = adminSelectors(mockInterface) - Object.keys(target.functions).forEach((signature) => { - const selector = target.getSighash(signature) + functionFragments(target).forEach((fragment) => { + const signature = fragment.format() + const { selector } = fragment if (reserved.has(selector)) { throw new Error( `${targetName}.${signature} has selector ${selector}, which collides ` + "with a MockContract administrative function. This mock cannot " + - "represent that interface." + "represent that interface.", ) } }) @@ -162,7 +178,7 @@ function assertNoSelectorCollision( function fragmentsByName(target: Interface): Map { const byName = new Map() - Object.values(target.functions).forEach((fragment) => { + functionFragments(target).forEach((fragment) => { const existing = byName.get(fragment.name) if (existing) { existing.push(fragment) @@ -182,12 +198,12 @@ function fragmentsByName(target: Interface): Map { function resolveFragment( fragments: FunctionFragment[], name: string, - targetName: string + targetName: string, ): FunctionFragment { if (fragments.length > 1) { throw new Error( `${targetName}.${name} is overloaded (${fragments.length} signatures). ` + - "Address it through the mock's mockContract handle instead." + "Address it through the mock's mockContract handle instead.", ) } @@ -202,21 +218,21 @@ function resolveFragment( * layout. */ function zeroValueFor(type: ParamType): unknown { - if (type.baseType === "array") { + if (type.isArray()) { if (type.arrayLength === -1) { return [] } return Array.from({ length: type.arrayLength }, () => - zeroValueFor(type.arrayChildren) + zeroValueFor(type.arrayChildren), ) } - if (type.baseType === "tuple") { + if (type.isTuple()) { return type.components.map((component) => zeroValueFor(component)) } if (type.baseType === "address") { - return ethers.constants.AddressZero + return ethers.ZeroAddress } if (type.baseType === "bool") { @@ -249,7 +265,10 @@ function zeroValueFor(type: ParamType): unknown { * those positionally, so they are mapped back by output name. A single-output * function is different: an object there is a struct, and the coder handles it. */ -function toPositional(outputs: ParamType[], value: unknown): unknown[] { +function toPositional( + outputs: readonly ParamType[], + value: unknown, +): unknown[] { if (outputs.length === 1) { return [value] } @@ -261,7 +280,7 @@ function toPositional(outputs: ParamType[], value: unknown): unknown[] { if (value !== null && typeof value === "object") { const named = value as Record return outputs.map((output, index) => - output.name && output.name in named ? named[output.name] : named[index] + output.name && output.name in named ? named[output.name] : named[index], ) } @@ -269,13 +288,13 @@ function toPositional(outputs: ParamType[], value: unknown): unknown[] { } function encodeReturn(fragment: FunctionFragment, value: unknown): string { - if (fragment.outputs === null || fragment.outputs.length === 0) { + if (fragment.outputs == null || fragment.outputs.length === 0) { return "0x" } - return ethers.utils.defaultAbiCoder.encode( + return ethers.AbiCoder.defaultAbiCoder().encode( fragment.outputs, - toPositional(fragment.outputs, value) + toPositional(fragment.outputs, value), ) } @@ -285,8 +304,8 @@ function encodeRevert(reason?: string): string { } return ( - ethers.utils.id("Error(string)").slice(0, 10) + - ethers.utils.defaultAbiCoder.encode(["string"], [reason]).slice(2) + ethers.id("Error(string)").slice(0, 10) + + ethers.AbiCoder.defaultAbiCoder().encode(["string"], [reason]).slice(2) ) } @@ -300,18 +319,20 @@ function encodeRevert(reason?: string): string { * @returns A handle exposing each of `target`'s functions with `returns`, * `whenCalledWith`, `reverts`, `reset`, `callCount` and `getCall`. */ -export async function createMock( +export async function createMock( target: string, - options: { address?: string } = {} + options: { address?: string } = {}, ): Promise> { const targetArtifact = await artifacts.readArtifact(target) - const targetInterface = new ethers.utils.Interface(targetArtifact.abi) + const targetInterface = new ethers.Interface(targetArtifact.abi) const mockFactory = await ethers.getContractFactory("MockContract") // Deploying is a transaction too, and a mock is routinely created inside a // `before` hook after the test has already captured a baseline timestamp. - let mockContract = await withoutAdvancingTime(() => mockFactory.deploy()) - await mockContract.deployed() + let mockContract: MockContract = await withoutAdvancingTime(() => + mockFactory.deploy(), + ) + await mockContract.waitForDeployment() assertNoSelectorCollision(targetInterface, mockContract.interface, target) @@ -321,27 +342,25 @@ export async function createMock( // configuration below — the base returns, the non-recording flags, and // later every `returns`/`whenCalledWith` — is storage. Configuring first // and relocating afterwards left a pinned mock with none of it. - const code = await ethers.provider.getCode(mockContract.address) + const code = await ethers.provider.getCode(await mockContract.getAddress()) await ethers.provider.send("hardhat_setCode", [options.address, code]) - mockContract = mockContract.attach(options.address) + mockContract = await ethers.getContractAt("MockContract", options.address) } // Install the response of last resort for every function, so an unstubbed // one answers with a correctly sized zero instead of reverting the caller. - const baseFragments = Object.values(targetInterface.functions) - const baseSelectors = baseFragments.map((fragment) => - targetInterface.getSighash(fragment) - ) + const baseFragments = functionFragments(targetInterface) + const baseSelectors = baseFragments.map((fragment) => fragment.selector) const baseReturns = baseFragments.map((fragment) => - fragment.outputs === null || fragment.outputs.length === 0 + fragment.outputs == null || fragment.outputs.length === 0 ? "0x" - : ethers.utils.defaultAbiCoder.encode( + : ethers.AbiCoder.defaultAbiCoder().encode( fragment.outputs, - fragment.outputs.map((output) => zeroValueFor(output)) - ) + fragment.outputs.map((output) => zeroValueFor(output)), + ), ) await withoutAdvancingTime(() => - mockContract.__mock__setBaseReturns(baseSelectors, baseReturns) + mockContract.__mock__setBaseReturns(baseSelectors, baseReturns), ) // Flag the read-only functions. Solidity reaches them by STATICCALL, where @@ -352,29 +371,28 @@ export async function createMock( .filter( (fragment) => fragment.stateMutability === "view" || - fragment.stateMutability === "pure" + fragment.stateMutability === "pure", ) - .map((fragment) => targetInterface.getSighash(fragment)) + .map((fragment) => fragment.selector) if (nonRecordingSelectors.length > 0) { await withoutAdvancingTime(() => - mockContract.__mock__setNonRecordingSelectors(nonRecordingSelectors) + mockContract.__mock__setNonRecordingSelectors(nonRecordingSelectors), ) } - await ethers.provider.send("hardhat_impersonateAccount", [ - mockContract.address, - ]) + const address = await mockContract.getAddress() + await ethers.provider.send("hardhat_impersonateAccount", [address]) await ethers.provider.send("hardhat_setBalance", [ - mockContract.address, + address, "0x21e19e0c9bab2400000", // 10_000 ETH, so the mock can pay for its own sends ]) - const wallet = await ethers.getSigner(mockContract.address) + const wallet = await ethers.getSigner(address) const byName = fragmentsByName(targetInterface) function buildFunction(name: string): MockedFunction { const fragment = resolveFragment(byName.get(name) ?? [], name, target) - const selector = targetInterface.getSighash(fragment) + const { selector } = fragment const readOnly = fragment.stateMutability === "view" || fragment.stateMutability === "pure" @@ -386,7 +404,7 @@ export async function createMock( `${target}.${name} is ${fragment.stateMutability}, so Solidity ` + "reaches it by STATICCALL and the mock cannot record the call. " + "Assert on the state-changing function that consumed the value " + - "instead." + "instead.", ) } } @@ -394,7 +412,7 @@ export async function createMock( const setForCalldata = async ( args: unknown[], behaviour: "return" | "revert", - payload: unknown + payload: unknown, ): Promise => { let callData: string try { @@ -415,7 +433,7 @@ export async function createMock( console.warn( `mock: ${target}.${name} whenCalledWith(...) arguments cannot be ` + "encoded for this signature, so the entry can never match and " + - `is being skipped: ${(error as Error).message.split("(")[0].trim()}` + `is being skipped: ${(error as Error).message.split("(")[0].trim()}`, ) return } @@ -424,18 +442,18 @@ export async function createMock( behaviour === "return" ? mockContract.__mock__setReturnForCalldata( callData, - encodeReturn(fragment, payload) + encodeReturn(fragment, payload), ) : mockContract.__mock__setRevertForCalldata( callData, - encodeRevert(payload as string | undefined) - ) + encodeRevert(payload as string | undefined), + ), ) } - const decodeCall = (callData: string, value: BigNumber): MockCall => ({ + const decodeCall = (callData: string, value: bigint): MockCall => ({ args: Array.from( - targetInterface.decodeFunctionData(fragment, callData) + targetInterface.decodeFunctionData(fragment, callData), ) as unknown[], value, }) @@ -445,8 +463,8 @@ export async function createMock( await withoutAdvancingTime(() => mockContract.__mock__setReturnForSelector( selector, - encodeReturn(fragment, value) - ) + encodeReturn(fragment, value), + ), ) }, @@ -454,8 +472,8 @@ export async function createMock( await withoutAdvancingTime(() => mockContract.__mock__setRevertForSelector( selector, - encodeRevert(reason) - ) + encodeRevert(reason), + ), ) }, @@ -468,7 +486,7 @@ export async function createMock( async reset(): Promise { await withoutAdvancingTime(() => - mockContract.__mock__resetSelector(selector) + mockContract.__mock__resetSelector(selector), ) }, @@ -487,7 +505,7 @@ export async function createMock( mockContract.__mock__callForSelectorAt(selector, index), mockContract.__mock__callValueForSelectorAt(selector, index), ]) - return decodeCall(callData as string, value as BigNumber) + return decodeCall(callData as string, value as bigint) }, async getCalls(): Promise { @@ -504,7 +522,7 @@ export async function createMock( mockContract.__mock__callForSelectorAt(selector, i), mockContract.__mock__callValueForSelectorAt(selector, i), ]) - calls.push(decodeCall(callData as string, value as BigNumber)) + calls.push(decodeCall(callData as string, value as bigint)) } return calls @@ -514,28 +532,28 @@ export async function createMock( const functions = new Map() const readContract = new ethers.Contract( - mockContract.address, + address, targetArtifact.abi, - ethers.provider + ethers.provider, ) const handle = { - address: mockContract.address, + address, wallet, mockContract, - connect(signer: Signer): Contract { + connect(signer: Signer): T { return new ethers.Contract( - mockContract.address, + address, targetArtifact.abi, - signer - ) + signer, + ) as unknown as T }, async reset(): Promise { await withoutAdvancingTime(() => mockContract.__mock__reset()) }, async setRecording(enabled: boolean): Promise { await withoutAdvancingTime(() => - mockContract.__mock__setRecording(enabled) + mockContract.__mock__setRecording(enabled), ) }, } @@ -557,7 +575,7 @@ export async function createMock( const callable = (...args: unknown[]) => readContract[property](...args) functions.set( property, - Object.assign(callable, buildFunction(property)) as MockedFunction + Object.assign(callable, buildFunction(property)) as MockedFunction, ) } @@ -585,7 +603,7 @@ async function counted(fn: MockedFunction): Promise { export async function expectCalled(fn: MockedFunction): Promise { const count = await counted(fn) expect(count, "expected the function to have been called").to.be.greaterThan( - 0 + 0, ) } @@ -613,13 +631,9 @@ export async function expectCalledTwice(fn: MockedFunction): Promise { /** * Puts one recorded or expected argument into a comparable form. * - * The two sides never arrive in the same representation. ethers decodes an ABI - * integer to a `BigNumber` above 48 bits and to a plain `number` at or below - * it, so a `uint256` argument reaches this as a `BigNumber` while the - * `uint32` getter the test compared it against yields a `number`; and a struct - * or dynamic array puts both one level down, where the previous top-level-only - * check never looked. smock compared `BigNumberish` values numerically at any - * depth, so both shapes used to pass. + * ethers v6 decodes every ABI integer as a bigint, while test expectations + * can contain ordinary numbers. Arrays and structs can nest those values, + * so numeric comparison is normalized recursively. * * Numerics are wrapped rather than rendered bare, so that a genuine string * argument of `"100"` still fails against a numeric `100`. Everything else — @@ -628,9 +642,6 @@ export async function expectCalledTwice(fn: MockedFunction): Promise { * real mismatch. */ function normalizeForComparison(value: unknown): unknown { - if (BigNumber.isBigNumber(value)) { - return { numeric: value.toString() } - } if (typeof value === "number" || typeof value === "bigint") { return { numeric: value.toString() } } @@ -642,7 +653,7 @@ function normalizeForComparison(value: unknown): unknown { export async function expectCalledOnceWith( fn: MockedFunction, - args: unknown[] + args: unknown[], ): Promise { expect(await counted(fn), "expected exactly one call").to.equal(1) @@ -652,7 +663,7 @@ export async function expectCalledOnceWith( args.forEach((expected, index) => { const actual = call.args[index] expect(normalizeForComparison(actual), `argument ${index}`).to.deep.equal( - normalizeForComparison(expected) + normalizeForComparison(expected), ) }) } @@ -666,7 +677,7 @@ export async function expectCalledOnceWith( */ export async function expectCalledWith( fn: MockedFunction, - args: unknown[] + args: unknown[], ): Promise { const calls = await fn.getCalls() @@ -677,7 +688,7 @@ export async function expectCalledWith( expect( seen, - `expected a call with ${calls.length} recorded, none matching` + `expected a call with ${calls.length} recorded, none matching`, ).to.deep.include(wanted) } diff --git a/solidity/ecdsa/test/tasks/initialize.test.ts b/solidity/ecdsa/test/tasks/initialize.test.ts new file mode 100644 index 0000000000..a1fcf0e787 --- /dev/null +++ b/solidity/ecdsa/test/tasks/initialize.test.ts @@ -0,0 +1,102 @@ +import hre, { deployments, ethers, helpers } from "hardhat" +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" +import { expect } from "chai" + +import type { + WalletRegistry, + TokenStaking, + T, + SortitionPool, +} from "../../typechain" + +async function taskContracts() { + await deployments.fixture() + const [owner, provider, operator, beneficiary, authorizer] = ( + await ethers.getSigners() + ).slice(10) + return { + args: { + owner: owner.address, + provider: provider.address, + operator: operator.address, + beneficiary: beneficiary.address, + authorizer: authorizer.address, + amount: 1_000_000, + }, + staking: await helpers.contracts.getContract("TokenStaking"), + registry: + await helpers.contracts.getContract("WalletRegistry"), + token: await helpers.contracts.getContract("T"), + pool: await helpers.contracts.getContract( + "EcdsaSortitionPool", + ), + } +} + +async function initializedOperator() { + const contracts = await taskContracts() + await hre.run("initialize", contracts.args) + return contracts +} + +describe("ECDSA initialization tasks", () => { + it("initializes staking with distinct beneficiary and authorizer accounts", async () => { + const { args, staking, token } = await loadFixture(taskContracts) + await hre.run("initialize:staking", args) + expect((await staking.stakes(args.provider)).tStake).to.equal( + ethers.parseEther("1000000"), + ) + expect(await staking.rolesOf(args.provider)).to.deep.equal([ + args.owner, + args.beneficiary, + args.authorizer, + ]) + expect(await token.balanceOf(args.owner)).to.equal(0n) + }) + + it("registers an operator through register:ecdsa", async () => { + const { args, registry } = await loadFixture(taskContracts) + await hre.run("register:ecdsa", args) + expect(await registry.operatorToStakingProvider(args.operator)).to.equal( + args.provider, + ) + }) + + it("initializes staking, minimum authorization, registration and beta membership", async () => { + const { args, staking, registry, pool } = + await loadFixture(initializedOperator) + expect((await staking.stakes(args.provider)).tStake).to.equal( + ethers.parseEther("1000000"), + ) + expect( + await staking.authorizedStake(args.provider, await registry.getAddress()), + ).to.equal(await registry.minimumAuthorization()) + expect(await registry.operatorToStakingProvider(args.operator)).to.equal( + args.provider, + ) + expect(await pool.isBetaOperator(args.operator)).to.equal(true) + }) + + it("does not send another transaction when stake, authorization and registration match", async () => { + const { args } = await loadFixture(initializedOperator) + const before = await ethers.provider.getBlockNumber() + await hre.run("initialize:staking", args) + await hre.run("authorize:ecdsa", args) + await hre.run("register:ecdsa", args) + expect(await ethers.provider.getBlockNumber()).to.equal(before) + }) + + it("tops up an existing stake and increases ECDSA authorization", async () => { + const { args, staking, registry, token } = + await loadFixture(initializedOperator) + await hre.run("initialize:staking", { ...args, amount: 1_200_000 }) + await hre.run("authorize:ecdsa", { ...args, authorization: 700_000 }) + expect((await staking.stakes(args.provider)).tStake).to.equal( + ethers.parseEther("1200000"), + ) + expect( + await staking.authorizedStake(args.provider, await registry.getAddress()), + ).to.equal(ethers.parseEther("700000")) + expect(await token.balanceOf(args.owner)).to.equal(0n) + }) +}) diff --git a/solidity/ecdsa/test/tasks/unlock-accounts.test.ts b/solidity/ecdsa/test/tasks/unlock-accounts.test.ts new file mode 100644 index 0000000000..7984761d30 --- /dev/null +++ b/solidity/ecdsa/test/tasks/unlock-accounts.test.ts @@ -0,0 +1,63 @@ +import hre, { ethers } from "hardhat" +import { expect } from "chai" + +import type { HttpNetworkConfig } from "hardhat/types" + +describe("ECDSA account unlock task", () => { + it("uses the ethers v6 provider and signer APIs on development", async () => { + const account = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" + const requests: { + method: string + params: Array | Record + }[] = [] + + // Exercise the registered task without opening an RPC connection. + class TestProvider extends ethers.JsonRpcProvider { + private readonly rpcRequests = requests + + async listAccounts() { + return [new ethers.JsonRpcSigner(this, account)] + } + + async send( + method: string, + params: Array | Record, + ) { + this.rpcRequests.push({ method, params }) + return true + } + } + + const taskRuntime = { + ...hre, + ethers: { ...ethers, JsonRpcProvider: TestProvider }, + network: { + ...hre.network, + name: "development", + config: { url: "http://unused.invalid" } as HttpNetworkConfig, + }, + } + const password = process.env.KEEP_ETHEREUM_PASSWORD + process.env.KEEP_ETHEREUM_PASSWORD = "task-test-password" + try { + await hre.tasks["unlock-accounts"].action( + {}, + taskRuntime, + Object.assign(async () => undefined, { isDefined: false }), + ) + } finally { + if (password === undefined) { + delete process.env.KEEP_ETHEREUM_PASSWORD + } else { + process.env.KEEP_ETHEREUM_PASSWORD = password + } + } + + expect(requests).to.deep.equal([ + { + method: "personal_unlockAccount", + params: [account.toLowerCase(), "task-test-password", 0], + }, + ]) + }) +}) diff --git a/solidity/ecdsa/test/utils/dkg.ts b/solidity/ecdsa/test/utils/dkg.ts index 473d097950..17d9cb3422 100644 --- a/solidity/ecdsa/test/utils/dkg.ts +++ b/solidity/ecdsa/test/utils/dkg.ts @@ -2,18 +2,23 @@ import { ethers } from "hardhat" import { expect } from "chai" -import { BigNumber } from "ethers" + +import requireResult from "../helpers/chain" import { selectGroup } from "./groups" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" -import type { BigNumberish, ContractTransaction, BytesLike } from "ethers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" +import type { + BigNumberish, + ContractTransactionResponse, + BytesLike, +} from "ethers" import type { SortitionPool, WalletRegistry } from "../../typechain" import type { Operator } from "./operators" import type { DkgResultSubmittedEvent, - ResultStruct, -} from "../../typechain/EcdsaDkg" + EcdsaDkg, +} from "../../typechain/contracts/WalletRegistry" const { provider } = ethers @@ -34,15 +39,15 @@ export const noMisbehaved: number[] = [] export function calculateDkgSeed( relayEntry: BigNumberish, - blockNumber: BigNumberish -): BigNumber { - return ethers.BigNumber.from( - ethers.utils.keccak256( - ethers.utils.solidityPack( + blockNumber: BigNumberish, +): bigint { + return BigInt( + ethers.keccak256( + ethers.solidityPacked( ["uint256", "uint256"], - [ethers.BigNumber.from(relayEntry), ethers.BigNumber.from(blockNumber)] - ) - ) + [BigInt(relayEntry), BigInt(blockNumber)], + ), + ), ) } @@ -52,22 +57,22 @@ export function calculateDkgSeed( export async function signAndSubmitCorrectDkgResult( walletRegistry: WalletRegistry, groupPublicKey: BytesLike, - seed: BigNumber, + seed: bigint, startBlock: number, misbehavedIndices = noMisbehaved, submitterIndex = 1, - numberOfSignatures = 51 + numberOfSignatures = 51, ): Promise<{ signers: Operator[] dkgResult: DkgResult dkgResultHash: string submitter: SignerWithAddress - submitterInitialBalance: BigNumber - transaction: ContractTransaction + submitterInitialBalance: bigint + transaction: ContractTransactionResponse }> { const sortitionPool = (await ethers.getContractAt( "SortitionPool", - await walletRegistry.sortitionPool() + await walletRegistry.sortitionPool(), )) as SortitionPool const signers = await selectGroup(sortitionPool, seed) @@ -81,7 +86,7 @@ export async function signAndSubmitCorrectDkgResult( startBlock, misbehavedIndices, submitterIndex, - numberOfSignatures + numberOfSignatures, )), } } @@ -99,13 +104,13 @@ export async function signAndSubmitArbitraryDkgResult( startBlock: number, misbehavedIndices: number[], submitterIndex = 1, - numberOfSignatures = 51 + numberOfSignatures = 51, ): Promise<{ dkgResult: DkgResult dkgResultHash: string submitter: SignerWithAddress - submitterInitialBalance: BigNumber - transaction: ContractTransaction + submitterInitialBalance: bigint + transaction: ContractTransactionResponse }> { const { dkgResult } = await signDkgResult( signers, @@ -113,19 +118,19 @@ export async function signAndSubmitArbitraryDkgResult( misbehavedIndices, startBlock, submitterIndex, - numberOfSignatures + numberOfSignatures, ) - const dkgResultHash = ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode( + const dkgResultHash = ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( [DKG_RESULT_PARAMS_SIGNATURE], - [dkgResult] - ) + [dkgResult], + ), ) const submitter = signers[submitterIndex - 1].signer const submitterInitialBalance = await provider.getBalance( - await submitter.getAddress() + await submitter.getAddress(), ) return { @@ -147,12 +152,12 @@ export async function signAndSubmitUnrecoverableDkgResult( startBlock: number, misbehavedIndices: number[], submitterIndex = 1, - numberOfSignatures = 51 + numberOfSignatures = 51, ): Promise<{ dkgResult: DkgResult dkgResultHash: string submitter: SignerWithAddress - transaction: ContractTransaction + transaction: ContractTransactionResponse }> { const { dkgResult } = await signDkgResult( signers, @@ -160,21 +165,21 @@ export async function signAndSubmitUnrecoverableDkgResult( misbehavedIndices, startBlock, submitterIndex, - numberOfSignatures + numberOfSignatures, ) // Break the result const signatureHexStrLength = 2 * 65 const unrecoverableSignatures = `0x${"a".repeat( - signatureHexStrLength * numberOfSignatures + signatureHexStrLength * numberOfSignatures, )}` dkgResult.signatures = unrecoverableSignatures - const dkgResultHash = ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode( + const dkgResultHash = ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( [DKG_RESULT_PARAMS_SIGNATURE], - [dkgResult] - ) + [dkgResult], + ), ) const submitter = signers[submitterIndex - 1].signer @@ -193,17 +198,17 @@ export async function signDkgResult( misbehavedMembersIndices: number[], startBlock: number, submitterIndex = 1, - numberOfSignatures = 51 + numberOfSignatures = 51, ): Promise<{ dkgResult: DkgResult signingMembersIndices: number[] signaturesBytes: string }> { - const resultHash = ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode( + const resultHash = ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( ["uint256", "bytes", "uint8[]", "uint256"], - [hardhatNetworkId, groupPublicKey, misbehavedMembersIndices, startBlock] - ) + [hardhatNetworkId, groupPublicKey, misbehavedMembersIndices, startBlock], + ), ) const members: number[] = [] @@ -223,13 +228,13 @@ export async function signDkgResult( signingMembersIndices.push(signerIndex) const signature = await ethersSigner.signMessage( - ethers.utils.arrayify(resultHash) + ethers.getBytes(resultHash), ) signatures.push(signature) } - const signaturesBytes: string = ethers.utils.hexConcat(signatures) + const signaturesBytes: string = ethers.concat(signatures) const dkgResult: DkgResult = { submitterMemberIndex: submitterIndex, @@ -247,9 +252,9 @@ export async function signDkgResult( export async function submitDkgResult( walletRegistry: WalletRegistry, dkgResult: DkgResult, - submitter: SignerWithAddress + submitter: SignerWithAddress, ): Promise<{ - transaction: ContractTransaction + transaction: ContractTransactionResponse }> { const transaction = await walletRegistry .connect(submitter) @@ -261,7 +266,7 @@ export async function submitDkgResult( // Creates a members hash that actively participated in dkg export function hashDKGMembers( members: number[], - misbehavedMembersIndices?: number[] + misbehavedMembersIndices?: number[], ): string { if (misbehavedMembersIndices && misbehavedMembersIndices.length > 0) { const activeDkgMembers = [...members] @@ -271,86 +276,90 @@ export function hashDKGMembers( } } - return ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode(["uint32[]"], [activeDkgMembers]) + return ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( + ["uint32[]"], + [activeDkgMembers], + ), ) } - return ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode(["uint32[]"], [members]) + return ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode(["uint32[]"], [members]), ) } export interface DkgResultSubmittedEventArgs { resultHash: string - seed: BigNumber - result: ResultStruct + seed: bigint + result: EcdsaDkg.ResultStruct } // Decode this event explicitly. The assertion was introduced as a workaround // for Waffle's inability to verify events with an array nested in a struct. // See: https://github.com/EthWorks/Waffle/issues/245 export async function expectDkgResultSubmittedEvent( - tx: ContractTransaction, - expectedArgs: DkgResultSubmittedEventArgs + tx: ContractTransactionResponse, + expectedArgs: DkgResultSubmittedEventArgs, ): Promise { const eventName = "DkgResultSubmitted" - const event: DkgResultSubmittedEvent = (await tx.wait()).events.find( - (e) => e.event === eventName - ) as unknown as DkgResultSubmittedEvent + const event = requireResult(await tx.wait()).logs.find( + (log): log is DkgResultSubmittedEvent.Log => + log instanceof ethers.EventLog && log.eventName === eventName, + ) - await expect(event, `Event ${eventName} not emitted`).to.be.not.null + if (!event) { + throw new Error(`Event ${eventName} not emitted`) + } const actualArgs = event.args await expect(actualArgs.length, "invalid event args length").to.be.equal( - Object.keys(expectedArgs).length + Object.keys(expectedArgs).length, ) await expect( actualArgs.result.length, - "invalid result args length" + "invalid result args length", ).to.be.equal(Object.keys(expectedArgs.result).length) await expect(actualArgs.resultHash, "invalid resultHash").to.be.equal( - expectedArgs.resultHash + expectedArgs.resultHash, ) await expect(actualArgs.seed, "invalid seed").to.be.equal(expectedArgs.seed) await expect( actualArgs.result.submitterMemberIndex, - "invalid submitterMemberIndex" + "invalid submitterMemberIndex", ).to.be.equal(expectedArgs.result.submitterMemberIndex) await expect( actualArgs.result.groupPubKey, - "invalid groupPubKey" + "invalid groupPubKey", ).to.be.equal(expectedArgs.result.groupPubKey) await expect( actualArgs.result.misbehavedMembersIndices, - "invalid misbehavedMembersIndices" - ).to.be.deep.equal(expectedArgs.result.misbehavedMembersIndices) + "invalid misbehavedMembersIndices", + ).to.be.deep.equal(expectedArgs.result.misbehavedMembersIndices.map(BigInt)) await expect(actualArgs.result.signatures, "invalid signatures").to.be.equal( - expectedArgs.result.signatures + expectedArgs.result.signatures, ) await expect( actualArgs.result.signingMembersIndices, - "invalid signingMembersIndices" - ).to.be.deep.equal( - expectedArgs.result.signingMembersIndices.map(BigNumber.from) - ) + "invalid signingMembersIndices", + ).to.be.deep.equal(expectedArgs.result.signingMembersIndices.map(BigInt)) await expect(actualArgs.result.members, "invalid members").to.be.deep.equal( - expectedArgs.result.members + expectedArgs.result.members.map(BigInt), ) await expect( actualArgs.result.membersHash, - "invalid membersHash" + "invalid membersHash", ).to.be.equal(expectedArgs.result.membersHash) } diff --git a/solidity/ecdsa/test/utils/governance.ts b/solidity/ecdsa/test/utils/governance.ts index a69065b0f9..0d57484cf5 100644 --- a/solidity/ecdsa/test/utils/governance.ts +++ b/solidity/ecdsa/test/utils/governance.ts @@ -5,12 +5,12 @@ import type { WalletRegistry, WalletRegistryGovernance } from "../../typechain" // eslint-disable-next-line import/prefer-default-export export async function upgradeRandomBeacon( walletRegistry: WalletRegistry, - newRandomBeaconAddress: string + newRandomBeaconAddress: string, ): Promise { const walletRegistryGovernance: WalletRegistryGovernance = await ethers.getContractAt( "WalletRegistryGovernance", - await walletRegistry.governance() + await walletRegistry.governance(), ) const { governance } = await helpers.signers.getNamedSigners() diff --git a/solidity/ecdsa/test/utils/groups.ts b/solidity/ecdsa/test/utils/groups.ts index 14cc4990a0..3c6ba8ea84 100644 --- a/solidity/ecdsa/test/utils/groups.ts +++ b/solidity/ecdsa/test/utils/groups.ts @@ -1,33 +1,34 @@ -/* eslint-disable import/prefer-default-export */ - +import { toBeHex } from "ethers" import { ethers } from "hardhat" import { constants } from "../fixtures" -import type { BigNumber, BigNumberish } from "ethers" +import type { BigNumberish } from "ethers" import type { Operator } from "./operators" import type { SortitionPool } from "../../typechain" -const { keccak256, defaultAbiCoder } = ethers.utils +const { keccak256 } = ethers +const defaultAbiCoder = ethers.AbiCoder.defaultAbiCoder() export async function selectGroup( sortitionPool: SortitionPool, - seed: BigNumber + seed: bigint, ): Promise { - const identifiers = await sortitionPool.selectGroup( - constants.groupSize, - ethers.utils.hexZeroPad(seed.toHexString(), 32) + // Copy the immutable ethers Result before passing these IDs to another call. + const identifiers = Array.from( + await sortitionPool.selectGroup( + constants.groupSize, + ethers.zeroPadValue(toBeHex(seed), 32), + ), ) const addresses = await sortitionPool.getIDOperators(identifiers) return Promise.all( - identifiers.map( - async (identifier, i): Promise => ({ - id: identifier, - signer: await ethers.getSigner(addresses[i]), - }) - ) + identifiers.map(async (identifier, i): Promise => ({ + id: Number(identifier), + signer: await ethers.getSigner(addresses[i]), + })), ) } diff --git a/solidity/ecdsa/test/utils/inactivity.ts b/solidity/ecdsa/test/utils/inactivity.ts index 08adff02b7..90f6e5311d 100644 --- a/solidity/ecdsa/test/utils/inactivity.ts +++ b/solidity/ecdsa/test/utils/inactivity.ts @@ -12,13 +12,13 @@ export async function signOperatorInactivityClaim( groupPubKey: string, failedHeartbeat: boolean, inactiveMembersIndices: number[], - numberOfSignatures: number + numberOfSignatures: number, ): Promise<{ signatures: string signingMembersIndices: number[] }> { - const messageHash = ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode( + const messageHash = ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( ["uint256", "uint256", "bytes", "uint8[]", "bool"], [ hardhatNetworkId, @@ -26,8 +26,8 @@ export async function signOperatorInactivityClaim( groupPubKey, inactiveMembersIndices, failedHeartbeat, - ] - ) + ], + ), ) const signingMembersIndices: number[] = [] @@ -45,14 +45,14 @@ export async function signOperatorInactivityClaim( // eslint-disable-next-line no-await-in-loop const signature = await signers[i].signer.signMessage( - ethers.utils.arrayify(messageHash) + ethers.getBytes(messageHash), ) signatures.push(signature) } return { - signatures: ethers.utils.hexConcat(signatures), + signatures: ethers.concat(signatures), signingMembersIndices, } } diff --git a/solidity/ecdsa/test/utils/operators.ts b/solidity/ecdsa/test/utils/operators.ts index e9c359b249..8ad85e13a9 100644 --- a/solidity/ecdsa/test/utils/operators.ts +++ b/solidity/ecdsa/test/utils/operators.ts @@ -36,8 +36,8 @@ import { ethers, helpers } from "hardhat" import { params } from "../fixtures" import { testConfig } from "../../hardhat.config" -import type { BigNumber, BigNumberish, Contract } from "ethers" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import type { BigNumberish, Contract } from "ethers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" import type { WalletRegistry, T, @@ -47,7 +47,7 @@ import type { } from "../../typechain" /** Minimal ABI for legacy TokenStaking methods not present on the generated typechain ABI. */ -const legacyTokenStakingIface = new ethers.utils.Interface([ +const legacyTokenStakingIface = new ethers.Interface([ "function stake(address,address,address,uint96)", "function increaseAuthorization(address,address,uint96)", "function approveApplication(address)", @@ -55,10 +55,10 @@ const legacyTokenStakingIface = new ethers.utils.Interface([ ]) export function legacyTokenStakingAt( - staking: Pick, - signer: SignerWithAddress + staking: Pick, + signer: SignerWithAddress, ): Contract { - return new ethers.Contract(staking.address, legacyTokenStakingIface, signer) + return new ethers.Contract(staking, legacyTokenStakingIface, signer) } export type OperatorID = number @@ -116,29 +116,29 @@ export async function registerOperators( t: T, numberOfOperators = testConfig.operatorsCount, unnamedSignersOffset = testConfig.nonStakingAccountsCount, - stakeAmount: BigNumber = params.minimumAuthorization, - authorizationSource?: Allowlist + stakeAmount: bigint = params.minimumAuthorization, + authorizationSource?: Allowlist, ): Promise { const operators: Operator[] = [] const sortitionPool: SortitionPool = await ethers.getContractAt( "SortitionPool", - await walletRegistry.sortitionPool() + await walletRegistry.sortitionPool(), ) const staking: TokenStaking = await ethers.getContractAt( "TokenStaking", - await walletRegistry.staking() + await walletRegistry.staking(), ) const signers = (await helpers.signers.getUnnamedSigners()).slice( - unnamedSignersOffset + unnamedSignersOffset, ) // We use unique accounts for each staking role for each operator. if (signers.length < numberOfOperators * 5) { throw new Error( - "not enough unnamed signers; update hardhat network's configuration account count" + "not enough unnamed signers; update hardhat network's configuration account count", ) } @@ -181,7 +181,7 @@ export async function registerOperators( stakingProvider, stakeAmount, beneficiary, - authorizer + authorizer, ) } @@ -191,7 +191,7 @@ export async function registerOperators( await walletRegistry.connect(operator).joinSortitionPool() - const id = await sortitionPool.getOperatorID(operator.address) + const id = Number(await sortitionPool.getOperatorID(operator.address)) operators.push({ id, signer: operator, stakingProvider }) } @@ -227,7 +227,7 @@ export async function registerOperators( * is managed directly via Allowlist.addStakingProvider() without token staking. * * @example - * await stake(tToken, tokenStaking, walletRegistry, owner, provider, ethers.utils.parseEther("40000")) + * await stake(tToken, tokenStaking, walletRegistry, owner, provider, ethers.parseEther("40000")) */ export async function stake( t: T, @@ -237,23 +237,23 @@ export async function stake( stakingProvider: SignerWithAddress, stakeAmount: BigNumberish, beneficiary = stakingProvider, - authorizer = stakingProvider + authorizer = stakingProvider, ): Promise { const { deployer } = await helpers.signers.getNamedSigners() await t.connect(deployer).mint(owner.address, stakeAmount) - await t.connect(owner).approve(staking.address, stakeAmount) + await t.connect(owner).approve(await staking.getAddress(), stakeAmount) await legacyTokenStakingAt(staking, owner).stake( stakingProvider.address, beneficiary.address, authorizer.address, - stakeAmount + stakeAmount, ) await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - stakeAmount + await randomBeacon.getAddress(), + stakeAmount, ) } diff --git a/solidity/ecdsa/test/utils/random-beacon-export.test.ts b/solidity/ecdsa/test/utils/random-beacon-export.test.ts new file mode 100644 index 0000000000..54a963cbb0 --- /dev/null +++ b/solidity/ecdsa/test/utils/random-beacon-export.test.ts @@ -0,0 +1,166 @@ +import fs from "fs" +import os from "os" +import path from "path" + +import { expect } from "chai" + +import resolveRandomBeaconExport, { + resolveRandomBeaconExportIn, +} from "../../utils/random-beacon-export" + +const temporaryRoots: string[] = [] + +function temporaryRoot(...subdirectories: string[]): string { + const root = fs.mkdtempSync(path.join(os.tmpdir(), "beacon-export-")) + temporaryRoots.push(root) + subdirectories.forEach((subdirectory) => { + fs.mkdirSync(path.join(root, subdirectory), { recursive: true }) + }) + return root +} + +// utils/ sits inside the package, so the source root is the package root. +function sourceCheckout(root: string): string { + const packageRoot = path.join(root, "ecdsa") + fs.mkdirSync(packageRoot, { recursive: true }) + fs.writeFileSync(path.join(packageRoot, "hardhat.config.ts"), "") + return packageRoot +} + +function record(logs: string[]): (message: string) => void { + return (message) => { + logs.push(message) + } +} + +describe("resolveRandomBeaconExport", () => { + const originalExportPath = process.env.RANDOM_BEACON_EXPORT_PATH + + beforeEach(() => { + delete process.env.RANDOM_BEACON_EXPORT_PATH + }) + + afterEach(() => { + if (originalExportPath === undefined) { + delete process.env.RANDOM_BEACON_EXPORT_PATH + } else { + process.env.RANDOM_BEACON_EXPORT_PATH = originalExportPath + } + temporaryRoots.splice(0).forEach((root) => { + fs.rmSync(root, { recursive: true, force: true }) + }) + }) + + it("resolves the configured export path", () => { + const root = temporaryRoot("export/deploy") + process.env.RANDOM_BEACON_EXPORT_PATH = path.join(root, "export") + const logs: string[] = [] + const resolved = resolveRandomBeaconExportIn( + "deploy", + { sourceRoot: root, packageRoot: root }, + record(logs), + ) + expect(resolved).to.equal(path.join(root, "export", "deploy")) + expect(logs).to.deep.equal([ + `Random Beacon deploy from RANDOM_BEACON_EXPORT_PATH: ${resolved}`, + ]) + }) + + it("throws when the configured path misses the export", () => { + const root = temporaryRoot("export/deploy") + process.env.RANDOM_BEACON_EXPORT_PATH = path.join(root, "export") + const missingArtifacts = () => + resolveRandomBeaconExportIn( + "artifacts", + { sourceRoot: root, packageRoot: root }, + record([]), + ) + expect(missingArtifacts).to.throw( + /Random Beacon artifacts export is missing/, + ) + }) + + it("prefers the sibling checkout over the bundled scripts", () => { + const root = temporaryRoot( + "random-beacon/export/deploy", + "ecdsa/external/random-beacon-export/deploy", + ) + const packageRoot = sourceCheckout(root) + const logs: string[] = [] + const resolved = resolveRandomBeaconExportIn( + "deploy", + { sourceRoot: packageRoot, packageRoot }, + record(logs), + ) + expect(resolved).to.equal(path.join(root, "random-beacon/export/deploy")) + expect(logs).to.deep.equal([ + `Random Beacon deploy from the sibling checkout: ${resolved}`, + ]) + }) + + it("throws when the sibling checkout is partially built", () => { + const root = temporaryRoot( + "random-beacon/export/deploy", + "ecdsa/external/random-beacon-export/deploy", + ) + const packageRoot = sourceCheckout(root) + const partialSibling = () => + resolveRandomBeaconExportIn( + "artifacts", + { sourceRoot: packageRoot, packageRoot }, + record([]), + ) + expect(partialSibling).to.throw(/missing in the sibling checkout/) + }) + + it("uses the bundled scripts without a sibling checkout", () => { + const root = temporaryRoot("ecdsa/external/random-beacon-export/tasks") + const packageRoot = sourceCheckout(root) + const logs: string[] = [] + const resolved = resolveRandomBeaconExportIn( + "tasks", + { sourceRoot: packageRoot, packageRoot }, + record(logs), + ) + expect(resolved).to.equal( + path.join(packageRoot, "external/random-beacon-export/tasks"), + ) + expect(logs).to.deep.equal([ + `Random Beacon tasks from the bundled copy: ${resolved}`, + ]) + }) + + it("never falls back to the npm package for deploy scripts", () => { + const root = temporaryRoot("ecdsa") + const packageRoot = path.join(root, "ecdsa") + const missingBundle = () => + resolveRandomBeaconExportIn( + "deploy", + { sourceRoot: packageRoot, packageRoot }, + record([]), + ) + expect(missingBundle).to.throw(/Random Beacon deploy export is missing/) + }) + + it("resolves artifacts from the bundled export", () => { + const root = temporaryRoot("ecdsa/external/random-beacon-export/artifacts") + const packageRoot = path.join(root, "ecdsa") + const logs: string[] = [] + const resolved = resolveRandomBeaconExportIn( + "artifacts", + { sourceRoot: packageRoot, packageRoot }, + record(logs), + ) + expect(resolved).to.equal( + path.join(packageRoot, "external/random-beacon-export/artifacts"), + ) + expect(logs).to.deep.equal([ + `Random Beacon artifacts from the bundled copy: ${resolved}`, + ]) + }) + + it("resolves artifacts from the bundled export in the real checkout", () => { + const resolved = resolveRandomBeaconExport("artifacts") + expect(resolved).to.not.match(/node_modules/) + }) +}) diff --git a/solidity/ecdsa/test/utils/randomBeacon.ts b/solidity/ecdsa/test/utils/randomBeacon.ts index 1954b36c30..007707c599 100644 --- a/solidity/ecdsa/test/utils/randomBeacon.ts +++ b/solidity/ecdsa/test/utils/randomBeacon.ts @@ -1,23 +1,24 @@ +import { toBigInt } from "ethers" import { ethers } from "hardhat" +import requireResult from "../helpers/chain" import { createMock } from "../helpers/mock" -import type { BigNumber } from "ethers" import type { WalletRegistry, IRandomBeacon } from "../../typechain" import type { Mock } from "../helpers/mock" export async function fakeRandomBeacon( - walletRegistry: WalletRegistry + walletRegistry: WalletRegistry, ): Promise> { const randomBeacon = await createMock("IRandomBeacon", { - address: await walletRegistry.callStatic.randomBeacon(), + address: await walletRegistry.randomBeacon.staticCall(), }) await ( await ethers.getSigners() )[0].sendTransaction({ to: randomBeacon.address, - value: ethers.utils.parseEther("1000"), + value: ethers.parseEther("1000"), }) return randomBeacon @@ -25,27 +26,25 @@ export async function fakeRandomBeacon( export async function submitRelayEntry( walletRegistry: WalletRegistry, - randomBeacon?: Mock + randomBeacon?: Mock, ): Promise<{ startBlock: number - dkgSeed: BigNumber + dkgSeed: bigint }> { if (!randomBeacon) { // eslint-disable-next-line no-param-reassign randomBeacon = await fakeRandomBeacon(walletRegistry) } - const relayEntry: BigNumber = ethers.BigNumber.from( - ethers.utils.randomBytes(32) - ) + const relayEntry: bigint = toBigInt(ethers.randomBytes(32)) // eslint-disable-next-line no-underscore-dangle const tx = await walletRegistry .connect(randomBeacon.wallet) - .__beaconCallback(relayEntry, 0) + .__beaconCallback(ethers.toBigInt(relayEntry), 0) return { - startBlock: tx.blockNumber, + startBlock: requireResult(await tx.wait()).blockNumber, dkgSeed: relayEntry, } } diff --git a/solidity/ecdsa/test/utils/wallets.ts b/solidity/ecdsa/test/utils/wallets.ts index f7d4558136..0a86d58240 100644 --- a/solidity/ecdsa/test/utils/wallets.ts +++ b/solidity/ecdsa/test/utils/wallets.ts @@ -1,5 +1,6 @@ import { helpers, ethers } from "hardhat" +import requireResult from "../helpers/chain" import { params } from "../fixtures" import ecdsaData from "../data/ecdsa" @@ -9,35 +10,35 @@ import type { Mock } from "../helpers/mock" import type { DkgResult } from "./dkg" import type { IRandomBeacon, WalletRegistry } from "../../typechain" import type { Operator } from "./operators" -import type { BytesLike, ContractTransaction, Signer } from "ethers" +import type { BytesLike, ContractTransactionResponse, Signer } from "ethers" const { mineBlocks } = helpers.time -const { keccak256 } = ethers.utils +const { keccak256 } = ethers // eslint-disable-next-line import/prefer-default-export export async function createNewWallet( walletRegistry: WalletRegistry, walletOwner: Signer, randomBeacon: Mock, - publicKey: BytesLike = ecdsaData.group1.publicKey + publicKey: BytesLike = ecdsaData.group1.publicKey, ): Promise<{ members: Operator[] dkgResult: DkgResult walletID: string - tx: ContractTransaction + tx: ContractTransactionResponse }> { const requestNewWalletTx = await walletRegistry .connect(walletOwner) .requestNewWallet() - const relayEntry = ethers.utils.randomBytes(32) + const relayEntry = ethers.randomBytes(32) - const dkgSeed = ethers.BigNumber.from(keccak256(relayEntry)) + const dkgSeed = BigInt(keccak256(relayEntry)) // eslint-disable-next-line no-underscore-dangle await walletRegistry .connect(randomBeacon.wallet) - .__beaconCallback(relayEntry, 0) + .__beaconCallback(ethers.toBigInt(relayEntry), 0) const { dkgResult, @@ -47,8 +48,8 @@ export async function createNewWallet( walletRegistry, publicKey, dkgSeed, - requestNewWalletTx.blockNumber, - noMisbehaved + requireResult(await requestNewWalletTx.wait()).blockNumber, + noMisbehaved, ) await mineBlocks(params.dkgResultChallengePeriodLength) diff --git a/solidity/ecdsa/tsconfig.export.json b/solidity/ecdsa/tsconfig.export.json index 7832a5ea32..7409ea250c 100644 --- a/solidity/ecdsa/tsconfig.export.json +++ b/solidity/ecdsa/tsconfig.export.json @@ -1,8 +1,10 @@ { "extends": "./tsconfig.json", - "exclude": ["./test", "./typechain"], + "exclude": ["./test", "./typechain", "./scripts"], "compilerOptions": { - "target": "es5", + "target": "ES2020", + // hardhat-deploy v1 requires the published deployment scripts. + "module": "CommonJS", "outDir": "export" } } diff --git a/solidity/ecdsa/tsconfig.json b/solidity/ecdsa/tsconfig.json index 93f21c958f..eba3777f16 100644 --- a/solidity/ecdsa/tsconfig.json +++ b/solidity/ecdsa/tsconfig.json @@ -1,7 +1,27 @@ { "files": ["./hardhat.config.ts"], - "include": ["./deploy", "./tasks", "./test", "./typechain", "./types"], + "include": [ + "./deploy", + "./tasks", + "./test", + "./typechain", + "./types", + "./utils", + "./scripts" + ], "compilerOptions": { - "esModuleInterop": true + "strict": true, + // ts-node also needs an explicit target; its fallback is ES5. + "target": "ES2020", + // TypeScript 6 stopped including every `node_modules/@types` package + // automatically, which silently drops the mocha and chai globals. These + // are the four that contribute globals here. + "types": ["mocha", "chai", "chai-as-promised", "node"], + // Required by TypeScript 6 once a project spans several top-level + // directories. `--noEmit` does not need it, but ts-node's emit path does, + // so hardhat will not start without it. + "rootDir": ".", + "esModuleInterop": true, + "skipLibCheck": true } } diff --git a/solidity/ecdsa/types/TokenStaking.extensions.d.ts b/solidity/ecdsa/types/TokenStaking.extensions.d.ts index 85ed4bdcf1..4104fa0e2f 100644 --- a/solidity/ecdsa/types/TokenStaking.extensions.d.ts +++ b/solidity/ecdsa/types/TokenStaking.extensions.d.ts @@ -15,26 +15,26 @@ declare module "../typechain/TokenStaking" { beneficiary: string, authorizer: string, amount: BigNumberish, - overrides?: CallOverrides + overrides?: CallOverrides, ): Promise increaseAuthorization( stakingProvider: string, application: string, amount: BigNumberish, - overrides?: CallOverrides + overrides?: CallOverrides, ): Promise processSlashing( count: BigNumberish, - overrides?: CallOverrides + overrides?: CallOverrides, ): Promise getSlashingQueueLength(overrides?: CallOverrides): Promise slashingQueue( index: BigNumberish, - overrides?: CallOverrides + overrides?: CallOverrides, ): Promise< [string, BigNumber] & { stakingProvider: string; amount: BigNumber } > diff --git a/solidity/ecdsa/types/chai.d.ts b/solidity/ecdsa/types/chai.d.ts index 4766628d13..7a19d33219 100644 --- a/solidity/ecdsa/types/chai.d.ts +++ b/solidity/ecdsa/types/chai.d.ts @@ -6,7 +6,7 @@ declare namespace Chai { interface Assertion { revertedWithCustomError( contract: unknown, - errorName: string + errorName: string, ): RevertedWithCustomErrorAssertion } diff --git a/solidity/ecdsa/types/random-beacon.d.ts b/solidity/ecdsa/types/random-beacon.d.ts new file mode 100644 index 0000000000..ee84a77e64 --- /dev/null +++ b/solidity/ecdsa/types/random-beacon.d.ts @@ -0,0 +1,36 @@ +import type { BigNumberish } from "ethers" +import type { HardhatRuntimeEnvironment } from "hardhat/types" + +// The resolved Beacon task exports are generated JavaScript. Keep this narrow +// interface in sync with the ethers v6 source in random-beacon/tasks. +export interface InitializationTasks { + TASK_INITIALIZE: string + TASK_INITIALIZE_STAKING: string + TASK_AUTHORIZE: string + TASK_REGISTER: string + TASK_ADD_BETA_OPERATOR: string +} + +export interface TaskUtils { + authorize( + hre: HardhatRuntimeEnvironment, + deploymentName: string, + owner: string, + provider: string, + authorizer?: string, + authorization?: BigNumberish, + ): Promise + + register( + hre: HardhatRuntimeEnvironment, + deploymentName: string, + provider: string, + operator: string, + ): Promise + + addBetaOperator( + hre: HardhatRuntimeEnvironment, + sortitionPoolDeploymentName: string, + operator: string, + ): Promise +} diff --git a/solidity/ecdsa/utils/random-beacon-export.ts b/solidity/ecdsa/utils/random-beacon-export.ts new file mode 100644 index 0000000000..bea5083b01 --- /dev/null +++ b/solidity/ecdsa/utils/random-beacon-export.ts @@ -0,0 +1,79 @@ +import fs from "fs" +import path from "path" + +// This module also runs from export/utils in a packed ECDSA package. +const sourceRoot = path.resolve(__dirname, "..") +const packageRoot = fs.existsSync(path.join(sourceRoot, "package.json")) + ? sourceRoot + : path.dirname(sourceRoot) + +export type RandomBeaconExportKind = "deploy" | "artifacts" | "tasks" + +export interface RandomBeaconExportRoots { + /** Directory holding this module's parent: a checkout or a packed export. */ + sourceRoot: string + /** Directory holding the ECDSA package.json. */ + packageRoot: string +} + +/** + * Resolves a Random Beacon export directory and logs the producer it came + * from. Every subdirectory comes from a single producer: the sibling checkout + * is selected on its export root alone, so a half-built sibling fails loudly + * instead of pairing its fresh deploy scripts with another producer's + * artifacts. + */ +export function resolveRandomBeaconExportIn( + subdir: RandomBeaconExportKind, + roots: RandomBeaconExportRoots, + log: (message: string) => void = console.log, +): string { + // Explicit producer checks must never fall back to another package's code. + const exportRoot = process.env.RANDOM_BEACON_EXPORT_PATH + if (exportRoot) { + const configured = path.resolve(exportRoot, subdir) + if (!fs.existsSync(configured)) { + throw new Error( + `Random Beacon ${subdir} export is missing: ${configured}`, + ) + } + log(`Random Beacon ${subdir} from RANDOM_BEACON_EXPORT_PATH: ${configured}`) + return configured + } + + // Published packages have only export/hardhat.config.js. Without a source + // config, the adjacent random-beacon is an npm dependency, potentially v5. + const siblingRoot = path.join(roots.packageRoot, "../random-beacon/export") + if ( + fs.existsSync(path.join(roots.sourceRoot, "hardhat.config.ts")) && + fs.existsSync(siblingRoot) + ) { + const sibling = path.join(siblingRoot, subdir) + if (!fs.existsSync(sibling)) { + throw new Error( + `Random Beacon ${subdir} export is missing in the sibling checkout: ${sibling}`, + ) + } + log(`Random Beacon ${subdir} from the sibling checkout: ${sibling}`) + return sibling + } + + // The published Random Beacon npm package was removed; the committed + // snapshot in external/random-beacon-export is the only fallback. + const bundled = path.join( + roots.packageRoot, + "external/random-beacon-export", + subdir, + ) + if (!fs.existsSync(bundled)) { + throw new Error(`Random Beacon ${subdir} export is missing: ${bundled}`) + } + log(`Random Beacon ${subdir} from the bundled copy: ${bundled}`) + return bundled +} + +export default function resolveRandomBeaconExport( + subdir: RandomBeaconExportKind, +): string { + return resolveRandomBeaconExportIn(subdir, { sourceRoot, packageRoot }) +} diff --git a/solidity/ecdsa/yarn.lock b/solidity/ecdsa/yarn.lock index 9733ae7237..80d2974c36 100644 --- a/solidity/ecdsa/yarn.lock +++ b/solidity/ecdsa/yarn.lock @@ -5,7 +5,7 @@ __metadata: version: 8 cacheKey: 10c0 -"@adraffy/ens-normalize@npm:^1.11.0": +"@adraffy/ens-normalize@npm:1.11.1, @adraffy/ens-normalize@npm:^1.11.0": version: 1.11.1 resolution: "@adraffy/ens-normalize@npm:1.11.1" checksum: 10c0/b364e2a57131db278ebf2f22d1a1ac6d8aea95c49dd2bbbc1825870b38aa91fd8816aba580a1f84edc50a45eb6389213dacfd1889f32893afc8549a82d304767 @@ -53,15 +53,6 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:7.12.11": - version: 7.12.11 - resolution: "@babel/code-frame@npm:7.12.11" - dependencies: - "@babel/highlight": "npm:^7.10.4" - checksum: 10c0/836ffd155506768e991d6dd8c51db37cad5958ed1c8e0a2329ccd9527165d5c752e943d66a5c3c92ffd45f343419f0742e7636629a529f4fbd5303e3637746b9 - languageName: node - linkType: hard - "@babel/code-frame@npm:^7.0.0": version: 7.16.7 resolution: "@babel/code-frame@npm:7.16.7" @@ -71,6 +62,17 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.27.1": + version: 7.29.7 + resolution: "@babel/code-frame@npm:7.29.7" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.29.7" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.1.1" + checksum: 10c0/169fc2080169a40c1760155eaaaf739bcb882df0bec76a83adbda5493645bc17270a3434b8848c494b1933e96fe1d147370001e3cda09a39f43ae30f08ef2069 + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.16.7": version: 7.16.7 resolution: "@babel/helper-validator-identifier@npm:7.16.7" @@ -78,7 +80,14 @@ __metadata: languageName: node linkType: hard -"@babel/highlight@npm:^7.10.4, @babel/highlight@npm:^7.16.7": +"@babel/helper-validator-identifier@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-validator-identifier@npm:7.29.7" + checksum: 10c0/4795354e7ae0dcafa72de1cd04ec51252dc1498517170beaf019e03effc5b7bf13c6b21a3949a77e07b8125be7f106ed1131350d8ebd4566ae874094a726d62b + languageName: node + linkType: hard + +"@babel/highlight@npm:^7.16.7": version: 7.16.10 resolution: "@babel/highlight@npm:7.16.10" dependencies: @@ -96,6 +105,35 @@ __metadata: languageName: node linkType: hard +"@bytecodealliance/preview2-shim@npm:^0.19.0": + version: 0.19.0 + resolution: "@bytecodealliance/preview2-shim@npm:0.19.0" + checksum: 10c0/c15b6aff80dfcb8cd2c2fb532f7b5a35bef0031d1df1f08064d8ef591668621ce379e5a285a3f48d2de5101fbc5a8e6badc935eaaa97eeb9ccb73d60c280c74d + languageName: node + linkType: hard + +"@cacheable/memory@npm:^2.2.0": + version: 2.2.0 + resolution: "@cacheable/memory@npm:2.2.0" + dependencies: + "@cacheable/utils": "npm:^2.5.0" + "@keyv/bigmap": "npm:^1.3.1" + hookified: "npm:^1.15.1" + keyv: "npm:^5.6.0" + checksum: 10c0/c74889eb09871be0696065778fff013a498ddc73b538d113c2cb6ece361746f2959fbddfa4ce03ce53c9259998be05949e393212e72413dbd07616744eabd261 + languageName: node + linkType: hard + +"@cacheable/utils@npm:^2.5.0": + version: 2.5.0 + resolution: "@cacheable/utils@npm:2.5.0" + dependencies: + hashery: "npm:^1.5.1" + keyv: "npm:^5.6.0" + checksum: 10c0/99e901accd71eeb0bce91484d6c66d7ef2c731b541561eb5dc9ea7fed78bdc0b65e5dd2a80edde50191143bcfc5f238fc4742475b32e82d43b43eea224038e35 + languageName: node + linkType: hard + "@colors/colors@npm:1.5.0": version: 1.5.0 resolution: "@colors/colors@npm:1.5.0" @@ -119,20 +157,104 @@ __metadata: languageName: node linkType: hard -"@eslint/eslintrc@npm:^0.4.3": - version: 0.4.3 - resolution: "@eslint/eslintrc@npm:0.4.3" +"@cspotcode/source-map-support@npm:^0.8.0": + version: 0.8.1 + resolution: "@cspotcode/source-map-support@npm:0.8.1" dependencies: - ajv: "npm:^6.12.4" - debug: "npm:^4.1.1" - espree: "npm:^7.3.0" - globals: "npm:^13.9.0" - ignore: "npm:^4.0.6" - import-fresh: "npm:^3.2.1" - js-yaml: "npm:^3.13.1" - minimatch: "npm:^3.0.4" - strip-json-comments: "npm:^3.1.1" - checksum: 10c0/0eed93369f72ef044686d07824742121f9b95153ff34f4614e4e69d64332ee68c84eb70da851a9005bb76b3d1d64ad76c2e6293a808edc0f7dfb883689ca136d + "@jridgewell/trace-mapping": "npm:0.3.9" + checksum: 10c0/05c5368c13b662ee4c122c7bfbe5dc0b613416672a829f3e78bc49a357a197e0218d6e74e7c66cfcd04e15a179acab080bd3c69658c9fbefd0e1ccd950a07fc6 + languageName: node + linkType: hard + +"@emnapi/core@npm:1.10.0": + version: 1.10.0 + resolution: "@emnapi/core@npm:1.10.0" + dependencies: + "@emnapi/wasi-threads": "npm:1.2.1" + tslib: "npm:^2.4.0" + checksum: 10c0/f51d08227857b60632de7714d708124f0e100a1462dde6df8221760939aa3204a73193830371830fac0716f3ccd2129f2cac1b17cd7d7958bc4da9018a296edb + languageName: node + linkType: hard + +"@emnapi/runtime@npm:1.10.0": + version: 1.10.0 + resolution: "@emnapi/runtime@npm:1.10.0" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/953f14991d1aefb92ee6f8eb27dea725e484791a53a0cb5f47d9e0087b9a2c929ff2e92adf95af15d6ad456db6300c6b761ebf72b50a875b874a83520b3ba093 + languageName: node + linkType: hard + +"@emnapi/wasi-threads@npm:1.2.1": + version: 1.2.1 + resolution: "@emnapi/wasi-threads@npm:1.2.1" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/32fcfa81ab396533b2ec1f4082b1ff779a05d9c836bbbd3f4398405b0e6814c0d9503b7993130e37bc6941dbc1ded49f55e9700ae9ca4e803bab2b5bc5deb331 + languageName: node + linkType: hard + +"@eslint-community/eslint-utils@npm:^4.8.0, @eslint-community/eslint-utils@npm:^4.9.1": + version: 4.10.1 + resolution: "@eslint-community/eslint-utils@npm:4.10.1" + dependencies: + eslint-visitor-keys: "npm:^3.4.3" + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + checksum: 10c0/b514586655698bc6b74db72a496c77e813c78b63e36a83429845ac7057dd77113b0b6c31e6e590d5baaeee2abae6ea22363a41209bcafa078d895ab83ce83011 + languageName: node + linkType: hard + +"@eslint-community/regexpp@npm:^4.12.2": + version: 4.12.2 + resolution: "@eslint-community/regexpp@npm:4.12.2" + checksum: 10c0/fddcbc66851b308478d04e302a4d771d6917a0b3740dc351513c0da9ca2eab8a1adf99f5e0aa7ab8b13fa0df005c81adeee7e63a92f3effd7d367a163b721c2d + languageName: node + linkType: hard + +"@eslint/config-array@npm:^0.23.5": + version: 0.23.5 + resolution: "@eslint/config-array@npm:0.23.5" + dependencies: + "@eslint/object-schema": "npm:^3.0.5" + debug: "npm:^4.3.1" + minimatch: "npm:^10.2.4" + checksum: 10c0/b24833c4c76e78ee075d306cd3f095db46b2db0f90cc13a6ee6e4275f9889731c05bf5403ab5fefb79c756e07ac9184ed0e04570341382f9eccbccc80e6d1a0c + languageName: node + linkType: hard + +"@eslint/config-helpers@npm:^0.7.0": + version: 0.7.0 + resolution: "@eslint/config-helpers@npm:0.7.0" + dependencies: + "@eslint/core": "npm:^1.2.1" + checksum: 10c0/fd40d57d6f1db49f7b647048b88a433dc7f6522ef3edf855a43cb526ef4fc40622ceed0dc8de2e03d254f30f8e035370570de1d4bd8e7c2b1200131451e0d331 + languageName: node + linkType: hard + +"@eslint/core@npm:^1.2.1": + version: 1.2.1 + resolution: "@eslint/core@npm:1.2.1" + dependencies: + "@types/json-schema": "npm:^7.0.15" + checksum: 10c0/10979b40588ecfef771fcb5013a542a35fb30692cc95a65f3481b0b36fbd89f5679efeb30d57f4eed35203d859aabace2a620177d6c536f71b299a1af2f3398f + languageName: node + linkType: hard + +"@eslint/object-schema@npm:^3.0.5": + version: 3.0.5 + resolution: "@eslint/object-schema@npm:3.0.5" + checksum: 10c0/1db337431f520b99e9edda64ef5fafd7ec6a029843eeb608753025125b6649d861d843cffafafd3c4e37926d7d5f9ec0c6a8e3665c13c3da2144e8132892e92e + languageName: node + linkType: hard + +"@eslint/plugin-kit@npm:^0.7.3": + version: 0.7.3 + resolution: "@eslint/plugin-kit@npm:0.7.3" + dependencies: + "@eslint/core": "npm:^1.2.1" + levn: "npm:^0.4.1" + checksum: 10c0/2daebaedcfbd261478e8b87dfb46d3118f48277c19eb298483ebc6f3b438e9688b86ddca13b3aeb08dfb06be00fb6073506852386aa124645c1170e7e33d140c languageName: node linkType: hard @@ -155,23 +277,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/abi@npm:5.5.0, @ethersproject/abi@npm:^5.1.2, @ethersproject/abi@npm:^5.5.0": - version: 5.5.0 - resolution: "@ethersproject/abi@npm:5.5.0" - dependencies: - "@ethersproject/address": "npm:^5.5.0" - "@ethersproject/bignumber": "npm:^5.5.0" - "@ethersproject/bytes": "npm:^5.5.0" - "@ethersproject/constants": "npm:^5.5.0" - "@ethersproject/hash": "npm:^5.5.0" - "@ethersproject/keccak256": "npm:^5.5.0" - "@ethersproject/logger": "npm:^5.5.0" - "@ethersproject/properties": "npm:^5.5.0" - "@ethersproject/strings": "npm:^5.5.0" - checksum: 10c0/8b38b4462c6599fb83f9cbadfff4aa2bdfdc5ff7796c896f45360ab8edbecaf9dab4eb15c719393c1e7b5f7269c5940c553c3d7d256972291920208c75648f33 - languageName: node - linkType: hard - "@ethersproject/abi@npm:5.7.0, @ethersproject/abi@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/abi@npm:5.7.0" @@ -189,7 +294,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/abi@npm:^5.6.3": +"@ethersproject/abi@npm:5.8.0, @ethersproject/abi@npm:^5.8.0": version: 5.8.0 resolution: "@ethersproject/abi@npm:5.8.0" dependencies: @@ -206,18 +311,20 @@ __metadata: languageName: node linkType: hard -"@ethersproject/abstract-provider@npm:5.5.1, @ethersproject/abstract-provider@npm:^5.5.0": - version: 5.5.1 - resolution: "@ethersproject/abstract-provider@npm:5.5.1" +"@ethersproject/abi@npm:^5.1.2": + version: 5.5.0 + resolution: "@ethersproject/abi@npm:5.5.0" dependencies: + "@ethersproject/address": "npm:^5.5.0" "@ethersproject/bignumber": "npm:^5.5.0" "@ethersproject/bytes": "npm:^5.5.0" + "@ethersproject/constants": "npm:^5.5.0" + "@ethersproject/hash": "npm:^5.5.0" + "@ethersproject/keccak256": "npm:^5.5.0" "@ethersproject/logger": "npm:^5.5.0" - "@ethersproject/networks": "npm:^5.5.0" "@ethersproject/properties": "npm:^5.5.0" - "@ethersproject/transactions": "npm:^5.5.0" - "@ethersproject/web": "npm:^5.5.0" - checksum: 10c0/4eceaa1c48d7d4662eb56e78aab837dfb58f74823fee138bb5715e48b475d34946d2b9bc9c347e9d2bdd70a1e4e2f5aa82a0a7c3f68881e1a4eba8a948c4b315 + "@ethersproject/strings": "npm:^5.5.0" + checksum: 10c0/8b38b4462c6599fb83f9cbadfff4aa2bdfdc5ff7796c896f45360ab8edbecaf9dab4eb15c719393c1e7b5f7269c5940c553c3d7d256972291920208c75648f33 languageName: node linkType: hard @@ -236,7 +343,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/abstract-provider@npm:^5.8.0": +"@ethersproject/abstract-provider@npm:5.8.0, @ethersproject/abstract-provider@npm:^5.8.0": version: 5.8.0 resolution: "@ethersproject/abstract-provider@npm:5.8.0" dependencies: @@ -251,16 +358,18 @@ __metadata: languageName: node linkType: hard -"@ethersproject/abstract-signer@npm:5.5.0, @ethersproject/abstract-signer@npm:^5.5.0": - version: 5.5.0 - resolution: "@ethersproject/abstract-signer@npm:5.5.0" +"@ethersproject/abstract-provider@npm:^5.5.0": + version: 5.5.1 + resolution: "@ethersproject/abstract-provider@npm:5.5.1" dependencies: - "@ethersproject/abstract-provider": "npm:^5.5.0" "@ethersproject/bignumber": "npm:^5.5.0" "@ethersproject/bytes": "npm:^5.5.0" "@ethersproject/logger": "npm:^5.5.0" + "@ethersproject/networks": "npm:^5.5.0" "@ethersproject/properties": "npm:^5.5.0" - checksum: 10c0/6fdc8ee7b0ccbc2ea2cb493578b5ea1e6c33a462f4681066edd68638ae9fa8f58608f835daa27c1da94739e8f23ccbcafd22329b9e6b220bfc8092a88ea10715 + "@ethersproject/transactions": "npm:^5.5.0" + "@ethersproject/web": "npm:^5.5.0" + checksum: 10c0/4eceaa1c48d7d4662eb56e78aab837dfb58f74823fee138bb5715e48b475d34946d2b9bc9c347e9d2bdd70a1e4e2f5aa82a0a7c3f68881e1a4eba8a948c4b315 languageName: node linkType: hard @@ -277,7 +386,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/abstract-signer@npm:^5.8.0": +"@ethersproject/abstract-signer@npm:5.8.0, @ethersproject/abstract-signer@npm:^5.8.0": version: 5.8.0 resolution: "@ethersproject/abstract-signer@npm:5.8.0" dependencies: @@ -290,16 +399,16 @@ __metadata: languageName: node linkType: hard -"@ethersproject/address@npm:5.5.0, @ethersproject/address@npm:^5.0.2, @ethersproject/address@npm:^5.5.0": +"@ethersproject/abstract-signer@npm:^5.5.0": version: 5.5.0 - resolution: "@ethersproject/address@npm:5.5.0" + resolution: "@ethersproject/abstract-signer@npm:5.5.0" dependencies: + "@ethersproject/abstract-provider": "npm:^5.5.0" "@ethersproject/bignumber": "npm:^5.5.0" "@ethersproject/bytes": "npm:^5.5.0" - "@ethersproject/keccak256": "npm:^5.5.0" "@ethersproject/logger": "npm:^5.5.0" - "@ethersproject/rlp": "npm:^5.5.0" - checksum: 10c0/55f358c1edf8c4f4951acab9ed4db9bc64cc65d6897ba4820a6dbff4eeb99bf49bbfe36447a6fff39f50e86bc3f089bf658f56db9b8c792f5b05bbc6fd99cc39 + "@ethersproject/properties": "npm:^5.5.0" + checksum: 10c0/6fdc8ee7b0ccbc2ea2cb493578b5ea1e6c33a462f4681066edd68638ae9fa8f58608f835daa27c1da94739e8f23ccbcafd22329b9e6b220bfc8092a88ea10715 languageName: node linkType: hard @@ -316,7 +425,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/address@npm:^5.8.0": +"@ethersproject/address@npm:5.8.0, @ethersproject/address@npm:^5.8.0": version: 5.8.0 resolution: "@ethersproject/address@npm:5.8.0" dependencies: @@ -329,12 +438,16 @@ __metadata: languageName: node linkType: hard -"@ethersproject/base64@npm:5.5.0, @ethersproject/base64@npm:^5.5.0": +"@ethersproject/address@npm:^5.0.2, @ethersproject/address@npm:^5.5.0": version: 5.5.0 - resolution: "@ethersproject/base64@npm:5.5.0" + resolution: "@ethersproject/address@npm:5.5.0" dependencies: + "@ethersproject/bignumber": "npm:^5.5.0" "@ethersproject/bytes": "npm:^5.5.0" - checksum: 10c0/1c93c88420be379222021ad3b3e2dc775fa0ead584a308de31d01be87fbf9fe3d5eb982cdd68db2d3a4686510df1ad426a4f968b90fa0372abcf24b51a5d88fa + "@ethersproject/keccak256": "npm:^5.5.0" + "@ethersproject/logger": "npm:^5.5.0" + "@ethersproject/rlp": "npm:^5.5.0" + checksum: 10c0/55f358c1edf8c4f4951acab9ed4db9bc64cc65d6897ba4820a6dbff4eeb99bf49bbfe36447a6fff39f50e86bc3f089bf658f56db9b8c792f5b05bbc6fd99cc39 languageName: node linkType: hard @@ -347,7 +460,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/base64@npm:^5.8.0": +"@ethersproject/base64@npm:5.8.0, @ethersproject/base64@npm:^5.8.0": version: 5.8.0 resolution: "@ethersproject/base64@npm:5.8.0" dependencies: @@ -356,13 +469,12 @@ __metadata: languageName: node linkType: hard -"@ethersproject/basex@npm:5.5.0, @ethersproject/basex@npm:^5.5.0": +"@ethersproject/base64@npm:^5.5.0": version: 5.5.0 - resolution: "@ethersproject/basex@npm:5.5.0" + resolution: "@ethersproject/base64@npm:5.5.0" dependencies: "@ethersproject/bytes": "npm:^5.5.0" - "@ethersproject/properties": "npm:^5.5.0" - checksum: 10c0/ec08761b4df546406ccda432c92a32ab6ac6b4b36c73a129f0a5b262a3af31c94b6749973f26900c541ebead4586d6551120644a0e2557c7bb107f4a3000ef0e + checksum: 10c0/1c93c88420be379222021ad3b3e2dc775fa0ead584a308de31d01be87fbf9fe3d5eb982cdd68db2d3a4686510df1ad426a4f968b90fa0372abcf24b51a5d88fa languageName: node linkType: hard @@ -376,14 +488,13 @@ __metadata: languageName: node linkType: hard -"@ethersproject/bignumber@npm:5.5.0, @ethersproject/bignumber@npm:^5.5.0": - version: 5.5.0 - resolution: "@ethersproject/bignumber@npm:5.5.0" +"@ethersproject/basex@npm:5.8.0, @ethersproject/basex@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/basex@npm:5.8.0" dependencies: - "@ethersproject/bytes": "npm:^5.5.0" - "@ethersproject/logger": "npm:^5.5.0" - bn.js: "npm:^4.11.9" - checksum: 10c0/9d0e827e0575b0e852c709b7fe56766f10edb04afb31ad7e18776eca837fcc08778458867dc23f8f02f773c37b2591f52dc14b6e329aff077feacc8f2dae0ed8 + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + checksum: 10c0/46a94ba9678fc458ab0bee4a0af9f659f1d3f5df5bb98485924fe8ecbd46eda37d81f95f882243d56f0f5efe051b0749163f5056e48ff836c5fba648754d4956 languageName: node linkType: hard @@ -398,18 +509,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/bignumber@npm:^5.6.2": - version: 5.6.2 - resolution: "@ethersproject/bignumber@npm:5.6.2" - dependencies: - "@ethersproject/bytes": "npm:^5.6.1" - "@ethersproject/logger": "npm:^5.6.0" - bn.js: "npm:^5.2.1" - checksum: 10c0/4298b49f8f16078fd2ec39656c92a7ae1a93a8032a218805694db0f99179055ee93a548dff38228dc08add8c14a6eefbb8b49c6d802bd48180a91aa79f28d969 - languageName: node - linkType: hard - -"@ethersproject/bignumber@npm:^5.8.0": +"@ethersproject/bignumber@npm:5.8.0, @ethersproject/bignumber@npm:^5.8.0": version: 5.8.0 resolution: "@ethersproject/bignumber@npm:5.8.0" dependencies: @@ -420,12 +520,14 @@ __metadata: languageName: node linkType: hard -"@ethersproject/bytes@npm:5.5.0, @ethersproject/bytes@npm:^5.5.0": +"@ethersproject/bignumber@npm:^5.5.0": version: 5.5.0 - resolution: "@ethersproject/bytes@npm:5.5.0" + resolution: "@ethersproject/bignumber@npm:5.5.0" dependencies: + "@ethersproject/bytes": "npm:^5.5.0" "@ethersproject/logger": "npm:^5.5.0" - checksum: 10c0/4964aace98f17c9d8a4c13decdcc9b5a6362bf6ea9647aabeae0e834faa470ea80ce5ae0e4c4d08697102aafe5b97e5fb29a58623a4fb4d5a06e19bedc5de779 + bn.js: "npm:^4.11.9" + checksum: 10c0/9d0e827e0575b0e852c709b7fe56766f10edb04afb31ad7e18776eca837fcc08778458867dc23f8f02f773c37b2591f52dc14b6e329aff077feacc8f2dae0ed8 languageName: node linkType: hard @@ -438,16 +540,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/bytes@npm:^5.6.1": - version: 5.6.1 - resolution: "@ethersproject/bytes@npm:5.6.1" - dependencies: - "@ethersproject/logger": "npm:^5.6.0" - checksum: 10c0/6bc6c8d7eebfe13b2976851920bf11e6b0dcc2ee91a8e013ca6ab9b55a4de7ccf9b3c8f4cdc777547c5ddc795a8ada0bf79ca91482e88d01e3957c901c0fef55 - languageName: node - linkType: hard - -"@ethersproject/bytes@npm:^5.8.0": +"@ethersproject/bytes@npm:5.8.0, @ethersproject/bytes@npm:^5.8.0": version: 5.8.0 resolution: "@ethersproject/bytes@npm:5.8.0" dependencies: @@ -456,12 +549,12 @@ __metadata: languageName: node linkType: hard -"@ethersproject/constants@npm:5.5.0, @ethersproject/constants@npm:^5.5.0": +"@ethersproject/bytes@npm:^5.5.0": version: 5.5.0 - resolution: "@ethersproject/constants@npm:5.5.0" + resolution: "@ethersproject/bytes@npm:5.5.0" dependencies: - "@ethersproject/bignumber": "npm:^5.5.0" - checksum: 10c0/68ea669b79e6e2735561a32fc1d1237d8cc940c2a986885a6ba1dcd067ce23e2659103ce90e804a24533262da5231c81b374370b1fb4a838dae625254341e84b + "@ethersproject/logger": "npm:^5.5.0" + checksum: 10c0/4964aace98f17c9d8a4c13decdcc9b5a6362bf6ea9647aabeae0e834faa470ea80ce5ae0e4c4d08697102aafe5b97e5fb29a58623a4fb4d5a06e19bedc5de779 languageName: node linkType: hard @@ -474,7 +567,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/constants@npm:^5.8.0": +"@ethersproject/constants@npm:5.8.0, @ethersproject/constants@npm:^5.8.0": version: 5.8.0 resolution: "@ethersproject/constants@npm:5.8.0" dependencies: @@ -483,21 +576,12 @@ __metadata: languageName: node linkType: hard -"@ethersproject/contracts@npm:5.5.0": +"@ethersproject/constants@npm:^5.5.0": version: 5.5.0 - resolution: "@ethersproject/contracts@npm:5.5.0" + resolution: "@ethersproject/constants@npm:5.5.0" dependencies: - "@ethersproject/abi": "npm:^5.5.0" - "@ethersproject/abstract-provider": "npm:^5.5.0" - "@ethersproject/abstract-signer": "npm:^5.5.0" - "@ethersproject/address": "npm:^5.5.0" "@ethersproject/bignumber": "npm:^5.5.0" - "@ethersproject/bytes": "npm:^5.5.0" - "@ethersproject/constants": "npm:^5.5.0" - "@ethersproject/logger": "npm:^5.5.0" - "@ethersproject/properties": "npm:^5.5.0" - "@ethersproject/transactions": "npm:^5.5.0" - checksum: 10c0/53904d7a76b930812dd70ad9b8fd3544821a8bec77aa62b01a2039706fb09d3461737ec1c68d95b3d1b7ebe458e36d2d9af4ad093caa110c43177f0962aab86b + checksum: 10c0/68ea669b79e6e2735561a32fc1d1237d8cc940c2a986885a6ba1dcd067ce23e2659103ce90e804a24533262da5231c81b374370b1fb4a838dae625254341e84b languageName: node linkType: hard @@ -519,19 +603,21 @@ __metadata: languageName: node linkType: hard -"@ethersproject/hash@npm:5.5.0, @ethersproject/hash@npm:^5.5.0": - version: 5.5.0 - resolution: "@ethersproject/hash@npm:5.5.0" +"@ethersproject/contracts@npm:5.8.0, @ethersproject/contracts@npm:^5.7.0": + version: 5.8.0 + resolution: "@ethersproject/contracts@npm:5.8.0" dependencies: - "@ethersproject/abstract-signer": "npm:^5.5.0" - "@ethersproject/address": "npm:^5.5.0" - "@ethersproject/bignumber": "npm:^5.5.0" - "@ethersproject/bytes": "npm:^5.5.0" - "@ethersproject/keccak256": "npm:^5.5.0" - "@ethersproject/logger": "npm:^5.5.0" - "@ethersproject/properties": "npm:^5.5.0" - "@ethersproject/strings": "npm:^5.5.0" - checksum: 10c0/ac1abdb4e76b3537bd989d42aac0fda55a8c647141c87ccd03691f4922d3cb29ced4d50f5bbfd09560c178471121d6e68a67b570d1cb476481ea1ab9242effb3 + "@ethersproject/abi": "npm:^5.8.0" + "@ethersproject/abstract-provider": "npm:^5.8.0" + "@ethersproject/abstract-signer": "npm:^5.8.0" + "@ethersproject/address": "npm:^5.8.0" + "@ethersproject/bignumber": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/constants": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + "@ethersproject/transactions": "npm:^5.8.0" + checksum: 10c0/49961b92334c4f2fab5f4da8f3119e97c1dc39cc8695e3043931757968213f5e732c00bf896193cf0186dcb33101dcd6efb70690dee0dd2cfbfd3843f55485aa languageName: node linkType: hard @@ -552,7 +638,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/hash@npm:^5.8.0": +"@ethersproject/hash@npm:5.8.0, @ethersproject/hash@npm:^5.8.0": version: 5.8.0 resolution: "@ethersproject/hash@npm:5.8.0" dependencies: @@ -569,23 +655,19 @@ __metadata: languageName: node linkType: hard -"@ethersproject/hdnode@npm:5.5.0, @ethersproject/hdnode@npm:^5.5.0": +"@ethersproject/hash@npm:^5.5.0": version: 5.5.0 - resolution: "@ethersproject/hdnode@npm:5.5.0" + resolution: "@ethersproject/hash@npm:5.5.0" dependencies: "@ethersproject/abstract-signer": "npm:^5.5.0" - "@ethersproject/basex": "npm:^5.5.0" + "@ethersproject/address": "npm:^5.5.0" "@ethersproject/bignumber": "npm:^5.5.0" "@ethersproject/bytes": "npm:^5.5.0" + "@ethersproject/keccak256": "npm:^5.5.0" "@ethersproject/logger": "npm:^5.5.0" - "@ethersproject/pbkdf2": "npm:^5.5.0" "@ethersproject/properties": "npm:^5.5.0" - "@ethersproject/sha2": "npm:^5.5.0" - "@ethersproject/signing-key": "npm:^5.5.0" "@ethersproject/strings": "npm:^5.5.0" - "@ethersproject/transactions": "npm:^5.5.0" - "@ethersproject/wordlists": "npm:^5.5.0" - checksum: 10c0/b0e3b55c954fb366ba60fb060ee04d15ac9fe0125587cc911e119086d807b9a5ea13e38b96dafc826f9c018e3342b306777251094dd903e6f459bb172e2f2be1 + checksum: 10c0/ac1abdb4e76b3537bd989d42aac0fda55a8c647141c87ccd03691f4922d3cb29ced4d50f5bbfd09560c178471121d6e68a67b570d1cb476481ea1ab9242effb3 languageName: node linkType: hard @@ -609,24 +691,23 @@ __metadata: languageName: node linkType: hard -"@ethersproject/json-wallets@npm:5.5.0, @ethersproject/json-wallets@npm:^5.5.0": - version: 5.5.0 - resolution: "@ethersproject/json-wallets@npm:5.5.0" +"@ethersproject/hdnode@npm:5.8.0, @ethersproject/hdnode@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/hdnode@npm:5.8.0" dependencies: - "@ethersproject/abstract-signer": "npm:^5.5.0" - "@ethersproject/address": "npm:^5.5.0" - "@ethersproject/bytes": "npm:^5.5.0" - "@ethersproject/hdnode": "npm:^5.5.0" - "@ethersproject/keccak256": "npm:^5.5.0" - "@ethersproject/logger": "npm:^5.5.0" - "@ethersproject/pbkdf2": "npm:^5.5.0" - "@ethersproject/properties": "npm:^5.5.0" - "@ethersproject/random": "npm:^5.5.0" - "@ethersproject/strings": "npm:^5.5.0" - "@ethersproject/transactions": "npm:^5.5.0" - aes-js: "npm:3.0.0" - scrypt-js: "npm:3.0.1" - checksum: 10c0/383a982701a04312bfccbc99633b24b7ff5b070f7a220d071e6b8e2f1d7c4c9038ca0e76177ff741ab26b40c12e8341217481b5c6aaee91979bac9b9158acbcc + "@ethersproject/abstract-signer": "npm:^5.8.0" + "@ethersproject/basex": "npm:^5.8.0" + "@ethersproject/bignumber": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/pbkdf2": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + "@ethersproject/sha2": "npm:^5.8.0" + "@ethersproject/signing-key": "npm:^5.8.0" + "@ethersproject/strings": "npm:^5.8.0" + "@ethersproject/transactions": "npm:^5.8.0" + "@ethersproject/wordlists": "npm:^5.8.0" + checksum: 10c0/da0ac7d60e76a76471be1f4f3bba3f28a24165dc3b63c6930a9ec24481e9f8b23936e5fc96363b3591cdfda4381d4623f25b06898b89bf5530b158cb5ea58fdd languageName: node linkType: hard @@ -651,13 +732,24 @@ __metadata: languageName: node linkType: hard -"@ethersproject/keccak256@npm:5.5.0, @ethersproject/keccak256@npm:^5.5.0": - version: 5.5.0 - resolution: "@ethersproject/keccak256@npm:5.5.0" +"@ethersproject/json-wallets@npm:5.8.0, @ethersproject/json-wallets@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/json-wallets@npm:5.8.0" dependencies: - "@ethersproject/bytes": "npm:^5.5.0" - js-sha3: "npm:0.8.0" - checksum: 10c0/e88d9db6f84227dc8216677fc692a10289c383bf63d207da7ad8beb0d8b112650dc3fbacadb6cc864304d9fe5243235bc6a49de6a37321ab05793717cedcaaac + "@ethersproject/abstract-signer": "npm:^5.8.0" + "@ethersproject/address": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/hdnode": "npm:^5.8.0" + "@ethersproject/keccak256": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/pbkdf2": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + "@ethersproject/random": "npm:^5.8.0" + "@ethersproject/strings": "npm:^5.8.0" + "@ethersproject/transactions": "npm:^5.8.0" + aes-js: "npm:3.0.0" + scrypt-js: "npm:3.0.1" + checksum: 10c0/6c5cac87bdfac9ac47bf6ac25168a85865dc02e398e97f83820568c568a8cb27cf13a3a5d482f71a2534c7d704a3faa46023bb7ebe8737872b376bec1b66c67b languageName: node linkType: hard @@ -671,7 +763,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/keccak256@npm:^5.8.0": +"@ethersproject/keccak256@npm:5.8.0, @ethersproject/keccak256@npm:^5.8.0": version: 5.8.0 resolution: "@ethersproject/keccak256@npm:5.8.0" dependencies: @@ -681,10 +773,13 @@ __metadata: languageName: node linkType: hard -"@ethersproject/logger@npm:5.5.0, @ethersproject/logger@npm:^5.5.0": +"@ethersproject/keccak256@npm:^5.5.0": version: 5.5.0 - resolution: "@ethersproject/logger@npm:5.5.0" - checksum: 10c0/e8f83396ee505f8556dfc04aad252ddab4cdc40636cb186e420977e498864312d9b32f336843ab666b30730893bd972b57658518eefacc425ca469adaa8f385e + resolution: "@ethersproject/keccak256@npm:5.5.0" + dependencies: + "@ethersproject/bytes": "npm:^5.5.0" + js-sha3: "npm:0.8.0" + checksum: 10c0/e88d9db6f84227dc8216677fc692a10289c383bf63d207da7ad8beb0d8b112650dc3fbacadb6cc864304d9fe5243235bc6a49de6a37321ab05793717cedcaaac languageName: node linkType: hard @@ -695,26 +790,17 @@ __metadata: languageName: node linkType: hard -"@ethersproject/logger@npm:^5.6.0": - version: 5.6.0 - resolution: "@ethersproject/logger@npm:5.6.0" - checksum: 10c0/f4c2610cf25d833cc1bc0a4ce99227c30508f15c8acb423e8a15f12ac25e37f9f86779485e6f79a887b24df831bdbee949249eb5feb75c6b45ca761161739516 - languageName: node - linkType: hard - -"@ethersproject/logger@npm:^5.8.0": +"@ethersproject/logger@npm:5.8.0, @ethersproject/logger@npm:^5.8.0": version: 5.8.0 resolution: "@ethersproject/logger@npm:5.8.0" checksum: 10c0/7f39f33e8f254ee681d4778bb71ce3c5de248e1547666f85c43bfbc1c18996c49a31f969f056b66d23012f2420f2d39173107284bc41eb98d0482ace1d06403e languageName: node linkType: hard -"@ethersproject/networks@npm:5.5.2, @ethersproject/networks@npm:^5.5.0": - version: 5.5.2 - resolution: "@ethersproject/networks@npm:5.5.2" - dependencies: - "@ethersproject/logger": "npm:^5.5.0" - checksum: 10c0/46b65590f33f1221fbed1d3fc7fe3ff8e5d431e9137ec725dd505ededbcbecfd40f89f71dfdf754fc1168a3ee7c1e0adf2ff888ac500c5ab4fefa146d6a89d8d +"@ethersproject/logger@npm:^5.5.0": + version: 5.5.0 + resolution: "@ethersproject/logger@npm:5.5.0" + checksum: 10c0/e8f83396ee505f8556dfc04aad252ddab4cdc40636cb186e420977e498864312d9b32f336843ab666b30730893bd972b57658518eefacc425ca469adaa8f385e languageName: node linkType: hard @@ -727,7 +813,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/networks@npm:^5.8.0": +"@ethersproject/networks@npm:5.8.0, @ethersproject/networks@npm:^5.8.0": version: 5.8.0 resolution: "@ethersproject/networks@npm:5.8.0" dependencies: @@ -736,13 +822,12 @@ __metadata: languageName: node linkType: hard -"@ethersproject/pbkdf2@npm:5.5.0, @ethersproject/pbkdf2@npm:^5.5.0": - version: 5.5.0 - resolution: "@ethersproject/pbkdf2@npm:5.5.0" +"@ethersproject/networks@npm:^5.5.0": + version: 5.5.2 + resolution: "@ethersproject/networks@npm:5.5.2" dependencies: - "@ethersproject/bytes": "npm:^5.5.0" - "@ethersproject/sha2": "npm:^5.5.0" - checksum: 10c0/ac761fa8286463dafd4531be3de8f0f0421fc4b6fe008226e828b5a7c0369fe965fc6985539b0f1facaa80e332f25e52d4fc460ab082486d079255da9e570f7a + "@ethersproject/logger": "npm:^5.5.0" + checksum: 10c0/46b65590f33f1221fbed1d3fc7fe3ff8e5d431e9137ec725dd505ededbcbecfd40f89f71dfdf754fc1168a3ee7c1e0adf2ff888ac500c5ab4fefa146d6a89d8d languageName: node linkType: hard @@ -756,12 +841,13 @@ __metadata: languageName: node linkType: hard -"@ethersproject/properties@npm:5.5.0, @ethersproject/properties@npm:^5.5.0": - version: 5.5.0 - resolution: "@ethersproject/properties@npm:5.5.0" +"@ethersproject/pbkdf2@npm:5.8.0, @ethersproject/pbkdf2@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/pbkdf2@npm:5.8.0" dependencies: - "@ethersproject/logger": "npm:^5.5.0" - checksum: 10c0/bc5521fe27f648d90def99333f579852902d7ee0842401c9e76fe60c96f905b0e3f06aa0f2581befa61107ec9b5e36106dab7af293896a474389efef61bdd1be + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/sha2": "npm:^5.8.0" + checksum: 10c0/0397cf5370cfd568743c3e46ac431f1bd425239baa2691689f1430997d44d310cef5051ea9ee53fabe444f96aced8d6324b41da698e8d7021389dce36251e7e9 languageName: node linkType: hard @@ -774,7 +860,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/properties@npm:^5.8.0": +"@ethersproject/properties@npm:5.8.0, @ethersproject/properties@npm:^5.8.0": version: 5.8.0 resolution: "@ethersproject/properties@npm:5.8.0" dependencies: @@ -783,30 +869,12 @@ __metadata: languageName: node linkType: hard -"@ethersproject/providers@npm:5.5.2": - version: 5.5.2 - resolution: "@ethersproject/providers@npm:5.5.2" +"@ethersproject/properties@npm:^5.5.0": + version: 5.5.0 + resolution: "@ethersproject/properties@npm:5.5.0" dependencies: - "@ethersproject/abstract-provider": "npm:^5.5.0" - "@ethersproject/abstract-signer": "npm:^5.5.0" - "@ethersproject/address": "npm:^5.5.0" - "@ethersproject/basex": "npm:^5.5.0" - "@ethersproject/bignumber": "npm:^5.5.0" - "@ethersproject/bytes": "npm:^5.5.0" - "@ethersproject/constants": "npm:^5.5.0" - "@ethersproject/hash": "npm:^5.5.0" "@ethersproject/logger": "npm:^5.5.0" - "@ethersproject/networks": "npm:^5.5.0" - "@ethersproject/properties": "npm:^5.5.0" - "@ethersproject/random": "npm:^5.5.0" - "@ethersproject/rlp": "npm:^5.5.0" - "@ethersproject/sha2": "npm:^5.5.0" - "@ethersproject/strings": "npm:^5.5.0" - "@ethersproject/transactions": "npm:^5.5.0" - "@ethersproject/web": "npm:^5.5.0" - bech32: "npm:1.1.4" - ws: "npm:7.4.6" - checksum: 10c0/a65b0d1a6e2a85c1ce4f07bea6ee7d7ce4d24c168a8a49cd115ead6df13d4f08a5d637612c9475a43a9e31cb8861f699a8221f9dc05077b1c040368d3c1cf7ef + checksum: 10c0/bc5521fe27f648d90def99333f579852902d7ee0842401c9e76fe60c96f905b0e3f06aa0f2581befa61107ec9b5e36106dab7af293896a474389efef61bdd1be languageName: node linkType: hard @@ -838,13 +906,31 @@ __metadata: languageName: node linkType: hard -"@ethersproject/random@npm:5.5.1, @ethersproject/random@npm:^5.5.0": - version: 5.5.1 - resolution: "@ethersproject/random@npm:5.5.1" +"@ethersproject/providers@npm:5.8.0, @ethersproject/providers@npm:^5.7.2": + version: 5.8.0 + resolution: "@ethersproject/providers@npm:5.8.0" dependencies: - "@ethersproject/bytes": "npm:^5.5.0" - "@ethersproject/logger": "npm:^5.5.0" - checksum: 10c0/241f7b60b6983a17b698f8f9a67bbcac98b1f6eed8ea1f96577279a6ecc5dc457f41d1c8e8d2f534bade3e4bfbed7d0d8b89be1b0b01a16a4584abbd58cb55cc + "@ethersproject/abstract-provider": "npm:^5.8.0" + "@ethersproject/abstract-signer": "npm:^5.8.0" + "@ethersproject/address": "npm:^5.8.0" + "@ethersproject/base64": "npm:^5.8.0" + "@ethersproject/basex": "npm:^5.8.0" + "@ethersproject/bignumber": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/constants": "npm:^5.8.0" + "@ethersproject/hash": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/networks": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + "@ethersproject/random": "npm:^5.8.0" + "@ethersproject/rlp": "npm:^5.8.0" + "@ethersproject/sha2": "npm:^5.8.0" + "@ethersproject/strings": "npm:^5.8.0" + "@ethersproject/transactions": "npm:^5.8.0" + "@ethersproject/web": "npm:^5.8.0" + bech32: "npm:1.1.4" + ws: "npm:8.18.0" + checksum: 10c0/893dba429443bbf0a3eadef850e772ad1c706cf17ae6ae48b73467a23b614a3f461e9004850e24439b5c73d30e9259bc983f0f90a911ba11af749e6384fd355a languageName: node linkType: hard @@ -858,13 +944,13 @@ __metadata: languageName: node linkType: hard -"@ethersproject/rlp@npm:5.5.0, @ethersproject/rlp@npm:^5.5.0": - version: 5.5.0 - resolution: "@ethersproject/rlp@npm:5.5.0" +"@ethersproject/random@npm:5.8.0, @ethersproject/random@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/random@npm:5.8.0" dependencies: - "@ethersproject/bytes": "npm:^5.5.0" - "@ethersproject/logger": "npm:^5.5.0" - checksum: 10c0/0e3a3297843531aa572ce5eae6ec9ef0c9b3aecc4829d970f370e6a1cda58b71a8340378618f0e4e9b52b830f99081b3b4ec02c3cdf5a50cec3bb2cf25745ece + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + checksum: 10c0/e44c010715668fc29383141ae16cd2ec00c34a434d47e23338e740b8c97372515d95d3b809b969eab2055c19e92b985ca591d326fbb71270c26333215f9925d1 languageName: node linkType: hard @@ -878,7 +964,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/rlp@npm:^5.8.0": +"@ethersproject/rlp@npm:5.8.0, @ethersproject/rlp@npm:^5.8.0": version: 5.8.0 resolution: "@ethersproject/rlp@npm:5.8.0" dependencies: @@ -888,14 +974,13 @@ __metadata: languageName: node linkType: hard -"@ethersproject/sha2@npm:5.5.0, @ethersproject/sha2@npm:^5.5.0": +"@ethersproject/rlp@npm:^5.5.0": version: 5.5.0 - resolution: "@ethersproject/sha2@npm:5.5.0" + resolution: "@ethersproject/rlp@npm:5.5.0" dependencies: "@ethersproject/bytes": "npm:^5.5.0" "@ethersproject/logger": "npm:^5.5.0" - hash.js: "npm:1.1.7" - checksum: 10c0/fef85ce64f285773580d5a9903557d6b356109745267314b8b94f0976dbce48295f56668a01b175adcaaa0820f9567e4fce56febd1f93539619214183069d48e + checksum: 10c0/0e3a3297843531aa572ce5eae6ec9ef0c9b3aecc4829d970f370e6a1cda58b71a8340378618f0e4e9b52b830f99081b3b4ec02c3cdf5a50cec3bb2cf25745ece languageName: node linkType: hard @@ -910,17 +995,14 @@ __metadata: languageName: node linkType: hard -"@ethersproject/signing-key@npm:5.5.0, @ethersproject/signing-key@npm:^5.5.0": - version: 5.5.0 - resolution: "@ethersproject/signing-key@npm:5.5.0" +"@ethersproject/sha2@npm:5.8.0, @ethersproject/sha2@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/sha2@npm:5.8.0" dependencies: - "@ethersproject/bytes": "npm:^5.5.0" - "@ethersproject/logger": "npm:^5.5.0" - "@ethersproject/properties": "npm:^5.5.0" - bn.js: "npm:^4.11.9" - elliptic: "npm:6.5.4" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" hash.js: "npm:1.1.7" - checksum: 10c0/ab99a8477780bb92183cbd8b591668c7a58c15db3cee85ea522e081dfaf379a009995a6df390586bb9bf6d41b5c96d320e898b5c326c0db2b06bc823efb3fe5e + checksum: 10c0/eab941907b7d40ee8436acaaedee32306ed4de2cb9ab37543bc89b1dd2a78f28c8da21efd848525fa1b04a78575be426cfca28f5392f4d28ce6c84e7c26a9421 languageName: node linkType: hard @@ -938,7 +1020,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/signing-key@npm:^5.8.0": +"@ethersproject/signing-key@npm:5.8.0, @ethersproject/signing-key@npm:^5.8.0": version: 5.8.0 resolution: "@ethersproject/signing-key@npm:5.8.0" dependencies: @@ -952,17 +1034,17 @@ __metadata: languageName: node linkType: hard -"@ethersproject/solidity@npm:5.5.0": +"@ethersproject/signing-key@npm:^5.5.0": version: 5.5.0 - resolution: "@ethersproject/solidity@npm:5.5.0" + resolution: "@ethersproject/signing-key@npm:5.5.0" dependencies: - "@ethersproject/bignumber": "npm:^5.5.0" "@ethersproject/bytes": "npm:^5.5.0" - "@ethersproject/keccak256": "npm:^5.5.0" "@ethersproject/logger": "npm:^5.5.0" - "@ethersproject/sha2": "npm:^5.5.0" - "@ethersproject/strings": "npm:^5.5.0" - checksum: 10c0/1953cb73f2f7fb1f20165ad501dfaac2c65b921ae32c5b1acd3de7ff6d6236eca4ba22ec1db67392d22dc5d90680d0a18c12c9fcea33c7c67a0d5f5a40d4ab02 + "@ethersproject/properties": "npm:^5.5.0" + bn.js: "npm:^4.11.9" + elliptic: "npm:6.5.4" + hash.js: "npm:1.1.7" + checksum: 10c0/ab99a8477780bb92183cbd8b591668c7a58c15db3cee85ea522e081dfaf379a009995a6df390586bb9bf6d41b5c96d320e898b5c326c0db2b06bc823efb3fe5e languageName: node linkType: hard @@ -980,14 +1062,17 @@ __metadata: languageName: node linkType: hard -"@ethersproject/strings@npm:5.5.0, @ethersproject/strings@npm:^5.5.0": - version: 5.5.0 - resolution: "@ethersproject/strings@npm:5.5.0" +"@ethersproject/solidity@npm:5.8.0, @ethersproject/solidity@npm:^5.7.0": + version: 5.8.0 + resolution: "@ethersproject/solidity@npm:5.8.0" dependencies: - "@ethersproject/bytes": "npm:^5.5.0" - "@ethersproject/constants": "npm:^5.5.0" - "@ethersproject/logger": "npm:^5.5.0" - checksum: 10c0/b1893dbfaeff931ca6193b06e58a4929b527922154372c07877340ed744b3dce2cc529efdaa01e59a98fc2a8703ea17aacbb4f9581df284fdf0f8a30eb99cb32 + "@ethersproject/bignumber": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/keccak256": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/sha2": "npm:^5.8.0" + "@ethersproject/strings": "npm:^5.8.0" + checksum: 10c0/5b5e0531bcec1d919cfbd261694694c8999ca5c379c1bb276ec779b896d299bb5db8ed7aa5652eb2c7605fe66455832b56ef123dec07f6ddef44231a7aa6fe6c languageName: node linkType: hard @@ -1002,7 +1087,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/strings@npm:^5.8.0": +"@ethersproject/strings@npm:5.8.0, @ethersproject/strings@npm:^5.8.0": version: 5.8.0 resolution: "@ethersproject/strings@npm:5.8.0" dependencies: @@ -1013,20 +1098,14 @@ __metadata: languageName: node linkType: hard -"@ethersproject/transactions@npm:5.5.0, @ethersproject/transactions@npm:^5.5.0": +"@ethersproject/strings@npm:^5.5.0": version: 5.5.0 - resolution: "@ethersproject/transactions@npm:5.5.0" + resolution: "@ethersproject/strings@npm:5.5.0" dependencies: - "@ethersproject/address": "npm:^5.5.0" - "@ethersproject/bignumber": "npm:^5.5.0" "@ethersproject/bytes": "npm:^5.5.0" "@ethersproject/constants": "npm:^5.5.0" - "@ethersproject/keccak256": "npm:^5.5.0" "@ethersproject/logger": "npm:^5.5.0" - "@ethersproject/properties": "npm:^5.5.0" - "@ethersproject/rlp": "npm:^5.5.0" - "@ethersproject/signing-key": "npm:^5.5.0" - checksum: 10c0/7dc61ad8bc8e7542b7034d37ee0b896b192a8610084111eaa70eb495c3d3a4e282407a568fcf40baae1cc9db87bb7345bfd2c15512ae7ac9036b8227525f02e1 + checksum: 10c0/b1893dbfaeff931ca6193b06e58a4929b527922154372c07877340ed744b3dce2cc529efdaa01e59a98fc2a8703ea17aacbb4f9581df284fdf0f8a30eb99cb32 languageName: node linkType: hard @@ -1047,7 +1126,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/transactions@npm:^5.8.0": +"@ethersproject/transactions@npm:5.8.0, @ethersproject/transactions@npm:^5.8.0": version: 5.8.0 resolution: "@ethersproject/transactions@npm:5.8.0" dependencies: @@ -1064,14 +1143,20 @@ __metadata: languageName: node linkType: hard -"@ethersproject/units@npm:5.5.0": +"@ethersproject/transactions@npm:^5.5.0": version: 5.5.0 - resolution: "@ethersproject/units@npm:5.5.0" + resolution: "@ethersproject/transactions@npm:5.5.0" dependencies: + "@ethersproject/address": "npm:^5.5.0" "@ethersproject/bignumber": "npm:^5.5.0" + "@ethersproject/bytes": "npm:^5.5.0" "@ethersproject/constants": "npm:^5.5.0" + "@ethersproject/keccak256": "npm:^5.5.0" "@ethersproject/logger": "npm:^5.5.0" - checksum: 10c0/dc24228ef7c3336087494ceb3fc0b274a5c57fba8e39e6f960c085e1661908d68670790c15953c440ebf590850045572578a4bec947549d77b0134280aab8e00 + "@ethersproject/properties": "npm:^5.5.0" + "@ethersproject/rlp": "npm:^5.5.0" + "@ethersproject/signing-key": "npm:^5.5.0" + checksum: 10c0/7dc61ad8bc8e7542b7034d37ee0b896b192a8610084111eaa70eb495c3d3a4e282407a568fcf40baae1cc9db87bb7345bfd2c15512ae7ac9036b8227525f02e1 languageName: node linkType: hard @@ -1086,7 +1171,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/units@npm:^5.7.0": +"@ethersproject/units@npm:5.8.0, @ethersproject/units@npm:^5.7.0": version: 5.8.0 resolution: "@ethersproject/units@npm:5.8.0" dependencies: @@ -1097,29 +1182,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/wallet@npm:5.5.0": - version: 5.5.0 - resolution: "@ethersproject/wallet@npm:5.5.0" - dependencies: - "@ethersproject/abstract-provider": "npm:^5.5.0" - "@ethersproject/abstract-signer": "npm:^5.5.0" - "@ethersproject/address": "npm:^5.5.0" - "@ethersproject/bignumber": "npm:^5.5.0" - "@ethersproject/bytes": "npm:^5.5.0" - "@ethersproject/hash": "npm:^5.5.0" - "@ethersproject/hdnode": "npm:^5.5.0" - "@ethersproject/json-wallets": "npm:^5.5.0" - "@ethersproject/keccak256": "npm:^5.5.0" - "@ethersproject/logger": "npm:^5.5.0" - "@ethersproject/properties": "npm:^5.5.0" - "@ethersproject/random": "npm:^5.5.0" - "@ethersproject/signing-key": "npm:^5.5.0" - "@ethersproject/transactions": "npm:^5.5.0" - "@ethersproject/wordlists": "npm:^5.5.0" - checksum: 10c0/b824957e482b3df43a9b09d589157ee89bf8d2e7d40e74dc5dbc3b65f861c0d7d9b8ff44392b878a9cb6c8e91e494da7a4b189dade343f08dd5d21043010221a - languageName: node - linkType: hard - "@ethersproject/wallet@npm:5.7.0": version: 5.7.0 resolution: "@ethersproject/wallet@npm:5.7.0" @@ -1143,16 +1205,26 @@ __metadata: languageName: node linkType: hard -"@ethersproject/web@npm:5.5.1, @ethersproject/web@npm:^5.5.0": - version: 5.5.1 - resolution: "@ethersproject/web@npm:5.5.1" +"@ethersproject/wallet@npm:5.8.0, @ethersproject/wallet@npm:^5.7.0": + version: 5.8.0 + resolution: "@ethersproject/wallet@npm:5.8.0" dependencies: - "@ethersproject/base64": "npm:^5.5.0" - "@ethersproject/bytes": "npm:^5.5.0" - "@ethersproject/logger": "npm:^5.5.0" - "@ethersproject/properties": "npm:^5.5.0" - "@ethersproject/strings": "npm:^5.5.0" - checksum: 10c0/6933c952a1638fdff949babc37c7eb47c1fcb2245ae2accb67f4fb03e5b00ee099c5f80bd2d1dc93f2b4fb9f3e2d3f3b4d7a8ac4eb46d3adbf1081611968bb52 + "@ethersproject/abstract-provider": "npm:^5.8.0" + "@ethersproject/abstract-signer": "npm:^5.8.0" + "@ethersproject/address": "npm:^5.8.0" + "@ethersproject/bignumber": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/hash": "npm:^5.8.0" + "@ethersproject/hdnode": "npm:^5.8.0" + "@ethersproject/json-wallets": "npm:^5.8.0" + "@ethersproject/keccak256": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + "@ethersproject/random": "npm:^5.8.0" + "@ethersproject/signing-key": "npm:^5.8.0" + "@ethersproject/transactions": "npm:^5.8.0" + "@ethersproject/wordlists": "npm:^5.8.0" + checksum: 10c0/6da450872dda3d9008bad3ccf8467816a63429241e51c66627647123c0fe5625494c4f6c306e098eb8419cc5702ac017d41f5161af5ff670a41fe5d199883c09 languageName: node linkType: hard @@ -1169,7 +1241,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/web@npm:^5.8.0": +"@ethersproject/web@npm:5.8.0, @ethersproject/web@npm:^5.8.0": version: 5.8.0 resolution: "@ethersproject/web@npm:5.8.0" dependencies: @@ -1182,16 +1254,16 @@ __metadata: languageName: node linkType: hard -"@ethersproject/wordlists@npm:5.5.0, @ethersproject/wordlists@npm:^5.5.0": - version: 5.5.0 - resolution: "@ethersproject/wordlists@npm:5.5.0" +"@ethersproject/web@npm:^5.5.0": + version: 5.5.1 + resolution: "@ethersproject/web@npm:5.5.1" dependencies: + "@ethersproject/base64": "npm:^5.5.0" "@ethersproject/bytes": "npm:^5.5.0" - "@ethersproject/hash": "npm:^5.5.0" "@ethersproject/logger": "npm:^5.5.0" "@ethersproject/properties": "npm:^5.5.0" "@ethersproject/strings": "npm:^5.5.0" - checksum: 10c0/6f690525f787d177354e2ac49c607ea885c688505aba6666893cfa75ece216904e91581c8b88f48991b9662976fd130fc37f273067e89a29d4917603d91518cc + checksum: 10c0/6933c952a1638fdff949babc37c7eb47c1fcb2245ae2accb67f4fb03e5b00ee099c5f80bd2d1dc93f2b4fb9f3e2d3f3b4d7a8ac4eb46d3adbf1081611968bb52 languageName: node linkType: hard @@ -1208,6 +1280,19 @@ __metadata: languageName: node linkType: hard +"@ethersproject/wordlists@npm:5.8.0, @ethersproject/wordlists@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/wordlists@npm:5.8.0" + dependencies: + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/hash": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + "@ethersproject/strings": "npm:^5.8.0" + checksum: 10c0/e230a2ba075006bc3a2538e096003e43ef9ba453317f37a4d99638720487ec447c1fa61a592c80483f8a8ad6466511cf4cf5c49cf84464a1679999171ce311f4 + languageName: node + linkType: hard + "@gar/promise-retry@npm:^1.0.0": version: 1.0.3 resolution: "@gar/promise-retry@npm:1.0.3" @@ -1215,21 +1300,51 @@ __metadata: languageName: node linkType: hard -"@humanwhocodes/config-array@npm:^0.5.0": - version: 0.5.0 - resolution: "@humanwhocodes/config-array@npm:0.5.0" +"@humanfs/core@npm:^0.19.2": + version: 0.19.2 + resolution: "@humanfs/core@npm:0.19.2" dependencies: - "@humanwhocodes/object-schema": "npm:^1.2.0" - debug: "npm:^4.1.1" - minimatch: "npm:^3.0.4" - checksum: 10c0/217fac9e03492361825a2bf761d4bb7ec6d10002a10f7314142245eb13ac9d123523d24d5619c3c4159af215c7b3e583ed386108e227014bef4efbf9caca8ccc + "@humanfs/types": "npm:^0.15.0" + checksum: 10c0/d0a1d52d7b30c27d49475a53072d1510b81c5803e44b342fb8faf3887f1aa27593a1e6dc76a45268e7892d3f4e198146659281f6b6d55eacf3fd5a38bac30c5c languageName: node linkType: hard -"@humanwhocodes/object-schema@npm:^1.2.0": - version: 1.2.1 - resolution: "@humanwhocodes/object-schema@npm:1.2.1" - checksum: 10c0/c3c35fdb70c04a569278351c75553e293ae339684ed75895edc79facc7276e351115786946658d78133130c0cca80e57e2203bc07f8fa7fe7980300e8deef7db +"@humanfs/node@npm:^0.16.6": + version: 0.16.8 + resolution: "@humanfs/node@npm:0.16.8" + dependencies: + "@humanfs/core": "npm:^0.19.2" + "@humanfs/types": "npm:^0.15.0" + "@humanwhocodes/retry": "npm:^0.4.0" + checksum: 10c0/56140579db811af4e160b195d45d0f29acf644d192c93fe24c9e594ebf06f19dfc157494a07c84540b8a071c0e4b37209c2362765d31734f4d0be869c2422e25 + languageName: node + linkType: hard + +"@humanfs/types@npm:^0.15.0": + version: 0.15.0 + resolution: "@humanfs/types@npm:0.15.0" + checksum: 10c0/fc26b9a024b0e55f7eaf64036df94345bf5d36d6a41ef80ef38e78f1f7430ce26cf435af736adae58913baae18eac3f38c18739054a3d379102015978eae862e + languageName: node + linkType: hard + +"@humanwhocodes/module-importer@npm:^1.0.1": + version: 1.0.1 + resolution: "@humanwhocodes/module-importer@npm:1.0.1" + checksum: 10c0/909b69c3b86d482c26b3359db16e46a32e0fb30bd306a3c176b8313b9e7313dba0f37f519de6aa8b0a1921349e505f259d19475e123182416a506d7f87e7f529 + languageName: node + linkType: hard + +"@humanwhocodes/momoa@npm:^2.0.4": + version: 2.0.4 + resolution: "@humanwhocodes/momoa@npm:2.0.4" + checksum: 10c0/ff081fb5239eb23ae40c59bd51e8128d34b043be3b7c2adb2522cdff51b01ec3129e57d5a24a1eb3a082159d5b41fddfbaffc4cf46cae4fe11a51393f60424fd + languageName: node + linkType: hard + +"@humanwhocodes/retry@npm:^0.4.0, @humanwhocodes/retry@npm:^0.4.2": + version: 0.4.3 + resolution: "@humanwhocodes/retry@npm:0.4.3" + checksum: 10c0/3775bb30087d4440b3f7406d5a057777d90e4b9f435af488a4923ef249e93615fb78565a85f173a186a076c7706a81d0d57d563a2624e4de2c5c9c66c486ce42 languageName: node linkType: hard @@ -1256,106 +1371,147 @@ __metadata: languageName: node linkType: hard +"@jridgewell/resolve-uri@npm:^3.0.3": + version: 3.1.2 + resolution: "@jridgewell/resolve-uri@npm:3.1.2" + checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e + languageName: node + linkType: hard + +"@jridgewell/sourcemap-codec@npm:^1.4.10": + version: 1.6.0 + resolution: "@jridgewell/sourcemap-codec@npm:1.6.0" + checksum: 10c0/b5be700e45a775f218589c3466c4ffea630582b4988657652da464e5ab8a7d18bf928ee4fd2363fb346ede4bea9c6ff0bae05a538358c4565ece6199531b5f72 + languageName: node + linkType: hard + +"@jridgewell/trace-mapping@npm:0.3.9": + version: 0.3.9 + resolution: "@jridgewell/trace-mapping@npm:0.3.9" + dependencies: + "@jridgewell/resolve-uri": "npm:^3.0.3" + "@jridgewell/sourcemap-codec": "npm:^1.4.10" + checksum: 10c0/fa425b606d7c7ee5bfa6a31a7b050dd5814b4082f318e0e4190f991902181b4330f43f4805db1dd4f2433fd0ed9cc7a7b9c2683f1deeab1df1b0a98b1e24055b + languageName: node + linkType: hard + "@keep-network/ecdsa@workspace:.": version: 0.0.0-use.local resolution: "@keep-network/ecdsa@workspace:." dependencies: - "@keep-network/hardhat-helpers": "npm:^0.6.0-pre.15" - "@keep-network/hardhat-local-networks-config": "npm:^0.1.0-pre.4" - "@keep-network/random-beacon": "npm:development" - "@keep-network/sortition-pools": "npm:^2.0.0-pre.16" - "@nomicfoundation/hardhat-chai-matchers": "npm:^1.0.6" + "@keep-network/hardhat-helpers": "patch:@keep-network/hardhat-helpers@npm%3A0.7.2#~/.yarn/patches/@keep-network-hardhat-helpers-npm-0.7.2-086cf3da54.patch" + "@keep-network/hardhat-local-networks-config": "github:threshold-network/hardhat-local-networks-config#6dff5bc8648127ca5d8696c321076bddb6d4142a" + "@nomicfoundation/hardhat-chai-matchers": "npm:^2.1.2" + "@nomicfoundation/hardhat-ethers": "npm:^3.1.3" + "@nomicfoundation/hardhat-network-helpers": "npm:^1.1.2" "@nomicfoundation/hardhat-verify": "npm:^2.1.3" - "@nomiclabs/hardhat-ethers": "npm:^2.0.6" "@openzeppelin/contracts": "npm:^4.9.6" "@openzeppelin/contracts-upgradeable": "npm:^4.9.6" - "@openzeppelin/hardhat-upgrades": "npm:^1.20.4" - "@tenderly/hardhat-tenderly": "npm:>=1.0.13 <1.2.0" - "@thesis-co/eslint-config": "https://codeload.github.com/thesis/eslint-config/tar.gz/778365bbebb6b056bf973d25c57b8b466d21cbcf" + "@openzeppelin/hardhat-upgrades": "patch:@openzeppelin/hardhat-upgrades@npm%3A2.5.1#~/.yarn/patches/@openzeppelin-hardhat-upgrades-npm-2.5.1-etherscan-v2.patch" + "@stylistic/eslint-plugin": "npm:^5.10.0" + "@tenderly/hardhat-tenderly": "npm:2.1.1" "@threshold-network/solidity-contracts": "npm:1.3.0-dev.14" - "@typechain/ethers-v5": "npm:^8.0.5" - "@typechain/hardhat": "npm:^4.0.0" - "@types/chai": "npm:^4.3.0" + "@typechain/ethers-v6": "patch:@typechain/ethers-v6@npm%3A0.5.1#~/.yarn/patches/@typechain-ethers-v6-npm-0.5.1-e825560376.patch" + "@typechain/hardhat": "npm:^9.1.0" + "@types/chai": "npm:^4.3.20" "@types/chai-as-promised": "npm:^7.1.5" - "@types/mocha": "npm:^9.1.0" - "@types/node": "npm:^17.0.10" + "@types/mocha": "npm:^10.0.10" + "@types/node": "npm:^24.13.3" chai: "npm:^4.3.4" chai-as-promised: "npm:^7.1.1" - eslint: "npm:^7.32.0" - ethers: "npm:^5.5.3" + commander: "npm:^14.0.3" + eslint: "npm:^10.10.0" + eslint-import-resolver-typescript: "npm:^4.4.5" + eslint-plugin-import-x: "npm:^4.17.1" + eslint-plugin-no-only-tests: "npm:^3.4.0" + ethers: "npm:^6.17.0" fs-extra: "npm:^11.2.0" + globals: "npm:^17.12.0" hardhat: "npm:2.29.0" hardhat-contract-sizer: "npm:^2.3.0" hardhat-dependency-compiler: "npm:^1.1.2" - hardhat-deploy: "npm:^0.11.11" + hardhat-deploy: "npm:^1.0.4" hardhat-gas-reporter: "npm:^2.3.0" - prettier: "npm:^2.5.1" - prettier-plugin-sh: "npm:^0.8.1" - prettier-plugin-solidity: "npm:^1.0.0-beta.19" - solhint: "npm:^3.3.6" - solhint-config-keep: "https://codeload.github.com/keep-network/solhint-config-keep/tar.gz/5e1751e58c0f1c507305ffc8c7f6c58047657ada" + prettier: "npm:^3.9.6" + prettier-plugin-sh: "npm:^0.19.0" + prettier-plugin-solidity: "npm:^2.4.1" + solhint: "npm:^6.2.4" solidity-docgen: "npm:^0.6.0-beta.35" ts-node: "npm:^10.4.0" - typechain: "npm:^6.1.0" - typescript: "npm:^4.5.4" + typechain: "npm:^8.3.2" + typescript: "npm:^6.0.3" + typescript-eslint: "npm:^8.70.0" languageName: unknown linkType: soft -"@keep-network/hardhat-helpers@npm:^0.6.0-pre.15": - version: 0.6.0-pre.15 - resolution: "@keep-network/hardhat-helpers@npm:0.6.0-pre.15" +"@keep-network/hardhat-helpers@npm:0.7.2": + version: 0.7.2 + resolution: "@keep-network/hardhat-helpers@npm:0.7.2" + peerDependencies: + "@nomicfoundation/hardhat-ethers": ^3.0.5 + "@nomicfoundation/hardhat-verify": ^2.0.3 + "@openzeppelin/hardhat-upgrades": ^3.0.2 + ethers: ^6.10.0 + hardhat: ^2.19.4 + hardhat-deploy: ^0.11.45 + checksum: 10c0/55949a24dd5425629cd914d17c60aaced658c84820f5eb6cfb27ab8e1e231afc17d3a360b03700ebde11c10013e7eee8fe3f45bc7866121c80ffbdaf1f6d9185 + languageName: node + linkType: hard + +"@keep-network/hardhat-helpers@patch:@keep-network/hardhat-helpers@npm%3A0.7.2#~/.yarn/patches/@keep-network-hardhat-helpers-npm-0.7.2-086cf3da54.patch": + version: 0.7.2 + resolution: "@keep-network/hardhat-helpers@patch:@keep-network/hardhat-helpers@npm%3A0.7.2#~/.yarn/patches/@keep-network-hardhat-helpers-npm-0.7.2-086cf3da54.patch::version=0.7.2&hash=b77b8f" peerDependencies: - "@nomiclabs/hardhat-ethers": ^2.1.0 - "@nomiclabs/hardhat-etherscan": ^3.1.0 - "@openzeppelin/hardhat-upgrades": ^1.20.0 - ethers: ^5.6.9 - hardhat: ^2.10.0 - hardhat-deploy: ^0.11.11 - checksum: 10c0/584803efa4aac6b81f8be9e24dab48ecd838adb33d8d54baeb4394ba92210d6cba40e12317604b25452fb4028cb2815194681469a526bea4a304749110854bf2 + "@nomicfoundation/hardhat-ethers": ^3.0.5 + "@nomicfoundation/hardhat-verify": ^2.0.3 + "@openzeppelin/hardhat-upgrades": ^3.0.2 + ethers: ^6.10.0 + hardhat: ^2.19.4 + hardhat-deploy: ^0.11.45 + checksum: 10c0/5705dad93a94d9f571853a325c7134bf2bddcb2fd9811e330e1744033449628175adc2b9e60c0987622b9a465b2744fa8f766ef7114ffee8370b920b4ad5d4c0 languageName: node linkType: hard -"@keep-network/hardhat-local-networks-config@npm:^0.1.0-pre.4": - version: 0.1.0-pre.4 - resolution: "@keep-network/hardhat-local-networks-config@npm:0.1.0-pre.4" +"@keep-network/hardhat-local-networks-config@github:threshold-network/hardhat-local-networks-config#6dff5bc8648127ca5d8696c321076bddb6d4142a": + version: 0.1.0-tlabs.0 + resolution: "@keep-network/hardhat-local-networks-config@https://github.com/threshold-network/hardhat-local-networks-config.git#commit=6dff5bc8648127ca5d8696c321076bddb6d4142a" dependencies: deepmerge: "npm:^4.2.2" untildify: "npm:^4.0.0" peerDependencies: hardhat: ^2.0.8 - checksum: 10c0/ef718645d44b320be3c09c6d394b2a320d2487b5a54e96b21cfa55cff6269aa2749d5921ee8b66ed014f70a0cb90cfe2b70e196a18d1baf77a3b29d4bdf209cc + checksum: 10c0/c6fe0ab5ded18f1275d3e4f0c3a9b30cc68450354faff40e7c78bbaf329486a24fb80f30dc9bf88017afb7a627fc57ef8faf909160454ab40149785b190dba09 languageName: node linkType: hard -"@keep-network/keep-core@npm:>1.8.1-dev <1.8.1-goerli": - version: 1.8.1-dev.0 - resolution: "@keep-network/keep-core@npm:1.8.1-dev.0" +"@keyv/bigmap@npm:^1.3.1": + version: 1.3.1 + resolution: "@keyv/bigmap@npm:1.3.1" dependencies: - "@openzeppelin/upgrades": "npm:^2.7.2" - openzeppelin-solidity: "npm:2.4.0" - checksum: 10c0/e6ee78a5c57b86017080615d80619b710770ab4c12f20a36075d577aae41c4ee7245eea07516583cb30514fedf0001ccbc437c886bc95271c350b21b149e1649 + hashery: "npm:^1.4.0" + hookified: "npm:^1.15.0" + peerDependencies: + keyv: ^5.6.0 + checksum: 10c0/acc6a4a5edf462ce23e95672ab4bfaf7cd1941dff6bf3a2f671ce467961ace1fac9d3eb75a9ed9a8e92012e00a7d8b16ad1677bc539a52c3ad0cec31473e2349 languageName: node linkType: hard -"@keep-network/random-beacon@npm:development": - version: 2.1.0-dev.18 - resolution: "@keep-network/random-beacon@npm:2.1.0-dev.18" - dependencies: - "@keep-network/sortition-pools": "npm:^2.0.0-pre.16" - "@openzeppelin/contracts": "npm:4.7.3" - "@thesis/solidity-contracts": "github:thesis/solidity-contracts#4985bcf" - "@threshold-network/solidity-contracts": "npm:1.3.0-dev.11" - checksum: 10c0/6f259e1c55d48be8d410dce4c37aac4517881a70ccb6fdcc35f2805637578bda38d6bc85606ff6325abe6ef0610c42ab57f5ed0dd773ed83aa06cd1e500d1232 +"@keyv/serialize@npm:^1.1.1": + version: 1.1.1 + resolution: "@keyv/serialize@npm:1.1.1" + checksum: 10c0/b0008cae4a54400c3abf587b8cc2474c6f528ee58969ce6cf9cb07a04006f80c73c85971d6be6544408318a2bc40108236a19a82aea0a6de95aae49533317374 languageName: node linkType: hard -"@keep-network/sortition-pools@npm:^2.0.0-pre.16": - version: 2.0.0 - resolution: "@keep-network/sortition-pools@npm:2.0.0" +"@napi-rs/wasm-runtime@npm:^1.1.4": + version: 1.2.3 + resolution: "@napi-rs/wasm-runtime@npm:1.2.3" dependencies: - "@openzeppelin/contracts": "npm:^4.3.2" - "@thesis/solidity-contracts": "github:thesis/solidity-contracts#4985bcf" - checksum: 10c0/976b32eda6ebd1c1ac05be818b9229623a47c4b788210851db4cc22539477082838b70d46d7010e35157ddd16b7177307013b0fece89a0b5e17303ab0bd7d9d4 + "@tybys/wasm-util": "npm:^0.10.3" + peerDependencies: + "@emnapi/core": ^1.7.1 || ^2.0.0-alpha.4 + "@emnapi/runtime": ^1.7.1 || ^2.0.0-alpha.4 + checksum: 10c0/6da0a4bf9df79e9abfb3e3d462f6a5d42889be39426040038c9dd5925865585d7dbd06dd439c2ffc20f49ef2751412da5bd748cfb3c5b049142d72c0550f6f79 languageName: node linkType: hard @@ -1366,6 +1522,15 @@ __metadata: languageName: node linkType: hard +"@noble/curves@npm:1.2.0": + version: 1.2.0 + resolution: "@noble/curves@npm:1.2.0" + dependencies: + "@noble/hashes": "npm:1.3.2" + checksum: 10c0/0bac7d1bbfb3c2286910b02598addd33243cb97c3f36f987ecc927a4be8d7d88e0fcb12b0f0ef8a044e7307d1844dd5c49bb724bfa0a79c8ec50ba60768c97f6 + languageName: node + linkType: hard + "@noble/curves@npm:1.4.2, @noble/curves@npm:~1.4.0": version: 1.4.2 resolution: "@noble/curves@npm:1.4.2" @@ -1409,6 +1574,13 @@ __metadata: languageName: node linkType: hard +"@noble/hashes@npm:1.3.2": + version: 1.3.2 + resolution: "@noble/hashes@npm:1.3.2" + checksum: 10c0/2482cce3bce6a596626f94ca296e21378e7a5d4c09597cbc46e65ffacc3d64c8df73111f2265444e36a3168208628258bbbaccba2ef24f65f58b2417638a20e7 + languageName: node + linkType: hard + "@noble/hashes@npm:1.4.0, @noble/hashes@npm:~1.4.0": version: 1.4.0 resolution: "@noble/hashes@npm:1.4.0" @@ -1444,33 +1616,6 @@ __metadata: languageName: node linkType: hard -"@nodelib/fs.scandir@npm:2.1.5": - version: 2.1.5 - resolution: "@nodelib/fs.scandir@npm:2.1.5" - dependencies: - "@nodelib/fs.stat": "npm:2.0.5" - run-parallel: "npm:^1.1.9" - checksum: 10c0/732c3b6d1b1e967440e65f284bd06e5821fedf10a1bea9ed2bb75956ea1f30e08c44d3def9d6a230666574edbaf136f8cfd319c14fd1f87c66e6a44449afb2eb - languageName: node - linkType: hard - -"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2": - version: 2.0.5 - resolution: "@nodelib/fs.stat@npm:2.0.5" - checksum: 10c0/88dafe5e3e29a388b07264680dc996c17f4bda48d163a9d4f5c1112979f0ce8ec72aa7116122c350b4e7976bc5566dc3ddb579be1ceaacc727872eb4ed93926d - languageName: node - linkType: hard - -"@nodelib/fs.walk@npm:^1.2.3": - version: 1.2.8 - resolution: "@nodelib/fs.walk@npm:1.2.8" - dependencies: - "@nodelib/fs.scandir": "npm:2.1.5" - fastq: "npm:^1.6.0" - checksum: 10c0/db9de047c3bb9b51f9335a7bb46f4fcfb6829fb628318c12115fbaf7d369bfce71c15b103d1fc3b464812d936220ee9bc1c8f762d032c9f6be9acc99249095b1 - languageName: node - linkType: hard - "@nomicfoundation/edr-darwin-arm64@npm:0.12.0-next.23": version: 0.12.0-next.23 resolution: "@nomicfoundation/edr-darwin-arm64@npm:0.12.0-next.23" @@ -1535,21 +1680,44 @@ __metadata: languageName: node linkType: hard -"@nomicfoundation/hardhat-chai-matchers@npm:^1.0.6": - version: 1.0.6 - resolution: "@nomicfoundation/hardhat-chai-matchers@npm:1.0.6" +"@nomicfoundation/hardhat-chai-matchers@npm:^2.1.2": + version: 2.1.2 + resolution: "@nomicfoundation/hardhat-chai-matchers@npm:2.1.2" dependencies: - "@ethersproject/abi": "npm:^5.1.2" "@types/chai-as-promised": "npm:^7.1.3" chai-as-promised: "npm:^7.1.1" deep-eql: "npm:^4.0.1" ordinal: "npm:^1.0.3" peerDependencies: - "@nomiclabs/hardhat-ethers": ^2.0.0 + "@nomicfoundation/hardhat-ethers": ^3.1.0 chai: ^4.2.0 - ethers: ^5.0.0 - hardhat: ^2.9.4 - checksum: 10c0/d5e0327aee476ddd1ff25ab6d0fb47af0ccf081a9ff072499dccba7656eea9911aab4bd7e19fe46e5dfb920d2690df3c64dbb324a83e15f8ec9dd13a56ebbe66 + ethers: ^6.14.0 + hardhat: ^2.26.0 + checksum: 10c0/ed51e9d5e20869fc50f13ee7c8ad65e9531a6222a8b19c1afe21c28d563c8d2361c2f6f36a0c8a7b4e9b6c9c8df9f1878d6512b27919e18ea4e71bf28249bf86 + languageName: node + linkType: hard + +"@nomicfoundation/hardhat-ethers@npm:^3.0.4, @nomicfoundation/hardhat-ethers@npm:^3.1.3": + version: 3.1.3 + resolution: "@nomicfoundation/hardhat-ethers@npm:3.1.3" + dependencies: + debug: "npm:^4.1.1" + lodash.isequal: "npm:^4.5.0" + peerDependencies: + ethers: ^6.14.0 + hardhat: ^2.28.0 + checksum: 10c0/77a20741634a4028324cf329cac28205eff4a318ab92b0f42af4e714ebaab97a760bdba551fec446f4cea171a8964a6a89d19f33105fb8c8538d779a8a975093 + languageName: node + linkType: hard + +"@nomicfoundation/hardhat-network-helpers@npm:^1.1.2": + version: 1.1.2 + resolution: "@nomicfoundation/hardhat-network-helpers@npm:1.1.2" + dependencies: + ethereumjs-util: "npm:^7.1.4" + peerDependencies: + hardhat: ^2.26.0 + checksum: 10c0/00fb7392bc0a0c3df635a52fe350ae5e5a71610f3718e11e6b17753f6723231c81def37a19933cd96174cbc5362c0168c8fa98ea73910d46dd9d4bbba0c7990f languageName: node linkType: hard @@ -1572,7 +1740,16 @@ __metadata: languageName: node linkType: hard -"@nomicfoundation/slang@npm:^0.18.3": +"@nomicfoundation/slang@npm:1.3.8": + version: 1.3.8 + resolution: "@nomicfoundation/slang@npm:1.3.8" + dependencies: + "@bytecodealliance/preview2-shim": "npm:^0.19.0" + checksum: 10c0/ec97aff9bc16bffcecddaca99e1c264e3b54138f148c72b41e033c17a269e62c6862ed05efee42a1f4f6bdda5726f0c804cdea56279630c26f529d35266c255d + languageName: node + linkType: hard + +"@nomicfoundation/slang@npm:^0.18.3": version: 0.18.3 resolution: "@nomicfoundation/slang@npm:0.18.3" dependencies: @@ -1660,16 +1837,6 @@ __metadata: languageName: node linkType: hard -"@nomiclabs/hardhat-ethers@npm:^2.0.6": - version: 2.0.6 - resolution: "@nomiclabs/hardhat-ethers@npm:2.0.6" - peerDependencies: - ethers: ^5.0.0 - hardhat: ^2.0.0 - checksum: 10c0/f8bad2d51f05bc65ebd0061e80a3a3e9f3731bdabde3881aa913c94868916c01c3bef4835a170538a56544cd361f7dc06bdf38e6c46ca20e29c854c0038da8d5 - languageName: node - linkType: hard - "@npmcli/agent@npm:^4.0.0": version: 4.0.0 resolution: "@npmcli/agent@npm:4.0.0" @@ -1713,13 +1880,6 @@ __metadata: languageName: node linkType: hard -"@openzeppelin/contracts@npm:4.7.3, @openzeppelin/contracts@npm:^4.3.2": - version: 4.7.3 - resolution: "@openzeppelin/contracts@npm:4.7.3" - checksum: 10c0/fa4091de95f664e82c3db318d9914412e062684c2b423198bc0d63ac9b4084e3a77ef31ff46488edef41573cf0451e3583ae69055a52e8c2f44bb2dab52b352b - languageName: node - linkType: hard - "@openzeppelin/contracts@npm:^4.1.0, @openzeppelin/contracts@npm:^4.9.6": version: 4.9.6 resolution: "@openzeppelin/contracts@npm:4.9.6" @@ -1734,7 +1894,20 @@ __metadata: languageName: node linkType: hard -"@openzeppelin/defender-base-client@npm:^1.46.0": +"@openzeppelin/defender-admin-client@npm:^1.52.0": + version: 1.54.6 + resolution: "@openzeppelin/defender-admin-client@npm:1.54.6" + dependencies: + "@openzeppelin/defender-base-client": "npm:1.54.6" + axios: "npm:^1.4.0" + ethers: "npm:^5.7.2" + lodash: "npm:^4.17.19" + node-fetch: "npm:^2.6.0" + checksum: 10c0/784d7d0eee87916546654f8265f0823401b18f34f0c168daa5c3c353000b5a8e595edc26a384a5f4052dedf2602947e58620442c6f1f46760bfb99a77a5ae69d + languageName: node + linkType: hard + +"@openzeppelin/defender-base-client@npm:1.54.6, @openzeppelin/defender-base-client@npm:^1.52.0": version: 1.54.6 resolution: "@openzeppelin/defender-base-client@npm:1.54.6" dependencies: @@ -1747,83 +1920,101 @@ __metadata: languageName: node linkType: hard -"@openzeppelin/hardhat-upgrades@npm:^1.20.4": - version: 1.28.0 - resolution: "@openzeppelin/hardhat-upgrades@npm:1.28.0" +"@openzeppelin/defender-sdk-base-client@npm:^1.15.2, @openzeppelin/defender-sdk-base-client@npm:^1.8.0": + version: 1.15.2 + resolution: "@openzeppelin/defender-sdk-base-client@npm:1.15.2" + dependencies: + amazon-cognito-identity-js: "npm:^6.3.6" + async-retry: "npm:^1.3.3" + checksum: 10c0/cb1f5a286564b7f4da0c6f4b21f032b7e09697c2e476c2cf3d957287bc9dc880d0f1c2a4b21d42bc8246a99ea117ce39cfff6fd18f20ca63ac3dc859a43b62a1 + languageName: node + linkType: hard + +"@openzeppelin/defender-sdk-deploy-client@npm:^1.8.0": + version: 1.15.2 + resolution: "@openzeppelin/defender-sdk-deploy-client@npm:1.15.2" + dependencies: + "@openzeppelin/defender-sdk-base-client": "npm:^1.15.2" + axios: "npm:^1.7.2" + lodash: "npm:^4.17.21" + checksum: 10c0/af3db2976d14bdeb7b24e109209a37fcd98ab14176ebd62f0543d0dff552fd9359b382e35c2698315e195c42f55b2bc52b2aea0f598a070ac0a24274a1ba93d9 + languageName: node + linkType: hard + +"@openzeppelin/hardhat-upgrades@npm:2.5.1": + version: 2.5.1 + resolution: "@openzeppelin/hardhat-upgrades@npm:2.5.1" dependencies: - "@openzeppelin/defender-base-client": "npm:^1.46.0" - "@openzeppelin/platform-deploy-client": "npm:^0.8.0" - "@openzeppelin/upgrades-core": "npm:^1.27.0" + "@openzeppelin/defender-admin-client": "npm:^1.52.0" + "@openzeppelin/defender-base-client": "npm:^1.52.0" + "@openzeppelin/defender-sdk-base-client": "npm:^1.8.0" + "@openzeppelin/defender-sdk-deploy-client": "npm:^1.8.0" + "@openzeppelin/upgrades-core": "npm:^1.31.2" chalk: "npm:^4.1.0" debug: "npm:^4.1.1" + ethereumjs-util: "npm:^7.1.5" proper-lockfile: "npm:^4.1.1" + undici: "npm:^5.14.0" peerDependencies: - "@nomiclabs/hardhat-ethers": ^2.0.0 - "@nomiclabs/hardhat-etherscan": ^3.1.0 - ethers: ^5.0.5 + "@nomicfoundation/hardhat-ethers": ^3.0.0 + "@nomicfoundation/hardhat-verify": ^1.1.0 + ethers: ^6.6.0 hardhat: ^2.0.2 peerDependenciesMeta: - "@nomiclabs/harhdat-etherscan": + "@nomicfoundation/hardhat-verify": optional: true bin: migrate-oz-cli-project: dist/scripts/migrate-oz-cli-project.js - checksum: 10c0/8cd6c52ab966aac09435e58c8d5a80747adbd34ffbe3808205c30d6851a7e4ef35272a36f8c837da4841b4643ac3df8ea1d982218f38b99144df16e68ada3b9f + checksum: 10c0/3c032048a2d58fd59a1287234c5d045e7b231afb6ed3d906f9d5751b93f29dd5f1cbfdd0898c62cc8397ca111a98b7fa032cc93929adbc2072d1ad8bfbcded72 languageName: node linkType: hard -"@openzeppelin/platform-deploy-client@npm:^0.8.0": - version: 0.8.0 - resolution: "@openzeppelin/platform-deploy-client@npm:0.8.0" +"@openzeppelin/hardhat-upgrades@patch:@openzeppelin/hardhat-upgrades@npm%3A2.5.1#~/.yarn/patches/@openzeppelin-hardhat-upgrades-npm-2.5.1-etherscan-v2.patch": + version: 2.5.1 + resolution: "@openzeppelin/hardhat-upgrades@patch:@openzeppelin/hardhat-upgrades@npm%3A2.5.1#~/.yarn/patches/@openzeppelin-hardhat-upgrades-npm-2.5.1-etherscan-v2.patch::version=2.5.1&hash=6d2f71" dependencies: - "@ethersproject/abi": "npm:^5.6.3" - "@openzeppelin/defender-base-client": "npm:^1.46.0" - axios: "npm:^0.21.2" - lodash: "npm:^4.17.19" - node-fetch: "npm:^2.6.0" - checksum: 10c0/7a85c19fd94b268386fdcef5951218467ea146e7047fd4e0536f8044138a7867c904358e681cd6a56bf1e0d1a82ffe7172df4b291b4278c54094925c8890d35a + "@openzeppelin/defender-admin-client": "npm:^1.52.0" + "@openzeppelin/defender-base-client": "npm:^1.52.0" + "@openzeppelin/defender-sdk-base-client": "npm:^1.8.0" + "@openzeppelin/defender-sdk-deploy-client": "npm:^1.8.0" + "@openzeppelin/upgrades-core": "npm:^1.31.2" + chalk: "npm:^4.1.0" + debug: "npm:^4.1.1" + ethereumjs-util: "npm:^7.1.5" + proper-lockfile: "npm:^4.1.1" + undici: "npm:^5.14.0" + peerDependencies: + "@nomicfoundation/hardhat-ethers": ^3.0.0 + "@nomicfoundation/hardhat-verify": ^1.1.0 + ethers: ^6.6.0 + hardhat: ^2.0.2 + peerDependenciesMeta: + "@nomicfoundation/hardhat-verify": + optional: true + bin: + migrate-oz-cli-project: dist/scripts/migrate-oz-cli-project.js + checksum: 10c0/8a15e1ed75c3833f501bca1b53baf56babc4d6055576e92d3b18752a92352dbe7a39c7836d49bff0ba786c7c2fc842773da70aee8a7765c7fed8dd2530295dd4 languageName: node linkType: hard -"@openzeppelin/upgrades-core@npm:^1.27.0": - version: 1.42.1 - resolution: "@openzeppelin/upgrades-core@npm:1.42.1" +"@openzeppelin/upgrades-core@npm:^1.31.2": + version: 1.46.0 + resolution: "@openzeppelin/upgrades-core@npm:1.46.0" dependencies: "@nomicfoundation/slang": "npm:^0.18.3" + bignumber.js: "npm:^9.1.2" cbor: "npm:^10.0.0" chalk: "npm:^4.1.0" compare-versions: "npm:^6.0.0" debug: "npm:^4.1.1" ethereumjs-util: "npm:^7.0.3" - minimatch: "npm:^9.0.5" + minimatch: "npm:^10.2.5" minimist: "npm:^1.2.7" proper-lockfile: "npm:^4.1.1" - solidity-ast: "npm:^0.4.51" + solidity-ast: "npm:^0.4.60" bin: openzeppelin-upgrades-core: dist/cli/cli.js - checksum: 10c0/e4586ff5edeaf7436ec0c0a58def5b69576753d3dbc345f227f5d44e0a737d2bf46de679ef3369b7bc377006decdf46e9645274e2fe5de4aa1c0cefc07abc841 - languageName: node - linkType: hard - -"@openzeppelin/upgrades@npm:^2.7.2": - version: 2.8.0 - resolution: "@openzeppelin/upgrades@npm:2.8.0" - dependencies: - "@types/cbor": "npm:^2.0.0" - axios: "npm:^0.18.0" - bignumber.js: "npm:^7.2.0" - cbor: "npm:^4.1.5" - chalk: "npm:^2.4.1" - ethers: "npm:^4.0.20" - glob: "npm:^7.1.3" - lodash: "npm:^4.17.15" - semver: "npm:^5.5.1" - spinnies: "npm:^0.4.2" - truffle-flattener: "npm:^1.4.0" - web3: "npm:1.2.2" - web3-eth: "npm:1.2.2" - web3-eth-contract: "npm:1.2.2" - web3-utils: "npm:1.2.2" - checksum: 10c0/ac28881ae6b216578a5e5794d90380421a9fa136a23e18def247dd8f4f2688370001d6314807b9924d417268d1dee45b54bf4eb980e1f7348a7553a093212004 + checksum: 10c0/11b938ef442cecb8441a8022f67b5fb3e87e84f521b8d33d2b1f94ef954382f8538e59afa58e23cd5ec29f39446ea67f428d30416b8a03671dc509aff87167e4 languageName: node linkType: hard @@ -1834,52 +2025,81 @@ __metadata: languageName: node linkType: hard -"@resolver-engine/core@npm:^0.2.1": - version: 0.2.1 - resolution: "@resolver-engine/core@npm:0.2.1" - dependencies: - debug: "npm:^3.1.0" - request: "npm:^2.85.0" - checksum: 10c0/fa2c219402d27e1ee336cab4fdad045ecd8b82be4b674965c07303dd2ce72ada3bb1bf277861866eae890a690455c53058b38798aed39ba11bc6f00f4feafd93 +"@pnpm/config.env-replace@npm:^1.1.0": + version: 1.1.0 + resolution: "@pnpm/config.env-replace@npm:1.1.0" + checksum: 10c0/4cfc4a5c49ab3d0c6a1f196cfd4146374768b0243d441c7de8fa7bd28eaab6290f514b98490472cc65dbd080d34369447b3e9302585e1d5c099befd7c8b5e55f languageName: node linkType: hard -"@resolver-engine/fs@npm:^0.2.1": - version: 0.2.1 - resolution: "@resolver-engine/fs@npm:0.2.1" +"@pnpm/network.ca-file@npm:^1.0.1": + version: 1.0.2 + resolution: "@pnpm/network.ca-file@npm:1.0.2" dependencies: - "@resolver-engine/core": "npm:^0.2.1" - debug: "npm:^3.1.0" - checksum: 10c0/5027b128f345ab6b578161bfb451c618784e887b5a42ba6b12a1d31701996efa9d540dfda36c5244662bfa8d0a40d7dc7814a21fe93ba24969db07c0220b3dae + graceful-fs: "npm:4.2.10" + checksum: 10c0/95f6e0e38d047aca3283550719155ce7304ac00d98911e4ab026daedaf640a63bd83e3d13e17c623fa41ac72f3801382ba21260bcce431c14fbbc06430ecb776 languageName: node linkType: hard -"@resolver-engine/imports-fs@npm:^0.2.2": - version: 0.2.2 - resolution: "@resolver-engine/imports-fs@npm:0.2.2" +"@pnpm/npm-conf@npm:^3.0.2": + version: 3.0.3 + resolution: "@pnpm/npm-conf@npm:3.0.3" dependencies: - "@resolver-engine/fs": "npm:^0.2.1" - "@resolver-engine/imports": "npm:^0.2.2" - debug: "npm:^3.1.0" - checksum: 10c0/d65d86cacfb59741e43ff67cedc401ba259b0708b519071caa70800307e066f94c4aad4eca15e7c14fdde986607aa2ecdcaf35f5892cec8417b86f665f1055d4 + "@pnpm/config.env-replace": "npm:^1.1.0" + "@pnpm/network.ca-file": "npm:^1.0.1" + config-chain: "npm:^1.1.11" + checksum: 10c0/74a276b4acf609edd60300afef3e5c632ecf9f3e9b9da486314edd0478964815f4a03e9c9b1e0cb1f38e2acfef07e5c2d3211527b8f97a0c44cbb040f2755e5c languageName: node linkType: hard -"@resolver-engine/imports@npm:^0.2.2": - version: 0.2.2 - resolution: "@resolver-engine/imports@npm:0.2.2" - dependencies: - "@resolver-engine/core": "npm:^0.2.1" - debug: "npm:^3.1.0" - hosted-git-info: "npm:^2.6.0" - checksum: 10c0/a829b3fa17620a545a46a5c1bf7d6cbd874292c856f56bb955806fd5fa663b3a62c37f259a375594657b24c5e5795d81e35a9ee0e6463fc6e6a1c4d6c8fffc82 +"@reteps/dockerfmt-darwin-arm64@npm:0.5.4": + version: 0.5.4 + resolution: "@reteps/dockerfmt-darwin-arm64@npm:0.5.4" + conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rtsao/scc@npm:^1.1.0": - version: 1.1.0 - resolution: "@rtsao/scc@npm:1.1.0" - checksum: 10c0/b5bcfb0d87f7d1c1c7c0f7693f53b07866ed9fec4c34a97a8c948fb9a7c0082e416ce4d3b60beb4f5e167cbe04cdeefbf6771320f3ede059b9ce91188c409a5b +"@reteps/dockerfmt-darwin-x64@npm:0.5.4": + version: 0.5.4 + resolution: "@reteps/dockerfmt-darwin-x64@npm:0.5.4" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@reteps/dockerfmt-linux-arm64@npm:0.5.4": + version: 0.5.4 + resolution: "@reteps/dockerfmt-linux-arm64@npm:0.5.4" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@reteps/dockerfmt-linux-x64@npm:0.5.4": + version: 0.5.4 + resolution: "@reteps/dockerfmt-linux-x64@npm:0.5.4" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@reteps/dockerfmt@npm:^0.5.4": + version: 0.5.4 + resolution: "@reteps/dockerfmt@npm:0.5.4" + dependencies: + "@reteps/dockerfmt-darwin-arm64": "npm:0.5.4" + "@reteps/dockerfmt-darwin-x64": "npm:0.5.4" + "@reteps/dockerfmt-linux-arm64": "npm:0.5.4" + "@reteps/dockerfmt-linux-x64": "npm:0.5.4" + dependenciesMeta: + "@reteps/dockerfmt-darwin-arm64": + optional: true + "@reteps/dockerfmt-darwin-x64": + optional: true + "@reteps/dockerfmt-linux-arm64": + optional: true + "@reteps/dockerfmt-linux-x64": + optional: true + bin: + dockerfmt: dist/launcher.js + checksum: 10c0/b6f3037042d258bd3b84d53f879cffb0286fe245f41da54508870866b9bf2c97bb1a2e15c6f29a610ed70ce43ffb1d6e7281002325cd9b01a08aeb3f391ba12a languageName: node linkType: hard @@ -2049,10 +2269,10 @@ __metadata: languageName: node linkType: hard -"@sindresorhus/is@npm:^0.14.0": - version: 0.14.0 - resolution: "@sindresorhus/is@npm:0.14.0" - checksum: 10c0/7247aa9314d4fc3df9b3f63d8b5b962a89c7600a5db1f268546882bfc4d31a975a899f5f42a09dd41a11e58636e6402f7c40f92df853aee417247bb11faee9a0 +"@sindresorhus/is@npm:^5.2.0": + version: 5.6.0 + resolution: "@sindresorhus/is@npm:5.6.0" + checksum: 10c0/66727344d0c92edde5760b5fd1f8092b717f2298a162a5f7f29e4953e001479927402d9d387e245fb9dc7d3b37c72e335e93ed5875edfc5203c53be8ecba1b52 languageName: node linkType: hard @@ -2065,86 +2285,56 @@ __metadata: languageName: node linkType: hard -"@solidity-parser/parser@npm:^0.13.2": - version: 0.13.2 - resolution: "@solidity-parser/parser@npm:0.13.2" - dependencies: - antlr4ts: "npm:^0.5.0-alpha.4" - checksum: 10c0/bb26201e7bd34bb52b6cae54dfd593a42b18ca1011530c30eb91d47cdebd7e6f6c1be6099a33f314a6cc5e5351e4c50c12c7335bc1f1078d7c6555ac8804d317 - languageName: node - linkType: hard - -"@solidity-parser/parser@npm:^0.14.0, @solidity-parser/parser@npm:^0.14.1": - version: 0.14.5 - resolution: "@solidity-parser/parser@npm:0.14.5" - dependencies: - antlr4ts: "npm:^0.5.0-alpha.4" - checksum: 10c0/d5c689d8925a18e1ceb2f6449a8263915b1676117856109b7793eda8f7dafc975b6ed0d0d73fc08257903cac383484e4c8f8cf47b069621e81ba368c4ea4cf6a - languageName: node - linkType: hard - -"@solidity-parser/parser@npm:^0.20.1": +"@solidity-parser/parser@npm:^0.20.1, @solidity-parser/parser@npm:^0.20.2": version: 0.20.2 resolution: "@solidity-parser/parser@npm:0.20.2" checksum: 10c0/23b0b7ed343a4fa55cb8621cf4fc81b0bdd791a4ee7e96ced7778db07de66d4e418db2c2dc1525b1f82fc0310ac829c78382327292b37e35cb30a19961fcb429 languageName: node linkType: hard -"@szmarczak/http-timer@npm:^1.1.2": - version: 1.1.2 - resolution: "@szmarczak/http-timer@npm:1.1.2" - dependencies: - defer-to-connect: "npm:^1.0.1" - checksum: 10c0/0594140e027ce4e98970c6d176457fcbff80900b1b3101ac0d08628ca6d21d70e0b94c6aaada94d4f76c1423fcc7195af83da145ce0fd556fc0595ca74a17b8b - languageName: node - linkType: hard - -"@tenderly/hardhat-tenderly@npm:>=1.0.13 <1.2.0": - version: 1.1.6 - resolution: "@tenderly/hardhat-tenderly@npm:1.1.6" +"@stylistic/eslint-plugin@npm:^5.10.0": + version: 5.10.0 + resolution: "@stylistic/eslint-plugin@npm:5.10.0" dependencies: - "@ethersproject/bignumber": "npm:^5.6.2" - "@nomiclabs/hardhat-ethers": "npm:^2.0.6" - axios: "npm:^0.21.1" - ethers: "npm:^5.6.8" - fs-extra: "npm:^9.0.1" - hardhat-deploy: "npm:^0.11.10" - js-yaml: "npm:^3.14.0" + "@eslint-community/eslint-utils": "npm:^4.9.1" + "@typescript-eslint/types": "npm:^8.56.0" + eslint-visitor-keys: "npm:^4.2.1" + espree: "npm:^10.4.0" + estraverse: "npm:^5.3.0" + picomatch: "npm:^4.0.3" peerDependencies: - hardhat: ^2.10.1 - checksum: 10c0/8a6768949270bbec727641920dd7e344160fed5ff93777f404117d22cad754ea6623ef5873d05721e98330108044c577046d166702f82f95bc70376b4492e3fa + eslint: ^9.0.0 || ^10.0.0 + checksum: 10c0/2cc6e592d5b2ab691290cc39ed377c0f6226667b367ffc6a0bf3a4bf6dd36b011d17c83f377600a48946f6bb037390b35a8b3c273b3c40d161c00b44512a129e languageName: node linkType: hard -"@thesis-co/eslint-config@https://codeload.github.com/thesis/eslint-config/tar.gz/778365bbebb6b056bf973d25c57b8b466d21cbcf": - version: 0.1.0 - resolution: "@thesis-co/eslint-config@https://codeload.github.com/thesis/eslint-config/tar.gz/778365bbebb6b056bf973d25c57b8b466d21cbcf" - dependencies: - "@thesis-co/prettier-config": "github:thesis/prettier-config" - "@typescript-eslint/eslint-plugin": "npm:^4.32.0" - "@typescript-eslint/parser": "npm:^4.32.0" - eslint-config-airbnb: "npm:^18.2.1" - eslint-config-airbnb-base: "npm:^14.2.1" - eslint-config-airbnb-typescript: "npm:^14.0.0" - eslint-config-prettier: "npm:^8.3.0" - eslint-plugin-import: "npm:^2.23.4" - eslint-plugin-jsx-a11y: "npm:^6.4.1" - eslint-plugin-prettier: "npm:^4.0.0" - eslint-plugin-react: "npm:^7.25.2" - eslint-plugin-react-hooks: "npm:^4.2.0" - peerDependencies: - eslint: ">=6.8.0" - eslint-plugin-import: ^2.18.2 - checksum: 10c0/3313cf7d0ad067b376bdb09d7243f1d7392e2b61e088318e68ee57beff5a0089da5512c995744f2183d67bd844bbe68ee2f14d989bdd47f660a351f4a3dcf429 +"@szmarczak/http-timer@npm:^5.0.1": + version: 5.0.1 + resolution: "@szmarczak/http-timer@npm:5.0.1" + dependencies: + defer-to-connect: "npm:^2.0.1" + checksum: 10c0/4629d2fbb2ea67c2e9dc03af235c0991c79ebdddcbc19aed5d5732fb29ce01c13331e9b1a491584b9069bd6ecde6581dcbf871f11b7eefdebbab34de6cf2197e languageName: node linkType: hard -"@thesis-co/prettier-config@github:thesis/prettier-config": - version: 0.0.2 - resolution: "@thesis-co/prettier-config@https://github.com/thesis/prettier-config.git#commit=daeaac564056a7885e4366ce12bfde6fd823fc90" +"@tenderly/hardhat-tenderly@npm:2.1.1": + version: 2.1.1 + resolution: "@tenderly/hardhat-tenderly@npm:2.1.1" + dependencies: + "@ethersproject/bignumber": "npm:^5.7.0" + "@nomicfoundation/hardhat-ethers": "npm:^3.0.4" + axios: "npm:^0.27.2" + ethers: "npm:^6.8.1" + fs-extra: "npm:^10.1.0" + hardhat-deploy: "npm:^0.11.43" + tenderly: "npm:^0.8.0" + ts-node: "npm:^10.9.1" + tslog: "npm:^4.3.1" + typescript: "npm:^5.2.2" peerDependencies: - prettier: ">=2.3.0 <4" - checksum: 10c0/26e284c92868e34bf657a638983a1d10b12145b05aa9a9fc7ebac283ccee43f6fb77abb5673a29a0b1fd6ea99eda335d040a0de4e1319f12168ed07dd4d2de7d + ethers: ^6.8.1 + hardhat: ^2.19.0 + checksum: 10c0/f51fdef7e3b857d5f7f6bc0f139f2b565641dc9f31805376245d65af815493a79cf60a6888f3a70f0d29c55eabed4fe972e7ab6ac138a13d4fb71046d60a671f languageName: node linkType: hard @@ -2157,28 +2347,25 @@ __metadata: languageName: node linkType: hard -"@threshold-network/solidity-contracts@npm:1.3.0-dev.11": - version: 1.3.0-dev.11 - resolution: "@threshold-network/solidity-contracts@npm:1.3.0-dev.11" +"@threshold-network/solidity-contracts@npm:1.3.0-dev.14": + version: 1.3.0-dev.14 + resolution: "@threshold-network/solidity-contracts@npm:1.3.0-dev.14" dependencies: - "@keep-network/keep-core": "npm:>1.8.1-dev <1.8.1-goerli" "@openzeppelin/contracts": "npm:~4.5.0" "@openzeppelin/contracts-upgradeable": "npm:~4.5.2" "@thesis/solidity-contracts": "github:thesis/solidity-contracts#4985bcf" - peerDependencies: - "@keep-network/keep-core": ">1.8.1-dev <1.8.1-goerli" - checksum: 10c0/12c37d4a546827b824eecaa63860d3f88eb0d099a1030d68a67ef3b3b47c469956fd1d15e5881727387a83e3a701a689312355531eb5b965daf832a1a3b47f3d + checksum: 10c0/8b4f942f92a3ed6e27665bd164e45b96c13d2d6f3422e8733d3b4a382fa02b14dbf79b9843f31289a079d1cbadfd557b4bd1f75e42b95d5861011412123f32d7 languageName: node linkType: hard -"@threshold-network/solidity-contracts@npm:1.3.0-dev.14": +"@threshold-network/solidity-contracts@patch:@threshold-network/solidity-contracts@npm%3A1.3.0-dev.14#./.yarn/patches/@threshold-network-solidity-contracts-npm-1.3.0-dev.14-ethers-v6.patch::locator=%40keep-network%2Fecdsa%40workspace%3A.": version: 1.3.0-dev.14 - resolution: "@threshold-network/solidity-contracts@npm:1.3.0-dev.14" + resolution: "@threshold-network/solidity-contracts@patch:@threshold-network/solidity-contracts@npm%3A1.3.0-dev.14#./.yarn/patches/@threshold-network-solidity-contracts-npm-1.3.0-dev.14-ethers-v6.patch::version=1.3.0-dev.14&hash=fd9350&locator=%40keep-network%2Fecdsa%40workspace%3A." dependencies: "@openzeppelin/contracts": "npm:~4.5.0" "@openzeppelin/contracts-upgradeable": "npm:~4.5.2" "@thesis/solidity-contracts": "github:thesis/solidity-contracts#4985bcf" - checksum: 10c0/8b4f942f92a3ed6e27665bd164e45b96c13d2d6f3422e8733d3b4a382fa02b14dbf79b9843f31289a079d1cbadfd557b4bd1f75e42b95d5861011412123f32d7 + checksum: 10c0/a6a7d2facb4e5ee695b55706dfe2c47eeca68bc3e73a3e76eaffa4df5e677360a33282101a25209aada1d83c1234839a013f93d784bb9a9c435b24f1d3cbf902 languageName: node linkType: hard @@ -2210,42 +2397,54 @@ __metadata: languageName: node linkType: hard -"@typechain/ethers-v5@npm:^8.0.5": - version: 8.0.5 - resolution: "@typechain/ethers-v5@npm:8.0.5" +"@tybys/wasm-util@npm:^0.10.3": + version: 0.10.3 + resolution: "@tybys/wasm-util@npm:0.10.3" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/fd2bd2a79c6cd8c79ed1cf7a0fa375c64589264c88a27acaf9756d556b453ea222b62a4f68dd2fbb8b3a78b6bab3b1f4fb2431b6afc6aeda8344b53a521a1cd3 + languageName: node + linkType: hard + +"@typechain/ethers-v6@npm:0.5.1": + version: 0.5.1 + resolution: "@typechain/ethers-v6@npm:0.5.1" dependencies: lodash: "npm:^4.17.15" ts-essentials: "npm:^7.0.1" peerDependencies: - "@ethersproject/abi": ^5.0.0 - "@ethersproject/bytes": ^5.0.0 - "@ethersproject/providers": ^5.0.0 - ethers: ^5.1.3 - typechain: ^6.0.4 - typescript: ">=4.0.0" - checksum: 10c0/2febc9ff0356628b7e1c5e744e44077b3f077e6bab453f315679ae182c71f42fb94fc6c088f2cc8438530efab0e234d7554a78590426ed0ddf51e74d3e6be1fb + ethers: 6.x + typechain: ^8.3.2 + typescript: ">=4.7.0" + checksum: 10c0/f3c80151c07e01adbf520e0854426649edb0ee540920569487dd8da7eca2fa8615710f4c0eda008e7afdf255fbb8dfdebf721a5d324a4dffeb087611d9bd64b9 languageName: node linkType: hard -"@typechain/hardhat@npm:^4.0.0": - version: 4.0.0 - resolution: "@typechain/hardhat@npm:4.0.0" +"@typechain/ethers-v6@patch:@typechain/ethers-v6@npm%3A0.5.1#~/.yarn/patches/@typechain-ethers-v6-npm-0.5.1-e825560376.patch": + version: 0.5.1 + resolution: "@typechain/ethers-v6@patch:@typechain/ethers-v6@npm%3A0.5.1#~/.yarn/patches/@typechain-ethers-v6-npm-0.5.1-e825560376.patch::version=0.5.1&hash=496509" dependencies: - fs-extra: "npm:^9.1.0" + lodash: "npm:^4.17.15" + ts-essentials: "npm:^7.0.1" peerDependencies: - hardhat: ^2.0.10 - lodash: ^4.17.15 - typechain: ^7.0.0 - checksum: 10c0/f1004bfb11e08ea786a930401be0d22bab58eb1ee3c8901baa8cd467e45fe8a451d6f1e6b86d53ac84338c9fd3b7f422184d68274cbf7877196e695e2e301238 + ethers: 6.x + typechain: ^8.3.2 + typescript: ">=4.7.0" + checksum: 10c0/cbf3447ec6ac2351df39f69c11066d8f3e48d1c9792281127499cc53da66b537db97e4a4385c925ab9c2fe04ea25912a126bd71f28564a93343d4f1c901f764b languageName: node linkType: hard -"@types/bn.js@npm:^4.11.3, @types/bn.js@npm:^4.11.4": - version: 4.11.6 - resolution: "@types/bn.js@npm:4.11.6" +"@typechain/hardhat@npm:^9.1.0": + version: 9.1.0 + resolution: "@typechain/hardhat@npm:9.1.0" dependencies: - "@types/node": "npm:*" - checksum: 10c0/a5a19dafc106b1b2ab35c2024ca37b9d0938dced11cb1cca7d119de5a0dd5f54db525c82cb1392843fc921677452efcbbdce3aa96ecc1457d3de6e266915ebd0 + fs-extra: "npm:^9.1.0" + peerDependencies: + "@typechain/ethers-v6": ^0.5.1 + ethers: ^6.1.0 + hardhat: ^2.9.9 + typechain: ^8.3.2 + checksum: 10c0/3a1220efefc7b02ca335696167f6c5332a33ff3fbf9f20552468566a1760f76bc88d330683e97ca6213eb9518a2a901391c31c84c0548006b72bd2ec62d4af9c languageName: node linkType: hard @@ -2258,15 +2457,6 @@ __metadata: languageName: node linkType: hard -"@types/cbor@npm:^2.0.0": - version: 2.0.0 - resolution: "@types/cbor@npm:2.0.0" - dependencies: - "@types/node": "npm:*" - checksum: 10c0/981961ee25a3ca17bdd9e65ea63eddaf9266f5447caa8b96abe11a6a06b7f68779e4009db1f9b3223e613a0c5b73416ac283a00b2705fb304100070fc9b9d07d - languageName: node - linkType: hard - "@types/chai-as-promised@npm:^7.1.3, @types/chai-as-promised@npm:^7.1.5": version: 7.1.5 resolution: "@types/chai-as-promised@npm:7.1.5" @@ -2276,61 +2466,77 @@ __metadata: languageName: node linkType: hard -"@types/chai@npm:*, @types/chai@npm:^4.3.0": +"@types/chai@npm:*": version: 4.3.0 resolution: "@types/chai@npm:4.3.0" checksum: 10c0/d8107f1916e552633cb98509129241bf2576084b65726e9e03c5194e69e704af5c64b52e4a23b51060eaf2914c588fdf260a6fc49bf63e51808e7d78944e238c languageName: node linkType: hard -"@types/json-schema@npm:^7.0.7": - version: 7.0.15 - resolution: "@types/json-schema@npm:7.0.15" - checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db +"@types/chai@npm:^4.3.20": + version: 4.3.20 + resolution: "@types/chai@npm:4.3.20" + checksum: 10c0/4601189d611752e65018f1ecadac82e94eed29f348e1d5430e5681a60b01e1ecf855d9bcc74ae43b07394751f184f6970fac2b5561fc57a1f36e93a0f5ffb6e8 languageName: node linkType: hard -"@types/json5@npm:^0.0.29": - version: 0.0.29 - resolution: "@types/json5@npm:0.0.29" - checksum: 10c0/6bf5337bc447b706bb5b4431d37686aa2ea6d07cfd6f79cc31de80170d6ff9b1c7384a9c0ccbc45b3f512bae9e9f75c2e12109806a15331dc94e8a8db6dbb4ac +"@types/esrecurse@npm:^4.3.1": + version: 4.3.1 + resolution: "@types/esrecurse@npm:4.3.1" + checksum: 10c0/90dad74d5da3ad27606d8e8e757322f33171cfeaa15ad558b615cf71bb2a516492d18f55f4816384685a3eb2412142e732bbae9a4a7cd2cf3deb7572aa4ebe03 languageName: node linkType: hard -"@types/keyv@npm:^3.1.1": - version: 3.1.4 - resolution: "@types/keyv@npm:3.1.4" - dependencies: - "@types/node": "npm:*" - checksum: 10c0/ff8f54fc49621210291f815fe5b15d809fd7d032941b3180743440bd507ecdf08b9e844625fa346af568c84bf34114eb378dcdc3e921a08ba1e2a08d7e3c809c +"@types/estree@npm:^1.0.6, @types/estree@npm:^1.0.8": + version: 1.0.9 + resolution: "@types/estree@npm:1.0.9" + checksum: 10c0/3ad3286ca2988cd550dafb8f2ad599c8474868e954fa601a36655bdfefd8039f7c714b8c1c7f2ae219ffbd58bd4660e66fa7479a0120fc02d4777057d4865387 languageName: node linkType: hard -"@types/mocha@npm:^9.1.0": - version: 9.1.0 - resolution: "@types/mocha@npm:9.1.0" - checksum: 10c0/67c4662437ffbac955e8de0fa3e60860913201e46ac9a86305347b79dabe47c5f0a03b3b11c19f7aa8855c13de3337dc1bbd227ca8178f14e7688eab13bbe5af +"@types/http-cache-semantics@npm:^4.0.2": + version: 4.2.0 + resolution: "@types/http-cache-semantics@npm:4.2.0" + checksum: 10c0/82dd33cbe7d4843f1e884a251c6a12d385b62274353b9db167462e7fbffdbb3a83606f9952203017c5b8cabbd7b9eef0cf240a3a9dedd20f69875c9701939415 languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:^17.0.10": +"@types/json-schema@npm:^7.0.15": + version: 7.0.15 + resolution: "@types/json-schema@npm:7.0.15" + checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db + languageName: node + linkType: hard + +"@types/mocha@npm:^10.0.10": + version: 10.0.10 + resolution: "@types/mocha@npm:10.0.10" + checksum: 10c0/d2b8c48138cde6923493e42b38e839695eb42edd04629abe480a8f34c0e3f50dd82a55832c2e8d2b6e6f9e4deb492d7d733e600fbbdd5a0ceccbcfc6844ff9d5 + languageName: node + linkType: hard + +"@types/node@npm:*": version: 17.0.10 resolution: "@types/node@npm:17.0.10" checksum: 10c0/d250b5b010d84d7d5e0aaba90b50826bfce1b31e3359e2f277fbe2184fbaa7142d51c48c69973504f337f58370cd32ed4040816b36b4c7e9524cd07631bc457e languageName: node linkType: hard -"@types/node@npm:^10.12.18, @types/node@npm:^10.3.2": - version: 10.17.60 - resolution: "@types/node@npm:10.17.60" - checksum: 10c0/0742294912a6e79786cdee9ed77cff6ee8ff007b55d8e21170fc3e5994ad3a8101fea741898091876f8dc32b0a5ae3d64537b7176799e92da56346028d2cbcd2 +"@types/node@npm:22.7.5": + version: 22.7.5 + resolution: "@types/node@npm:22.7.5" + dependencies: + undici-types: "npm:~6.19.2" + checksum: 10c0/cf11f74f1a26053ec58066616e3a8685b6bcd7259bc569738b8f752009f9f0f7f85a1b2d24908e5b0f752482d1e8b6babdf1fbb25758711ec7bb9500bfcd6e60 languageName: node linkType: hard -"@types/node@npm:^12.6.1": - version: 12.20.55 - resolution: "@types/node@npm:12.20.55" - checksum: 10c0/3b190bb0410047d489c49bbaab592d2e6630de6a50f00ba3d7d513d59401d279972a8f5a598b5bb8ddc1702f8a2f4ec57a65d93852f9c329639738e7053637d1 +"@types/node@npm:^24.13.3": + version: 24.13.3 + resolution: "@types/node@npm:24.13.3" + dependencies: + undici-types: "npm:~7.18.0" + checksum: 10c0/a5bc08f49b9581dcdca90e02cd77197a3c799840807664942e5cd5161a553d4d2ae8064f7e3294410d748d7d098b5c1848be7fa50c06f29c4193ab16be4e59eb languageName: node linkType: hard @@ -2351,18 +2557,9 @@ __metadata: linkType: hard "@types/qs@npm:^6.9.7": - version: 6.9.7 - resolution: "@types/qs@npm:6.9.7" - checksum: 10c0/157eb05f4c75790b0ebdcf7b0547ff117feabc8cda03c3cac3d3ea82bb19a1912e76a411df3eb0bdd01026a9770f07bc0e7e3fbe39ebb31c1be4564c16be35f1 - languageName: node - linkType: hard - -"@types/responselike@npm:^1.0.0": - version: 1.0.3 - resolution: "@types/responselike@npm:1.0.3" - dependencies: - "@types/node": "npm:*" - checksum: 10c0/a58ba341cb9e7d74f71810a88862da7b2a6fa42e2a1fc0ce40498f6ea1d44382f0640117057da779f74c47039f7166bf48fad02dc876f94e005c7afa50f5e129 + version: 6.14.0 + resolution: "@types/qs@npm:6.14.0" + checksum: 10c0/5b3036df6e507483869cdb3858201b2e0b64b4793dc4974f188caa5b5732f2333ab9db45c08157975054d3b070788b35088b4bc60257ae263885016ee2131310 languageName: node linkType: hard @@ -2375,245 +2572,426 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^4.32.0": - version: 4.33.0 - resolution: "@typescript-eslint/eslint-plugin@npm:4.33.0" +"@typescript-eslint/eslint-plugin@npm:8.70.0": + version: 8.70.0 + resolution: "@typescript-eslint/eslint-plugin@npm:8.70.0" dependencies: - "@typescript-eslint/experimental-utils": "npm:4.33.0" - "@typescript-eslint/scope-manager": "npm:4.33.0" - debug: "npm:^4.3.1" - functional-red-black-tree: "npm:^1.0.1" - ignore: "npm:^5.1.8" - regexpp: "npm:^3.1.0" - semver: "npm:^7.3.5" - tsutils: "npm:^3.21.0" + "@eslint-community/regexpp": "npm:^4.12.2" + "@typescript-eslint/scope-manager": "npm:8.70.0" + "@typescript-eslint/type-utils": "npm:8.70.0" + "@typescript-eslint/utils": "npm:8.70.0" + "@typescript-eslint/visitor-keys": "npm:8.70.0" + ignore: "npm:^7.0.5" + natural-compare: "npm:^1.4.0" + ts-api-utils: "npm:^2.5.0" peerDependencies: - "@typescript-eslint/parser": ^4.0.0 - eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/c1e1e424e257fa6e5e8b18d7ff77e8a983a761f4acc0cd58ebd31de8ec56c8c472689989cff0290eee41457662a1e664b555cf74bfc1b37bdf8c87ccac2a4663 + "@typescript-eslint/parser": ^8.70.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/e69f6f697493f4b5cb0411498edd63d75afb3e6881c632f9b23c416e64dd06458956ae489a253f0d08b90645b935a32a509d1e2b17068974a2a34a5c2b3f334b languageName: node linkType: hard -"@typescript-eslint/experimental-utils@npm:4.33.0": - version: 4.33.0 - resolution: "@typescript-eslint/experimental-utils@npm:4.33.0" +"@typescript-eslint/parser@npm:8.70.0": + version: 8.70.0 + resolution: "@typescript-eslint/parser@npm:8.70.0" dependencies: - "@types/json-schema": "npm:^7.0.7" - "@typescript-eslint/scope-manager": "npm:4.33.0" - "@typescript-eslint/types": "npm:4.33.0" - "@typescript-eslint/typescript-estree": "npm:4.33.0" - eslint-scope: "npm:^5.1.1" - eslint-utils: "npm:^3.0.0" + "@typescript-eslint/scope-manager": "npm:8.70.0" + "@typescript-eslint/types": "npm:8.70.0" + "@typescript-eslint/typescript-estree": "npm:8.70.0" + "@typescript-eslint/visitor-keys": "npm:8.70.0" + debug: "npm:^4.4.3" peerDependencies: - eslint: "*" - checksum: 10c0/bb2a48c9df21ef06ccbcd083753b8c51b30a46cde67ab56d278b30ad7868d2e07641e51b6f7fb54437dcb7aff134fac44708e730e2b8f6e43027fefe8629bcb9 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/6d35e0cad56902295599c3da7e4f4c97ebf6f19fcc4333100ad05ef757ba9c431db9cdbd886b6748eb88afd0bc64f8c1c7a81b37589bbd4cc346f6e9eb4e3d12 languageName: node linkType: hard -"@typescript-eslint/parser@npm:^4.32.0": - version: 4.33.0 - resolution: "@typescript-eslint/parser@npm:4.33.0" +"@typescript-eslint/project-service@npm:8.70.0": + version: 8.70.0 + resolution: "@typescript-eslint/project-service@npm:8.70.0" dependencies: - "@typescript-eslint/scope-manager": "npm:4.33.0" - "@typescript-eslint/types": "npm:4.33.0" - "@typescript-eslint/typescript-estree": "npm:4.33.0" - debug: "npm:^4.3.1" + "@typescript-eslint/tsconfig-utils": "npm:^8.70.0" + "@typescript-eslint/types": "npm:^8.70.0" + debug: "npm:^4.4.3" peerDependencies: - eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/d6f91479b2c0d0ff20ac2dbc7540b28c175fd834a220a4f227209f6c74c55401ac6bd41b2bb4cf40b3ba7761075ccded2019bfc6096c2e4f273bd4ae86c44172 + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/eb7d0b4c91015e9aa47672ba20dfda0717e5fa09afa7e28f25b5d7b7b0cd8af4b394f94c3a1528358a7d8c8be4165ed4291a345cbe19bb137a24c6a4f006b398 languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:4.33.0": - version: 4.33.0 - resolution: "@typescript-eslint/scope-manager@npm:4.33.0" +"@typescript-eslint/scope-manager@npm:8.70.0": + version: 8.70.0 + resolution: "@typescript-eslint/scope-manager@npm:8.70.0" dependencies: - "@typescript-eslint/types": "npm:4.33.0" - "@typescript-eslint/visitor-keys": "npm:4.33.0" - checksum: 10c0/1dfe65777eeb430c1ef778bdad35e6065d4b3075ddb2639d0747d8db93c02eebf6832ba82388a7f80662e0e9f61f1922fe939b53a20889e11fb9f80c4029c6b7 + "@typescript-eslint/types": "npm:8.70.0" + "@typescript-eslint/visitor-keys": "npm:8.70.0" + checksum: 10c0/ca05825fb16266d90e73bd1745407f719fc6d5fdb33045cdae21d3259f13c9b54d8b956d5c64a3eb83baff7690527fb16d01a2d7318379f97fb79a1cbf8ca103 languageName: node linkType: hard -"@typescript-eslint/types@npm:4.33.0": - version: 4.33.0 - resolution: "@typescript-eslint/types@npm:4.33.0" - checksum: 10c0/6c94780a589eca7a75ae2b014f320bc412b50794c39ab04889918bb39a40e72584b65c8c0b035330cb0599579afaa3adccee40701f63cf39c0e89299de199d4b +"@typescript-eslint/tsconfig-utils@npm:8.70.0, @typescript-eslint/tsconfig-utils@npm:^8.70.0": + version: 8.70.0 + resolution: "@typescript-eslint/tsconfig-utils@npm:8.70.0" + peerDependencies: + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/925df7c1fbb4e8050dda3fa3dad4a6f515a1f7f2b43f5c145d9eaac856adb84bba04eb5038cc0f78c2307c1df4e2d64dbb4e2e47abffa4844e25cfe62ce402cf languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:4.33.0": - version: 4.33.0 - resolution: "@typescript-eslint/typescript-estree@npm:4.33.0" +"@typescript-eslint/type-utils@npm:8.70.0": + version: 8.70.0 + resolution: "@typescript-eslint/type-utils@npm:8.70.0" dependencies: - "@typescript-eslint/types": "npm:4.33.0" - "@typescript-eslint/visitor-keys": "npm:4.33.0" - debug: "npm:^4.3.1" - globby: "npm:^11.0.3" - is-glob: "npm:^4.0.1" - semver: "npm:^7.3.5" - tsutils: "npm:^3.21.0" - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/67609a7bdd680136765d103dec4b8afb38a17436e8a5cd830da84f62c6153c3acba561da3b9e2140137b1a0bcbbfc19d4256c692f7072acfebcff88db079e22b + "@typescript-eslint/types": "npm:8.70.0" + "@typescript-eslint/typescript-estree": "npm:8.70.0" + "@typescript-eslint/utils": "npm:8.70.0" + debug: "npm:^4.4.3" + ts-api-utils: "npm:^2.5.0" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/b745dc16a9ae50fc1bf7880388425d05d7d1775d23819dfcbdbe5930829fb426d7a011a9848494f427f61e236a4deeb9e8f0fd60db4b7a717a791c8454d63584 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:4.33.0": - version: 4.33.0 - resolution: "@typescript-eslint/visitor-keys@npm:4.33.0" - dependencies: - "@typescript-eslint/types": "npm:4.33.0" - eslint-visitor-keys: "npm:^2.0.0" - checksum: 10c0/95b3904db6113ef365892567d47365e6af3708e6fa905743426036f99e1b7fd4a275facec5d939afecb618369f9d615e379d39f96b8936f469e75507c41c249c +"@typescript-eslint/types@npm:8.70.0, @typescript-eslint/types@npm:^8.56.0, @typescript-eslint/types@npm:^8.70.0": + version: 8.70.0 + resolution: "@typescript-eslint/types@npm:8.70.0" + checksum: 10c0/e3f98d0c0e708fcadebb3b457bf3f38a2512220b6bc9823212cacf310377539fb3c24f9e9e754d13b611a3ac6028a0bba16d02eeef03198c65e7ba605bb2036d languageName: node linkType: hard -"abbrev@npm:^4.0.0": - version: 4.0.0 - resolution: "abbrev@npm:4.0.0" - checksum: 10c0/b4cc16935235e80702fc90192e349e32f8ef0ed151ef506aa78c81a7c455ec18375c4125414b99f84b2e055199d66383e787675f0bcd87da7a4dbd59f9eac1d5 +"@typescript-eslint/typescript-estree@npm:8.70.0": + version: 8.70.0 + resolution: "@typescript-eslint/typescript-estree@npm:8.70.0" + dependencies: + "@typescript-eslint/project-service": "npm:8.70.0" + "@typescript-eslint/tsconfig-utils": "npm:8.70.0" + "@typescript-eslint/types": "npm:8.70.0" + "@typescript-eslint/visitor-keys": "npm:8.70.0" + debug: "npm:^4.4.3" + minimatch: "npm:^10.2.2" + semver: "npm:^7.7.3" + tinyglobby: "npm:^0.2.15" + ts-api-utils: "npm:^2.5.0" + peerDependencies: + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/11e6c9c0108184902bc229376cce00eb81ee2b88a7cc3bf02a8c159bf59b2c7af21d2b330976b1751fedd5c27e257731b0d60840268299582c458c2a0a29525e languageName: node linkType: hard -"abitype@npm:1.2.3": - version: 1.2.3 - resolution: "abitype@npm:1.2.3" +"@typescript-eslint/utils@npm:8.70.0": + version: 8.70.0 + resolution: "@typescript-eslint/utils@npm:8.70.0" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.9.1" + "@typescript-eslint/scope-manager": "npm:8.70.0" + "@typescript-eslint/types": "npm:8.70.0" + "@typescript-eslint/typescript-estree": "npm:8.70.0" peerDependencies: - typescript: ">=5.0.4" - zod: ^3.22.0 || ^4.0.0 - peerDependenciesMeta: - typescript: - optional: true - zod: - optional: true - checksum: 10c0/c8740de1ae4961723a153224a52cb9a34a57903fb5c2ad61d5082b0b79b53033c9335381aa8c663c7ec213c9955a9853f694d51e95baceedef27356f7745c634 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/15353ecd0c5e29057e5846c6b84de601b679448e01293dbf1ae7dbe94ab6d4b586f8690a262630522441307fafad01ab3b0b46a85eb71907c19a2f124d7bba3f languageName: node linkType: hard -"abitype@npm:^1.2.3": - version: 1.3.0 - resolution: "abitype@npm:1.3.0" - peerDependencies: - typescript: ">=5.0.4" - zod: ^3.22.0 || ^4.0.0 - peerDependenciesMeta: - typescript: - optional: true - zod: - optional: true - checksum: 10c0/368b0209c10396952e57d0e927da0fad6c079dd23632ab463da2dfff0fe454ba218804322f6fdd6da014b3fbe96afafb4bb1da3585507f3891c2b47c69c63980 +"@typescript-eslint/visitor-keys@npm:8.70.0": + version: 8.70.0 + resolution: "@typescript-eslint/visitor-keys@npm:8.70.0" + dependencies: + "@typescript-eslint/types": "npm:8.70.0" + eslint-visitor-keys: "npm:^5.0.0" + checksum: 10c0/43fe28dc1045a686deead8c9334f6e9d8b3fa8f84917147aabd9747783b8bc531254a95a9bfb33355b25cf5ec9a72c62bcde313f13869d7a5e5603d96be593a9 languageName: node linkType: hard -"accepts@npm:~1.3.8": - version: 1.3.8 - resolution: "accepts@npm:1.3.8" - dependencies: - mime-types: "npm:~2.1.34" - negotiator: "npm:0.6.3" - checksum: 10c0/3a35c5f5586cfb9a21163ca47a5f77ac34fa8ceb5d17d2fa2c0d81f41cbd7f8c6fa52c77e2c039acc0f4d09e71abdc51144246900f6bef5e3c4b333f77d89362 +"@unrs/resolver-binding-android-arm-eabi@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-android-arm-eabi@npm:1.12.2" + conditions: os=android & cpu=arm languageName: node linkType: hard -"acorn-jsx@npm:^5.0.0, acorn-jsx@npm:^5.3.1": - version: 5.3.2 - resolution: "acorn-jsx@npm:5.3.2" - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: 10c0/4c54868fbef3b8d58927d5e33f0a4de35f59012fe7b12cf9dfbb345fb8f46607709e1c4431be869a23fb63c151033d84c4198fa9f79385cec34fcb1dd53974c1 +"@unrs/resolver-binding-android-arm64@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-android-arm64@npm:1.12.2" + conditions: os=android & cpu=arm64 languageName: node linkType: hard -"acorn-walk@npm:^8.1.1": - version: 8.2.0 - resolution: "acorn-walk@npm:8.2.0" - checksum: 10c0/dbe92f5b2452c93e960c5594e666dd1fae141b965ff2cb4a1e1d0381e3e4db4274c5ce4ffa3d681a86ca2a8d4e29d5efc0670a08e23fd2800051ea387df56ca2 +"@unrs/resolver-binding-darwin-arm64@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-darwin-arm64@npm:1.12.2" + conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"acorn@npm:^6.0.7": - version: 6.4.2 - resolution: "acorn@npm:6.4.2" - bin: - acorn: bin/acorn - checksum: 10c0/52a72d5d785fa64a95880f2951021a38954f8f69a4944dfeab6fb1449b0f02293eae109a56d55b58ff31a90a00d16a804658a12db8ef834c20b3d1201fe5ba5b +"@unrs/resolver-binding-darwin-x64@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-darwin-x64@npm:1.12.2" + conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"acorn@npm:^7.4.0": - version: 7.4.1 - resolution: "acorn@npm:7.4.1" - bin: - acorn: bin/acorn - checksum: 10c0/bd0b2c2b0f334bbee48828ff897c12bd2eb5898d03bf556dcc8942022cec795ac5bb5b6b585e2de687db6231faf07e096b59a361231dd8c9344d5df5f7f0e526 +"@unrs/resolver-binding-freebsd-x64@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-freebsd-x64@npm:1.12.2" + conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"acorn@npm:^8.4.1": - version: 8.7.0 - resolution: "acorn@npm:8.7.0" - bin: - acorn: bin/acorn - checksum: 10c0/8168e567c2f0b9fb7a418d2651b4b614326a0814b4937ebddee0f5e5e25ddd6320aec0c20d3a67efd97a02d836cc7f9e5c84befe3daeeea68ed89a48ee8f7a5d +"@unrs/resolver-binding-linux-arm-gnueabihf@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-arm-gnueabihf@npm:1.12.2" + conditions: os=linux & cpu=arm languageName: node linkType: hard -"adm-zip@npm:^0.4.16": - version: 0.4.16 - resolution: "adm-zip@npm:0.4.16" - checksum: 10c0/c56c6e138fd19006155fc716acae14d54e07c267ae19d78c8a8cdca04762bf20170a71a41aa8d8bad2f13b70d4f3e9a191009bafa5280e05a440ee506f871a55 +"@unrs/resolver-binding-linux-arm-musleabihf@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-arm-musleabihf@npm:1.12.2" + conditions: os=linux & cpu=arm languageName: node linkType: hard -"aes-js@npm:3.0.0": - version: 3.0.0 - resolution: "aes-js@npm:3.0.0" - checksum: 10c0/87dd5b2363534b867db7cef8bc85a90c355460783744877b2db7c8be09740aac5750714f9e00902822f692662bda74cdf40e03fbb5214ffec75c2666666288b8 +"@unrs/resolver-binding-linux-arm64-gnu@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-arm64-gnu@npm:1.12.2" + conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"agent-base@npm:6": - version: 6.0.2 - resolution: "agent-base@npm:6.0.2" - dependencies: - debug: "npm:4" - checksum: 10c0/dc4f757e40b5f3e3d674bc9beb4f1048f4ee83af189bae39be99f57bf1f48dde166a8b0a5342a84b5944ee8e6ed1e5a9d801858f4ad44764e84957122fe46261 +"@unrs/resolver-binding-linux-arm64-musl@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-arm64-musl@npm:1.12.2" + conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": - version: 7.1.4 - resolution: "agent-base@npm:7.1.4" - checksum: 10c0/c2c9ab7599692d594b6a161559ada307b7a624fa4c7b03e3afdb5a5e31cd0e53269115b620fcab024c5ac6a6f37fa5eb2e004f076ad30f5f7e6b8b671f7b35fe +"@unrs/resolver-binding-linux-loong64-gnu@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-loong64-gnu@npm:1.12.2" + conditions: os=linux & cpu=loong64 & libc=glibc languageName: node linkType: hard -"aggregate-error@npm:^3.0.0": - version: 3.1.0 - resolution: "aggregate-error@npm:3.1.0" - dependencies: +"@unrs/resolver-binding-linux-loong64-musl@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-loong64-musl@npm:1.12.2" + conditions: os=linux & cpu=loong64 & libc=musl + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-ppc64-gnu@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-ppc64-gnu@npm:1.12.2" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-riscv64-gnu@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-riscv64-gnu@npm:1.12.2" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-riscv64-musl@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-riscv64-musl@npm:1.12.2" + conditions: os=linux & cpu=riscv64 & libc=musl + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-s390x-gnu@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-s390x-gnu@npm:1.12.2" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-x64-gnu@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-x64-gnu@npm:1.12.2" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-x64-musl@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-x64-musl@npm:1.12.2" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@unrs/resolver-binding-openharmony-arm64@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-openharmony-arm64@npm:1.12.2" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + +"@unrs/resolver-binding-wasm32-wasi@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-wasm32-wasi@npm:1.12.2" + dependencies: + "@emnapi/core": "npm:1.10.0" + "@emnapi/runtime": "npm:1.10.0" + "@napi-rs/wasm-runtime": "npm:^1.1.4" + conditions: cpu=wasm32 + languageName: node + linkType: hard + +"@unrs/resolver-binding-win32-arm64-msvc@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-win32-arm64-msvc@npm:1.12.2" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@unrs/resolver-binding-win32-ia32-msvc@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-win32-ia32-msvc@npm:1.12.2" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@unrs/resolver-binding-win32-x64-msvc@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-win32-x64-msvc@npm:1.12.2" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"abbrev@npm:^4.0.0": + version: 4.0.0 + resolution: "abbrev@npm:4.0.0" + checksum: 10c0/b4cc16935235e80702fc90192e349e32f8ef0ed151ef506aa78c81a7c455ec18375c4125414b99f84b2e055199d66383e787675f0bcd87da7a4dbd59f9eac1d5 + languageName: node + linkType: hard + +"abitype@npm:1.2.3": + version: 1.2.3 + resolution: "abitype@npm:1.2.3" + peerDependencies: + typescript: ">=5.0.4" + zod: ^3.22.0 || ^4.0.0 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + checksum: 10c0/c8740de1ae4961723a153224a52cb9a34a57903fb5c2ad61d5082b0b79b53033c9335381aa8c663c7ec213c9955a9853f694d51e95baceedef27356f7745c634 + languageName: node + linkType: hard + +"abitype@npm:^1.2.3": + version: 1.3.0 + resolution: "abitype@npm:1.3.0" + peerDependencies: + typescript: ">=5.0.4" + zod: ^3.22.0 || ^4.0.0 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + checksum: 10c0/368b0209c10396952e57d0e927da0fad6c079dd23632ab463da2dfff0fe454ba218804322f6fdd6da014b3fbe96afafb4bb1da3585507f3891c2b47c69c63980 + languageName: node + linkType: hard + +"acorn-jsx@npm:^5.3.2": + version: 5.3.2 + resolution: "acorn-jsx@npm:5.3.2" + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: 10c0/4c54868fbef3b8d58927d5e33f0a4de35f59012fe7b12cf9dfbb345fb8f46607709e1c4431be869a23fb63c151033d84c4198fa9f79385cec34fcb1dd53974c1 + languageName: node + linkType: hard + +"acorn-walk@npm:^8.1.1": + version: 8.2.0 + resolution: "acorn-walk@npm:8.2.0" + checksum: 10c0/dbe92f5b2452c93e960c5594e666dd1fae141b965ff2cb4a1e1d0381e3e4db4274c5ce4ffa3d681a86ca2a8d4e29d5efc0670a08e23fd2800051ea387df56ca2 + languageName: node + linkType: hard + +"acorn@npm:^8.15.0, acorn@npm:^8.16.0": + version: 8.18.0 + resolution: "acorn@npm:8.18.0" + bin: + acorn: bin/acorn + checksum: 10c0/be771be2135cc07910cf76f444ad514d7dcfd6d4a8026e597e93155275abc8ef61eee12211d52146e9d962874269b634f397464942087be013c89d0c54c5f8e5 + languageName: node + linkType: hard + +"acorn@npm:^8.4.1": + version: 8.7.0 + resolution: "acorn@npm:8.7.0" + bin: + acorn: bin/acorn + checksum: 10c0/8168e567c2f0b9fb7a418d2651b4b614326a0814b4937ebddee0f5e5e25ddd6320aec0c20d3a67efd97a02d836cc7f9e5c84befe3daeeea68ed89a48ee8f7a5d + languageName: node + linkType: hard + +"adm-zip@npm:^0.4.16": + version: 0.4.16 + resolution: "adm-zip@npm:0.4.16" + checksum: 10c0/c56c6e138fd19006155fc716acae14d54e07c267ae19d78c8a8cdca04762bf20170a71a41aa8d8bad2f13b70d4f3e9a191009bafa5280e05a440ee506f871a55 + languageName: node + linkType: hard + +"aes-js@npm:3.0.0": + version: 3.0.0 + resolution: "aes-js@npm:3.0.0" + checksum: 10c0/87dd5b2363534b867db7cef8bc85a90c355460783744877b2db7c8be09740aac5750714f9e00902822f692662bda74cdf40e03fbb5214ffec75c2666666288b8 + languageName: node + linkType: hard + +"aes-js@npm:4.0.0-beta.5": + version: 4.0.0-beta.5 + resolution: "aes-js@npm:4.0.0-beta.5" + checksum: 10c0/444f4eefa1e602cbc4f2a3c644bc990f93fd982b148425fee17634da510586fc09da940dcf8ace1b2d001453c07ff042e55f7a0482b3cc9372bf1ef75479090c + languageName: node + linkType: hard + +"agent-base@npm:6": + version: 6.0.2 + resolution: "agent-base@npm:6.0.2" + dependencies: + debug: "npm:4" + checksum: 10c0/dc4f757e40b5f3e3d674bc9beb4f1048f4ee83af189bae39be99f57bf1f48dde166a8b0a5342a84b5944ee8e6ed1e5a9d801858f4ad44764e84957122fe46261 + languageName: node + linkType: hard + +"agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": + version: 7.1.4 + resolution: "agent-base@npm:7.1.4" + checksum: 10c0/c2c9ab7599692d594b6a161559ada307b7a624fa4c7b03e3afdb5a5e31cd0e53269115b620fcab024c5ac6a6f37fa5eb2e004f076ad30f5f7e6b8b671f7b35fe + languageName: node + linkType: hard + +"aggregate-error@npm:^3.0.0": + version: 3.1.0 + resolution: "aggregate-error@npm:3.1.0" + dependencies: clean-stack: "npm:^2.0.0" indent-string: "npm:^4.0.0" checksum: 10c0/a42f67faa79e3e6687a4923050e7c9807db3848a037076f791d10e092677d65c1d2d863b7848560699f40fc0502c19f40963fb1cd1fb3d338a7423df8e45e039 languageName: node linkType: hard -"ajv@npm:^6.10.0, ajv@npm:^6.10.2, ajv@npm:^6.12.3, ajv@npm:^6.12.4, ajv@npm:^6.6.1, ajv@npm:^6.9.1": - version: 6.12.6 - resolution: "ajv@npm:6.12.6" +"ajv@npm:^6.14.0": + version: 6.15.0 + resolution: "ajv@npm:6.15.0" dependencies: fast-deep-equal: "npm:^3.1.1" fast-json-stable-stringify: "npm:^2.0.0" json-schema-traverse: "npm:^0.4.1" uri-js: "npm:^4.2.2" - checksum: 10c0/41e23642cbe545889245b9d2a45854ebba51cda6c778ebced9649420d9205f2efb39cb43dbc41e358409223b1ea43303ae4839db682c848b891e4811da1a5a71 + checksum: 10c0/67966499dd272ecde1c2e467084411132891523d057487587879d39ac04207f4351b7b2324c83198013967fbfa632c1612adc960114a30770fbe07a0773b32c2 languageName: node linkType: hard @@ -2629,6 +3007,18 @@ __metadata: languageName: node linkType: hard +"ajv@npm:^8.18.0": + version: 8.20.0 + resolution: "ajv@npm:8.20.0" + dependencies: + fast-deep-equal: "npm:^3.1.3" + fast-uri: "npm:^3.0.1" + json-schema-traverse: "npm:^1.0.0" + require-from-string: "npm:^2.0.2" + checksum: 10c0/5df9a1c8f83863cde1bd3a9ddb426f599718f88e3dc9153616c79fb28e0be455335830d7f21d745576519f057b371352daa31047b6a33d7036fe08777d60cf2a + languageName: node + linkType: hard + "amazon-cognito-identity-js@npm:^6.0.1": version: 6.3.12 resolution: "amazon-cognito-identity-js@npm:6.3.12" @@ -2642,6 +3032,19 @@ __metadata: languageName: node linkType: hard +"amazon-cognito-identity-js@npm:^6.3.6": + version: 6.3.21 + resolution: "amazon-cognito-identity-js@npm:6.3.21" + dependencies: + "@aws-crypto/sha256-js": "npm:1.2.2" + buffer: "npm:4.9.2" + fast-base64-decode: "npm:^1.0.0" + isomorphic-unfetch: "npm:^3.0.0" + js-cookie: "npm:^3.0.7" + checksum: 10c0/c7541a70f5fc7a9cdc9642dec5c223420c4719219a24eab05decb1292741ebd82e4746dccc396f26436550896f5aa249311c4628f2b0f40ef4b436d50c05a16d + languageName: node + linkType: hard + "ansi-align@npm:^3.0.0": version: 3.0.1 resolution: "ansi-align@npm:3.0.1" @@ -2658,13 +3061,6 @@ __metadata: languageName: node linkType: hard -"ansi-escapes@npm:^3.2.0": - version: 3.2.0 - resolution: "ansi-escapes@npm:3.2.0" - checksum: 10c0/084e1ce38139ad2406f18a8e7efe2b850ddd06ce3c00f633392d1ce67756dab44fe290e573d09ef3c9a0cb13c12881e0e35a8f77a017d39a0a4ab85ae2fae04f - languageName: node - linkType: hard - "ansi-escapes@npm:^4.3.0": version: 4.3.2 resolution: "ansi-escapes@npm:4.3.2" @@ -2674,20 +3070,6 @@ __metadata: languageName: node linkType: hard -"ansi-regex@npm:^3.0.0": - version: 3.0.0 - resolution: "ansi-regex@npm:3.0.0" - checksum: 10c0/c6a2b226d009965decc65d330b953290039f0f2b31d200516a9a79b6010f5f8f9d6acbaa0917d925c578df0c0feaddcb56569aad05776f99e2918116d4233121 - languageName: node - linkType: hard - -"ansi-regex@npm:^4.1.0": - version: 4.1.1 - resolution: "ansi-regex@npm:4.1.1" - checksum: 10c0/d36d34234d077e8770169d980fed7b2f3724bfa2a01da150ccd75ef9707c80e883d27cdf7a0eac2f145ac1d10a785a8a855cffd05b85f778629a0db62e7033da - languageName: node - linkType: hard - "ansi-regex@npm:^5.0.1": version: 5.0.1 resolution: "ansi-regex@npm:5.0.1" @@ -2702,7 +3084,7 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^3.2.0, ansi-styles@npm:^3.2.1": +"ansi-styles@npm:^3.2.1": version: 3.2.1 resolution: "ansi-styles@npm:3.2.1" dependencies: @@ -2727,27 +3109,6 @@ __metadata: languageName: node linkType: hard -"antlr4@npm:4.7.1": - version: 4.7.1 - resolution: "antlr4@npm:4.7.1" - checksum: 10c0/384ffb8c048065af1284323b6fbacb47ad588b52c398a232d9f3702552897aad124386ef2704d8fb773e319da44197cac603a88044475f13f3917b10703eae47 - languageName: node - linkType: hard - -"antlr4ts@npm:^0.5.0-alpha.4": - version: 0.5.0-alpha.4 - resolution: "antlr4ts@npm:0.5.0-alpha.4" - checksum: 10c0/26a43d6769178fdf1b79ed2001f123fd49843e335f9a3687b63c090ab2024632fbac60a73b3f8289044c206edeb5d19c36b02603b018d8eaf3be3ce30136102f - languageName: node - linkType: hard - -"any-promise@npm:1.3.0": - version: 1.3.0 - resolution: "any-promise@npm:1.3.0" - checksum: 10c0/60f0298ed34c74fef50daab88e8dab786036ed5a7fad02e012ab57e376e0a0b4b29e83b95ea9b5e7d89df762f5f25119b83e00706ecaccb22cfbacee98d74889 - languageName: node - linkType: hard - "anymatch@npm:~3.1.2": version: 3.1.2 resolution: "anymatch@npm:3.1.2" @@ -2765,15 +3126,6 @@ __metadata: languageName: node linkType: hard -"argparse@npm:^1.0.7": - version: 1.0.10 - resolution: "argparse@npm:1.0.10" - dependencies: - sprintf-js: "npm:~1.0.2" - checksum: 10c0/b2972c5c23c63df66bca144dbc65d180efa74f25f8fd9b7d9a0a6c88ae839db32df3d54770dcb6460cf840d232b60695d1a6b1053f599d84e73f7437087712de - languageName: node - linkType: hard - "argparse@npm:^2.0.1": version: 2.0.1 resolution: "argparse@npm:2.0.1" @@ -2781,13 +3133,6 @@ __metadata: languageName: node linkType: hard -"aria-query@npm:^5.3.2": - version: 5.3.2 - resolution: "aria-query@npm:5.3.2" - checksum: 10c0/003c7e3e2cff5540bf7a7893775fc614de82b0c5dde8ae823d47b7a28a9d4da1f7ed85f340bdb93d5649caa927755f0e31ecc7ab63edfdfc00c8ef07e505e03e - languageName: node - linkType: hard - "array-back@npm:^3.0.1, array-back@npm:^3.1.0": version: 3.1.0 resolution: "array-back@npm:3.1.0" @@ -2802,345 +3147,92 @@ __metadata: languageName: node linkType: hard -"array-buffer-byte-length@npm:^1.0.1, array-buffer-byte-length@npm:^1.0.2": - version: 1.0.2 - resolution: "array-buffer-byte-length@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.3" - is-array-buffer: "npm:^3.0.5" - checksum: 10c0/74e1d2d996941c7a1badda9cabb7caab8c449db9086407cad8a1b71d2604cc8abf105db8ca4e02c04579ec58b7be40279ddb09aea4784832984485499f48432d - languageName: node - linkType: hard - -"array-flatten@npm:1.1.1": - version: 1.1.1 - resolution: "array-flatten@npm:1.1.1" - checksum: 10c0/806966c8abb2f858b08f5324d9d18d7737480610f3bd5d3498aaae6eb5efdc501a884ba019c9b4a8f02ff67002058749d05548fd42fa8643f02c9c7f22198b91 +"assertion-error@npm:^1.1.0": + version: 1.1.0 + resolution: "assertion-error@npm:1.1.0" + checksum: 10c0/25456b2aa333250f01143968e02e4884a34588a8538fbbf65c91a637f1dbfb8069249133cd2f4e530f10f624d206a664e7df30207830b659e9f5298b00a4099b languageName: node linkType: hard -"array-includes@npm:^3.1.6, array-includes@npm:^3.1.8, array-includes@npm:^3.1.9": - version: 3.1.9 - resolution: "array-includes@npm:3.1.9" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.4" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.24.0" - es-object-atoms: "npm:^1.1.1" - get-intrinsic: "npm:^1.3.0" - is-string: "npm:^1.1.1" - math-intrinsics: "npm:^1.1.0" - checksum: 10c0/0235fa69078abeac05ac4250699c44996bc6f774a9cbe45db48674ce6bd142f09b327d31482ff75cf03344db4ea03eae23edb862d59378b484b47ed842574856 +"ast-parents@npm:^0.0.1": + version: 0.0.1 + resolution: "ast-parents@npm:0.0.1" + checksum: 10c0/f170166a5d43526f26be95754773822f63d4f45e5ccf83949290ef09919cff6a45d30f9e85ea4a2648b9cd757c18f246ec0cf050094c3b686722c2e6136edfe2 languageName: node linkType: hard -"array-union@npm:^2.1.0": - version: 2.1.0 - resolution: "array-union@npm:2.1.0" - checksum: 10c0/429897e68110374f39b771ec47a7161fc6a8fc33e196857c0a396dc75df0b5f65e4d046674db764330b6bb66b39ef48dd7c53b6a2ee75cfb0681e0c1a7033962 +"astral-regex@npm:^2.0.0": + version: 2.0.0 + resolution: "astral-regex@npm:2.0.0" + checksum: 10c0/f63d439cc383db1b9c5c6080d1e240bd14dae745f15d11ec5da863e182bbeca70df6c8191cffef5deba0b566ef98834610a68be79ac6379c95eeb26e1b310e25 languageName: node linkType: hard -"array.prototype.findlast@npm:^1.2.5": - version: 1.2.5 - resolution: "array.prototype.findlast@npm:1.2.5" +"async-retry@npm:^1.3.3": + version: 1.3.3 + resolution: "async-retry@npm:1.3.3" dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.2" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.0.0" - es-shim-unscopables: "npm:^1.0.2" - checksum: 10c0/ddc952b829145ab45411b9d6adcb51a8c17c76bf89c9dd64b52d5dffa65d033da8c076ed2e17091779e83bc892b9848188d7b4b33453c5565e65a92863cb2775 + retry: "npm:0.13.1" + checksum: 10c0/cabced4fb46f8737b95cc88dc9c0ff42656c62dc83ce0650864e891b6c155a063af08d62c446269b51256f6fbcb69a6563b80e76d0ea4a5117b0c0377b6b19d8 languageName: node linkType: hard -"array.prototype.findlastindex@npm:^1.2.6": - version: 1.2.6 - resolution: "array.prototype.findlastindex@npm:1.2.6" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.4" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.9" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.1.1" - es-shim-unscopables: "npm:^1.1.0" - checksum: 10c0/82559310d2e57ec5f8fc53d7df420e3abf0ba497935de0a5570586035478ba7d07618cb18e2d4ada2da514c8fb98a034aaf5c06caa0a57e2f7f4c4adedef5956 +"asynckit@npm:^0.4.0": + version: 0.4.0 + resolution: "asynckit@npm:0.4.0" + checksum: 10c0/d73e2ddf20c4eb9337e1b3df1a0f6159481050a5de457c55b14ea2e5cb6d90bb69e004c9af54737a5ee0917fcf2c9e25de67777bbe58261847846066ba75bc9d languageName: node linkType: hard -"array.prototype.flat@npm:^1.3.1, array.prototype.flat@npm:^1.3.3": - version: 1.3.3 - resolution: "array.prototype.flat@npm:1.3.3" - dependencies: - call-bind: "npm:^1.0.8" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.5" - es-shim-unscopables: "npm:^1.0.2" - checksum: 10c0/d90e04dfbc43bb96b3d2248576753d1fb2298d2d972e29ca7ad5ec621f0d9e16ff8074dae647eac4f31f4fb7d3f561a7ac005fb01a71f51705a13b5af06a7d8a +"at-least-node@npm:^1.0.0": + version: 1.0.0 + resolution: "at-least-node@npm:1.0.0" + checksum: 10c0/4c058baf6df1bc5a1697cf182e2029c58cd99975288a13f9e70068ef5d6f4e1f1fd7c4d2c3c4912eae44797d1725be9700995736deca441b39f3e66d8dee97ef languageName: node linkType: hard -"array.prototype.flatmap@npm:^1.3.2, array.prototype.flatmap@npm:^1.3.3": - version: 1.3.3 - resolution: "array.prototype.flatmap@npm:1.3.3" +"axios@npm:^1.8.4": + version: 1.20.0 + resolution: "axios@npm:1.20.0" dependencies: - call-bind: "npm:^1.0.8" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.5" - es-shim-unscopables: "npm:^1.0.2" - checksum: 10c0/ba899ea22b9dc9bf276e773e98ac84638ed5e0236de06f13d63a90b18ca9e0ec7c97d622d899796e3773930b946cd2413d098656c0c5d8cc58c6f25c21e6bd54 + follow-redirects: "npm:^1.16.0" + form-data: "npm:^4.0.6" + https-proxy-agent: "npm:^5.0.1" + proxy-from-env: "npm:^2.1.0" + checksum: 10c0/976088acf532286356f4c2e65df1ef47ba7da3936d83e928d0d64357bbf5370456abd3eb5826c15df322335fcb1fe200d4a84b4fcf20ffccdd63b40d80fa495c languageName: node linkType: hard -"array.prototype.tosorted@npm:^1.1.4": - version: 1.1.4 - resolution: "array.prototype.tosorted@npm:1.1.4" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.3" - es-errors: "npm:^1.3.0" - es-shim-unscopables: "npm:^1.0.2" - checksum: 10c0/eb3c4c4fc0381b0bf6dba2ea4d48d367c2827a0d4236a5718d97caaccc6b78f11f4cadf090736e86301d295a6aa4967ed45568f92ced51be8cbbacd9ca410943 +"balanced-match@npm:^1.0.0": + version: 1.0.2 + resolution: "balanced-match@npm:1.0.2" + checksum: 10c0/9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee languageName: node linkType: hard -"arraybuffer.prototype.slice@npm:^1.0.4": - version: 1.0.4 - resolution: "arraybuffer.prototype.slice@npm:1.0.4" - dependencies: - array-buffer-byte-length: "npm:^1.0.1" - call-bind: "npm:^1.0.8" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.5" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.6" - is-array-buffer: "npm:^3.0.4" - checksum: 10c0/2f2459caa06ae0f7f615003f9104b01f6435cc803e11bd2a655107d52a1781dc040532dc44d93026b694cc18793993246237423e13a5337e86b43ed604932c06 +"balanced-match@npm:^4.0.2": + version: 4.0.4 + resolution: "balanced-match@npm:4.0.4" + checksum: 10c0/07e86102a3eb2ee2a6a1a89164f29d0dbaebd28f2ca3f5ca786f36b8b23d9e417eb3be45a4acf754f837be5ac0a2317de90d3fcb7f4f4dc95720a1f36b26a17b languageName: node linkType: hard -"asn1.js@npm:^5.2.0": - version: 5.4.1 - resolution: "asn1.js@npm:5.4.1" +"base-x@npm:^3.0.2": + version: 3.0.9 + resolution: "base-x@npm:3.0.9" dependencies: - bn.js: "npm:^4.0.0" - inherits: "npm:^2.0.1" - minimalistic-assert: "npm:^1.0.0" - safer-buffer: "npm:^2.1.0" - checksum: 10c0/b577232fa6069cc52bb128e564002c62b2b1fe47f7137bdcd709c0b8495aa79cee0f8cc458a831b2d8675900eea0d05781b006be5e1aa4f0ae3577a73ec20324 + safe-buffer: "npm:^5.0.1" + checksum: 10c0/e6bbeae30b24f748b546005affb710c5fbc8b11a83f6cd0ca999bd1ab7ad3a22e42888addc40cd145adc4edfe62fcfab4ebc91da22e4259aae441f95a77aee1a languageName: node linkType: hard -"asn1@npm:~0.2.3": - version: 0.2.6 - resolution: "asn1@npm:0.2.6" - dependencies: - safer-buffer: "npm:~2.1.0" - checksum: 10c0/00c8a06c37e548762306bcb1488388d2f76c74c36f70c803f0c081a01d3bdf26090fc088cd812afc5e56a6d49e33765d451a5f8a68ab9c2b087eba65d2e980e0 - languageName: node - linkType: hard - -"assert-plus@npm:1.0.0, assert-plus@npm:^1.0.0": - version: 1.0.0 - resolution: "assert-plus@npm:1.0.0" - checksum: 10c0/b194b9d50c3a8f872ee85ab110784911e696a4d49f7ee6fc5fb63216dedbefd2c55999c70cb2eaeb4cf4a0e0338b44e9ace3627117b5bf0d42460e9132f21b91 - languageName: node - linkType: hard - -"assertion-error@npm:^1.1.0": - version: 1.1.0 - resolution: "assertion-error@npm:1.1.0" - checksum: 10c0/25456b2aa333250f01143968e02e4884a34588a8538fbbf65c91a637f1dbfb8069249133cd2f4e530f10f624d206a664e7df30207830b659e9f5298b00a4099b - languageName: node - linkType: hard - -"ast-parents@npm:0.0.1": - version: 0.0.1 - resolution: "ast-parents@npm:0.0.1" - checksum: 10c0/f170166a5d43526f26be95754773822f63d4f45e5ccf83949290ef09919cff6a45d30f9e85ea4a2648b9cd757c18f246ec0cf050094c3b686722c2e6136edfe2 - languageName: node - linkType: hard - -"ast-types-flow@npm:^0.0.8": - version: 0.0.8 - resolution: "ast-types-flow@npm:0.0.8" - checksum: 10c0/f2a0ba8055353b743c41431974521e5e852a9824870cd6fce2db0e538ac7bf4da406bbd018d109af29ff3f8f0993f6a730c9eddbd0abd031fbcb29ca75c1014e - languageName: node - linkType: hard - -"astral-regex@npm:^1.0.0": - version: 1.0.0 - resolution: "astral-regex@npm:1.0.0" - checksum: 10c0/ca460207a19d84c65671e1a85940101522d42f31a450cdb8f93b3464e6daeaf4b58a362826a6c11c57e6cd1976403d197abb0447cfc2087993a29b35c6d63b63 - languageName: node - linkType: hard - -"astral-regex@npm:^2.0.0": - version: 2.0.0 - resolution: "astral-regex@npm:2.0.0" - checksum: 10c0/f63d439cc383db1b9c5c6080d1e240bd14dae745f15d11ec5da863e182bbeca70df6c8191cffef5deba0b566ef98834610a68be79ac6379c95eeb26e1b310e25 - languageName: node - linkType: hard - -"async-function@npm:^1.0.0": - version: 1.0.0 - resolution: "async-function@npm:1.0.0" - checksum: 10c0/669a32c2cb7e45091330c680e92eaeb791bc1d4132d827591e499cd1f776ff5a873e77e5f92d0ce795a8d60f10761dec9ddfe7225a5de680f5d357f67b1aac73 - languageName: node - linkType: hard - -"async-limiter@npm:~1.0.0": - version: 1.0.1 - resolution: "async-limiter@npm:1.0.1" - checksum: 10c0/0693d378cfe86842a70d4c849595a0bb50dc44c11649640ca982fa90cbfc74e3cc4753b5a0847e51933f2e9c65ce8e05576e75e5e1fd963a086e673735b35969 - languageName: node - linkType: hard - -"async-retry@npm:^1.3.3": - version: 1.3.3 - resolution: "async-retry@npm:1.3.3" - dependencies: - retry: "npm:0.13.1" - checksum: 10c0/cabced4fb46f8737b95cc88dc9c0ff42656c62dc83ce0650864e891b6c155a063af08d62c446269b51256f6fbcb69a6563b80e76d0ea4a5117b0c0377b6b19d8 - languageName: node - linkType: hard - -"asynckit@npm:^0.4.0": - version: 0.4.0 - resolution: "asynckit@npm:0.4.0" - checksum: 10c0/d73e2ddf20c4eb9337e1b3df1a0f6159481050a5de457c55b14ea2e5cb6d90bb69e004c9af54737a5ee0917fcf2c9e25de67777bbe58261847846066ba75bc9d - languageName: node - linkType: hard - -"at-least-node@npm:^1.0.0": - version: 1.0.0 - resolution: "at-least-node@npm:1.0.0" - checksum: 10c0/4c058baf6df1bc5a1697cf182e2029c58cd99975288a13f9e70068ef5d6f4e1f1fd7c4d2c3c4912eae44797d1725be9700995736deca441b39f3e66d8dee97ef - languageName: node - linkType: hard - -"available-typed-arrays@npm:^1.0.7": - version: 1.0.7 - resolution: "available-typed-arrays@npm:1.0.7" - dependencies: - possible-typed-array-names: "npm:^1.0.0" - checksum: 10c0/d07226ef4f87daa01bd0fe80f8f310982e345f372926da2e5296aecc25c41cab440916bbaa4c5e1034b453af3392f67df5961124e4b586df1e99793a1374bdb2 - languageName: node - linkType: hard - -"aws-sign2@npm:~0.7.0": - version: 0.7.0 - resolution: "aws-sign2@npm:0.7.0" - checksum: 10c0/021d2cc5547d4d9ef1633e0332e746a6f447997758b8b68d6fb33f290986872d2bff5f0c37d5832f41a7229361f093cd81c40898d96ed153493c0fb5cd8575d2 - languageName: node - linkType: hard - -"aws4@npm:^1.8.0": - version: 1.11.0 - resolution: "aws4@npm:1.11.0" - checksum: 10c0/00c32a5dc0f864a731e26406fa7d51595e09359dd8f9c813fa3122e3833f564bf95b78cdf6acf8b5d0462403d7c73ce5f22ad19050d75b17019c7978f970c4fa - languageName: node - linkType: hard - -"axe-core@npm:^4.10.0": - version: 4.11.0 - resolution: "axe-core@npm:4.11.0" - checksum: 10c0/7d7020a568a824c303711858c2fcfe56d001d27e46c0c2ff75dc31b436cfddfd4857a301e70536cc9e64829d25338f7fb782102d23497ebdc66801e9900fc895 - languageName: node - linkType: hard - -"axios@npm:^0.18.0": - version: 0.18.1 - resolution: "axios@npm:0.18.1" - dependencies: - follow-redirects: "npm:1.5.10" - is-buffer: "npm:^2.0.2" - checksum: 10c0/13d86542ad3e1de286a6262213b1cd62654307d89617bef5015e82aad389408c6f66bafa1e467b80af971cfe5ac5ed0b40a250f682f46ab9a1487060f0b6b661 - languageName: node - linkType: hard - -"axios@npm:^0.21.1, axios@npm:^0.21.2": - version: 0.21.4 - resolution: "axios@npm:0.21.4" - dependencies: - follow-redirects: "npm:^1.14.0" - checksum: 10c0/fbcff55ec68f71f02d3773d467db2fcecdf04e749826c82c2427a232f9eba63242150a05f15af9ef15818352b814257541155de0281f8fb2b7e8a5b79f7f2142 - languageName: node - linkType: hard - -"axios@npm:^1.4.0": - version: 1.8.1 - resolution: "axios@npm:1.8.1" - dependencies: - follow-redirects: "npm:^1.15.6" - form-data: "npm:^4.0.0" - proxy-from-env: "npm:^1.1.0" - checksum: 10c0/b2e1d5a61264502deee4b50f0a6df0aa3b174c546ccf68c0dff714a2b8863232e0bd8cb5b84f853303e97f242a98260f9bb9beabeafe451ad5af538e9eb7ac22 - languageName: node - linkType: hard - -"axios@npm:^1.6.7": - version: 1.18.1 - resolution: "axios@npm:1.18.1" - dependencies: - follow-redirects: "npm:^1.16.0" - form-data: "npm:^4.0.5" - https-proxy-agent: "npm:^5.0.1" - proxy-from-env: "npm:^2.1.0" - checksum: 10c0/9d9378a3af0d0ad730a52ad9d15ec7201f3926ad6e7e8bbffc5ae21ca2835ad11d1d9598698f5dd9718917486039f55ea1d7dc23d8e44fa827a55cc3262c02fc - languageName: node - linkType: hard - -"axobject-query@npm:^4.1.0": - version: 4.1.0 - resolution: "axobject-query@npm:4.1.0" - checksum: 10c0/c470e4f95008f232eadd755b018cb55f16c03ccf39c027b941cd8820ac6b68707ce5d7368a46756db4256fbc91bb4ead368f84f7fb034b2b7932f082f6dc0775 - languageName: node - linkType: hard - -"balanced-match@npm:^1.0.0": - version: 1.0.2 - resolution: "balanced-match@npm:1.0.2" - checksum: 10c0/9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee - languageName: node - linkType: hard - -"balanced-match@npm:^4.0.2": - version: 4.0.4 - resolution: "balanced-match@npm:4.0.4" - checksum: 10c0/07e86102a3eb2ee2a6a1a89164f29d0dbaebd28f2ca3f5ca786f36b8b23d9e417eb3be45a4acf754f837be5ac0a2317de90d3fcb7f4f4dc95720a1f36b26a17b - languageName: node - linkType: hard - -"base-x@npm:^3.0.2": - version: 3.0.9 - resolution: "base-x@npm:3.0.9" - dependencies: - safe-buffer: "npm:^5.0.1" - checksum: 10c0/e6bbeae30b24f748b546005affb710c5fbc8b11a83f6cd0ca999bd1ab7ad3a22e42888addc40cd145adc4edfe62fcfab4ebc91da22e4259aae441f95a77aee1a - languageName: node - linkType: hard - -"base64-js@npm:^1.0.2, base64-js@npm:^1.3.1": +"base64-js@npm:^1.0.2": version: 1.5.1 resolution: "base64-js@npm:1.5.1" checksum: 10c0/f23823513b63173a001030fae4f2dabe283b99a9d324ade3ad3d148e218134676f1ee8568c877cd79ec1c53158dcf2d2ba527a97c606618928ba99dd930102bf languageName: node linkType: hard -"bcrypt-pbkdf@npm:^1.0.0": - version: 1.0.2 - resolution: "bcrypt-pbkdf@npm:1.0.2" - dependencies: - tweetnacl: "npm:^0.14.3" - checksum: 10c0/ddfe85230b32df25aeebfdccfbc61d3bc493ace49c884c9c68575de1f5dcf733a5d7de9def3b0f318b786616b8d85bad50a28b1da1750c43e0012c93badcc148 - languageName: node - linkType: hard - "bech32@npm:1.1.4": version: 1.1.4 resolution: "bech32@npm:1.1.4" @@ -3148,17 +3240,25 @@ __metadata: languageName: node linkType: hard -"bignumber.js@npm:^7.2.0": - version: 7.2.1 - resolution: "bignumber.js@npm:7.2.1" - checksum: 10c0/7e2cb10cdc1991696666b129f3b888c44a5e35bd3a5e990b2d2c934c7bc6863fb42b45fdea830484ca0d9e0b9a70d15e1d43fcd03a0e04326612b8e3ac76a0ae +"better-ajv-errors@npm:^2.0.2": + version: 2.0.3 + resolution: "better-ajv-errors@npm:2.0.3" + dependencies: + "@babel/code-frame": "npm:^7.27.1" + "@humanwhocodes/momoa": "npm:^2.0.4" + chalk: "npm:^4.1.2" + jsonpointer: "npm:^5.0.1" + leven: "npm:^3.1.0 < 4" + peerDependencies: + ajv: 4.11.8 - 8 + checksum: 10c0/168f6ff274c1b71a897d0267a3a4c52a5e70e33b3d858d8c455b42e2da1abdf9a8d31cba09572bbd549778774a4f5c1cb2a1cec52f5298c9f7fb77f3cdfb95ba languageName: node linkType: hard -"bignumber.js@npm:^9.0.0": - version: 9.1.0 - resolution: "bignumber.js@npm:9.1.0" - checksum: 10c0/82b7314c9b1480e0471c21ac154342b910bd00807050e4ae248e291168eb23140456191c3f9b522da822c87a7730e8e18524db4db836d4455d821222c0acdfac +"bignumber.js@npm:^9.1.2": + version: 9.3.1 + resolution: "bignumber.js@npm:9.3.1" + checksum: 10c0/61342ba5fe1c10887f0ecf5be02ff6709271481aff48631f86b4d37d55a99b87ce441cfd54df3d16d10ee07ceab7e272fc0be430c657ffafbbbf7b7d631efb75 languageName: node linkType: hard @@ -3169,16 +3269,6 @@ __metadata: languageName: node linkType: hard -"bl@npm:^1.0.0": - version: 1.2.3 - resolution: "bl@npm:1.2.3" - dependencies: - readable-stream: "npm:^2.3.5" - safe-buffer: "npm:^5.1.1" - checksum: 10c0/ee6478864d3b1295614f269f3fbabeb2362a2f2fc7f8dc2f6c1f944a278d84e0572ecefd6d0b0736d7418763f98dc3b2738253191ea9e98e4b08de211cfac0a6 - languageName: node - linkType: hard - "blakejs@npm:^1.1.0": version: 1.2.1 resolution: "blakejs@npm:1.2.1" @@ -3186,41 +3276,13 @@ __metadata: languageName: node linkType: hard -"bluebird@npm:^3.5.0": - version: 3.7.2 - resolution: "bluebird@npm:3.7.2" - checksum: 10c0/680de03adc54ff925eaa6c7bb9a47a0690e8b5de60f4792604aae8ed618c65e6b63a7893b57ca924beaf53eee69c5af4f8314148c08124c550fe1df1add897d2 - languageName: node - linkType: hard - -"bn.js@npm:4.11.6": - version: 4.11.6 - resolution: "bn.js@npm:4.11.6" - checksum: 10c0/e6ee7d3f597f60722cc3361071e23ccf71d3387e166de02381f180f22d2fa79f5dbbdf9e4909e81faaf5da01c16ec6857ddff02678339ce085e2058fd0e405db - languageName: node - linkType: hard - -"bn.js@npm:4.11.8, bn.js@npm:^4.4.0": - version: 4.11.8 - resolution: "bn.js@npm:4.11.8" - checksum: 10c0/d1bd5f8721c9c101c5e5bb3077d8689b3116f618506c6dd009fee5701b8b116da373b35c60d437549c8c720b6b62a161ab070d6a8266a164ef4503a1582b634e - languageName: node - linkType: hard - -"bn.js@npm:^4.0.0, bn.js@npm:^4.1.0, bn.js@npm:^4.11.0, bn.js@npm:^4.11.6, bn.js@npm:^4.11.9": +"bn.js@npm:^4.11.9": version: 4.12.0 resolution: "bn.js@npm:4.12.0" checksum: 10c0/9736aaa317421b6b3ed038ff3d4491935a01419ac2d83ddcfebc5717385295fcfcf0c57311d90fe49926d0abbd7a9dbefdd8861e6129939177f7e67ebc645b21 languageName: node linkType: hard -"bn.js@npm:^5.0.0, bn.js@npm:^5.1.1, bn.js@npm:^5.2.0, bn.js@npm:^5.2.1": - version: 5.2.1 - resolution: "bn.js@npm:5.2.1" - checksum: 10c0/bed3d8bd34ec89dbcf9f20f88bd7d4a49c160fda3b561c7bb227501f974d3e435a48fb9b61bc3de304acab9215a3bda0803f7017ffb4d0016a0c3a740a283caa - languageName: node - linkType: hard - "bn.js@npm:^5.1.2": version: 5.2.0 resolution: "bn.js@npm:5.2.0" @@ -3228,23 +3290,10 @@ __metadata: languageName: node linkType: hard -"body-parser@npm:1.20.0, body-parser@npm:^1.16.0": - version: 1.20.0 - resolution: "body-parser@npm:1.20.0" - dependencies: - bytes: "npm:3.1.2" - content-type: "npm:~1.0.4" - debug: "npm:2.6.9" - depd: "npm:2.0.0" - destroy: "npm:1.2.0" - http-errors: "npm:2.0.0" - iconv-lite: "npm:0.4.24" - on-finished: "npm:2.4.1" - qs: "npm:6.10.3" - raw-body: "npm:2.5.1" - type-is: "npm:~1.6.18" - unpipe: "npm:1.0.0" - checksum: 10c0/36aa63aa7862ccbb32ea92fc3e6e1dea25b8c2fda03762bc26d0f82f61272635c532b2d77ef43d312de779fac83f24061a375d047be7f2bbf3ece66dc6b2c460 +"bn.js@npm:^5.2.0, bn.js@npm:^5.2.1": + version: 5.2.1 + resolution: "bn.js@npm:5.2.1" + checksum: 10c0/bed3d8bd34ec89dbcf9f20f88bd7d4a49c160fda3b561c7bb227501f974d3e435a48fb9b61bc3de304acab9215a3bda0803f7017ffb4d0016a0c3a740a283caa languageName: node linkType: hard @@ -3301,7 +3350,16 @@ __metadata: languageName: node linkType: hard -"braces@npm:^3.0.3, braces@npm:~3.0.2": +"brace-expansion@npm:^5.0.8": + version: 5.0.9 + resolution: "brace-expansion@npm:5.0.9" + dependencies: + balanced-match: "npm:^4.0.2" + checksum: 10c0/3dea38884a1c3c8b1c9c44a7402a0c76fca460f70cffb3127242b0b4cbf4472019e022ade021eec44838ff19f1dac2625dfd11dd459d7e1e055b0698a8d52fec + languageName: node + linkType: hard + +"braces@npm:~3.0.2": version: 3.0.3 resolution: "braces@npm:3.0.3" dependencies: @@ -3310,7 +3368,7 @@ __metadata: languageName: node linkType: hard -"brorand@npm:^1.0.1, brorand@npm:^1.1.0": +"brorand@npm:^1.1.0": version: 1.1.0 resolution: "brorand@npm:1.1.0" checksum: 10c0/6f366d7c4990f82c366e3878492ba9a372a73163c09871e80d82fb4ae0d23f9f8924cb8a662330308206e6b3b76ba1d528b4601c9ef73c2166b440b2ea3b7571 @@ -3331,7 +3389,7 @@ __metadata: languageName: node linkType: hard -"browserify-aes@npm:^1.0.0, browserify-aes@npm:^1.0.4, browserify-aes@npm:^1.2.0": +"browserify-aes@npm:^1.2.0": version: 1.2.0 resolution: "browserify-aes@npm:1.2.0" dependencies: @@ -3345,56 +3403,6 @@ __metadata: languageName: node linkType: hard -"browserify-cipher@npm:^1.0.0": - version: 1.0.1 - resolution: "browserify-cipher@npm:1.0.1" - dependencies: - browserify-aes: "npm:^1.0.4" - browserify-des: "npm:^1.0.0" - evp_bytestokey: "npm:^1.0.0" - checksum: 10c0/aa256dcb42bc53a67168bbc94ab85d243b0a3b56109dee3b51230b7d010d9b78985ffc1fb36e145c6e4db151f888076c1cfc207baf1525d3e375cbe8187fe27d - languageName: node - linkType: hard - -"browserify-des@npm:^1.0.0": - version: 1.0.2 - resolution: "browserify-des@npm:1.0.2" - dependencies: - cipher-base: "npm:^1.0.1" - des.js: "npm:^1.0.0" - inherits: "npm:^2.0.1" - safe-buffer: "npm:^5.1.2" - checksum: 10c0/943eb5d4045eff80a6cde5be4e5fbb1f2d5002126b5a4789c3c1aae3cdddb1eb92b00fb92277f512288e5c6af330730b1dbabcf7ce0923e749e151fcee5a074d - languageName: node - linkType: hard - -"browserify-rsa@npm:^4.0.0, browserify-rsa@npm:^4.0.1": - version: 4.1.0 - resolution: "browserify-rsa@npm:4.1.0" - dependencies: - bn.js: "npm:^5.0.0" - randombytes: "npm:^2.0.1" - checksum: 10c0/fb2b5a8279d8a567a28d8ee03fb62e448428a906bab5c3dc9e9c3253ace551b5ea271db15e566ac78f1b1d71b243559031446604168b9235c351a32cae99d02a - languageName: node - linkType: hard - -"browserify-sign@npm:^4.0.0": - version: 4.2.1 - resolution: "browserify-sign@npm:4.2.1" - dependencies: - bn.js: "npm:^5.1.1" - browserify-rsa: "npm:^4.0.1" - create-hash: "npm:^1.2.0" - create-hmac: "npm:^1.1.7" - elliptic: "npm:^6.5.3" - inherits: "npm:^2.0.4" - parse-asn1: "npm:^5.1.5" - readable-stream: "npm:^3.6.0" - safe-buffer: "npm:^5.2.0" - checksum: 10c0/8f00a370e3e97060977dc58e51251d3ca398ee73523994a44430321e8de2c7d85395362d59014b2b07efe4190f369baee2ff28eb8f405ff4660b776651cf052d - languageName: node - linkType: hard - "bs58@npm:^4.0.0": version: 4.0.1 resolution: "bs58@npm:4.0.1" @@ -3415,37 +3423,6 @@ __metadata: languageName: node linkType: hard -"buffer-alloc-unsafe@npm:^1.1.0": - version: 1.1.0 - resolution: "buffer-alloc-unsafe@npm:1.1.0" - checksum: 10c0/06b9298c9369621a830227c3797ceb3ff5535e323946d7b39a7398fed8b3243798259b3c85e287608c5aad35ccc551cec1a0a5190cc8f39652e8eee25697fc9c - languageName: node - linkType: hard - -"buffer-alloc@npm:^1.2.0": - version: 1.2.0 - resolution: "buffer-alloc@npm:1.2.0" - dependencies: - buffer-alloc-unsafe: "npm:^1.1.0" - buffer-fill: "npm:^1.0.0" - checksum: 10c0/09d87dd53996342ccfbeb2871257d8cdb25ce9ee2259adc95c6490200cd6e528c5fbae8f30bcc323fe8d8efb0fe541e4ac3bbe9ee3f81c6b7c4b27434cc02ab4 - languageName: node - linkType: hard - -"buffer-crc32@npm:~0.2.3": - version: 0.2.13 - resolution: "buffer-crc32@npm:0.2.13" - checksum: 10c0/cb0a8ddf5cf4f766466db63279e47761eb825693eeba6a5a95ee4ec8cb8f81ede70aa7f9d8aeec083e781d47154290eb5d4d26b3f7a465ec57fb9e7d59c47150 - languageName: node - linkType: hard - -"buffer-fill@npm:^1.0.0": - version: 1.0.0 - resolution: "buffer-fill@npm:1.0.0" - checksum: 10c0/55b5654fbbf2d7ceb4991bb537f5e5b5b5b9debca583fee416a74fcec47c16d9e7a90c15acd27577da7bd750b7fa6396e77e7c221e7af138b6d26242381c6e4d - languageName: node - linkType: hard - "buffer-from@npm:^1.0.0": version: 1.1.2 resolution: "buffer-from@npm:1.1.2" @@ -3453,13 +3430,6 @@ __metadata: languageName: node linkType: hard -"buffer-to-arraybuffer@npm:^0.0.5": - version: 0.0.5 - resolution: "buffer-to-arraybuffer@npm:0.0.5" - checksum: 10c0/0eea361112a67725e098796b931d931a279b8925cae906f07ed876fab4131e3a83073933a4a33b79d96251722a61c1b875b0ef1e04190734921b9e808a73978c - languageName: node - linkType: hard - "buffer-xor@npm:^1.0.3": version: 1.0.3 resolution: "buffer-xor@npm:1.0.3" @@ -3478,16 +3448,6 @@ __metadata: languageName: node linkType: hard -"buffer@npm:^5.0.5, buffer@npm:^5.2.1": - version: 5.7.1 - resolution: "buffer@npm:5.7.1" - dependencies: - base64-js: "npm:^1.3.1" - ieee754: "npm:^1.1.13" - checksum: 10c0/27cac81cff434ed2876058d72e7c4789d11ff1120ef32c9de48f59eab58179b66710c488987d295ae89a228f835fc66d088652dffeb8e3ba8659f80eb091d55e - languageName: node - linkType: hard - "busboy@npm:^1.6.0": version: 1.6.0 resolution: "busboy@npm:1.6.0" @@ -3504,13 +3464,6 @@ __metadata: languageName: node linkType: hard -"bytes@npm:3.1.2": - version: 3.1.2 - resolution: "bytes@npm:3.1.2" - checksum: 10c0/76d1c43cbd602794ad8ad2ae94095cddeb1de78c5dddaa7005c51af10b0176c69971a6d88e805a90c2b6550d76636e43c40d8427a808b8645ede885de4a0358e - languageName: node - linkType: hard - "cacache@npm:^20.0.1": version: 20.0.4 resolution: "cacache@npm:20.0.4" @@ -3529,22 +3482,42 @@ __metadata: languageName: node linkType: hard -"cacheable-request@npm:^6.0.0": - version: 6.1.0 - resolution: "cacheable-request@npm:6.1.0" +"cacheable-lookup@npm:^7.0.0": + version: 7.0.0 + resolution: "cacheable-lookup@npm:7.0.0" + checksum: 10c0/63a9c144c5b45cb5549251e3ea774c04d63063b29e469f7584171d059d3a88f650f47869a974e2d07de62116463d742c287a81a625e791539d987115cb081635 + languageName: node + linkType: hard + +"cacheable-request@npm:^10.2.8": + version: 10.2.14 + resolution: "cacheable-request@npm:10.2.14" dependencies: - clone-response: "npm:^1.0.2" - get-stream: "npm:^5.1.0" - http-cache-semantics: "npm:^4.0.0" - keyv: "npm:^3.0.0" - lowercase-keys: "npm:^2.0.0" - normalize-url: "npm:^4.1.0" - responselike: "npm:^1.0.2" - checksum: 10c0/e92f2b2078c014ba097647ab4ff6a6149dc2974a65670ee97ec593ec9f4148ecc988e86b9fcd8ebf7fe255774a53d5dc3db6b01065d44f09a7452c7a7d8e4844 + "@types/http-cache-semantics": "npm:^4.0.2" + get-stream: "npm:^6.0.1" + http-cache-semantics: "npm:^4.1.1" + keyv: "npm:^4.5.3" + mimic-response: "npm:^4.0.0" + normalize-url: "npm:^8.0.0" + responselike: "npm:^3.0.0" + checksum: 10c0/41b6658db369f20c03128227ecd219ca7ac52a9d24fc0f499cc9aa5d40c097b48b73553504cebd137024d957c0ddb5b67cf3ac1439b136667f3586257763f88d + languageName: node + linkType: hard + +"cacheable@npm:^2.5.0": + version: 2.5.0 + resolution: "cacheable@npm:2.5.0" + dependencies: + "@cacheable/memory": "npm:^2.2.0" + "@cacheable/utils": "npm:^2.5.0" + hookified: "npm:^1.15.0" + keyv: "npm:^5.6.0" + qified: "npm:^0.10.1" + checksum: 10c0/ad4086a60ed327196901c16360312705e35bfde5118457449cfabaf4ece0fecad046985ea8b66b3ece46dd469cb33798d87e1dac3ed2c00746578054bccbf74d languageName: node linkType: hard -"call-bind-apply-helpers@npm:^1.0.0, call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2": +"call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2": version: 1.0.2 resolution: "call-bind-apply-helpers@npm:1.0.2" dependencies: @@ -3554,19 +3527,7 @@ __metadata: languageName: node linkType: hard -"call-bind@npm:^1.0.7, call-bind@npm:^1.0.8": - version: 1.0.8 - resolution: "call-bind@npm:1.0.8" - dependencies: - call-bind-apply-helpers: "npm:^1.0.0" - es-define-property: "npm:^1.0.0" - get-intrinsic: "npm:^1.2.4" - set-function-length: "npm:^1.2.2" - checksum: 10c0/a13819be0681d915144467741b69875ae5f4eba8961eb0bf322aab63ec87f8250eb6d6b0dcbb2e1349876412a56129ca338592b3829ef4343527f5f18a0752d4 - languageName: node - linkType: hard - -"call-bound@npm:^1.0.2, call-bound@npm:^1.0.3, call-bound@npm:^1.0.4": +"call-bound@npm:^1.0.2": version: 1.0.4 resolution: "call-bound@npm:1.0.4" dependencies: @@ -3576,49 +3537,17 @@ __metadata: languageName: node linkType: hard -"caller-callsite@npm:^2.0.0": - version: 2.0.0 - resolution: "caller-callsite@npm:2.0.0" - dependencies: - callsites: "npm:^2.0.0" - checksum: 10c0/a00ca91280e10ee2321de21dda6c168e427df7a63aeaca027ea45e3e466ac5e1a5054199f6547ba1d5a513d3b6b5933457266daaa47f8857fb532a343ee6b5e1 +"callsites@npm:^3.0.0": + version: 3.1.0 + resolution: "callsites@npm:3.1.0" + checksum: 10c0/fff92277400eb06c3079f9e74f3af120db9f8ea03bad0e84d9aede54bbe2d44a56cccb5f6cf12211f93f52306df87077ecec5b712794c5a9b5dac6d615a3f301 languageName: node linkType: hard -"caller-path@npm:^2.0.0": - version: 2.0.0 - resolution: "caller-path@npm:2.0.0" - dependencies: - caller-callsite: "npm:^2.0.0" - checksum: 10c0/029b5b2c557d831216305c3218e9ff30fa668be31d58dd08088f74c8eabc8362c303e0908b3a93abb25ba10e3a5bfc9cff5eb7fab6ab9cf820e3b160ccb67581 - languageName: node - linkType: hard - -"callsites@npm:^2.0.0": - version: 2.0.0 - resolution: "callsites@npm:2.0.0" - checksum: 10c0/13bff4fee946e6020b37e76284e95e24aa239c9e34ac4f3451e4c5330fca6f2f962e1d1ab69e4da7940e1fce135107a2b2b98c01d62ea33144350fc89dc5494e - languageName: node - linkType: hard - -"callsites@npm:^3.0.0": - version: 3.1.0 - resolution: "callsites@npm:3.1.0" - checksum: 10c0/fff92277400eb06c3079f9e74f3af120db9f8ea03bad0e84d9aede54bbe2d44a56cccb5f6cf12211f93f52306df87077ecec5b712794c5a9b5dac6d615a3f301 - languageName: node - linkType: hard - -"camelcase@npm:^6.0.0, camelcase@npm:^6.2.0": - version: 6.3.0 - resolution: "camelcase@npm:6.3.0" - checksum: 10c0/0d701658219bd3116d12da3eab31acddb3f9440790c0792e0d398f0a520a6a4058018e546862b6fba89d7ae990efaeb97da71e1913e9ebf5a8b5621a3d55c710 - languageName: node - linkType: hard - -"caseless@npm:~0.12.0": - version: 0.12.0 - resolution: "caseless@npm:0.12.0" - checksum: 10c0/ccf64bcb6c0232cdc5b7bd91ddd06e23a4b541f138336d4725233ac538041fb2f29c2e86c3c4a7a61ef990b665348db23a047060b9414c3a6603e9fa61ad4626 +"camelcase@npm:^6.0.0, camelcase@npm:^6.2.0": + version: 6.3.0 + resolution: "camelcase@npm:6.3.0" + checksum: 10c0/0d701658219bd3116d12da3eab31acddb3f9440790c0792e0d398f0a520a6a4058018e546862b6fba89d7ae990efaeb97da71e1913e9ebf5a8b5621a3d55c710 languageName: node linkType: hard @@ -3631,23 +3560,6 @@ __metadata: languageName: node linkType: hard -"cbor@npm:^4.1.5": - version: 4.3.0 - resolution: "cbor@npm:4.3.0" - dependencies: - bignumber.js: "npm:^9.0.0" - commander: "npm:^3.0.0" - json-text-sequence: "npm:^0.1" - nofilter: "npm:^1.0.3" - bin: - cbor2comment: ./bin/cbor2comment - cbor2diag: ./bin/cbor2diag - cbor2json: ./bin/cbor2json - json2cbor: ./bin/json2cbor - checksum: 10c0/94cbb341b5329a5bccab8d7a60a775ddb64997c4ede3459ec681351f9090952f7c5f98d42524058a3241727c4f336c1e70ac5a688f85684ef0d7c6535c178c58 - languageName: node - linkType: hard - "cbor@npm:^8.1.0": version: 8.1.0 resolution: "cbor@npm:8.1.0" @@ -3692,7 +3604,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^2.0.0, chalk@npm:^2.1.0, chalk@npm:^2.4.1, chalk@npm:^2.4.2": +"chalk@npm:^2.0.0, chalk@npm:^2.4.2": version: 2.4.2 resolution: "chalk@npm:2.4.2" dependencies: @@ -3703,13 +3615,6 @@ __metadata: languageName: node linkType: hard -"chardet@npm:^0.7.0": - version: 0.7.0 - resolution: "chardet@npm:0.7.0" - checksum: 10c0/96e4731b9ec8050cbb56ab684e8c48d6c33f7826b755802d14e3ebfdc51c57afeece3ea39bc6b09acc359e4363525388b915e16640c1378053820f5e70d0f27d - languageName: node - linkType: hard - "charenc@npm:>= 0.0.1": version: 0.0.2 resolution: "charenc@npm:0.0.2" @@ -3752,13 +3657,6 @@ __metadata: languageName: node linkType: hard -"chownr@npm:^1.1.4": - version: 1.1.4 - resolution: "chownr@npm:1.1.4" - checksum: 10c0/ed57952a84cc0c802af900cf7136de643d3aba2eecb59d29344bc2f3f9bf703a301b9d84cdc71f82c3ffc9ccde831b0d92f5b45f91727d6c9da62f23aef9d9db - languageName: node - linkType: hard - "chownr@npm:^3.0.0": version: 3.0.0 resolution: "chownr@npm:3.0.0" @@ -3797,24 +3695,6 @@ __metadata: languageName: node linkType: hard -"cli-cursor@npm:^2.1.0": - version: 2.1.0 - resolution: "cli-cursor@npm:2.1.0" - dependencies: - restore-cursor: "npm:^2.0.0" - checksum: 10c0/09ee6d8b5b818d840bf80ec9561eaf696672197d3a02a7daee2def96d5f52ce6e0bbe7afca754ccf14f04830b5a1b4556273e983507d5029f95bba3016618eda - languageName: node - linkType: hard - -"cli-cursor@npm:^3.0.0": - version: 3.1.0 - resolution: "cli-cursor@npm:3.1.0" - dependencies: - restore-cursor: "npm:^3.1.0" - checksum: 10c0/92a2f98ff9037d09be3dfe1f0d749664797fb674bf388375a2207a1203b69d41847abf16434203e0089212479e47a358b13a0222ab9fccfe8e2644a7ccebd111 - languageName: node - linkType: hard - "cli-table3@npm:^0.6.0": version: 0.6.1 resolution: "cli-table3@npm:0.6.1" @@ -3828,7 +3708,7 @@ __metadata: languageName: node linkType: hard -"cli-table3@npm:^0.6.3": +"cli-table3@npm:^0.6.2, cli-table3@npm:^0.6.3": version: 0.6.5 resolution: "cli-table3@npm:0.6.5" dependencies: @@ -3841,13 +3721,6 @@ __metadata: languageName: node linkType: hard -"cli-width@npm:^2.0.0": - version: 2.2.1 - resolution: "cli-width@npm:2.2.1" - checksum: 10c0/e3a6d422d657ca111c630f69ee0f1a499e8f114eea158ccb2cdbedd19711edffa217093bbd43dafb34b68d1b1a3b5334126e51d059b9ec1d19afa53b42b3ef86 - languageName: node - linkType: hard - "cliui@npm:^8.0.1": version: 8.0.1 resolution: "cliui@npm:8.0.1" @@ -3859,15 +3732,6 @@ __metadata: languageName: node linkType: hard -"clone-response@npm:^1.0.2": - version: 1.0.3 - resolution: "clone-response@npm:1.0.3" - dependencies: - mimic-response: "npm:^1.0.0" - checksum: 10c0/06a2b611824efb128810708baee3bd169ec9a1bf5976a5258cd7eb3f7db25f00166c6eee5961f075c7e38e194f373d4fdf86b8166ad5b9c7e82bbd2e333a6087 - languageName: node - linkType: hard - "color-convert@npm:^1.9.0": version: 1.9.3 resolution: "color-convert@npm:1.9.3" @@ -3907,7 +3771,7 @@ __metadata: languageName: node linkType: hard -"combined-stream@npm:^1.0.6, combined-stream@npm:^1.0.8, combined-stream@npm:~1.0.6": +"combined-stream@npm:^1.0.8": version: 1.0.8 resolution: "combined-stream@npm:1.0.8" dependencies: @@ -3947,24 +3811,17 @@ __metadata: languageName: node linkType: hard -"commander@npm:2.18.0": - version: 2.18.0 - resolution: "commander@npm:2.18.0" - checksum: 10c0/34fe2c3bf52c697ba79e690f26c38163d3c68bbb60cdcc9376c3f686e12276f158113a8d15e569f9b7ea974b52963bd2fdcbdd98d659caccca14d9495ba01a6a - languageName: node - linkType: hard - -"commander@npm:^2.8.1": - version: 2.20.3 - resolution: "commander@npm:2.20.3" - checksum: 10c0/74c781a5248c2402a0a3e966a0a2bba3c054aad144f5c023364be83265e796b20565aa9feff624132ff629aa64e16999fa40a743c10c12f7c61e96a794b99288 +"commander@npm:^10.0.0": + version: 10.0.1 + resolution: "commander@npm:10.0.1" + checksum: 10c0/53f33d8927758a911094adadda4b2cbac111a5b377d8706700587650fd8f45b0bbe336de4b5c3fe47fd61f420a3d9bd452b6e0e6e5600a7e74d7bf0174f6efe3 languageName: node linkType: hard -"commander@npm:^3.0.0": - version: 3.0.2 - resolution: "commander@npm:3.0.2" - checksum: 10c0/8a279b4bacde68f03664086260ccb623122d2bdae6f380a41c9e06b646e830372c30a4b88261238550e0ad69d53f7af8883cb705d8237fdd22947e84913b149c +"commander@npm:^14.0.3": + version: 14.0.3 + resolution: "commander@npm:14.0.3" + checksum: 10c0/755652564bbf56ff2ff083313912b326450d3f8d8c85f4b71416539c9a05c3c67dbd206821ca72635bf6b160e2afdefcb458e86b317827d5cb333b69ce7f1a24 languageName: node linkType: hard @@ -3975,6 +3832,20 @@ __metadata: languageName: node linkType: hard +"commander@npm:^9.4.0": + version: 9.5.0 + resolution: "commander@npm:9.5.0" + checksum: 10c0/5f7784fbda2aaec39e89eb46f06a999e00224b3763dc65976e05929ec486e174fe9aac2655f03ba6a5e83875bd173be5283dc19309b7c65954701c02025b3c1d + languageName: node + linkType: hard + +"comment-parser@npm:^1.4.1": + version: 1.4.8 + resolution: "comment-parser@npm:1.4.8" + checksum: 10c0/7638c29abefdd705917ee73a1a28e0b5851f59b73ed3ebb3369583c74e87d1b4bb2ceae1c94e699e7bf00f06ad679d5a32adc2a42c656965912c9ac85fa17e90 + languageName: node + linkType: hard + "compare-versions@npm:^6.0.0": version: 6.1.1 resolution: "compare-versions@npm:6.1.1" @@ -3989,40 +3860,13 @@ __metadata: languageName: node linkType: hard -"confusing-browser-globals@npm:^1.0.10": - version: 1.0.11 - resolution: "confusing-browser-globals@npm:1.0.11" - checksum: 10c0/475d0a284fa964a5182b519af5738b5b64bf7e413cfd703c1b3496bf6f4df9f827893a9b221c0ea5873c1476835beb1e0df569ba643eff0734010c1eb780589e - languageName: node - linkType: hard - -"content-disposition@npm:0.5.4": - version: 0.5.4 - resolution: "content-disposition@npm:0.5.4" +"config-chain@npm:^1.1.11": + version: 1.1.13 + resolution: "config-chain@npm:1.1.13" dependencies: - safe-buffer: "npm:5.2.1" - checksum: 10c0/bac0316ebfeacb8f381b38285dc691c9939bf0a78b0b7c2d5758acadad242d04783cee5337ba7d12a565a19075af1b3c11c728e1e4946de73c6ff7ce45f3f1bb - languageName: node - linkType: hard - -"content-type@npm:~1.0.4": - version: 1.0.4 - resolution: "content-type@npm:1.0.4" - checksum: 10c0/19e08f406f9ae3f80fb4607c75fbde1f22546647877e8047c9fa0b1c61e38f3ede853f51e915c95fd499c2e1c7478cb23c35cfb804d0e8e0495e8db88cfaed75 - languageName: node - linkType: hard - -"cookie-signature@npm:1.0.6": - version: 1.0.6 - resolution: "cookie-signature@npm:1.0.6" - checksum: 10c0/b36fd0d4e3fef8456915fcf7742e58fbfcc12a17a018e0eb9501c9d5ef6893b596466f03b0564b81af29ff2538fd0aa4b9d54fe5ccbfb4c90ea50ad29fe2d221 - languageName: node - linkType: hard - -"cookie@npm:0.5.0": - version: 0.5.0 - resolution: "cookie@npm:0.5.0" - checksum: 10c0/c01ca3ef8d7b8187bae434434582288681273b5a9ed27521d4d7f9f7928fe0c920df0decd9f9d3bbd2d14ac432b8c8cf42b98b3bdd5bfe0e6edddeebebe8b61d + ini: "npm:^1.3.4" + proto-list: "npm:~1.2.1" + checksum: 10c0/39d1df18739d7088736cc75695e98d7087aea43646351b028dfabd5508d79cf6ef4c5bcd90471f52cd87ae470d1c5490c0a8c1a292fbe6ee9ff688061ea0963e languageName: node linkType: hard @@ -4033,56 +3877,20 @@ __metadata: languageName: node linkType: hard -"cookiejar@npm:^2.1.1": - version: 2.1.4 - resolution: "cookiejar@npm:2.1.4" - checksum: 10c0/2dae55611c6e1678f34d93984cbd4bda58f4fe3e5247cc4993f4a305cd19c913bbaf325086ed952e892108115073a747596453d3dc1c34947f47f731818b8ad1 - languageName: node - linkType: hard - -"core-util-is@npm:1.0.2": - version: 1.0.2 - resolution: "core-util-is@npm:1.0.2" - checksum: 10c0/980a37a93956d0de8a828ce508f9b9e3317039d68922ca79995421944146700e4aaf490a6dbfebcb1c5292a7184600c7710b957d724be1e37b8254c6bc0fe246 - languageName: node - linkType: hard - -"core-util-is@npm:~1.0.0": - version: 1.0.3 - resolution: "core-util-is@npm:1.0.3" - checksum: 10c0/90a0e40abbddfd7618f8ccd63a74d88deea94e77d0e8dbbea059fa7ebebb8fbb4e2909667fe26f3a467073de1a542ebe6ae4c73a73745ac5833786759cd906c9 - languageName: node - linkType: hard - -"cors@npm:^2.8.1": - version: 2.8.5 - resolution: "cors@npm:2.8.5" - dependencies: - object-assign: "npm:^4" - vary: "npm:^1" - checksum: 10c0/373702b7999409922da80de4a61938aabba6929aea5b6fd9096fefb9e8342f626c0ebd7507b0e8b0b311380744cc985f27edebc0a26e0ddb784b54e1085de761 - languageName: node - linkType: hard - -"cosmiconfig@npm:^5.0.7": - version: 5.2.1 - resolution: "cosmiconfig@npm:5.2.1" - dependencies: - import-fresh: "npm:^2.0.0" - is-directory: "npm:^0.3.1" - js-yaml: "npm:^3.13.1" - parse-json: "npm:^4.0.0" - checksum: 10c0/ae9ba309cdbb42d0c9d63dad5c1dfa1c56bb8f818cb8633eea14fd2dbdc9f33393b77658ba96fdabda497bc943afed8c3371d1222afe613c518ba676fa624645 - languageName: node - linkType: hard - -"create-ecdh@npm:^4.0.0": - version: 4.0.4 - resolution: "create-ecdh@npm:4.0.4" +"cosmiconfig@npm:^8.0.0": + version: 8.3.6 + resolution: "cosmiconfig@npm:8.3.6" dependencies: - bn.js: "npm:^4.1.0" - elliptic: "npm:^6.5.3" - checksum: 10c0/77b11a51360fec9c3bce7a76288fc0deba4b9c838d5fb354b3e40c59194d23d66efe6355fd4b81df7580da0661e1334a235a2a5c040b7569ba97db428d466e7f + import-fresh: "npm:^3.3.0" + js-yaml: "npm:^4.1.0" + parse-json: "npm:^5.2.0" + path-type: "npm:^4.0.0" + peerDependencies: + typescript: ">=4.9.5" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/0382a9ed13208f8bfc22ca2f62b364855207dffdb73dc26e150ade78c3093f1cf56172df2dd460c8caf2afa91c0ed4ec8a88c62f8f9cd1cf423d26506aa8797a languageName: node linkType: hard @@ -4099,7 +3907,7 @@ __metadata: languageName: node linkType: hard -"create-hmac@npm:^1.1.0, create-hmac@npm:^1.1.4, create-hmac@npm:^1.1.7": +"create-hmac@npm:^1.1.4, create-hmac@npm:^1.1.7": version: 1.1.7 resolution: "create-hmac@npm:1.1.7" dependencies: @@ -4120,30 +3928,6 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^6.0.5": - version: 6.0.5 - resolution: "cross-spawn@npm:6.0.5" - dependencies: - nice-try: "npm:^1.0.4" - path-key: "npm:^2.0.1" - semver: "npm:^5.5.0" - shebang-command: "npm:^1.2.0" - which: "npm:^1.2.9" - checksum: 10c0/e05544722e9d7189b4292c66e42b7abeb21db0d07c91b785f4ae5fefceb1f89e626da2703744657b287e86dcd4af57b54567cef75159957ff7a8a761d9055012 - languageName: node - linkType: hard - -"cross-spawn@npm:^7.0.2": - version: 7.0.3 - resolution: "cross-spawn@npm:7.0.3" - dependencies: - path-key: "npm:^3.1.0" - shebang-command: "npm:^2.0.0" - which: "npm:^2.0.1" - checksum: 10c0/5738c312387081c98d69c98e105b6327b069197f864a60593245d64c8089c8a0a744e16349281210d56835bb9274130d825a78b2ad6853ca13cfbeffc0c31750 - languageName: node - linkType: hard - "cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" @@ -4162,94 +3946,7 @@ __metadata: languageName: node linkType: hard -"crypto-browserify@npm:3.12.0": - version: 3.12.0 - resolution: "crypto-browserify@npm:3.12.0" - dependencies: - browserify-cipher: "npm:^1.0.0" - browserify-sign: "npm:^4.0.0" - create-ecdh: "npm:^4.0.0" - create-hash: "npm:^1.1.0" - create-hmac: "npm:^1.1.0" - diffie-hellman: "npm:^5.0.0" - inherits: "npm:^2.0.1" - pbkdf2: "npm:^3.0.3" - public-encrypt: "npm:^4.0.0" - randombytes: "npm:^2.0.0" - randomfill: "npm:^1.0.3" - checksum: 10c0/0c20198886576050a6aa5ba6ae42f2b82778bfba1753d80c5e7a090836890dc372bdc780986b2568b4fb8ed2a91c958e61db1f0b6b1cc96af4bd03ffc298ba92 - languageName: node - linkType: hard - -"d@npm:1, d@npm:^1.0.1": - version: 1.0.1 - resolution: "d@npm:1.0.1" - dependencies: - es5-ext: "npm:^0.10.50" - type: "npm:^1.0.1" - checksum: 10c0/1fedcb3b956a461f64d86b94b347441beff5cef8910b6ac4ec509a2c67eeaa7093660a98b26601ac91f91260238add73bdf25867a9c0cb783774642bc4c1523f - languageName: node - linkType: hard - -"damerau-levenshtein@npm:^1.0.8": - version: 1.0.8 - resolution: "damerau-levenshtein@npm:1.0.8" - checksum: 10c0/4c2647e0f42acaee7d068756c1d396e296c3556f9c8314bac1ac63ffb236217ef0e7e58602b18bb2173deec7ec8e0cac8e27cccf8f5526666b4ff11a13ad54a3 - languageName: node - linkType: hard - -"dashdash@npm:^1.12.0": - version: 1.14.1 - resolution: "dashdash@npm:1.14.1" - dependencies: - assert-plus: "npm:^1.0.0" - checksum: 10c0/64589a15c5bd01fa41ff7007e0f2c6552c5ef2028075daa16b188a3721f4ba001841bf306dfc2eee6e2e6e7f76b38f5f17fb21fa847504192290ffa9e150118a - languageName: node - linkType: hard - -"data-view-buffer@npm:^1.0.2": - version: 1.0.2 - resolution: "data-view-buffer@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.3" - es-errors: "npm:^1.3.0" - is-data-view: "npm:^1.0.2" - checksum: 10c0/7986d40fc7979e9e6241f85db8d17060dd9a71bd53c894fa29d126061715e322a4cd47a00b0b8c710394854183d4120462b980b8554012acc1c0fa49df7ad38c - languageName: node - linkType: hard - -"data-view-byte-length@npm:^1.0.2": - version: 1.0.2 - resolution: "data-view-byte-length@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.3" - es-errors: "npm:^1.3.0" - is-data-view: "npm:^1.0.2" - checksum: 10c0/f8a4534b5c69384d95ac18137d381f18a5cfae1f0fc1df0ef6feef51ef0d568606d970b69e02ea186c6c0f0eac77fe4e6ad96fec2569cc86c3afcc7475068c55 - languageName: node - linkType: hard - -"data-view-byte-offset@npm:^1.0.1": - version: 1.0.1 - resolution: "data-view-byte-offset@npm:1.0.1" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - is-data-view: "npm:^1.0.1" - checksum: 10c0/fa7aa40078025b7810dcffc16df02c480573b7b53ef1205aa6a61533011005c1890e5ba17018c692ce7c900212b547262d33279fde801ad9843edc0863bf78c4 - languageName: node - linkType: hard - -"debug@npm:2.6.9, debug@npm:^2.2.0": - version: 2.6.9 - resolution: "debug@npm:2.6.9" - dependencies: - ms: "npm:2.0.0" - checksum: 10c0/121908fb839f7801180b69a7e218a40b5a0b718813b886b7d6bdb82001b931c938e2941d1e4450f33a1b1df1da653f5f7a0440c197f29fbf8a6e9d45ff6ef589 - languageName: node - linkType: hard - -"debug@npm:4, debug@npm:^4.0.1, debug@npm:^4.1.1, debug@npm:^4.3.2": +"debug@npm:4, debug@npm:^4.1.1, debug@npm:^4.3.2": version: 4.3.3 resolution: "debug@npm:4.3.3" dependencies: @@ -4261,25 +3958,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:=3.1.0": - version: 3.1.0 - resolution: "debug@npm:3.1.0" - dependencies: - ms: "npm:2.0.0" - checksum: 10c0/5bff34a352d7b2eaa31886eeaf2ee534b5461ec0548315b2f9f80bd1d2533cab7df1fa52e130ce27bc31c3945fbffb0fc72baacdceb274b95ce853db89254ea4 - languageName: node - linkType: hard - -"debug@npm:^3.1.0, debug@npm:^3.2.7": - version: 3.2.7 - resolution: "debug@npm:3.2.7" - dependencies: - ms: "npm:^2.1.1" - checksum: 10c0/37d96ae42cbc71c14844d2ae3ba55adf462ec89fd3a999459dec3833944cd999af6007ff29c780f1c61153bcaaf2c842d1e4ce1ec621e4fc4923244942e4a02a - languageName: node - linkType: hard - -"debug@npm:^4.3.1, debug@npm:^4.3.4, debug@npm:^4.3.5": +"debug@npm:^4.3.1, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.4.1, debug@npm:^4.4.3": version: 4.4.3 resolution: "debug@npm:4.4.3" dependencies: @@ -4298,82 +3977,12 @@ __metadata: languageName: node linkType: hard -"decode-uri-component@npm:^0.2.0": - version: 0.2.0 - resolution: "decode-uri-component@npm:0.2.0" - checksum: 10c0/dbc3c72e4a740703f76fb3f51e35bb81546aa3e8c7897e015b8bc289813d3044ad6eaa6048fbb43f6b7b34ef005527b7511da50399caa78b91ee39266a341822 - languageName: node - linkType: hard - -"decompress-response@npm:^3.2.0, decompress-response@npm:^3.3.0": - version: 3.3.0 - resolution: "decompress-response@npm:3.3.0" - dependencies: - mimic-response: "npm:^1.0.0" - checksum: 10c0/5ffaf1d744277fd51c68c94ddc3081cd011b10b7de06637cccc6ecba137d45304a09ba1a776dee1c47fccc60b4a056c4bc74468eeea798ff1f1fca0024b45c9d - languageName: node - linkType: hard - -"decompress-tar@npm:^4.0.0, decompress-tar@npm:^4.1.0, decompress-tar@npm:^4.1.1": - version: 4.1.1 - resolution: "decompress-tar@npm:4.1.1" - dependencies: - file-type: "npm:^5.2.0" - is-stream: "npm:^1.1.0" - tar-stream: "npm:^1.5.2" - checksum: 10c0/92d86c5dfe2a89f9b5db584668f8ed2a3107339083872c7f78b5f7d55222d954545e018c10346a50991542ad6d1406128bf1c97a24f023810993a1dcfb3c3f21 - languageName: node - linkType: hard - -"decompress-tarbz2@npm:^4.0.0": - version: 4.1.1 - resolution: "decompress-tarbz2@npm:4.1.1" - dependencies: - decompress-tar: "npm:^4.1.0" - file-type: "npm:^6.1.0" - is-stream: "npm:^1.1.0" - seek-bzip: "npm:^1.0.5" - unbzip2-stream: "npm:^1.0.9" - checksum: 10c0/d5ab2c2435a53f45da8348ffdb5ae0a3ff8fec55948b7890a1c55413de4d1e539a22978e7dcd8bd3561985878c9778253fe146cbdea429f04fa4529abb57c54e - languageName: node - linkType: hard - -"decompress-targz@npm:^4.0.0": - version: 4.1.1 - resolution: "decompress-targz@npm:4.1.1" - dependencies: - decompress-tar: "npm:^4.1.1" - file-type: "npm:^5.2.0" - is-stream: "npm:^1.1.0" - checksum: 10c0/42514fb2df6248c56b2b115494b7d1d046bc582e960354ba4faad5792f261782a61d17d9ef53845abe78c0f0ecafc195cb0754c00227fa0bd0642a1bfd8eafad - languageName: node - linkType: hard - -"decompress-unzip@npm:^4.0.1": - version: 4.0.1 - resolution: "decompress-unzip@npm:4.0.1" - dependencies: - file-type: "npm:^3.8.0" - get-stream: "npm:^2.2.0" - pify: "npm:^2.3.0" - yauzl: "npm:^2.4.2" - checksum: 10c0/896f88e1c23b59cdce022227a8910c06158bd4b296c21d61af7167bd50d00e9e4355b605bdbfd7ba75d46ad277d4f881cdd037aec7165a40ccd0ee4ef59443a8 - languageName: node - linkType: hard - -"decompress@npm:^4.0.0": - version: 4.2.1 - resolution: "decompress@npm:4.2.1" +"decompress-response@npm:^6.0.0": + version: 6.0.0 + resolution: "decompress-response@npm:6.0.0" dependencies: - decompress-tar: "npm:^4.0.0" - decompress-tarbz2: "npm:^4.0.0" - decompress-targz: "npm:^4.0.0" - decompress-unzip: "npm:^4.0.1" - graceful-fs: "npm:^4.1.10" - make-dir: "npm:^1.0.0" - pify: "npm:^2.3.0" - strip-dirs: "npm:^2.0.0" - checksum: 10c0/6730279fa206aad04a8338a88ab49c596034c502b2d5f23a28d0a28290b82d9217f9e60c8b5739805474ca842fc856e08e2d64ed759f2118c2bcabe42fa9eece + mimic-response: "npm:^3.1.0" + checksum: 10c0/bd89d23141b96d80577e70c54fb226b2f40e74a6817652b80a116d7befb8758261ad073a8895648a29cc0a5947021ab66705cb542fa9c143c82022b27c5b175e languageName: node linkType: hard @@ -4395,14 +4004,14 @@ __metadata: languageName: node linkType: hard -"deep-extend@npm:~0.6.0": +"deep-extend@npm:^0.6.0, deep-extend@npm:~0.6.0": version: 0.6.0 resolution: "deep-extend@npm:0.6.0" checksum: 10c0/1c6b0abcdb901e13a44c7d699116d3d4279fdb261983122a3783e7273844d5f2537dc2e1c454a23fcf645917f93fbf8d07101c1d03c015a87faa662755212566 languageName: node linkType: hard -"deep-is@npm:^0.1.3, deep-is@npm:~0.1.3": +"deep-is@npm:^0.1.3": version: 0.1.4 resolution: "deep-is@npm:0.1.4" checksum: 10c0/7f0ee496e0dff14a573dc6127f14c95061b448b87b995fc96c017ce0a1e66af1675e73f1d6064407975bc4ea6ab679497a29fff7b5b9c4e99cb10797c1ad0b4c @@ -4416,32 +4025,17 @@ __metadata: languageName: node linkType: hard -"defer-to-connect@npm:^1.0.1": - version: 1.1.3 - resolution: "defer-to-connect@npm:1.1.3" - checksum: 10c0/9feb161bd7d21836fdff31eba79c2b11b7aaf844be58faf727121f8b0d9c2e82b494560df0903f41b52dd75027dc7c9455c11b3739f3202b28ca92b56c8f960e - languageName: node - linkType: hard - -"define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.4": - version: 1.1.4 - resolution: "define-data-property@npm:1.1.4" - dependencies: - es-define-property: "npm:^1.0.0" - es-errors: "npm:^1.3.0" - gopd: "npm:^1.0.1" - checksum: 10c0/dea0606d1483eb9db8d930d4eac62ca0fa16738b0b3e07046cddfacf7d8c868bbe13fa0cb263eb91c7d0d527960dc3f2f2471a69ed7816210307f6744fe62e37 +"defer-to-connect@npm:^2.0.1": + version: 2.0.1 + resolution: "defer-to-connect@npm:2.0.1" + checksum: 10c0/625ce28e1b5ad10cf77057b9a6a727bf84780c17660f6644dab61dd34c23de3001f03cedc401f7d30a4ed9965c2e8a7336e220a329146f2cf85d4eddea429782 languageName: node linkType: hard -"define-properties@npm:^1.1.3, define-properties@npm:^1.2.1": - version: 1.2.1 - resolution: "define-properties@npm:1.2.1" - dependencies: - define-data-property: "npm:^1.0.1" - has-property-descriptors: "npm:^1.0.0" - object-keys: "npm:^1.1.1" - checksum: 10c0/88a152319ffe1396ccc6ded510a3896e77efac7a1bfbaa174a7b00414a1747377e0bb525d303794a47cf30e805c2ec84e575758512c6e44a993076d29fd4e6c3 +"define-lazy-prop@npm:^2.0.0": + version: 2.0.0 + resolution: "define-lazy-prop@npm:2.0.0" + checksum: 10c0/db6c63864a9d3b7dc9def55d52764968a5af296de87c1b2cc71d8be8142e445208071953649e0386a8cc37cfcf9a2067a47207f1eb9ff250c2a269658fdae422 languageName: node linkType: hard @@ -4452,20 +4046,6 @@ __metadata: languageName: node linkType: hard -"delimit-stream@npm:0.1.0": - version: 0.1.0 - resolution: "delimit-stream@npm:0.1.0" - checksum: 10c0/6c099043b2831e5c4d51a8639d402b1618b16e5ddb559f9d5568530aa8b3fd71090808c3666dece955525021b642fb7cd700aad98b666e79b2d7ec0aeb16296c - languageName: node - linkType: hard - -"depd@npm:2.0.0": - version: 2.0.0 - resolution: "depd@npm:2.0.0" - checksum: 10c0/58bd06ec20e19529b06f7ad07ddab60e504d9e0faca4bd23079fac2d279c3594334d736508dc350e06e510aba5e22e4594483b3a6562ce7c17dd797f4cc4ad2c - languageName: node - linkType: hard - "depd@npm:~1.1.2": version: 1.1.2 resolution: "depd@npm:1.1.2" @@ -4473,23 +4053,6 @@ __metadata: languageName: node linkType: hard -"des.js@npm:^1.0.0": - version: 1.0.1 - resolution: "des.js@npm:1.0.1" - dependencies: - inherits: "npm:^2.0.1" - minimalistic-assert: "npm:^1.0.0" - checksum: 10c0/69bf742d1c381e01d75151bdcaac71a18d251d7debfc9b6ae5ee4b4edaf39691ae203c5ec9173ba89aedb3ddc622cdff4fca065448c6c2afb1140d9fb826339d - languageName: node - linkType: hard - -"destroy@npm:1.2.0": - version: 1.2.0 - resolution: "destroy@npm:1.2.0" - checksum: 10c0/bd7633942f57418f5a3b80d5cb53898127bcf53e24cdf5d5f4396be471417671f0fee48a4ebe9a1e9defbde2a31280011af58a57e090ff822f589b443ed4e643 - languageName: node - linkType: hard - "diff@npm:^4.0.1": version: 4.0.2 resolution: "diff@npm:4.0.2" @@ -4504,108 +4067,27 @@ __metadata: languageName: node linkType: hard -"diffie-hellman@npm:^5.0.0": - version: 5.0.3 - resolution: "diffie-hellman@npm:5.0.3" - dependencies: - bn.js: "npm:^4.1.0" - miller-rabin: "npm:^4.0.0" - randombytes: "npm:^2.0.0" - checksum: 10c0/ce53ccafa9ca544b7fc29b08a626e23a9b6562efc2a98559a0c97b4718937cebaa9b5d7d0a05032cc9c1435e9b3c1532b9e9bf2e0ede868525922807ad6e1ecf - languageName: node - linkType: hard - -"dir-glob@npm:^3.0.1": - version: 3.0.1 - resolution: "dir-glob@npm:3.0.1" +"dunder-proto@npm:^1.0.1": + version: 1.0.1 + resolution: "dunder-proto@npm:1.0.1" dependencies: - path-type: "npm:^4.0.0" - checksum: 10c0/dcac00920a4d503e38bb64001acb19df4efc14536ada475725e12f52c16777afdee4db827f55f13a908ee7efc0cb282e2e3dbaeeb98c0993dd93d1802d3bf00c + call-bind-apply-helpers: "npm:^1.0.1" + es-errors: "npm:^1.3.0" + gopd: "npm:^1.2.0" + checksum: 10c0/199f2a0c1c16593ca0a145dbf76a962f8033ce3129f01284d48c45ed4e14fea9bbacd7b3610b6cdc33486cef20385ac054948fefc6272fcce645c09468f93031 languageName: node linkType: hard -"doctrine@npm:^2.1.0": - version: 2.1.0 - resolution: "doctrine@npm:2.1.0" - dependencies: - esutils: "npm:^2.0.2" - checksum: 10c0/b6416aaff1f380bf56c3b552f31fdf7a69b45689368deca72d28636f41c16bb28ec3ebc40ace97db4c1afc0ceeb8120e8492fe0046841c94c2933b2e30a7d5ac +"eastasianwidth@npm:^0.2.0": + version: 0.2.0 + resolution: "eastasianwidth@npm:0.2.0" + checksum: 10c0/26f364ebcdb6395f95124fda411f63137a4bfb5d3a06453f7f23dfe52502905bd84e0488172e0f9ec295fdc45f05c23d5d91baf16bd26f0fe9acd777a188dc39 languageName: node linkType: hard -"doctrine@npm:^3.0.0": - version: 3.0.0 - resolution: "doctrine@npm:3.0.0" - dependencies: - esutils: "npm:^2.0.2" - checksum: 10c0/c96bdccabe9d62ab6fea9399fdff04a66e6563c1d6fb3a3a063e8d53c3bb136ba63e84250bbf63d00086a769ad53aef92d2bd483f03f837fc97b71cbee6b2520 - languageName: node - linkType: hard - -"dom-walk@npm:^0.1.0": - version: 0.1.2 - resolution: "dom-walk@npm:0.1.2" - checksum: 10c0/4d2ad9062a9423d890f8577aa202b597a6b85f9489bdde656b9443901b8b322b289655c3affefc58ec2e41931e0828dfee0a1d2db6829a607d76def5901fc5a9 - languageName: node - linkType: hard - -"dunder-proto@npm:^1.0.0, dunder-proto@npm:^1.0.1": - version: 1.0.1 - resolution: "dunder-proto@npm:1.0.1" - dependencies: - call-bind-apply-helpers: "npm:^1.0.1" - es-errors: "npm:^1.3.0" - gopd: "npm:^1.2.0" - checksum: 10c0/199f2a0c1c16593ca0a145dbf76a962f8033ce3129f01284d48c45ed4e14fea9bbacd7b3610b6cdc33486cef20385ac054948fefc6272fcce645c09468f93031 - languageName: node - linkType: hard - -"duplexer3@npm:^0.1.4": - version: 0.1.5 - resolution: "duplexer3@npm:0.1.5" - checksum: 10c0/02195030d61c4d6a2a34eca71639f2ea5e05cb963490e5bd9527623c2ac7f50c33842a34d14777ea9cbfd9bc2be5a84065560b897d9fabb99346058a5b86ca98 - languageName: node - linkType: hard - -"eastasianwidth@npm:^0.2.0": - version: 0.2.0 - resolution: "eastasianwidth@npm:0.2.0" - checksum: 10c0/26f364ebcdb6395f95124fda411f63137a4bfb5d3a06453f7f23dfe52502905bd84e0488172e0f9ec295fdc45f05c23d5d91baf16bd26f0fe9acd777a188dc39 - languageName: node - linkType: hard - -"ecc-jsbn@npm:~0.1.1": - version: 0.1.2 - resolution: "ecc-jsbn@npm:0.1.2" - dependencies: - jsbn: "npm:~0.1.0" - safer-buffer: "npm:^2.1.0" - checksum: 10c0/6cf168bae1e2dad2e46561d9af9cbabfbf5ff592176ad4e9f0f41eaaf5fe5e10bb58147fe0a804de62b1ee9dad42c28810c88d652b21b6013c47ba8efa274ca1 - languageName: node - linkType: hard - -"ee-first@npm:1.1.1": - version: 1.1.1 - resolution: "ee-first@npm:1.1.1" - checksum: 10c0/b5bb125ee93161bc16bfe6e56c6b04de5ad2aa44234d8f644813cc95d861a6910903132b05093706de2b706599367c4130eb6d170f6b46895686b95f87d017b7 - languageName: node - linkType: hard - -"elliptic@npm:6.3.3": - version: 6.3.3 - resolution: "elliptic@npm:6.3.3" - dependencies: - bn.js: "npm:^4.4.0" - brorand: "npm:^1.0.1" - hash.js: "npm:^1.0.0" - inherits: "npm:^2.0.1" - checksum: 10c0/ee6a7db311def1b12a13aeac49522edea0084ff7dcb3de78d22bd69fd3fee87befb17269d3ac64e809dc8396eb229a3ca749a1b3fbb20b4d1d48d116eb50bd31 - languageName: node - linkType: hard - -"elliptic@npm:6.5.4, elliptic@npm:^6.4.0, elliptic@npm:^6.5.2, elliptic@npm:^6.5.3, elliptic@npm:^6.5.4": - version: 6.5.4 - resolution: "elliptic@npm:6.5.4" +"elliptic@npm:6.5.4, elliptic@npm:^6.5.4": + version: 6.5.4 + resolution: "elliptic@npm:6.5.4" dependencies: bn.js: "npm:^4.11.9" brorand: "npm:^1.1.0" @@ -4633,20 +4115,6 @@ __metadata: languageName: node linkType: hard -"emoji-regex@npm:^10.0.0": - version: 10.0.0 - resolution: "emoji-regex@npm:10.0.0" - checksum: 10c0/9fdfe2c4d5e74a61ca90776a848a1ecc0f177742d1cfe616a29c4690db89f2e39215f5e642aab675820402d0bc0756f2a6f31ef8b93755e6499ad670a7e58a7e - languageName: node - linkType: hard - -"emoji-regex@npm:^7.0.1": - version: 7.0.3 - resolution: "emoji-regex@npm:7.0.3" - checksum: 10c0/a8917d695c3a3384e4b7230a6a06fd2de6b3db3709116792e8b7b36ddbb3db4deb28ad3e983e70d4f2a1f9063b5dab9025e4e26e9ca08278da4fbb73e213743f - languageName: node - linkType: hard - "emoji-regex@npm:^8.0.0": version: 8.0.0 resolution: "emoji-regex@npm:8.0.0" @@ -4668,23 +4136,7 @@ __metadata: languageName: node linkType: hard -"encodeurl@npm:~1.0.2": - version: 1.0.2 - resolution: "encodeurl@npm:1.0.2" - checksum: 10c0/f6c2387379a9e7c1156c1c3d4f9cb7bb11cf16dd4c1682e1f6746512564b053df5781029b6061296832b59fb22f459dbe250386d217c2f6e203601abb2ee0bec - languageName: node - linkType: hard - -"end-of-stream@npm:^1.0.0, end-of-stream@npm:^1.1.0": - version: 1.4.4 - resolution: "end-of-stream@npm:1.4.4" - dependencies: - once: "npm:^1.4.0" - checksum: 10c0/870b423afb2d54bb8d243c63e07c170409d41e20b47eeef0727547aea5740bd6717aca45597a9f2745525667a6b804c1e7bede41f856818faee5806dd9ff3975 - languageName: node - linkType: hard - -"enquirer@npm:^2.3.0, enquirer@npm:^2.3.5, enquirer@npm:^2.3.6": +"enquirer@npm:^2.3.0, enquirer@npm:^2.3.6": version: 2.3.6 resolution: "enquirer@npm:2.3.6" dependencies: @@ -4709,69 +4161,7 @@ __metadata: languageName: node linkType: hard -"es-abstract@npm:^1.17.5, es-abstract@npm:^1.23.2, es-abstract@npm:^1.23.3, es-abstract@npm:^1.23.5, es-abstract@npm:^1.23.6, es-abstract@npm:^1.23.9, es-abstract@npm:^1.24.0": - version: 1.24.0 - resolution: "es-abstract@npm:1.24.0" - dependencies: - array-buffer-byte-length: "npm:^1.0.2" - arraybuffer.prototype.slice: "npm:^1.0.4" - available-typed-arrays: "npm:^1.0.7" - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.4" - data-view-buffer: "npm:^1.0.2" - data-view-byte-length: "npm:^1.0.2" - data-view-byte-offset: "npm:^1.0.1" - es-define-property: "npm:^1.0.1" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.1.1" - es-set-tostringtag: "npm:^2.1.0" - es-to-primitive: "npm:^1.3.0" - function.prototype.name: "npm:^1.1.8" - get-intrinsic: "npm:^1.3.0" - get-proto: "npm:^1.0.1" - get-symbol-description: "npm:^1.1.0" - globalthis: "npm:^1.0.4" - gopd: "npm:^1.2.0" - has-property-descriptors: "npm:^1.0.2" - has-proto: "npm:^1.2.0" - has-symbols: "npm:^1.1.0" - hasown: "npm:^2.0.2" - internal-slot: "npm:^1.1.0" - is-array-buffer: "npm:^3.0.5" - is-callable: "npm:^1.2.7" - is-data-view: "npm:^1.0.2" - is-negative-zero: "npm:^2.0.3" - is-regex: "npm:^1.2.1" - is-set: "npm:^2.0.3" - is-shared-array-buffer: "npm:^1.0.4" - is-string: "npm:^1.1.1" - is-typed-array: "npm:^1.1.15" - is-weakref: "npm:^1.1.1" - math-intrinsics: "npm:^1.1.0" - object-inspect: "npm:^1.13.4" - object-keys: "npm:^1.1.1" - object.assign: "npm:^4.1.7" - own-keys: "npm:^1.0.1" - regexp.prototype.flags: "npm:^1.5.4" - safe-array-concat: "npm:^1.1.3" - safe-push-apply: "npm:^1.0.0" - safe-regex-test: "npm:^1.1.0" - set-proto: "npm:^1.0.0" - stop-iteration-iterator: "npm:^1.1.0" - string.prototype.trim: "npm:^1.2.10" - string.prototype.trimend: "npm:^1.0.9" - string.prototype.trimstart: "npm:^1.0.8" - typed-array-buffer: "npm:^1.0.3" - typed-array-byte-length: "npm:^1.0.3" - typed-array-byte-offset: "npm:^1.0.4" - typed-array-length: "npm:^1.0.7" - unbox-primitive: "npm:^1.1.0" - which-typed-array: "npm:^1.1.19" - checksum: 10c0/b256e897be32df5d382786ce8cce29a1dd8c97efbab77a26609bd70f2ed29fbcfc7a31758cb07488d532e7ccccdfca76c1118f2afe5a424cdc05ca007867c318 - languageName: node - linkType: hard - -"es-define-property@npm:^1.0.0, es-define-property@npm:^1.0.1": +"es-define-property@npm:^1.0.1": version: 1.0.1 resolution: "es-define-property@npm:1.0.1" checksum: 10c0/3f54eb49c16c18707949ff25a1456728c883e81259f045003499efba399c08bad00deebf65cccde8c0e07908c1a225c9d472b7107e558f2a48e28d530e34527c @@ -4785,30 +4175,6 @@ __metadata: languageName: node linkType: hard -"es-iterator-helpers@npm:^1.2.1": - version: 1.2.1 - resolution: "es-iterator-helpers@npm:1.2.1" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.6" - es-errors: "npm:^1.3.0" - es-set-tostringtag: "npm:^2.0.3" - function-bind: "npm:^1.1.2" - get-intrinsic: "npm:^1.2.6" - globalthis: "npm:^1.0.4" - gopd: "npm:^1.2.0" - has-property-descriptors: "npm:^1.0.2" - has-proto: "npm:^1.2.0" - has-symbols: "npm:^1.1.0" - internal-slot: "npm:^1.1.0" - iterator.prototype: "npm:^1.1.4" - safe-array-concat: "npm:^1.1.3" - checksum: 10c0/97e3125ca472d82d8aceea11b790397648b52c26d8768ea1c1ee6309ef45a8755bb63225a43f3150c7591cffc17caf5752459f1e70d583b4184370a8f04ebd2f - languageName: node - linkType: hard - "es-object-atoms@npm:^1.0.0, es-object-atoms@npm:^1.1.1": version: 1.1.1 resolution: "es-object-atoms@npm:1.1.1" @@ -4818,7 +4184,7 @@ __metadata: languageName: node linkType: hard -"es-set-tostringtag@npm:^2.0.3, es-set-tostringtag@npm:^2.1.0": +"es-set-tostringtag@npm:^2.1.0": version: 2.1.0 resolution: "es-set-tostringtag@npm:2.1.0" dependencies: @@ -4830,58 +4196,6 @@ __metadata: languageName: node linkType: hard -"es-shim-unscopables@npm:^1.0.2, es-shim-unscopables@npm:^1.1.0": - version: 1.1.0 - resolution: "es-shim-unscopables@npm:1.1.0" - dependencies: - hasown: "npm:^2.0.2" - checksum: 10c0/1b9702c8a1823fc3ef39035a4e958802cf294dd21e917397c561d0b3e195f383b978359816b1732d02b255ccf63e1e4815da0065b95db8d7c992037be3bbbcdb - languageName: node - linkType: hard - -"es-to-primitive@npm:^1.3.0": - version: 1.3.0 - resolution: "es-to-primitive@npm:1.3.0" - dependencies: - is-callable: "npm:^1.2.7" - is-date-object: "npm:^1.0.5" - is-symbol: "npm:^1.0.4" - checksum: 10c0/c7e87467abb0b438639baa8139f701a06537d2b9bc758f23e8622c3b42fd0fdb5bde0f535686119e446dd9d5e4c0f238af4e14960f4771877cf818d023f6730b - languageName: node - linkType: hard - -"es5-ext@npm:^0.10.35, es5-ext@npm:^0.10.50": - version: 0.10.62 - resolution: "es5-ext@npm:0.10.62" - dependencies: - es6-iterator: "npm:^2.0.3" - es6-symbol: "npm:^3.1.3" - next-tick: "npm:^1.1.0" - checksum: 10c0/72dfbec5e4bce24754be9f2c2a1c67c01de3fe000103c115f52891f6a51f44a59674c40a1f6bd2390fcd43987746dccb76efafea91c7bb6295bdca8d63ba3db4 - languageName: node - linkType: hard - -"es6-iterator@npm:^2.0.3": - version: 2.0.3 - resolution: "es6-iterator@npm:2.0.3" - dependencies: - d: "npm:1" - es5-ext: "npm:^0.10.35" - es6-symbol: "npm:^3.1.1" - checksum: 10c0/91f20b799dba28fb05bf623c31857fc1524a0f1c444903beccaf8929ad196c8c9ded233e5ac7214fc63a92b3f25b64b7f2737fcca8b1f92d2d96cf3ac902f5d8 - languageName: node - linkType: hard - -"es6-symbol@npm:^3.1.1, es6-symbol@npm:^3.1.3": - version: 3.1.3 - resolution: "es6-symbol@npm:3.1.3" - dependencies: - d: "npm:^1.0.1" - ext: "npm:^1.1.2" - checksum: 10c0/22982f815f00df553a89f4fb74c5048fed85df598482b4bd38dbd173174247949c72982a7d7132a58b147525398400e5f182db59b0916cb49f1e245fb0e22233 - languageName: node - linkType: hard - "escalade@npm:^3.1.1": version: 3.1.1 resolution: "escalade@npm:3.1.1" @@ -4889,13 +4203,6 @@ __metadata: languageName: node linkType: hard -"escape-html@npm:~1.0.3": - version: 1.0.3 - resolution: "escape-html@npm:1.0.3" - checksum: 10c0/524c739d776b36c3d29fa08a22e03e8824e3b2fd57500e5e44ecf3cc4707c34c60f9ca0781c0e33d191f2991161504c295e98f68c78fe7baa6e57081ec6ac0a3 - languageName: node - linkType: hard - "escape-string-regexp@npm:^1.0.5": version: 1.0.5 resolution: "escape-string-regexp@npm:1.0.5" @@ -4910,390 +4217,188 @@ __metadata: languageName: node linkType: hard -"eslint-config-airbnb-base@npm:^14.2.1": - version: 14.2.1 - resolution: "eslint-config-airbnb-base@npm:14.2.1" - dependencies: - confusing-browser-globals: "npm:^1.0.10" - object.assign: "npm:^4.1.2" - object.entries: "npm:^1.1.2" - peerDependencies: - eslint: ^5.16.0 || ^6.8.0 || ^7.2.0 - eslint-plugin-import: ^2.22.1 - checksum: 10c0/960654ae93f085800850ba5d54d745e576fb1c9e1fe46d0a64086586a1a6a78753ce6990b46c5543c35ba00ba4aee9018e4d3d3307dba8a0bf864a6ac803de16 - languageName: node - linkType: hard - -"eslint-config-airbnb-typescript@npm:^14.0.0": - version: 14.0.2 - resolution: "eslint-config-airbnb-typescript@npm:14.0.2" +"eslint-import-context@npm:^0.1.8, eslint-import-context@npm:^0.1.9": + version: 0.1.9 + resolution: "eslint-import-context@npm:0.1.9" dependencies: - eslint-config-airbnb-base: "npm:^14.2.1" + get-tsconfig: "npm:^4.10.1" + stable-hash-x: "npm:^0.2.0" peerDependencies: - "@typescript-eslint/eslint-plugin": ^4.29.3 - "@typescript-eslint/parser": ^4.29.3 - checksum: 10c0/47182b3f95ea7d86fe1fa6dc9af5710667b323ff3b4071291598c1679e7001c6bb53c18c8d8557e0d8b43ee6a3c71b5e0129cc42da8544daa36b92e4ad48be7f + unrs-resolver: ^1.0.0 + peerDependenciesMeta: + unrs-resolver: + optional: true + checksum: 10c0/07851103443b70af681c5988e2702e681ff9b956e055e11d4bd9b2322847fa0d9e8da50c18fc7cb1165106b043f34fbd0384d7011c239465c4645c52132e56f3 languageName: node linkType: hard -"eslint-config-airbnb@npm:^18.2.1": - version: 18.2.1 - resolution: "eslint-config-airbnb@npm:18.2.1" +"eslint-import-resolver-typescript@npm:^4.4.5": + version: 4.4.5 + resolution: "eslint-import-resolver-typescript@npm:4.4.5" dependencies: - eslint-config-airbnb-base: "npm:^14.2.1" - object.assign: "npm:^4.1.2" - object.entries: "npm:^1.1.2" - peerDependencies: - eslint: ^5.16.0 || ^6.8.0 || ^7.2.0 - eslint-plugin-import: ^2.22.1 - eslint-plugin-jsx-a11y: ^6.4.1 - eslint-plugin-react: ^7.21.5 - eslint-plugin-react-hooks: ^4 || ^3 || ^2.3.0 || ^1.7.0 - checksum: 10c0/236ce3faf1c43079b441c8c5fe530d42f000d5abd9f5e55f0b7e559fcbe60f01b908a18977b0df6fdb9acd14961422fbf5e8c0734ffa380dea0dcd5dce78b8d2 - languageName: node - linkType: hard - -"eslint-config-prettier@npm:^8.3.0": - version: 8.10.2 - resolution: "eslint-config-prettier@npm:8.10.2" + debug: "npm:^4.4.1" + eslint-import-context: "npm:^0.1.8" + get-tsconfig: "npm:^4.10.1" + is-bun-module: "npm:^2.0.0" + stable-hash-x: "npm:^0.2.0" + tinyglobby: "npm:^0.2.14" + unrs-resolver: "npm:^1.7.11" peerDependencies: - eslint: ">=7.0.0" - bin: - eslint-config-prettier: bin/cli.js - checksum: 10c0/b5953cf7a86f685e1218b16707bf36643b525513d08495226a6820caccd8b7bfc6b9aa64ac7cb2415dbe2c1f7dc4995832148bdc53ad45777f75a8ded1073b29 - languageName: node - linkType: hard - -"eslint-import-resolver-node@npm:^0.3.9": - version: 0.3.9 - resolution: "eslint-import-resolver-node@npm:0.3.9" - dependencies: - debug: "npm:^3.2.7" - is-core-module: "npm:^2.13.0" - resolve: "npm:^1.22.4" - checksum: 10c0/0ea8a24a72328a51fd95aa8f660dcca74c1429806737cf10261ab90cfcaaf62fd1eff664b76a44270868e0a932711a81b250053942595bcd00a93b1c1575dd61 - languageName: node - linkType: hard - -"eslint-module-utils@npm:^2.12.1": - version: 2.12.1 - resolution: "eslint-module-utils@npm:2.12.1" - dependencies: - debug: "npm:^3.2.7" + eslint: "*" + eslint-plugin-import: "*" + eslint-plugin-import-x: "*" peerDependenciesMeta: - eslint: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: optional: true - checksum: 10c0/6f4efbe7a91ae49bf67b4ab3644cb60bc5bd7db4cb5521de1b65be0847ffd3fb6bce0dd68f0995e1b312d137f768e2a1f842ee26fe73621afa05f850628fdc40 + checksum: 10c0/15fa1c47dfc508deaef638d8f9b65eedfd4722c23c1b4e51391082daf4f23a75fc5e42ebcbc5ebcae8a3977f9aa204dd2574528ab0c27b678e582122f3c8cc02 languageName: node linkType: hard -"eslint-plugin-import@npm:^2.23.4": - version: 2.32.0 - resolution: "eslint-plugin-import@npm:2.32.0" +"eslint-plugin-import-x@npm:^4.17.1": + version: 4.17.1 + resolution: "eslint-plugin-import-x@npm:4.17.1" dependencies: - "@rtsao/scc": "npm:^1.1.0" - array-includes: "npm:^3.1.9" - array.prototype.findlastindex: "npm:^1.2.6" - array.prototype.flat: "npm:^1.3.3" - array.prototype.flatmap: "npm:^1.3.3" - debug: "npm:^3.2.7" - doctrine: "npm:^2.1.0" - eslint-import-resolver-node: "npm:^0.3.9" - eslint-module-utils: "npm:^2.12.1" - hasown: "npm:^2.0.2" - is-core-module: "npm:^2.16.1" + "@typescript-eslint/types": "npm:^8.56.0" + comment-parser: "npm:^1.4.1" + debug: "npm:^4.4.1" + eslint-import-context: "npm:^0.1.9" is-glob: "npm:^4.0.3" - minimatch: "npm:^3.1.2" - object.fromentries: "npm:^2.0.8" - object.groupby: "npm:^1.0.3" - object.values: "npm:^1.2.1" - semver: "npm:^6.3.1" - string.prototype.trimend: "npm:^1.0.9" - tsconfig-paths: "npm:^3.15.0" - peerDependencies: - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 - checksum: 10c0/bfb1b8fc8800398e62ddfefbf3638d185286edfed26dfe00875cc2846d954491b4f5112457831588b757fa789384e1ae585f812614c4797f0499fa234fd4a48b - languageName: node - linkType: hard - -"eslint-plugin-jsx-a11y@npm:^6.4.1": - version: 6.10.2 - resolution: "eslint-plugin-jsx-a11y@npm:6.10.2" - dependencies: - aria-query: "npm:^5.3.2" - array-includes: "npm:^3.1.8" - array.prototype.flatmap: "npm:^1.3.2" - ast-types-flow: "npm:^0.0.8" - axe-core: "npm:^4.10.0" - axobject-query: "npm:^4.1.0" - damerau-levenshtein: "npm:^1.0.8" - emoji-regex: "npm:^9.2.2" - hasown: "npm:^2.0.2" - jsx-ast-utils: "npm:^3.3.5" - language-tags: "npm:^1.0.9" - minimatch: "npm:^3.1.2" - object.fromentries: "npm:^2.0.8" - safe-regex-test: "npm:^1.0.3" - string.prototype.includes: "npm:^2.0.1" - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 - checksum: 10c0/d93354e03b0cf66f018d5c50964e074dffe4ddf1f9b535fa020d19c4ae45f89c1a16e9391ca61ac3b19f7042c751ac0d361a056a65cbd1de24718a53ff8daa6e - languageName: node - linkType: hard - -"eslint-plugin-prettier@npm:^4.0.0": - version: 4.2.5 - resolution: "eslint-plugin-prettier@npm:4.2.5" - dependencies: - prettier-linter-helpers: "npm:^1.0.0" + minimatch: "npm:^9.0.3 || ^10.1.2" + semver: "npm:^7.7.2" + stable-hash-x: "npm:^0.2.0" + unrs-resolver: "npm:^1.9.2" peerDependencies: - eslint: ">=7.28.0" - prettier: ">=2.0.0" + "@typescript-eslint/utils": ^8.56.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + eslint-import-resolver-node: "*" peerDependenciesMeta: - eslint-config-prettier: + "@typescript-eslint/utils": optional: true - checksum: 10c0/75b3cdc90328aacf4cc7fabc522e651bd8208d40634c9b2772274332a696548136dac4608b141863bc462500c5a8012fbc2495623f684f631ddb62c2f5bca0a3 - languageName: node - linkType: hard - -"eslint-plugin-react-hooks@npm:^4.2.0": - version: 4.6.2 - resolution: "eslint-plugin-react-hooks@npm:4.6.2" - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - checksum: 10c0/4844e58c929bc05157fb70ba1e462e34f1f4abcbc8dd5bbe5b04513d33e2699effb8bca668297976ceea8e7ebee4e8fc29b9af9d131bcef52886feaa2308b2cc - languageName: node - linkType: hard - -"eslint-plugin-react@npm:^7.25.2": - version: 7.37.5 - resolution: "eslint-plugin-react@npm:7.37.5" - dependencies: - array-includes: "npm:^3.1.8" - array.prototype.findlast: "npm:^1.2.5" - array.prototype.flatmap: "npm:^1.3.3" - array.prototype.tosorted: "npm:^1.1.4" - doctrine: "npm:^2.1.0" - es-iterator-helpers: "npm:^1.2.1" - estraverse: "npm:^5.3.0" - hasown: "npm:^2.0.2" - jsx-ast-utils: "npm:^2.4.1 || ^3.0.0" - minimatch: "npm:^3.1.2" - object.entries: "npm:^1.1.9" - object.fromentries: "npm:^2.0.8" - object.values: "npm:^1.2.1" - prop-types: "npm:^15.8.1" - resolve: "npm:^2.0.0-next.5" - semver: "npm:^6.3.1" - string.prototype.matchall: "npm:^4.0.12" - string.prototype.repeat: "npm:^1.0.0" - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - checksum: 10c0/c850bfd556291d4d9234f5ca38db1436924a1013627c8ab1853f77cac73ec19b020e861e6c7b783436a48b6ffcdfba4547598235a37ad4611b6739f65fd8ad57 + eslint-import-resolver-node: + optional: true + checksum: 10c0/4ea2ace22c3d805f2253063912211c438055f112ca9a2124df262311744975fc96443e4526fd80eef0acec7845a48fb6d1da444a4c4b0ff9786927fe2755f2a7 languageName: node linkType: hard -"eslint-scope@npm:^4.0.3": - version: 4.0.3 - resolution: "eslint-scope@npm:4.0.3" - dependencies: - esrecurse: "npm:^4.1.0" - estraverse: "npm:^4.1.1" - checksum: 10c0/a2a3fe5845938ce7cfd2e658c309a9bb27a7f9ce94f0cc447ed5f9fa95b16451556d7e1db4c8e5d2aaa02d02850f5346d23091bbe94f7097412ce846504b4dcc +"eslint-plugin-no-only-tests@npm:^3.4.0": + version: 3.4.0 + resolution: "eslint-plugin-no-only-tests@npm:3.4.0" + checksum: 10c0/7c2163ab71cce74bb276025463910ea760888290cc9a3fb3e8ed4058055fd69cc7c145beca2f809232488b62c331e17a7b9271a025ef462e87d706298fb6f87a languageName: node linkType: hard -"eslint-scope@npm:^5.1.1": - version: 5.1.1 - resolution: "eslint-scope@npm:5.1.1" +"eslint-scope@npm:^9.1.2": + version: 9.1.2 + resolution: "eslint-scope@npm:9.1.2" dependencies: + "@types/esrecurse": "npm:^4.3.1" + "@types/estree": "npm:^1.0.8" esrecurse: "npm:^4.3.0" - estraverse: "npm:^4.1.1" - checksum: 10c0/d30ef9dc1c1cbdece34db1539a4933fe3f9b14e1ffb27ecc85987902ee663ad7c9473bbd49a9a03195a373741e62e2f807c4938992e019b511993d163450e70a - languageName: node - linkType: hard - -"eslint-utils@npm:^1.3.1": - version: 1.4.3 - resolution: "eslint-utils@npm:1.4.3" - dependencies: - eslint-visitor-keys: "npm:^1.1.0" - checksum: 10c0/ba19a817177d5fc54ae89cd80ecc8bc24eefd640bd8b0db204f29dc79cf9621bb42d68bf31eae6c89ca1f52d748b6583214f57288f9a78d2bd368a2340abe41c - languageName: node - linkType: hard - -"eslint-utils@npm:^2.1.0": - version: 2.1.0 - resolution: "eslint-utils@npm:2.1.0" - dependencies: - eslint-visitor-keys: "npm:^1.1.0" - checksum: 10c0/69521c5d6569384b24093125d037ba238d3d6e54367f7143af9928f5286369e912c26cad5016d730c0ffb9797ac9e83831059d7f1d863f7dc84330eb02414611 - languageName: node - linkType: hard - -"eslint-utils@npm:^3.0.0": - version: 3.0.0 - resolution: "eslint-utils@npm:3.0.0" - dependencies: - eslint-visitor-keys: "npm:^2.0.0" - peerDependencies: - eslint: ">=5" - checksum: 10c0/45aa2b63667a8d9b474c98c28af908d0a592bed1a4568f3145cd49fb5d9510f545327ec95561625290313fe126e6d7bdfe3fdbdb6f432689fab6b9497d3bfb52 - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^1.0.0, eslint-visitor-keys@npm:^1.1.0, eslint-visitor-keys@npm:^1.3.0": - version: 1.3.0 - resolution: "eslint-visitor-keys@npm:1.3.0" - checksum: 10c0/10c91fdbbe36810dd4308e57f9a8bc7177188b2a70247e54e3af1fa05ebc66414ae6fd4ce3c6c6821591f43a556e9037bc6b071122e099b5f8b7d2f76df553e3 + estraverse: "npm:^5.2.0" + checksum: 10c0/9fb8bca5a73e5741efb6cec84467027b6cb6f4203ff9b43a938e272c5cd30800bde46a5c20dfd1609f840225f0b62b7673be391b20acadf8658ca9fa4729b3dd languageName: node linkType: hard -"eslint-visitor-keys@npm:^2.0.0": - version: 2.1.0 - resolution: "eslint-visitor-keys@npm:2.1.0" - checksum: 10c0/9f0e3a2db751d84067d15977ac4b4472efd6b303e369e6ff241a99feac04da758f46d5add022c33d06b53596038dbae4b4aceb27c7e68b8dfc1055b35e495787 +"eslint-visitor-keys@npm:^3.4.3": + version: 3.4.3 + resolution: "eslint-visitor-keys@npm:3.4.3" + checksum: 10c0/92708e882c0a5ffd88c23c0b404ac1628cf20104a108c745f240a13c332a11aac54f49a22d5762efbffc18ecbc9a580d1b7ad034bf5f3cc3307e5cbff2ec9820 languageName: node linkType: hard -"eslint@npm:^5.6.0": - version: 5.16.0 - resolution: "eslint@npm:5.16.0" - dependencies: - "@babel/code-frame": "npm:^7.0.0" - ajv: "npm:^6.9.1" - chalk: "npm:^2.1.0" - cross-spawn: "npm:^6.0.5" - debug: "npm:^4.0.1" - doctrine: "npm:^3.0.0" - eslint-scope: "npm:^4.0.3" - eslint-utils: "npm:^1.3.1" - eslint-visitor-keys: "npm:^1.0.0" - espree: "npm:^5.0.1" - esquery: "npm:^1.0.1" - esutils: "npm:^2.0.2" - file-entry-cache: "npm:^5.0.1" - functional-red-black-tree: "npm:^1.0.1" - glob: "npm:^7.1.2" - globals: "npm:^11.7.0" - ignore: "npm:^4.0.6" - import-fresh: "npm:^3.0.0" - imurmurhash: "npm:^0.1.4" - inquirer: "npm:^6.2.2" - js-yaml: "npm:^3.13.0" - json-stable-stringify-without-jsonify: "npm:^1.0.1" - levn: "npm:^0.3.0" - lodash: "npm:^4.17.11" - minimatch: "npm:^3.0.4" - mkdirp: "npm:^0.5.1" - natural-compare: "npm:^1.4.0" - optionator: "npm:^0.8.2" - path-is-inside: "npm:^1.0.2" - progress: "npm:^2.0.0" - regexpp: "npm:^2.0.1" - semver: "npm:^5.5.1" - strip-ansi: "npm:^4.0.0" - strip-json-comments: "npm:^2.0.1" - table: "npm:^5.2.3" - text-table: "npm:^0.2.0" - bin: - eslint: ./bin/eslint.js - checksum: 10c0/b80161becd85523ffabb185f1604844fb2fd4d58970dc1d49f47f1fa838ef894e89a221b743016e7b7a50c5d6203dfb2452155ff5e1b4d1e8c17e677260c43d8 +"eslint-visitor-keys@npm:^4.2.1": + version: 4.2.1 + resolution: "eslint-visitor-keys@npm:4.2.1" + checksum: 10c0/fcd43999199d6740db26c58dbe0c2594623e31ca307e616ac05153c9272f12f1364f5a0b1917a8e962268fdecc6f3622c1c2908b4fcc2e047a106fe6de69dc43 languageName: node linkType: hard -"eslint@npm:^7.32.0": - version: 7.32.0 - resolution: "eslint@npm:7.32.0" - dependencies: - "@babel/code-frame": "npm:7.12.11" - "@eslint/eslintrc": "npm:^0.4.3" - "@humanwhocodes/config-array": "npm:^0.5.0" - ajv: "npm:^6.10.0" - chalk: "npm:^4.0.0" - cross-spawn: "npm:^7.0.2" - debug: "npm:^4.0.1" - doctrine: "npm:^3.0.0" - enquirer: "npm:^2.3.5" +"eslint-visitor-keys@npm:^5.0.0, eslint-visitor-keys@npm:^5.0.1": + version: 5.0.1 + resolution: "eslint-visitor-keys@npm:5.0.1" + checksum: 10c0/16190bdf2cbae40a1109384c94450c526a79b0b9c3cb21e544256ed85ac48a4b84db66b74a6561d20fe6ab77447f150d711c2ad5ad74df4fcc133736bce99678 + languageName: node + linkType: hard + +"eslint@npm:^10.10.0": + version: 10.10.0 + resolution: "eslint@npm:10.10.0" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.8.0" + "@eslint-community/regexpp": "npm:^4.12.2" + "@eslint/config-array": "npm:^0.23.5" + "@eslint/config-helpers": "npm:^0.7.0" + "@eslint/core": "npm:^1.2.1" + "@eslint/plugin-kit": "npm:^0.7.3" + "@humanfs/node": "npm:^0.16.6" + "@humanwhocodes/module-importer": "npm:^1.0.1" + "@humanwhocodes/retry": "npm:^0.4.2" + "@types/estree": "npm:^1.0.6" + ajv: "npm:^6.14.0" + cross-spawn: "npm:^7.0.6" + debug: "npm:^4.3.2" escape-string-regexp: "npm:^4.0.0" - eslint-scope: "npm:^5.1.1" - eslint-utils: "npm:^2.1.0" - eslint-visitor-keys: "npm:^2.0.0" - espree: "npm:^7.3.1" - esquery: "npm:^1.4.0" + eslint-scope: "npm:^9.1.2" + eslint-visitor-keys: "npm:^5.0.1" + espree: "npm:^11.2.0" + esquery: "npm:^1.7.0" esutils: "npm:^2.0.2" fast-deep-equal: "npm:^3.1.3" - file-entry-cache: "npm:^6.0.1" - functional-red-black-tree: "npm:^1.0.1" - glob-parent: "npm:^5.1.2" - globals: "npm:^13.6.0" - ignore: "npm:^4.0.6" - import-fresh: "npm:^3.0.0" + file-entry-cache: "npm:11.1.5 || >11.1.6 <12" + find-up: "npm:^5.0.0" + glob-parent: "npm:^6.0.2" + ignore: "npm:^5.2.0" imurmurhash: "npm:^0.1.4" is-glob: "npm:^4.0.0" - js-yaml: "npm:^3.13.1" json-stable-stringify-without-jsonify: "npm:^1.0.1" - levn: "npm:^0.4.1" - lodash.merge: "npm:^4.6.2" - minimatch: "npm:^3.0.4" + minimatch: "npm:^10.2.5" natural-compare: "npm:^1.4.0" - optionator: "npm:^0.9.1" - progress: "npm:^2.0.0" - regexpp: "npm:^3.1.0" - semver: "npm:^7.2.1" - strip-ansi: "npm:^6.0.0" - strip-json-comments: "npm:^3.1.0" - table: "npm:^6.0.9" - text-table: "npm:^0.2.0" - v8-compile-cache: "npm:^2.0.3" + optionator: "npm:^0.9.3" + peerDependencies: + jiti: "*" + peerDependenciesMeta: + jiti: + optional: true bin: eslint: bin/eslint.js - checksum: 10c0/84409f7767556179cb11529f1215f335c7dfccf90419df6147f949f14c347a960c7b569e80ed84011a0b6d10da1ef5046edbbb9b11c3e59aa6696d5217092e93 + checksum: 10c0/ba583145305f088585f91c5dab6825492ec657614558e4610cffc94174cf800f456e39ec3cafd3eed73e04bd9a05794067ae33b553f1323e3e7c1157242409d2 languageName: node linkType: hard -"espree@npm:^5.0.1": - version: 5.0.1 - resolution: "espree@npm:5.0.1" +"espree@npm:^10.4.0": + version: 10.4.0 + resolution: "espree@npm:10.4.0" dependencies: - acorn: "npm:^6.0.7" - acorn-jsx: "npm:^5.0.0" - eslint-visitor-keys: "npm:^1.0.0" - checksum: 10c0/738d028bd1ccf0fa872bfd8b427bfc4a985624a5a240997ee2e7ea3f281f47c6ac71356e2f563d4807908f3c53a3370e75d3f81eddde55efd10e6ab0821ce968 + acorn: "npm:^8.15.0" + acorn-jsx: "npm:^5.3.2" + eslint-visitor-keys: "npm:^4.2.1" + checksum: 10c0/c63fe06131c26c8157b4083313cb02a9a54720a08e21543300e55288c40e06c3fc284bdecf108d3a1372c5934a0a88644c98714f38b6ae8ed272b40d9ea08d6b languageName: node linkType: hard -"espree@npm:^7.3.0, espree@npm:^7.3.1": - version: 7.3.1 - resolution: "espree@npm:7.3.1" +"espree@npm:^11.2.0": + version: 11.2.0 + resolution: "espree@npm:11.2.0" dependencies: - acorn: "npm:^7.4.0" - acorn-jsx: "npm:^5.3.1" - eslint-visitor-keys: "npm:^1.3.0" - checksum: 10c0/f4e81b903f03eaf0e6925cea20571632da427deb6e14ca37e481f72c11f36d7bb4945fe8a2ff15ab22d078d3cd93ee65355fa94de9c27485c356481775f25d85 - languageName: node - linkType: hard - -"esprima@npm:^4.0.0": - version: 4.0.1 - resolution: "esprima@npm:4.0.1" - bin: - esparse: ./bin/esparse.js - esvalidate: ./bin/esvalidate.js - checksum: 10c0/ad4bab9ead0808cf56501750fd9d3fb276f6b105f987707d059005d57e182d18a7c9ec7f3a01794ebddcca676773e42ca48a32d67a250c9d35e009ca613caba3 + acorn: "npm:^8.16.0" + acorn-jsx: "npm:^5.3.2" + eslint-visitor-keys: "npm:^5.0.1" + checksum: 10c0/cf87e18ffd9dc113eb8d16588e7757701bc10c9934a71cce8b89c2611d51672681a918307bd6b19ac3ccd0e7ba1cbccc2f815b36b52fa7e73097b251014c3d81 languageName: node linkType: hard -"esquery@npm:^1.0.1, esquery@npm:^1.4.0": - version: 1.4.0 - resolution: "esquery@npm:1.4.0" +"esquery@npm:^1.7.0": + version: 1.7.0 + resolution: "esquery@npm:1.7.0" dependencies: estraverse: "npm:^5.1.0" - checksum: 10c0/b9b18178d33c4335210c76e062de979dc38ee6b49deea12bff1b2315e6cfcca1fd7f8bc49f899720ad8ff25967ac95b5b182e81a8b7b59ff09dbd0d978c32f64 + checksum: 10c0/77d5173db450b66f3bc685d11af4c90cffeedb340f34a39af96d43509a335ce39c894fd79233df32d38f5e4e219fa0f7076f6ec90bae8320170ba082c0db4793 languageName: node linkType: hard -"esrecurse@npm:^4.1.0, esrecurse@npm:^4.3.0": +"esrecurse@npm:^4.3.0": version: 4.3.0 resolution: "esrecurse@npm:4.3.0" dependencies: @@ -5302,13 +4407,6 @@ __metadata: languageName: node linkType: hard -"estraverse@npm:^4.1.1": - version: 4.3.0 - resolution: "estraverse@npm:4.3.0" - checksum: 10c0/9cb46463ef8a8a4905d3708a652d60122a0c20bb58dec7e0e12ab0e7235123d74214fc0141d743c381813e1b992767e2708194f6f6e0f9fd00c1b4e0887b8b6d - languageName: node - linkType: hard - "estraverse@npm:^5.1.0, estraverse@npm:^5.2.0, estraverse@npm:^5.3.0": version: 5.3.0 resolution: "estraverse@npm:5.3.0" @@ -5323,57 +4421,6 @@ __metadata: languageName: node linkType: hard -"etag@npm:~1.8.1": - version: 1.8.1 - resolution: "etag@npm:1.8.1" - checksum: 10c0/12be11ef62fb9817314d790089a0a49fae4e1b50594135dcb8076312b7d7e470884b5100d249b28c18581b7fd52f8b485689ffae22a11ed9ec17377a33a08f84 - languageName: node - linkType: hard - -"eth-ens-namehash@npm:2.0.8": - version: 2.0.8 - resolution: "eth-ens-namehash@npm:2.0.8" - dependencies: - idna-uts46-hx: "npm:^2.3.1" - js-sha3: "npm:^0.5.7" - checksum: 10c0/b0b60e5bdc8b0fc5a5cdf6011d221f1fdae8a2ac80775fec3f2d61db62470e57a6fcd7455fc8b2af532c86e0946d6611077ae3e30c7afd331f686e3cd7cc0977 - languageName: node - linkType: hard - -"eth-lib@npm:0.2.7": - version: 0.2.7 - resolution: "eth-lib@npm:0.2.7" - dependencies: - bn.js: "npm:^4.11.6" - elliptic: "npm:^6.4.0" - xhr-request-promise: "npm:^0.1.2" - checksum: 10c0/d3b934b43f723c0413e2f0d798266376eb106884bf686db46e653a74cf44c5741b0e57aee0bd9e6b2ceee93ff49a300a91e5b816481b012ae29fa3edbe5f823a - languageName: node - linkType: hard - -"eth-lib@npm:^0.1.26": - version: 0.1.29 - resolution: "eth-lib@npm:0.1.29" - dependencies: - bn.js: "npm:^4.11.6" - elliptic: "npm:^6.4.0" - nano-json-stream-parser: "npm:^0.1.2" - servify: "npm:^0.1.12" - ws: "npm:^3.0.0" - xhr-request-promise: "npm:^0.1.2" - checksum: 10c0/8759dffa412dce728620413d5a9d063b175c33bded2a5749f48b4433b1751fbb0cf03c7dbe7081e77eb805c613a5e1aea6a3b11669128202150622d6cb98c37d - languageName: node - linkType: hard - -"ethereum-bloom-filters@npm:^1.0.6": - version: 1.0.10 - resolution: "ethereum-bloom-filters@npm:1.0.10" - dependencies: - js-sha3: "npm:^0.8.0" - checksum: 10c0/ae70b0b0b6d83beece65638a634818f0bd1d00d7a4447e17b83797f4d8db4c49491b57119c5ed081c008fb766bb8f230f3603187fd6649d58a8cf3b9aa91549c - languageName: node - linkType: hard - "ethereum-cryptography@npm:^0.1.3": version: 0.1.3 resolution: "ethereum-cryptography@npm:0.1.3" @@ -5421,125 +4468,86 @@ __metadata: languageName: node linkType: hard -"ethereumjs-common@npm:^1.3.2, ethereumjs-common@npm:^1.5.0": - version: 1.5.2 - resolution: "ethereumjs-common@npm:1.5.2" - checksum: 10c0/9b0802e830c6a07c835322ac6a2519840741740bf0831c5d1626714255a24133d8df021332ed22aa75d13eacfc5efdd51ee6032bfc8d8e3088e6ca3a5335ca69 +"ethereumjs-util@npm:^7.0.3": + version: 7.1.4 + resolution: "ethereumjs-util@npm:7.1.4" + dependencies: + "@types/bn.js": "npm:^5.1.0" + bn.js: "npm:^5.1.2" + create-hash: "npm:^1.1.2" + ethereum-cryptography: "npm:^0.1.3" + rlp: "npm:^2.2.4" + checksum: 10c0/33907f4010f5f91cec75e4bfa941b7c9f1d8290e7e1e24637b205d0560ae16d0f817b6b3b0b0e4e39e8ba65e631b7e265cae3bcaf6b616c9588b689daea1d030 languageName: node linkType: hard -"ethereumjs-tx@npm:^2.1.1": - version: 2.1.2 - resolution: "ethereumjs-tx@npm:2.1.2" - dependencies: - ethereumjs-common: "npm:^1.5.0" - ethereumjs-util: "npm:^6.0.0" - checksum: 10c0/286ea734a32ce376d947953f7838cfd509b55ded75a1c86a049775cf77bd02b45fde81e00e48b844f1b2eb59486c5087877b579f879b172cbb8a477d5f74c135 - languageName: node - linkType: hard - -"ethereumjs-util@npm:^6.0.0": - version: 6.2.1 - resolution: "ethereumjs-util@npm:6.2.1" - dependencies: - "@types/bn.js": "npm:^4.11.3" - bn.js: "npm:^4.11.0" - create-hash: "npm:^1.1.2" - elliptic: "npm:^6.5.2" - ethereum-cryptography: "npm:^0.1.3" - ethjs-util: "npm:0.1.6" - rlp: "npm:^2.2.3" - checksum: 10c0/64aa7e6d591a0b890eb147c5d81f80a6456e87b3056e6bbafb54dff63f6ae9e646406763e8bd546c3b0b0162d027aecb3844873e894681826b03e0298f57e7a4 - languageName: node - linkType: hard - -"ethereumjs-util@npm:^7.0.3": - version: 7.1.4 - resolution: "ethereumjs-util@npm:7.1.4" +"ethereumjs-util@npm:^7.1.4, ethereumjs-util@npm:^7.1.5": + version: 7.1.5 + resolution: "ethereumjs-util@npm:7.1.5" dependencies: "@types/bn.js": "npm:^5.1.0" bn.js: "npm:^5.1.2" create-hash: "npm:^1.1.2" ethereum-cryptography: "npm:^0.1.3" rlp: "npm:^2.2.4" - checksum: 10c0/33907f4010f5f91cec75e4bfa941b7c9f1d8290e7e1e24637b205d0560ae16d0f817b6b3b0b0e4e39e8ba65e631b7e265cae3bcaf6b616c9588b689daea1d030 + checksum: 10c0/8b9487f35ecaa078bf9af6858eba6855fc61c73cc2b90c8c37486fcf94faf4fc1c5cda9758e6769f9ef2658daedaf2c18b366312ac461f8c8a122b392e3041eb languageName: node linkType: hard -"ethers@npm:4.0.0-beta.3": - version: 4.0.0-beta.3 - resolution: "ethers@npm:4.0.0-beta.3" - dependencies: - "@types/node": "npm:^10.3.2" - aes-js: "npm:3.0.0" - bn.js: "npm:^4.4.0" - elliptic: "npm:6.3.3" - hash.js: "npm:1.1.3" - js-sha3: "npm:0.5.7" - scrypt-js: "npm:2.0.3" - setimmediate: "npm:1.0.4" - uuid: "npm:2.0.1" - xmlhttprequest: "npm:1.8.0" - checksum: 10c0/9f2c9474777678765179599fba03fa1cd08236227db3beb68d42c1b8a9a20c09c24be76c38bc8425c598d0627bc32515d4dd2dc89ece8bf100afb3894049287c +"ethers@npm:^5.7.0, ethers@npm:^5.7.2": + version: 5.8.0 + resolution: "ethers@npm:5.8.0" + dependencies: + "@ethersproject/abi": "npm:5.8.0" + "@ethersproject/abstract-provider": "npm:5.8.0" + "@ethersproject/abstract-signer": "npm:5.8.0" + "@ethersproject/address": "npm:5.8.0" + "@ethersproject/base64": "npm:5.8.0" + "@ethersproject/basex": "npm:5.8.0" + "@ethersproject/bignumber": "npm:5.8.0" + "@ethersproject/bytes": "npm:5.8.0" + "@ethersproject/constants": "npm:5.8.0" + "@ethersproject/contracts": "npm:5.8.0" + "@ethersproject/hash": "npm:5.8.0" + "@ethersproject/hdnode": "npm:5.8.0" + "@ethersproject/json-wallets": "npm:5.8.0" + "@ethersproject/keccak256": "npm:5.8.0" + "@ethersproject/logger": "npm:5.8.0" + "@ethersproject/networks": "npm:5.8.0" + "@ethersproject/pbkdf2": "npm:5.8.0" + "@ethersproject/properties": "npm:5.8.0" + "@ethersproject/providers": "npm:5.8.0" + "@ethersproject/random": "npm:5.8.0" + "@ethersproject/rlp": "npm:5.8.0" + "@ethersproject/sha2": "npm:5.8.0" + "@ethersproject/signing-key": "npm:5.8.0" + "@ethersproject/solidity": "npm:5.8.0" + "@ethersproject/strings": "npm:5.8.0" + "@ethersproject/transactions": "npm:5.8.0" + "@ethersproject/units": "npm:5.8.0" + "@ethersproject/wallet": "npm:5.8.0" + "@ethersproject/web": "npm:5.8.0" + "@ethersproject/wordlists": "npm:5.8.0" + checksum: 10c0/8f187bb6af3736fbafcb613d8fb5be31fe7667a1bae480dd0a4c31b597ed47e0693d552adcababcb05111da39a059fac22e44840ce1671b1cc972de22d6d85d9 + languageName: node + linkType: hard + +"ethers@npm:^6.17.0, ethers@npm:^6.8.1": + version: 6.17.0 + resolution: "ethers@npm:6.17.0" + dependencies: + "@adraffy/ens-normalize": "npm:1.11.1" + "@noble/curves": "npm:1.2.0" + "@noble/hashes": "npm:1.3.2" + "@types/node": "npm:22.7.5" + aes-js: "npm:4.0.0-beta.5" + tslib: "npm:2.7.0" + ws: "npm:8.21.0" + checksum: 10c0/0a75f3b4cedaaddb95ba31fecdfca04202735564e66512f202069dd1a11946e01c310a158e3a1299b994274e9d9fe11db10c6f7997222a28d79dfecb8f1fd162 languageName: node linkType: hard -"ethers@npm:^4.0.20": - version: 4.0.49 - resolution: "ethers@npm:4.0.49" - dependencies: - aes-js: "npm:3.0.0" - bn.js: "npm:^4.11.9" - elliptic: "npm:6.5.4" - hash.js: "npm:1.1.3" - js-sha3: "npm:0.5.7" - scrypt-js: "npm:2.0.4" - setimmediate: "npm:1.0.4" - uuid: "npm:2.0.1" - xmlhttprequest: "npm:1.8.0" - checksum: 10c0/c2d6e659faca917469f95c1384db6717ad56fd386183b220907ab4fd31c7b8f649ec5975679245a482c9cfb63f2f796c014d465a0538cc2525b0f7b701753002 - languageName: node - linkType: hard - -"ethers@npm:^5.5.3": - version: 5.5.3 - resolution: "ethers@npm:5.5.3" - dependencies: - "@ethersproject/abi": "npm:5.5.0" - "@ethersproject/abstract-provider": "npm:5.5.1" - "@ethersproject/abstract-signer": "npm:5.5.0" - "@ethersproject/address": "npm:5.5.0" - "@ethersproject/base64": "npm:5.5.0" - "@ethersproject/basex": "npm:5.5.0" - "@ethersproject/bignumber": "npm:5.5.0" - "@ethersproject/bytes": "npm:5.5.0" - "@ethersproject/constants": "npm:5.5.0" - "@ethersproject/contracts": "npm:5.5.0" - "@ethersproject/hash": "npm:5.5.0" - "@ethersproject/hdnode": "npm:5.5.0" - "@ethersproject/json-wallets": "npm:5.5.0" - "@ethersproject/keccak256": "npm:5.5.0" - "@ethersproject/logger": "npm:5.5.0" - "@ethersproject/networks": "npm:5.5.2" - "@ethersproject/pbkdf2": "npm:5.5.0" - "@ethersproject/properties": "npm:5.5.0" - "@ethersproject/providers": "npm:5.5.2" - "@ethersproject/random": "npm:5.5.1" - "@ethersproject/rlp": "npm:5.5.0" - "@ethersproject/sha2": "npm:5.5.0" - "@ethersproject/signing-key": "npm:5.5.0" - "@ethersproject/solidity": "npm:5.5.0" - "@ethersproject/strings": "npm:5.5.0" - "@ethersproject/transactions": "npm:5.5.0" - "@ethersproject/units": "npm:5.5.0" - "@ethersproject/wallet": "npm:5.5.0" - "@ethersproject/web": "npm:5.5.1" - "@ethersproject/wordlists": "npm:5.5.0" - checksum: 10c0/9ba7d7a06e536e7374ec0aa769dc8a9bb38b42c18a1a486d8e2f5bf04573b3cc5c9149c8467f17af16db14acfe86f04b20432b9afa4cf541108f1223552e65c9 - languageName: node - linkType: hard - -"ethers@npm:^5.6.8": +"ethers@npm:~5.7.0": version: 5.7.2 resolution: "ethers@npm:5.7.2" dependencies: @@ -5577,33 +4585,6 @@ __metadata: languageName: node linkType: hard -"ethjs-unit@npm:0.1.6": - version: 0.1.6 - resolution: "ethjs-unit@npm:0.1.6" - dependencies: - bn.js: "npm:4.11.6" - number-to-bn: "npm:1.7.0" - checksum: 10c0/0115ddeb4bc932026b9cd259f6eb020a45b38be62e3786526b70e4c5fb0254184bf6e8b7b3f0c8bb80d4d596a73893e386c02221faf203895db7cb9c29b37188 - languageName: node - linkType: hard - -"ethjs-util@npm:0.1.6": - version: 0.1.6 - resolution: "ethjs-util@npm:0.1.6" - dependencies: - is-hex-prefixed: "npm:1.0.0" - strip-hex-prefix: "npm:1.0.0" - checksum: 10c0/9b4d6268705fd0620e73a56d2fa7b8a7c6b9770b2cf7f8ffe3a9c46b8bd1c5a08fff3d1181bb18cf85cf12b6fdbb6dca6d9aff6506005f3f565e742f026e6339 - languageName: node - linkType: hard - -"eventemitter3@npm:3.1.2": - version: 3.1.2 - resolution: "eventemitter3@npm:3.1.2" - checksum: 10c0/c67262eccbf85848b7cc6d4abb6c6e34155e15686db2a01c57669fd0d44441a574a19d44d25948b442929e065774cbe5003d8e77eed47674fbf876ac77887793 - languageName: node - linkType: hard - "eventemitter3@npm:5.0.1": version: 5.0.1 resolution: "eventemitter3@npm:5.0.1" @@ -5611,7 +4592,7 @@ __metadata: languageName: node linkType: hard -"evp_bytestokey@npm:^1.0.0, evp_bytestokey@npm:^1.0.3": +"evp_bytestokey@npm:^1.0.3": version: 1.0.3 resolution: "evp_bytestokey@npm:1.0.3" dependencies: @@ -5629,86 +4610,6 @@ __metadata: languageName: node linkType: hard -"express@npm:^4.14.0": - version: 4.18.1 - resolution: "express@npm:4.18.1" - dependencies: - accepts: "npm:~1.3.8" - array-flatten: "npm:1.1.1" - body-parser: "npm:1.20.0" - content-disposition: "npm:0.5.4" - content-type: "npm:~1.0.4" - cookie: "npm:0.5.0" - cookie-signature: "npm:1.0.6" - debug: "npm:2.6.9" - depd: "npm:2.0.0" - encodeurl: "npm:~1.0.2" - escape-html: "npm:~1.0.3" - etag: "npm:~1.8.1" - finalhandler: "npm:1.2.0" - fresh: "npm:0.5.2" - http-errors: "npm:2.0.0" - merge-descriptors: "npm:1.0.1" - methods: "npm:~1.1.2" - on-finished: "npm:2.4.1" - parseurl: "npm:~1.3.3" - path-to-regexp: "npm:0.1.7" - proxy-addr: "npm:~2.0.7" - qs: "npm:6.10.3" - range-parser: "npm:~1.2.1" - safe-buffer: "npm:5.2.1" - send: "npm:0.18.0" - serve-static: "npm:1.15.0" - setprototypeof: "npm:1.2.0" - statuses: "npm:2.0.1" - type-is: "npm:~1.6.18" - utils-merge: "npm:1.0.1" - vary: "npm:~1.1.2" - checksum: 10c0/eeca44d91a73a8aa9101b36d1fb2dc7942d994a3ea471664daf35a42f2d498c3d43bb4e8541667d9b46d1773756d256bc5eed59632a1205773e40e468e60b6d3 - languageName: node - linkType: hard - -"ext@npm:^1.1.2": - version: 1.7.0 - resolution: "ext@npm:1.7.0" - dependencies: - type: "npm:^2.7.2" - checksum: 10c0/a8e5f34e12214e9eee3a4af3b5c9d05ba048f28996450975b369fc86e5d0ef13b6df0615f892f5396a9c65d616213c25ec5b0ad17ef42eac4a500512a19da6c7 - languageName: node - linkType: hard - -"extend@npm:~3.0.2": - version: 3.0.2 - resolution: "extend@npm:3.0.2" - checksum: 10c0/73bf6e27406e80aa3e85b0d1c4fd987261e628064e170ca781125c0b635a3dabad5e05adbf07595ea0cf1e6c5396cacb214af933da7cbaf24fe75ff14818e8f9 - languageName: node - linkType: hard - -"external-editor@npm:^3.0.3": - version: 3.1.0 - resolution: "external-editor@npm:3.1.0" - dependencies: - chardet: "npm:^0.7.0" - iconv-lite: "npm:^0.4.24" - tmp: "npm:^0.0.33" - checksum: 10c0/c98f1ba3efdfa3c561db4447ff366a6adb5c1e2581462522c56a18bf90dfe4da382f9cd1feee3e330108c3595a854b218272539f311ba1b3298f841eb0fbf339 - languageName: node - linkType: hard - -"extsprintf@npm:1.3.0": - version: 1.3.0 - resolution: "extsprintf@npm:1.3.0" - checksum: 10c0/f75114a8388f0cbce68e277b6495dc3930db4dde1611072e4a140c24e204affd77320d004b947a132e9a3b97b8253017b2b62dce661975fb0adced707abf1ab5 - languageName: node - linkType: hard - -"extsprintf@npm:^1.2.0": - version: 1.4.1 - resolution: "extsprintf@npm:1.4.1" - checksum: 10c0/e10e2769985d0e9b6c7199b053a9957589d02e84de42832c295798cb422a025e6d4a92e0259c1fb4d07090f5bfde6b55fd9f880ac5855bd61d775f8ab75a7ab0 - languageName: node - linkType: hard - "fast-base64-decode@npm:^1.0.0": version: 1.0.0 resolution: "fast-base64-decode@npm:1.0.0" @@ -5723,23 +4624,10 @@ __metadata: languageName: node linkType: hard -"fast-diff@npm:^1.1.2": - version: 1.2.0 - resolution: "fast-diff@npm:1.2.0" - checksum: 10c0/2fbcb23957fb0bc920832a94ba627b860400f9cce45e1594e931dabf62e858369a58c6c2603e2ecc4f7679580f710b5b5b6e698a355a9a9bfcfd93c06c7c4350 - languageName: node - linkType: hard - -"fast-glob@npm:^3.2.9": - version: 3.3.3 - resolution: "fast-glob@npm:3.3.3" - dependencies: - "@nodelib/fs.stat": "npm:^2.0.2" - "@nodelib/fs.walk": "npm:^1.2.3" - glob-parent: "npm:^5.1.2" - merge2: "npm:^1.3.0" - micromatch: "npm:^4.0.8" - checksum: 10c0/f6aaa141d0d3384cf73cbcdfc52f475ed293f6d5b65bfc5def368b09163a9f7e5ec2b3014d80f733c405f58e470ee0cc451c2937685045cddcdeaa24199c43fe +"fast-diff@npm:^1.2.0": + version: 1.3.0 + resolution: "fast-diff@npm:1.3.0" + checksum: 10c0/5c19af237edb5d5effda008c891a18a585f74bf12953be57923f17a3a4d0979565fc64dbc73b9e20926b9d895f5b690c618cbb969af0cf022e3222471220ad29 languageName: node linkType: hard @@ -5750,28 +4638,17 @@ __metadata: languageName: node linkType: hard -"fast-levenshtein@npm:^2.0.6, fast-levenshtein@npm:~2.0.6": +"fast-levenshtein@npm:^2.0.6": version: 2.0.6 resolution: "fast-levenshtein@npm:2.0.6" checksum: 10c0/111972b37338bcb88f7d9e2c5907862c280ebf4234433b95bc611e518d192ccb2d38119c4ac86e26b668d75f7f3894f4ff5c4982899afced7ca78633b08287c4 languageName: node linkType: hard -"fastq@npm:^1.6.0": - version: 1.19.1 - resolution: "fastq@npm:1.19.1" - dependencies: - reusify: "npm:^1.0.4" - checksum: 10c0/ebc6e50ac7048daaeb8e64522a1ea7a26e92b3cee5cd1c7f2316cdca81ba543aa40a136b53891446ea5c3a67ec215fbaca87ad405f102dd97012f62916905630 - languageName: node - linkType: hard - -"fd-slicer@npm:~1.1.0": - version: 1.1.0 - resolution: "fd-slicer@npm:1.1.0" - dependencies: - pend: "npm:~1.2.0" - checksum: 10c0/304dd70270298e3ffe3bcc05e6f7ade2511acc278bc52d025f8918b48b6aa3b77f10361bddfadfe2a28163f7af7adbdce96f4d22c31b2f648ba2901f0c5fc20e +"fast-uri@npm:^3.0.1": + version: 3.1.7 + resolution: "fast-uri@npm:3.1.7" + checksum: 10c0/ca2baa4bde48fc7322bdc692c6636975943ebe4f6dd97e07d70b14e0ab85af2ff30de90f550f5ec2956684fe208e150d85d6cb5f3c74438c8ac1bf86bd435c13 languageName: node linkType: hard @@ -5787,51 +4664,12 @@ __metadata: languageName: node linkType: hard -"figures@npm:^2.0.0": - version: 2.0.0 - resolution: "figures@npm:2.0.0" - dependencies: - escape-string-regexp: "npm:^1.0.5" - checksum: 10c0/5dc5a75fec3e7e04ae65d6ce51d28b3e70d4656c51b06996b6fdb2cb5b542df512e3b3c04482f5193a964edddafa5521479ff948fa84e12ff556e53e094ab4ce - languageName: node - linkType: hard - -"file-entry-cache@npm:^5.0.1": - version: 5.0.1 - resolution: "file-entry-cache@npm:5.0.1" - dependencies: - flat-cache: "npm:^2.0.1" - checksum: 10c0/2480fb523a0342b8ede8b17717517f69ce6b775083d06e50e2e10ca45f16c94f1d4d95976ae627735716174033374a2d6717ba4b58569e1fea8564a1b1f2e4c1 - languageName: node - linkType: hard - -"file-entry-cache@npm:^6.0.1": - version: 6.0.1 - resolution: "file-entry-cache@npm:6.0.1" +"file-entry-cache@npm:11.1.5 || >11.1.6 <12": + version: 11.1.5 + resolution: "file-entry-cache@npm:11.1.5" dependencies: - flat-cache: "npm:^3.0.4" - checksum: 10c0/58473e8a82794d01b38e5e435f6feaf648e3f36fdb3a56e98f417f4efae71ad1c0d4ebd8a9a7c50c3ad085820a93fc7494ad721e0e4ebc1da3573f4e1c3c7cdd - languageName: node - linkType: hard - -"file-type@npm:^3.8.0": - version: 3.9.0 - resolution: "file-type@npm:3.9.0" - checksum: 10c0/7ae074b350c2300807a99d428600a8ee6b2ace901400898706a20ddc2c43c9abb7e05177ff55ed67a2fd26dfa9b91857b21ec9c0ab3202b9cabebc7e65900240 - languageName: node - linkType: hard - -"file-type@npm:^5.2.0": - version: 5.2.0 - resolution: "file-type@npm:5.2.0" - checksum: 10c0/c16c2f4e484a838c12b63e08637277905f08aebb1afbc291086029210aea17ded5ed701c9a4588313446ae0c1da71566b58df9a9c758a1ec300c4f80b9713cbf - languageName: node - linkType: hard - -"file-type@npm:^6.1.0": - version: 6.2.0 - resolution: "file-type@npm:6.2.0" - checksum: 10c0/3d7fe85a10bd97ca0c35fd9a20d21f5b20849bbb70985d37c34475051433f3c6109c76a3e5893bff6773037b769be9730a2db762789ecf25def9b62a4c2ee953 + flat-cache: "npm:^6.1.23" + checksum: 10c0/d05eca8794b27824d79a0f1a0bc76b81ca7232b6c9634bc086f365a6d9ddac749c4826b2b2d36bb7ef9ed84fdf0097f34979527daeb9255b4f17673a4ae50fc5 languageName: node linkType: hard @@ -5844,21 +4682,6 @@ __metadata: languageName: node linkType: hard -"finalhandler@npm:1.2.0": - version: 1.2.0 - resolution: "finalhandler@npm:1.2.0" - dependencies: - debug: "npm:2.6.9" - encodeurl: "npm:~1.0.2" - escape-html: "npm:~1.0.3" - on-finished: "npm:2.4.1" - parseurl: "npm:~1.3.3" - statuses: "npm:2.0.1" - unpipe: "npm:~1.0.0" - checksum: 10c0/64b7e5ff2ad1fcb14931cd012651631b721ce657da24aedb5650ddde9378bf8e95daa451da43398123f5de161a81e79ff5affe4f9f2a6d2df4a813d6d3e254b7 - languageName: node - linkType: hard - "find-replace@npm:^3.0.0": version: 3.0.0 resolution: "find-replace@npm:3.0.0" @@ -5868,15 +4691,6 @@ __metadata: languageName: node linkType: hard -"find-up@npm:^2.1.0": - version: 2.1.0 - resolution: "find-up@npm:2.1.0" - dependencies: - locate-path: "npm:^2.0.0" - checksum: 10c0/c080875c9fe28eb1962f35cbe83c683796a0321899f1eed31a37577800055539815de13d53495049697d3ba313013344f843bb9401dd337a1b832be5edfc6840 - languageName: node - linkType: hard - "find-up@npm:^5.0.0": version: 5.0.0 resolution: "find-up@npm:5.0.0" @@ -5887,24 +4701,14 @@ __metadata: languageName: node linkType: hard -"flat-cache@npm:^2.0.1": - version: 2.0.1 - resolution: "flat-cache@npm:2.0.1" - dependencies: - flatted: "npm:^2.0.0" - rimraf: "npm:2.6.3" - write: "npm:1.0.3" - checksum: 10c0/09e4d2300d05734eb2ac39ea0bb9cc6d64c0c856f6b77d2bdc7734490b4a8f860d721f59ffd5508f6938c577f8394fe7b5f6acf99a5ec4af6478d7c5c8390bcb - languageName: node - linkType: hard - -"flat-cache@npm:^3.0.4": - version: 3.0.4 - resolution: "flat-cache@npm:3.0.4" +"flat-cache@npm:^6.1.23": + version: 6.1.23 + resolution: "flat-cache@npm:6.1.23" dependencies: - flatted: "npm:^3.1.0" - rimraf: "npm:^3.0.2" - checksum: 10c0/f274dcbadb09ad8d7b6edf2ee9b034bc40bf0c12638f6c4084e9f1d39208cb104a5ebbb24b398880ef048200eaa116852f73d2d8b72e8c9627aba8c3e27ca057 + cacheable: "npm:^2.5.0" + flatted: "npm:^3.4.2" + hookified: "npm:^1.15.0" + checksum: 10c0/c757c24f51334e1917958cd9d62d4ed3d520a3815d5a1ec50d993ac3a93fa81b6de7e28264231914bb0d990babd426e4d713d3e2f3d782dae65c42a2ded1e651 languageName: node linkType: hard @@ -5917,17 +4721,10 @@ __metadata: languageName: node linkType: hard -"flatted@npm:^2.0.0": - version: 2.0.2 - resolution: "flatted@npm:2.0.2" - checksum: 10c0/1895ac3971c3a71b0384c6d8b8ef1f217dfe7e72bc7dabc51ef532772b761e626dd7cae53a729b9e65389409d7f03fd84f1900bde4f9e719ed04e57e8510e0d4 - languageName: node - linkType: hard - -"flatted@npm:^3.1.0": - version: 3.2.4 - resolution: "flatted@npm:3.2.4" - checksum: 10c0/c07ea1049868202cfb91570832fd3b549cfa3e5b5fdf9c03c7c6ad73277eef17c7e01c0491e1fa7301bb968c9b3061a6286a8bd94c192fd70c8f36c44c02395d +"flatted@npm:^3.4.2": + version: 3.4.4 + resolution: "flatted@npm:3.4.4" + checksum: 10c0/a3a52a88ea5a4c333e5a1f097dcd87a037fa31c236a77cf46222c2aa4036ef895ab9bc76138a66d9dc22bdb3652128f9598cd26e7439561bf19f67276e2bc37e languageName: node linkType: hard @@ -5940,16 +4737,7 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:1.5.10": - version: 1.5.10 - resolution: "follow-redirects@npm:1.5.10" - dependencies: - debug: "npm:=3.1.0" - checksum: 10c0/f56ca26dcf3c9996a6cf8868b61e369a35d4000ade0292bdd27b5e0934902681b037060b9fabe58e7042bb8b85166d5db8bbcf027f1825c1577e4cffd904fd3f - languageName: node - linkType: hard - -"follow-redirects@npm:^1.12.1, follow-redirects@npm:^1.14.0": +"follow-redirects@npm:^1.12.1": version: 1.14.7 resolution: "follow-redirects@npm:1.14.7" peerDependenciesMeta: @@ -5959,16 +4747,6 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.15.6": - version: 1.15.9 - resolution: "follow-redirects@npm:1.15.9" - peerDependenciesMeta: - debug: - optional: true - checksum: 10c0/5829165bd112c3c0e82be6c15b1a58fa9dcfaede3b3c54697a82fe4a62dd5ae5e8222956b448d2f98e331525f05d00404aba7d696de9e761ef6e42fdc780244f - languageName: node - linkType: hard - "follow-redirects@npm:^1.16.0": version: 1.16.0 resolution: "follow-redirects@npm:1.16.0" @@ -5979,15 +4757,6 @@ __metadata: languageName: node linkType: hard -"for-each@npm:^0.3.3, for-each@npm:^0.3.5": - version: 0.3.5 - resolution: "for-each@npm:0.3.5" - dependencies: - is-callable: "npm:^1.2.7" - checksum: 10c0/0e0b50f6a843a282637d43674d1fb278dda1dd85f4f99b640024cfb10b85058aac0cc781bf689d5fe50b4b7f638e91e548560723a4e76e04fe96ae35ef039cee - languageName: node - linkType: hard - "foreground-child@npm:^3.1.0": version: 3.3.1 resolution: "foreground-child@npm:3.3.1" @@ -5998,10 +4767,10 @@ __metadata: languageName: node linkType: hard -"forever-agent@npm:~0.6.1": - version: 0.6.1 - resolution: "forever-agent@npm:0.6.1" - checksum: 10c0/364f7f5f7d93ab661455351ce116a67877b66f59aca199559a999bd39e3cfadbfbfacc10415a915255e2210b30c23febe9aec3ca16bf2d1ff11c935a1000e24c +"form-data-encoder@npm:^2.1.2": + version: 2.1.4 + resolution: "form-data-encoder@npm:2.1.4" + checksum: 10c0/4c06ae2b79ad693a59938dc49ebd020ecb58e4584860a90a230f80a68b026483b022ba5e4143cff06ae5ac8fd446a0b500fabc87bbac3d1f62f2757f8dabcaf7 languageName: node linkType: hard @@ -6016,7 +4785,7 @@ __metadata: languageName: node linkType: hard -"form-data@npm:^4.0.5": +"form-data@npm:^4.0.6": version: 4.0.6 resolution: "form-data@npm:4.0.6" dependencies: @@ -6029,24 +4798,6 @@ __metadata: languageName: node linkType: hard -"form-data@npm:~2.3.2": - version: 2.3.3 - resolution: "form-data@npm:2.3.3" - dependencies: - asynckit: "npm:^0.4.0" - combined-stream: "npm:^1.0.6" - mime-types: "npm:^2.1.12" - checksum: 10c0/706ef1e5649286b6a61e5bb87993a9842807fd8f149cd2548ee807ea4fb882247bdf7f6e64ac4720029c0cd5c80343de0e22eee1dc9e9882e12db9cc7bc016a4 - languageName: node - linkType: hard - -"forwarded@npm:0.2.0": - version: 0.2.0 - resolution: "forwarded@npm:0.2.0" - checksum: 10c0/9b67c3fac86acdbc9ae47ba1ddd5f2f81526fa4c8226863ede5600a3f7c7416ef451f6f1e240a3cc32d0fd79fcfe6beb08fd0da454f360032bde70bf80afbb33 - languageName: node - linkType: hard - "fp-ts@npm:1.19.3": version: 1.19.3 resolution: "fp-ts@npm:1.19.3" @@ -6061,20 +4812,6 @@ __metadata: languageName: node linkType: hard -"fresh@npm:0.5.2": - version: 0.5.2 - resolution: "fresh@npm:0.5.2" - checksum: 10c0/c6d27f3ed86cc5b601404822f31c900dd165ba63fff8152a3ef714e2012e7535027063bc67ded4cb5b3a49fa596495d46cacd9f47d6328459cf570f08b7d9e5a - languageName: node - linkType: hard - -"fs-constants@npm:^1.0.0": - version: 1.0.0 - resolution: "fs-constants@npm:1.0.0" - checksum: 10c0/a0cde99085f0872f4d244e83e03a46aa387b74f5a5af750896c6b05e9077fac00e9932fdf5aef84f2f16634cd473c63037d7a512576da7d5c2b9163d1909f3a8 - languageName: node - linkType: hard - "fs-extra@npm:^10.0.0": version: 10.0.0 resolution: "fs-extra@npm:10.0.0" @@ -6086,25 +4823,25 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^11.2.0": - version: 11.3.4 - resolution: "fs-extra@npm:11.3.4" +"fs-extra@npm:^10.1.0": + version: 10.1.0 + resolution: "fs-extra@npm:10.1.0" dependencies: graceful-fs: "npm:^4.2.0" jsonfile: "npm:^6.0.1" universalify: "npm:^2.0.0" - checksum: 10c0/e08276f767a62496ae97d711aaa692c6a478177f24a85979b6a2881c9db9c68b8c2ad5da0bcf92c0b2a474cea6e935ec245656441527958fd8372cb647087df0 + checksum: 10c0/5f579466e7109719d162a9249abbeffe7f426eb133ea486e020b89bc6d67a741134076bf439983f2eb79276ceaf6bd7b7c1e43c3fd67fe889863e69072fb0a5e languageName: node linkType: hard -"fs-extra@npm:^4.0.2": - version: 4.0.3 - resolution: "fs-extra@npm:4.0.3" +"fs-extra@npm:^11.2.0": + version: 11.3.4 + resolution: "fs-extra@npm:11.3.4" dependencies: - graceful-fs: "npm:^4.1.2" - jsonfile: "npm:^4.0.0" - universalify: "npm:^0.1.0" - checksum: 10c0/b34344de77adaccb294e6dc116e8b247ae0a4da45b79749814893549e6f15e3baace2998db06a966a9f8d5a39b6b2d8e51543bd0a565a8927c37d6373dfd20b9 + graceful-fs: "npm:^4.2.0" + jsonfile: "npm:^6.0.1" + universalify: "npm:^2.0.0" + checksum: 10c0/e08276f767a62496ae97d711aaa692c6a478177f24a85979b6a2881c9db9c68b8c2ad5da0bcf92c0b2a474cea6e935ec245656441527958fd8372cb647087df0 languageName: node linkType: hard @@ -6119,7 +4856,7 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^9.0.1, fs-extra@npm:^9.1.0": +"fs-extra@npm:^9.1.0": version: 9.1.0 resolution: "fs-extra@npm:9.1.0" dependencies: @@ -6131,15 +4868,6 @@ __metadata: languageName: node linkType: hard -"fs-minipass@npm:^1.2.7": - version: 1.2.7 - resolution: "fs-minipass@npm:1.2.7" - dependencies: - minipass: "npm:^2.6.0" - checksum: 10c0/c8259ce8caab360f16b8c3774fd09dd1d5240d6f3f78fd8efa0a215b5f40edfa90e7b5b5ddc2335a4c50885e29d5983f9fe6ac3ac19320e6917a21dbb9f05c64 - languageName: node - linkType: hard - "fs-minipass@npm:^3.0.0": version: 3.0.3 resolution: "fs-minipass@npm:3.0.3" @@ -6182,41 +4910,6 @@ __metadata: languageName: node linkType: hard -"function.prototype.name@npm:^1.1.6, function.prototype.name@npm:^1.1.8": - version: 1.1.8 - resolution: "function.prototype.name@npm:1.1.8" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - define-properties: "npm:^1.2.1" - functions-have-names: "npm:^1.2.3" - hasown: "npm:^2.0.2" - is-callable: "npm:^1.2.7" - checksum: 10c0/e920a2ab52663005f3cbe7ee3373e3c71c1fb5558b0b0548648cdf3e51961085032458e26c71ff1a8c8c20e7ee7caeb03d43a5d1fa8610c459333323a2e71253 - languageName: node - linkType: hard - -"functional-red-black-tree@npm:^1.0.1": - version: 1.0.1 - resolution: "functional-red-black-tree@npm:1.0.1" - checksum: 10c0/5959eed0375803d9924f47688479bb017e0c6816a0e5ac151e22ba6bfe1d12c41de2f339188885e0aa8eeea2072dad509d8e4448467e816bde0a2ca86a0670d3 - languageName: node - linkType: hard - -"functions-have-names@npm:^1.2.3": - version: 1.2.3 - resolution: "functions-have-names@npm:1.2.3" - checksum: 10c0/33e77fd29bddc2d9bb78ab3eb854c165909201f88c75faa8272e35899e2d35a8a642a15e7420ef945e1f64a9670d6aa3ec744106b2aa42be68ca5114025954ca - languageName: node - linkType: hard - -"generator-function@npm:^2.0.0": - version: 2.0.1 - resolution: "generator-function@npm:2.0.1" - checksum: 10c0/8a9f59df0f01cfefafdb3b451b80555e5cf6d76487095db91ac461a0e682e4ff7a9dbce15f4ecec191e53586d59eece01949e05a4b4492879600bbbe8e28d6b8 - languageName: node - linkType: hard - "get-caller-file@npm:^2.0.5": version: 2.0.5 resolution: "get-caller-file@npm:2.0.5" @@ -6231,7 +4924,7 @@ __metadata: languageName: node linkType: hard -"get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.2.7, get-intrinsic@npm:^1.3.0": +"get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.3.0": version: 1.3.0 resolution: "get-intrinsic@npm:1.3.0" dependencies: @@ -6249,7 +4942,7 @@ __metadata: languageName: node linkType: hard -"get-proto@npm:^1.0.0, get-proto@npm:^1.0.1": +"get-proto@npm:^1.0.1": version: 1.0.1 resolution: "get-proto@npm:1.0.1" dependencies: @@ -6259,62 +4952,32 @@ __metadata: languageName: node linkType: hard -"get-stream@npm:^2.2.0": - version: 2.3.1 - resolution: "get-stream@npm:2.3.1" - dependencies: - object-assign: "npm:^4.0.1" - pinkie-promise: "npm:^2.0.0" - checksum: 10c0/46c12f496e7edec688a1cc570fe7556ce91e91201fa7efb146853fb9f0a8f0b0bb9a02cf9d9e4e9d4e2097f98c83b09621d9034c25ca0cf80ae6f4dace9c3465 - languageName: node - linkType: hard - -"get-stream@npm:^3.0.0": - version: 3.0.0 - resolution: "get-stream@npm:3.0.0" - checksum: 10c0/003f5f3b8870da59c6aafdf6ed7e7b07b48c2f8629cd461bd3900726548b6b8cfa2e14d6b7814fbb08f07a42f4f738407fa70b989928b2783a76b278505bba22 - languageName: node - linkType: hard - -"get-stream@npm:^4.1.0": - version: 4.1.0 - resolution: "get-stream@npm:4.1.0" - dependencies: - pump: "npm:^3.0.0" - checksum: 10c0/294d876f667694a5ca23f0ca2156de67da950433b6fb53024833733975d32582896dbc7f257842d331809979efccf04d5e0b6b75ad4d45744c45f193fd497539 - languageName: node - linkType: hard - -"get-stream@npm:^5.1.0": - version: 5.2.0 - resolution: "get-stream@npm:5.2.0" - dependencies: - pump: "npm:^3.0.0" - checksum: 10c0/43797ffd815fbb26685bf188c8cfebecb8af87b3925091dd7b9a9c915993293d78e3c9e1bce125928ff92f2d0796f3889b92b5ec6d58d1041b574682132e0a80 +"get-stream@npm:^6.0.1": + version: 6.0.1 + resolution: "get-stream@npm:6.0.1" + checksum: 10c0/49825d57d3fd6964228e6200a58169464b8e8970489b3acdc24906c782fb7f01f9f56f8e6653c4a50713771d6658f7cfe051e5eb8c12e334138c9c918b296341 languageName: node linkType: hard -"get-symbol-description@npm:^1.1.0": - version: 1.1.0 - resolution: "get-symbol-description@npm:1.1.0" +"get-tsconfig@npm:^4.10.1": + version: 4.14.3 + resolution: "get-tsconfig@npm:4.14.3" dependencies: - call-bound: "npm:^1.0.3" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.6" - checksum: 10c0/d6a7d6afca375779a4b307738c9e80dbf7afc0bdbe5948768d54ab9653c865523d8920e670991a925936eb524b7cb6a6361d199a760b21d0ca7620194455aa4b + resolve-pkg-maps: "npm:^1.0.0" + checksum: 10c0/22119bb5b7e37b922a973bfb50deac89ca845cef50a24cd27b6c628f314e91a2bccceb186e0b5183e231ad6480d7173738912975332caf60678af39b7236eeac languageName: node linkType: hard -"getpass@npm:^0.1.1": - version: 0.1.7 - resolution: "getpass@npm:0.1.7" +"glob-parent@npm:^6.0.2": + version: 6.0.2 + resolution: "glob-parent@npm:6.0.2" dependencies: - assert-plus: "npm:^1.0.0" - checksum: 10c0/c13f8530ecf16fc509f3fa5cd8dd2129ffa5d0c7ccdf5728b6022d52954c2d24be3706b4cdf15333eec52f1fbb43feb70a01dabc639d1d10071e371da8aaa52f + is-glob: "npm:^4.0.3" + checksum: 10c0/317034d88654730230b3f43bb7ad4f7c90257a426e872ea0bf157473ac61c99bf5d205fad8f0185f989be8d2fa6d3c7dce1645d99d545b6ea9089c39f838e7f8 languageName: node linkType: hard -"glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": +"glob-parent@npm:~5.1.2": version: 5.1.2 resolution: "glob-parent@npm:5.1.2" dependencies: @@ -6323,6 +4986,20 @@ __metadata: languageName: node linkType: hard +"glob@npm:7.1.7": + version: 7.1.7 + resolution: "glob@npm:7.1.7" + dependencies: + fs.realpath: "npm:^1.0.0" + inflight: "npm:^1.0.4" + inherits: "npm:2" + minimatch: "npm:^3.0.4" + once: "npm:^1.3.0" + path-is-absolute: "npm:^1.0.0" + checksum: 10c0/173245e6f9ccf904309eb7ef4a44a11f3bf68e9e341dff5a28b5db0dd7123b7506daf41497f3437a0710f57198187b758c2351eeaabce4d16935e956920da6a4 + languageName: node + linkType: hard + "glob@npm:^10.3.10, glob@npm:^10.4.5": version: 10.5.0 resolution: "glob@npm:10.5.0" @@ -6339,7 +5016,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^13.0.0": +"glob@npm:^13.0.0, glob@npm:^13.0.6": version: 13.0.6 resolution: "glob@npm:13.0.6" dependencies: @@ -6350,119 +5027,40 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.6": - version: 7.2.0 - resolution: "glob@npm:7.2.0" - dependencies: - fs.realpath: "npm:^1.0.0" - inflight: "npm:^1.0.4" - inherits: "npm:2" - minimatch: "npm:^3.0.4" - once: "npm:^1.3.0" - path-is-absolute: "npm:^1.0.0" - checksum: 10c0/478b40e38be5a3d514e64950e1e07e0ac120585add6a37c98d0ed24d72d9127d734d2a125786073c8deb687096e84ae82b641c441a869ada3a9cc91b68978632 - languageName: node - linkType: hard - -"global@npm:~4.4.0": - version: 4.4.0 - resolution: "global@npm:4.4.0" - dependencies: - min-document: "npm:^2.19.0" - process: "npm:^0.11.10" - checksum: 10c0/4a467aec6602c00a7c5685f310574ab04e289ad7f894f0f01c9c5763562b82f4b92d1e381ce6c5bbb12173e2a9f759c1b63dda6370cfb199970267e14d90aa91 - languageName: node - linkType: hard - -"globals@npm:^11.7.0": - version: 11.12.0 - resolution: "globals@npm:11.12.0" - checksum: 10c0/758f9f258e7b19226bd8d4af5d3b0dcf7038780fb23d82e6f98932c44e239f884847f1766e8fa9cc5635ccb3204f7fa7314d4408dd4002a5e8ea827b4018f0a1 - languageName: node - linkType: hard - -"globals@npm:^13.6.0, globals@npm:^13.9.0": - version: 13.12.0 - resolution: "globals@npm:13.12.0" - dependencies: - type-fest: "npm:^0.20.2" - checksum: 10c0/e9daf6459d4f1056e64434d7fbd8dadba1036ec85b33ef4649bfa2000b816234ec02c37debf9e93fa3d50eb5f6e828a1c12279983636f58f864c7afda1c32546 - languageName: node - linkType: hard - -"globalthis@npm:^1.0.4": - version: 1.0.4 - resolution: "globalthis@npm:1.0.4" - dependencies: - define-properties: "npm:^1.2.1" - gopd: "npm:^1.0.1" - checksum: 10c0/9d156f313af79d80b1566b93e19285f481c591ad6d0d319b4be5e03750d004dde40a39a0f26f7e635f9007a3600802f53ecd85a759b86f109e80a5f705e01846 - languageName: node - linkType: hard - -"globby@npm:^11.0.3": - version: 11.1.0 - resolution: "globby@npm:11.1.0" - dependencies: - array-union: "npm:^2.1.0" - dir-glob: "npm:^3.0.1" - fast-glob: "npm:^3.2.9" - ignore: "npm:^5.2.0" - merge2: "npm:^1.4.1" - slash: "npm:^3.0.0" - checksum: 10c0/b39511b4afe4bd8a7aead3a27c4ade2b9968649abab0a6c28b1a90141b96ca68ca5db1302f7c7bd29eab66bf51e13916b8e0a3d0ac08f75e1e84a39b35691189 +"globals@npm:^17.12.0": + version: 17.12.0 + resolution: "globals@npm:17.12.0" + checksum: 10c0/8325cf8818c848871d17c32974c2c74e9c5f09c1b0e04421886f64f21e77c3e95f3ba25586743895a73acd860ada151132481d87d44a1f12993ae7758a694d03 languageName: node linkType: hard -"gopd@npm:^1.0.1, gopd@npm:^1.2.0": +"gopd@npm:^1.2.0": version: 1.2.0 resolution: "gopd@npm:1.2.0" checksum: 10c0/50fff1e04ba2b7737c097358534eacadad1e68d24cccee3272e04e007bed008e68d2614f3987788428fd192a5ae3889d08fb2331417e4fc4a9ab366b2043cead languageName: node linkType: hard -"got@npm:9.6.0": - version: 9.6.0 - resolution: "got@npm:9.6.0" - dependencies: - "@sindresorhus/is": "npm:^0.14.0" - "@szmarczak/http-timer": "npm:^1.1.2" - cacheable-request: "npm:^6.0.0" - decompress-response: "npm:^3.3.0" - duplexer3: "npm:^0.1.4" - get-stream: "npm:^4.1.0" - lowercase-keys: "npm:^1.0.1" - mimic-response: "npm:^1.0.1" - p-cancelable: "npm:^1.0.0" - to-readable-stream: "npm:^1.0.0" - url-parse-lax: "npm:^3.0.0" - checksum: 10c0/5cb3111e14b48bf4fb8b414627be481ebfb14151ec867e80a74b6d1472489965b9c4f4ac5cf4f3b1f9b90c60a2ce63584d9072b16efd9a3171553e00afc5abc8 - languageName: node - linkType: hard - -"got@npm:^7.1.0": - version: 7.1.0 - resolution: "got@npm:7.1.0" - dependencies: - decompress-response: "npm:^3.2.0" - duplexer3: "npm:^0.1.4" - get-stream: "npm:^3.0.0" - is-plain-obj: "npm:^1.1.0" - is-retry-allowed: "npm:^1.0.0" - is-stream: "npm:^1.0.0" - isurl: "npm:^1.0.0-alpha5" - lowercase-keys: "npm:^1.0.0" - p-cancelable: "npm:^0.3.0" - p-timeout: "npm:^1.1.1" - safe-buffer: "npm:^5.0.1" - timed-out: "npm:^4.0.0" - url-parse-lax: "npm:^1.0.0" - url-to-options: "npm:^1.0.1" - checksum: 10c0/e5faeeb3763cc0c249581407d5e99beb289cef0253ebe17c1e7c68fc10fe213b1fa10a3a9ca7b0a91bf3e1ee756daf451499bb583481f12131a4afb6a29394fd +"got@npm:^12.1.0": + version: 12.6.1 + resolution: "got@npm:12.6.1" + dependencies: + "@sindresorhus/is": "npm:^5.2.0" + "@szmarczak/http-timer": "npm:^5.0.1" + cacheable-lookup: "npm:^7.0.0" + cacheable-request: "npm:^10.2.8" + decompress-response: "npm:^6.0.0" + form-data-encoder: "npm:^2.1.2" + get-stream: "npm:^6.0.1" + http2-wrapper: "npm:^2.1.10" + lowercase-keys: "npm:^3.0.0" + p-cancelable: "npm:^3.0.0" + responselike: "npm:^3.0.0" + checksum: 10c0/2fe97fcbd7a9ffc7c2d0ecf59aca0a0562e73a7749cadada9770eeb18efbdca3086262625fb65590594edc220a1eca58fab0d26b0c93c2f9a008234da71ca66b languageName: node linkType: hard -"graceful-fs@npm:^4.1.10, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.4": +"graceful-fs@npm:4.2.10, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.4": version: 4.2.10 resolution: "graceful-fs@npm:4.2.10" checksum: 10c0/4223a833e38e1d0d2aea630c2433cfb94ddc07dfc11d511dbd6be1d16688c5be848acc31f9a5d0d0ddbfb56d2ee5a6ae0278aceeb0ca6a13f27e06b9956fb952 @@ -6501,26 +5099,9 @@ __metadata: languageName: node linkType: hard -"har-schema@npm:^2.0.0": - version: 2.0.0 - resolution: "har-schema@npm:2.0.0" - checksum: 10c0/3856cb76152658e0002b9c2b45b4360bb26b3e832c823caed8fcf39a01096030bf09fa5685c0f7b0f2cb3ecba6e9dce17edaf28b64a423d6201092e6be56e592 - languageName: node - linkType: hard - -"har-validator@npm:~5.1.3": - version: 5.1.5 - resolution: "har-validator@npm:5.1.5" - dependencies: - ajv: "npm:^6.12.3" - har-schema: "npm:^2.0.0" - checksum: 10c0/f1d606eb1021839e3a905be5ef7cca81c2256a6be0748efb8fefc14312214f9e6c15d7f2eaf37514104071207d84f627b68bb9f6178703da4e06fbd1a0649a5e - languageName: node - linkType: hard - -"hardhat-contract-sizer@npm:^2.3.0": - version: 2.4.0 - resolution: "hardhat-contract-sizer@npm:2.4.0" +"hardhat-contract-sizer@npm:^2.3.0": + version: 2.4.0 + resolution: "hardhat-contract-sizer@npm:2.4.0" dependencies: chalk: "npm:^4.0.0" cli-table3: "npm:^0.6.0" @@ -6539,45 +5120,66 @@ __metadata: languageName: node linkType: hard -"hardhat-deploy@npm:^0.11.10": - version: 0.11.22 - resolution: "hardhat-deploy@npm:0.11.22" +"hardhat-deploy@npm:^0.11.43": + version: 0.11.45 + resolution: "hardhat-deploy@npm:0.11.45" dependencies: + "@ethersproject/abi": "npm:^5.7.0" + "@ethersproject/abstract-signer": "npm:^5.7.0" + "@ethersproject/address": "npm:^5.7.0" + "@ethersproject/bignumber": "npm:^5.7.0" + "@ethersproject/bytes": "npm:^5.7.0" + "@ethersproject/constants": "npm:^5.7.0" + "@ethersproject/contracts": "npm:^5.7.0" + "@ethersproject/providers": "npm:^5.7.2" + "@ethersproject/solidity": "npm:^5.7.0" + "@ethersproject/transactions": "npm:^5.7.0" + "@ethersproject/wallet": "npm:^5.7.0" "@types/qs": "npm:^6.9.7" axios: "npm:^0.21.1" chalk: "npm:^4.1.2" chokidar: "npm:^3.5.2" debug: "npm:^4.3.2" enquirer: "npm:^2.3.6" - ethers: "npm:^5.5.3" + ethers: "npm:^5.7.0" form-data: "npm:^4.0.0" fs-extra: "npm:^10.0.0" match-all: "npm:^1.2.6" murmur-128: "npm:^0.2.1" qs: "npm:^6.9.4" - zksync-web3: "npm:^0.8.1" - checksum: 10c0/b5eba6bc768ce38fdef8eef8b9b02d316a2c3549696f321f5cc6cc7679a48eb68e53133920889615b0ae9a4a10e44d144fbf53f03bd0e68834d93041d7394da1 + zksync-web3: "npm:^0.14.3" + checksum: 10c0/6171ffccd46bb21954ebf2303a00d35d3793ad7216adaaf2d6e1836ec9387583a34e1640ff93e0d2d89e61cd3b06454f40cb11573463d86900eb24a940ce3682 languageName: node linkType: hard -"hardhat-deploy@npm:^0.11.11": - version: 0.11.11 - resolution: "hardhat-deploy@npm:0.11.11" +"hardhat-deploy@npm:^1.0.4": + version: 1.0.4 + resolution: "hardhat-deploy@npm:1.0.4" dependencies: - "@types/qs": "npm:^6.9.7" + "@ethersproject/abi": "npm:^5.7.0" + "@ethersproject/abstract-signer": "npm:^5.7.0" + "@ethersproject/address": "npm:^5.7.0" + "@ethersproject/bignumber": "npm:^5.7.0" + "@ethersproject/bytes": "npm:^5.7.0" + "@ethersproject/constants": "npm:^5.7.0" + "@ethersproject/contracts": "npm:^5.7.0" + "@ethersproject/providers": "npm:^5.7.2" + "@ethersproject/solidity": "npm:^5.7.0" + "@ethersproject/transactions": "npm:^5.7.0" + "@ethersproject/wallet": "npm:^5.7.0" axios: "npm:^0.21.1" chalk: "npm:^4.1.2" chokidar: "npm:^3.5.2" debug: "npm:^4.3.2" enquirer: "npm:^2.3.6" - ethers: "npm:^5.5.3" + ethers: "npm:^5.7.0" form-data: "npm:^4.0.0" fs-extra: "npm:^10.0.0" match-all: "npm:^1.2.6" murmur-128: "npm:^0.2.1" - qs: "npm:^6.9.4" - zksync-web3: "npm:^0.7.8" - checksum: 10c0/71c07c86832bcd7968f202aad067c427042cd46115d1787302f6edac9087933684f7efb0eca773b88a2e121147fc2e8f73ac9de0a1f25477f482c065cb18b99d + neoqs: "npm:^6.13.0" + zksync-ethers: "npm:^5.0.0" + checksum: 10c0/21365c79ab169bf53ac8f10967de6ef2e962e8c9bdcba0a54f5424a1a953c6d2c1836136553d27b3b2db86aa708a9e7edde44abba768c40203ef5bc847c6a815 languageName: node linkType: hard @@ -6663,13 +5265,6 @@ __metadata: languageName: node linkType: hard -"has-bigints@npm:^1.0.2": - version: 1.1.0 - resolution: "has-bigints@npm:1.1.0" - checksum: 10c0/2de0cdc4a1ccf7a1e75ffede1876994525ac03cc6f5ae7392d3415dd475cd9eee5bceec63669ab61aa997ff6cceebb50ef75561c7002bed8988de2b9d1b40788 - languageName: node - linkType: hard - "has-flag@npm:^3.0.0": version: 3.0.0 resolution: "has-flag@npm:3.0.0" @@ -6684,31 +5279,6 @@ __metadata: languageName: node linkType: hard -"has-property-descriptors@npm:^1.0.0, has-property-descriptors@npm:^1.0.2": - version: 1.0.2 - resolution: "has-property-descriptors@npm:1.0.2" - dependencies: - es-define-property: "npm:^1.0.0" - checksum: 10c0/253c1f59e80bb476cf0dde8ff5284505d90c3bdb762983c3514d36414290475fe3fd6f574929d84de2a8eec00d35cf07cb6776205ff32efd7c50719125f00236 - languageName: node - linkType: hard - -"has-proto@npm:^1.2.0": - version: 1.2.0 - resolution: "has-proto@npm:1.2.0" - dependencies: - dunder-proto: "npm:^1.0.0" - checksum: 10c0/46538dddab297ec2f43923c3d35237df45d8c55a6fc1067031e04c13ed8a9a8f94954460632fd4da84c31a1721eefee16d901cbb1ae9602bab93bb6e08f93b95 - languageName: node - linkType: hard - -"has-symbol-support-x@npm:^1.4.1": - version: 1.4.2 - resolution: "has-symbol-support-x@npm:1.4.2" - checksum: 10c0/993f0e1a7a2c8f41f356b20c33cda49bc2f5c4442f858b0fa58b4852f4ba50e7d7400a2734822c415975114e6f768bba9bb6063dd687026baaeeed6453d94a03 - languageName: node - linkType: hard - "has-symbols@npm:^1.0.3, has-symbols@npm:^1.1.0": version: 1.1.0 resolution: "has-symbols@npm:1.1.0" @@ -6716,15 +5286,6 @@ __metadata: languageName: node linkType: hard -"has-to-string-tag-x@npm:^1.2.0": - version: 1.4.1 - resolution: "has-to-string-tag-x@npm:1.4.1" - dependencies: - has-symbol-support-x: "npm:^1.4.1" - checksum: 10c0/e7197e830fe55afe596fc3fe4ab23fa455f69a1ba850b493e527c728d1e6d2ecc7197ab38b8bdc7ae8a7669e23c19a8b9f52f853a509639c70e0efbdc5d175e5 - languageName: node - linkType: hard - "has-tostringtag@npm:^1.0.2": version: 1.0.2 resolution: "has-tostringtag@npm:1.0.2" @@ -6745,16 +5306,6 @@ __metadata: languageName: node linkType: hard -"hash.js@npm:1.1.3": - version: 1.1.3 - resolution: "hash.js@npm:1.1.3" - dependencies: - inherits: "npm:^2.0.3" - minimalistic-assert: "npm:^1.0.0" - checksum: 10c0/f085a856c31d51556f6153edcd4bb1c01a9d22e5882a7b9bae4e813c4abfad012d060b8fde1b993e353d6af1cf82b094599b65348cb529ca19a4b80ab32efded - languageName: node - linkType: hard - "hash.js@npm:1.1.7, hash.js@npm:^1.0.0, hash.js@npm:^1.0.3, hash.js@npm:^1.1.7": version: 1.1.7 resolution: "hash.js@npm:1.1.7" @@ -6765,6 +5316,15 @@ __metadata: languageName: node linkType: hard +"hashery@npm:^1.4.0, hashery@npm:^1.5.1": + version: 1.5.1 + resolution: "hashery@npm:1.5.1" + dependencies: + hookified: "npm:^1.15.0" + checksum: 10c0/ab4225b655a7b0d05df99b1a59d5b3a51fe433f82422ca25e6f3f4c4ddd30adb49ebd38e0047ef9bded93319c1e9fc857e16aa382e554929c871cb77d39fc463 + languageName: node + linkType: hard + "hasown@npm:^2.0.2": version: 2.0.2 resolution: "hasown@npm:2.0.2" @@ -6803,17 +5363,17 @@ __metadata: languageName: node linkType: hard -"hosted-git-info@npm:^2.6.0": - version: 2.8.9 - resolution: "hosted-git-info@npm:2.8.9" - checksum: 10c0/317cbc6b1bbbe23c2a40ae23f3dafe9fa349ce42a89a36f930e3f9c0530c179a3882d2ef1e4141a4c3674d6faaea862138ec55b43ad6f75e387fda2483a13c70 +"hookified@npm:^1.15.0, hookified@npm:^1.15.1": + version: 1.15.1 + resolution: "hookified@npm:1.15.1" + checksum: 10c0/6b691374fa97ae57169fb29f90e723499fda5e85494654fbe55c4768b3ccbf3e14c0adc8d0f365f32c503b60d7c06f907781f5966c03d41c423575eb5e16860c languageName: node linkType: hard -"http-cache-semantics@npm:^4.0.0": - version: 4.1.1 - resolution: "http-cache-semantics@npm:4.1.1" - checksum: 10c0/ce1319b8a382eb3cbb4a37c19f6bfe14e5bb5be3d09079e885e8c513ab2d3cd9214902f8a31c9dc4e37022633ceabfc2d697405deeaf1b8f3552bb4ed996fdfc +"hookified@npm:^2.1.1": + version: 2.2.0 + resolution: "hookified@npm:2.2.0" + checksum: 10c0/7017d2b66945490293a5aba239e7b39f39071dd940fa019348c7ffea92b91b8c267853c4c51680ed0f3687b33352582fa4d2cff6dd4c5a1c5c44b037276f07aa languageName: node linkType: hard @@ -6837,26 +5397,6 @@ __metadata: languageName: node linkType: hard -"http-errors@npm:2.0.0": - version: 2.0.0 - resolution: "http-errors@npm:2.0.0" - dependencies: - depd: "npm:2.0.0" - inherits: "npm:2.0.4" - setprototypeof: "npm:1.2.0" - statuses: "npm:2.0.1" - toidentifier: "npm:1.0.1" - checksum: 10c0/fc6f2715fe188d091274b5ffc8b3657bd85c63e969daa68ccb77afb05b071a4b62841acb7a21e417b5539014dff2ebf9550f0b14a9ff126f2734a7c1387f8e19 - languageName: node - linkType: hard - -"http-https@npm:^1.0.0": - version: 1.0.0 - resolution: "http-https@npm:1.0.0" - checksum: 10c0/ffdec0da28627110d1dd9fbe3f9d0b61b1876c3c856d460c532b69fc0536adba0e032cd7acafad82fcb970ae9c5b34ae8340ef17aa422124b56c27f4da8fc74a - languageName: node - linkType: hard - "http-proxy-agent@npm:^7.0.0": version: 7.0.2 resolution: "http-proxy-agent@npm:7.0.2" @@ -6867,14 +5407,13 @@ __metadata: languageName: node linkType: hard -"http-signature@npm:~1.2.0": - version: 1.2.0 - resolution: "http-signature@npm:1.2.0" +"http2-wrapper@npm:^2.1.10": + version: 2.2.1 + resolution: "http2-wrapper@npm:2.2.1" dependencies: - assert-plus: "npm:^1.0.0" - jsprim: "npm:^1.2.2" - sshpk: "npm:^1.7.0" - checksum: 10c0/582f7af7f354429e1fb19b3bbb9d35520843c69bb30a25b88ca3c5c2c10715f20ae7924e20cffbed220b1d3a726ef4fe8ccc48568d5744db87be9a79887d6733 + quick-lru: "npm:^5.1.1" + resolve-alpn: "npm:^1.2.0" + checksum: 10c0/7207201d3c6e53e72e510c9b8912e4f3e468d3ecc0cf3bf52682f2aac9cd99358b896d1da4467380adc151cf97c412bedc59dc13dae90c523f42053a7449eedb languageName: node linkType: hard @@ -6908,7 +5447,7 @@ __metadata: languageName: node linkType: hard -"iconv-lite@npm:0.4.24, iconv-lite@npm:^0.4.24": +"iconv-lite@npm:0.4.24": version: 0.4.24 resolution: "iconv-lite@npm:0.4.24" dependencies: @@ -6926,36 +5465,27 @@ __metadata: languageName: node linkType: hard -"idna-uts46-hx@npm:^2.3.1": - version: 2.3.1 - resolution: "idna-uts46-hx@npm:2.3.1" - dependencies: - punycode: "npm:2.1.0" - checksum: 10c0/e38d4684ca64449560bda9efc84554c7802a0a732a73c9eb89b561d970c26e431b1975264860c98c921da2126726ebd8ae8752099e9ea55914d0b5abcc950121 - languageName: node - linkType: hard - -"ieee754@npm:^1.1.13, ieee754@npm:^1.1.4": +"ieee754@npm:^1.1.4": version: 1.2.1 resolution: "ieee754@npm:1.2.1" checksum: 10c0/b0782ef5e0935b9f12883a2e2aa37baa75da6e66ce6515c168697b42160807d9330de9a32ec1ed73149aea02e0d822e572bca6f1e22bdcbd2149e13b050b17bb languageName: node linkType: hard -"ignore@npm:^4.0.6": - version: 4.0.6 - resolution: "ignore@npm:4.0.6" - checksum: 10c0/836ee7dc7fd9436096e2dba429359dbb9fa0e33d309e2b2d81692f375f6ca82024fc00567f798613d50c6b989e9cd2ad2b065acf116325cde177f02c86b7d4e0 - languageName: node - linkType: hard - -"ignore@npm:^5.1.8, ignore@npm:^5.2.0": +"ignore@npm:^5.2.0, ignore@npm:^5.2.4": version: 5.3.2 resolution: "ignore@npm:5.3.2" checksum: 10c0/f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337 languageName: node linkType: hard +"ignore@npm:^7.0.5": + version: 7.0.8 + resolution: "ignore@npm:7.0.8" + checksum: 10c0/95ed888e66ad46c478680af1628ac1d242a623fcac418bd5533b91549f609a6756985a32ebfe087b1d97806f52a20f991c804e3b074e9cf16fd1404f2bcd9c0a + languageName: node + linkType: hard + "immutable@npm:^4.0.0-rc.12": version: 4.0.0 resolution: "immutable@npm:4.0.0" @@ -6963,23 +5493,13 @@ __metadata: languageName: node linkType: hard -"import-fresh@npm:^2.0.0": - version: 2.0.0 - resolution: "import-fresh@npm:2.0.0" - dependencies: - caller-path: "npm:^2.0.0" - resolve-from: "npm:^3.0.0" - checksum: 10c0/116c55ee5215a7839062285b60df85dbedde084c02111dc58c1b9d03ff7876627059f4beb16cdc090a3db21fea9022003402aa782139dc8d6302589038030504 - languageName: node - linkType: hard - -"import-fresh@npm:^3.0.0, import-fresh@npm:^3.2.1": - version: 3.3.0 - resolution: "import-fresh@npm:3.3.0" +"import-fresh@npm:^3.3.0": + version: 3.3.1 + resolution: "import-fresh@npm:3.3.1" dependencies: parent-module: "npm:^1.0.0" resolve-from: "npm:^4.0.0" - checksum: 10c0/7f882953aa6b740d1f0e384d0547158bc86efbf2eea0f1483b8900a6f65c5a5123c2cf09b0d542cc419d0b98a759ecaeb394237e97ea427f2da221dc3cd80cc3 + checksum: 10c0/bf8cc494872fef783249709385ae883b447e3eb09db0ebd15dcead7d9afe7224dad7bd7591c6b73b0b19b3c0f9640eb8ee884f01cfaf2887ab995b0b36a0cbec languageName: node linkType: hard @@ -7014,42 +5534,17 @@ __metadata: languageName: node linkType: hard -"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3": +"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4": version: 2.0.4 resolution: "inherits@npm:2.0.4" checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 languageName: node linkType: hard -"inquirer@npm:^6.2.2": - version: 6.5.2 - resolution: "inquirer@npm:6.5.2" - dependencies: - ansi-escapes: "npm:^3.2.0" - chalk: "npm:^2.4.2" - cli-cursor: "npm:^2.1.0" - cli-width: "npm:^2.0.0" - external-editor: "npm:^3.0.3" - figures: "npm:^2.0.0" - lodash: "npm:^4.17.12" - mute-stream: "npm:0.0.7" - run-async: "npm:^2.2.0" - rxjs: "npm:^6.4.0" - string-width: "npm:^2.1.0" - strip-ansi: "npm:^5.1.0" - through: "npm:^2.3.6" - checksum: 10c0/a5aa53a8f88405cf1cff63111493f87a5b3b5deb5ea4a0dbcd73ccc06a51a6bba0c3f1a0747f8880e9e3ec2437c69f90417be16368abf636b1d29eebe35db0ac - languageName: node - linkType: hard - -"internal-slot@npm:^1.1.0": - version: 1.1.0 - resolution: "internal-slot@npm:1.1.0" - dependencies: - es-errors: "npm:^1.3.0" - hasown: "npm:^2.0.2" - side-channel: "npm:^1.1.0" - checksum: 10c0/03966f5e259b009a9bf1a78d60da920df198af4318ec004f57b8aef1dd3fe377fbc8cce63a96e8c810010302654de89f9e19de1cd8ad0061d15be28a695465c7 +"ini@npm:^1.3.4, ini@npm:~1.3.0": + version: 1.3.8 + resolution: "ini@npm:1.3.8" + checksum: 10c0/ec93838d2328b619532e4f1ff05df7909760b6f66d9c9e2ded11e5c1897d6f2f9980c54dd638f88654b00919ce31e827040631eab0a3969e4d1abefa0719516a languageName: node linkType: hard @@ -7069,24 +5564,6 @@ __metadata: languageName: node linkType: hard -"ipaddr.js@npm:1.9.1": - version: 1.9.1 - resolution: "ipaddr.js@npm:1.9.1" - checksum: 10c0/0486e775047971d3fdb5fb4f063829bac45af299ae0b82dcf3afa2145338e08290563a2a70f34b732d795ecc8311902e541a8530eeb30d75860a78ff4e94ce2a - languageName: node - linkType: hard - -"is-array-buffer@npm:^3.0.4, is-array-buffer@npm:^3.0.5": - version: 3.0.5 - resolution: "is-array-buffer@npm:3.0.5" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - get-intrinsic: "npm:^1.2.6" - checksum: 10c0/c5c9f25606e86dbb12e756694afbbff64bc8b348d1bc989324c037e1068695131930199d6ad381952715dad3a9569333817f0b1a72ce5af7f883ce802e49c83d - languageName: node - linkType: hard - "is-arrayish@npm:^0.2.1": version: 0.2.1 resolution: "is-arrayish@npm:0.2.1" @@ -7094,28 +5571,6 @@ __metadata: languageName: node linkType: hard -"is-async-function@npm:^2.0.0": - version: 2.1.1 - resolution: "is-async-function@npm:2.1.1" - dependencies: - async-function: "npm:^1.0.0" - call-bound: "npm:^1.0.3" - get-proto: "npm:^1.0.1" - has-tostringtag: "npm:^1.0.2" - safe-regex-test: "npm:^1.1.0" - checksum: 10c0/d70c236a5e82de6fc4d44368ffd0c2fee2b088b893511ce21e679da275a5ecc6015ff59a7d7e1bdd7ca39f71a8dbdd253cf8cce5c6b3c91cdd5b42b5ce677298 - languageName: node - linkType: hard - -"is-bigint@npm:^1.1.0": - version: 1.1.0 - resolution: "is-bigint@npm:1.1.0" - dependencies: - has-bigints: "npm:^1.0.2" - checksum: 10c0/f4f4b905ceb195be90a6ea7f34323bf1c18e3793f18922e3e9a73c684c29eeeeff5175605c3a3a74cc38185fe27758f07efba3dbae812e5c5afbc0d2316b40e4 - languageName: node - linkType: hard - "is-binary-path@npm:~2.1.0": version: 2.1.0 resolution: "is-binary-path@npm:2.1.0" @@ -7125,64 +5580,21 @@ __metadata: languageName: node linkType: hard -"is-boolean-object@npm:^1.2.1": - version: 1.2.2 - resolution: "is-boolean-object@npm:1.2.2" - dependencies: - call-bound: "npm:^1.0.3" - has-tostringtag: "npm:^1.0.2" - checksum: 10c0/36ff6baf6bd18b3130186990026f5a95c709345c39cd368468e6c1b6ab52201e9fd26d8e1f4c066357b4938b0f0401e1a5000e08257787c1a02f3a719457001e - languageName: node - linkType: hard - -"is-buffer@npm:^2.0.2": - version: 2.0.5 - resolution: "is-buffer@npm:2.0.5" - checksum: 10c0/e603f6fced83cf94c53399cff3bda1a9f08e391b872b64a73793b0928be3e5f047f2bcece230edb7632eaea2acdbfcb56c23b33d8a20c820023b230f1485679a - languageName: node - linkType: hard - -"is-callable@npm:^1.2.7": - version: 1.2.7 - resolution: "is-callable@npm:1.2.7" - checksum: 10c0/ceebaeb9d92e8adee604076971dd6000d38d6afc40bb843ea8e45c5579b57671c3f3b50d7f04869618242c6cee08d1b67806a8cb8edaaaf7c0748b3720d6066f - languageName: node - linkType: hard - -"is-core-module@npm:^2.13.0, is-core-module@npm:^2.16.0, is-core-module@npm:^2.16.1": - version: 2.16.1 - resolution: "is-core-module@npm:2.16.1" - dependencies: - hasown: "npm:^2.0.2" - checksum: 10c0/898443c14780a577e807618aaae2b6f745c8538eca5c7bc11388a3f2dc6de82b9902bcc7eb74f07be672b11bbe82dd6a6edded44a00cb3d8f933d0459905eedd - languageName: node - linkType: hard - -"is-data-view@npm:^1.0.1, is-data-view@npm:^1.0.2": - version: 1.0.2 - resolution: "is-data-view@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.2" - get-intrinsic: "npm:^1.2.6" - is-typed-array: "npm:^1.1.13" - checksum: 10c0/ef3548a99d7e7f1370ce21006baca6d40c73e9f15c941f89f0049c79714c873d03b02dae1c64b3f861f55163ecc16da06506c5b8a1d4f16650b3d9351c380153 - languageName: node - linkType: hard - -"is-date-object@npm:^1.0.5, is-date-object@npm:^1.1.0": - version: 1.1.0 - resolution: "is-date-object@npm:1.1.0" +"is-bun-module@npm:^2.0.0": + version: 2.0.0 + resolution: "is-bun-module@npm:2.0.0" dependencies: - call-bound: "npm:^1.0.2" - has-tostringtag: "npm:^1.0.2" - checksum: 10c0/1a4d199c8e9e9cac5128d32e6626fa7805175af9df015620ac0d5d45854ccf348ba494679d872d37301032e35a54fc7978fba1687e8721b2139aea7870cafa2f + semver: "npm:^7.7.1" + checksum: 10c0/7d27a0679cfa5be1f5052650391f9b11040cd70c48d45112e312c56bc6b6ca9c9aea70dcce6cc40b1e8947bfff8567a5c5715d3b066fb478522dab46ea379240 languageName: node linkType: hard -"is-directory@npm:^0.3.1": - version: 0.3.1 - resolution: "is-directory@npm:0.3.1" - checksum: 10c0/1c39c7d1753b04e9483b89fb88908b8137ab4743b6f481947e97ccf93ecb384a814c8d3f0b95b082b149c5aa19c3e9e4464e2791d95174bce95998c26bb1974b +"is-docker@npm:^2.0.0, is-docker@npm:^2.1.1": + version: 2.2.1 + resolution: "is-docker@npm:2.2.1" + bin: + is-docker: cli.js + checksum: 10c0/e828365958d155f90c409cdbe958f64051d99e8aedc2c8c4cd7c89dcf35329daed42f7b99346f7828df013e27deb8f721cf9408ba878c76eb9e8290235fbcdcc languageName: node linkType: hard @@ -7193,22 +5605,6 @@ __metadata: languageName: node linkType: hard -"is-finalizationregistry@npm:^1.1.0": - version: 1.1.1 - resolution: "is-finalizationregistry@npm:1.1.1" - dependencies: - call-bound: "npm:^1.0.3" - checksum: 10c0/818dff679b64f19e228a8205a1e2d09989a98e98def3a817f889208cfcbf918d321b251aadf2c05918194803ebd2eb01b14fc9d0b2bea53d984f4137bfca5e97 - languageName: node - linkType: hard - -"is-fullwidth-code-point@npm:^2.0.0": - version: 2.0.0 - resolution: "is-fullwidth-code-point@npm:2.0.0" - checksum: 10c0/e58f3e4a601fc0500d8b2677e26e9fe0cd450980e66adb29d85b6addf7969731e38f8e43ed2ec868a09c101a55ac3d8b78902209269f38c5286bc98f5bc1b4d9 - languageName: node - linkType: hard - "is-fullwidth-code-point@npm:^3.0.0": version: 3.0.0 resolution: "is-fullwidth-code-point@npm:3.0.0" @@ -7216,26 +5612,6 @@ __metadata: languageName: node linkType: hard -"is-function@npm:^1.0.1": - version: 1.0.2 - resolution: "is-function@npm:1.0.2" - checksum: 10c0/c55289042a0e828a773f1245e2652e0c029efacc78ebe03e61787746fda74e2c41006cd908f20b53c36e45f9e75464475a4b2d68b17f4c7b9f8018bcaec42f9e - languageName: node - linkType: hard - -"is-generator-function@npm:^1.0.10": - version: 1.1.2 - resolution: "is-generator-function@npm:1.1.2" - dependencies: - call-bound: "npm:^1.0.4" - generator-function: "npm:^2.0.0" - get-proto: "npm:^1.0.1" - has-tostringtag: "npm:^1.0.2" - safe-regex-test: "npm:^1.1.0" - checksum: 10c0/83da102e89c3e3b71d67b51d47c9f9bc862bceb58f87201727e27f7fa19d1d90b0ab223644ecaee6fc6e3d2d622bb25c966fbdaf87c59158b01ce7c0fe2fa372 - languageName: node - linkType: hard - "is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3, is-glob@npm:~4.0.1": version: 4.0.3 resolution: "is-glob@npm:4.0.3" @@ -7245,44 +5621,6 @@ __metadata: languageName: node linkType: hard -"is-hex-prefixed@npm:1.0.0": - version: 1.0.0 - resolution: "is-hex-prefixed@npm:1.0.0" - checksum: 10c0/767fa481020ae654ab085ca24c63c518705ff36fdfbfc732292dc69092c6f8fdc551f6ce8c5f6ae704b0a19294e6f62be1b4b9859f0e1ac76e3b1b0733599d94 - languageName: node - linkType: hard - -"is-map@npm:^2.0.3": - version: 2.0.3 - resolution: "is-map@npm:2.0.3" - checksum: 10c0/2c4d431b74e00fdda7162cd8e4b763d6f6f217edf97d4f8538b94b8702b150610e2c64961340015fe8df5b1fcee33ccd2e9b62619c4a8a3a155f8de6d6d355fc - languageName: node - linkType: hard - -"is-natural-number@npm:^4.0.1": - version: 4.0.1 - resolution: "is-natural-number@npm:4.0.1" - checksum: 10c0/f05c544cb0ad39d4410e2ae2244282bf61918ebbb808b665436ffca4f6bbe908d3ae3a8d21fe143d302951f157d969986dd432098b63899561639fcd1ce1c280 - languageName: node - linkType: hard - -"is-negative-zero@npm:^2.0.3": - version: 2.0.3 - resolution: "is-negative-zero@npm:2.0.3" - checksum: 10c0/bcdcf6b8b9714063ffcfa9929c575ac69bfdabb8f4574ff557dfc086df2836cf07e3906f5bbc4f2a5c12f8f3ba56af640c843cdfc74da8caed86c7c7d66fd08e - languageName: node - linkType: hard - -"is-number-object@npm:^1.1.1": - version: 1.1.1 - resolution: "is-number-object@npm:1.1.1" - dependencies: - call-bound: "npm:^1.0.3" - has-tostringtag: "npm:^1.0.2" - checksum: 10c0/97b451b41f25135ff021d85c436ff0100d84a039bb87ffd799cbcdbea81ef30c464ced38258cdd34f080be08fc3b076ca1f472086286d2aa43521d6ec6a79f53 - languageName: node - linkType: hard - "is-number@npm:^7.0.0": version: 7.0.0 resolution: "is-number@npm:7.0.0" @@ -7290,13 +5628,6 @@ __metadata: languageName: node linkType: hard -"is-object@npm:^1.0.1": - version: 1.0.2 - resolution: "is-object@npm:1.0.2" - checksum: 10c0/9cfb80c3a850f453d4a77297e0556bc2040ac6bea5b6e418aee208654938b36bab768169bef3945ccfac7a9bb460edd8034e7c6d8973bcf147d7571e1b53e764 - languageName: node - linkType: hard - "is-path-inside@npm:^3.0.3": version: 3.0.3 resolution: "is-path-inside@npm:3.0.3" @@ -7304,13 +5635,6 @@ __metadata: languageName: node linkType: hard -"is-plain-obj@npm:^1.1.0": - version: 1.1.0 - resolution: "is-plain-obj@npm:1.1.0" - checksum: 10c0/daaee1805add26f781b413fdf192fc91d52409583be30ace35c82607d440da63cc4cac0ac55136716688d6c0a2c6ef3edb2254fecbd1fe06056d6bd15975ee8c - languageName: node - linkType: hard - "is-plain-obj@npm:^2.1.0": version: 2.1.0 resolution: "is-plain-obj@npm:2.1.0" @@ -7318,193 +5642,59 @@ __metadata: languageName: node linkType: hard -"is-regex@npm:^1.2.1": - version: 1.2.1 - resolution: "is-regex@npm:1.2.1" - dependencies: - call-bound: "npm:^1.0.2" - gopd: "npm:^1.2.0" - has-tostringtag: "npm:^1.0.2" - hasown: "npm:^2.0.2" - checksum: 10c0/1d3715d2b7889932349241680032e85d0b492cfcb045acb75ffc2c3085e8d561184f1f7e84b6f8321935b4aea39bc9c6ba74ed595b57ce4881a51dfdbc214e04 - languageName: node - linkType: hard - -"is-retry-allowed@npm:^1.0.0": - version: 1.2.0 - resolution: "is-retry-allowed@npm:1.2.0" - checksum: 10c0/a80f14e1e11c27a58f268f2927b883b635703e23a853cb7b8436e3456bf2ea3efd5082a4e920093eec7bd372c1ce6ea7cea78a9376929c211039d0cc4a393a44 - languageName: node - linkType: hard - -"is-set@npm:^2.0.3": - version: 2.0.3 - resolution: "is-set@npm:2.0.3" - checksum: 10c0/f73732e13f099b2dc879c2a12341cfc22ccaca8dd504e6edae26484bd5707a35d503fba5b4daad530a9b088ced1ae6c9d8200fd92e09b428fe14ea79ce8080b7 +"is-unicode-supported@npm:^0.1.0": + version: 0.1.0 + resolution: "is-unicode-supported@npm:0.1.0" + checksum: 10c0/00cbe3455c3756be68d2542c416cab888aebd5012781d6819749fefb15162ff23e38501fe681b3d751c73e8ff561ac09a5293eba6f58fdf0178462ce6dcb3453 languageName: node linkType: hard -"is-shared-array-buffer@npm:^1.0.4": - version: 1.0.4 - resolution: "is-shared-array-buffer@npm:1.0.4" +"is-wsl@npm:^2.2.0": + version: 2.2.0 + resolution: "is-wsl@npm:2.2.0" dependencies: - call-bound: "npm:^1.0.3" - checksum: 10c0/65158c2feb41ff1edd6bbd6fd8403a69861cf273ff36077982b5d4d68e1d59278c71691216a4a64632bd76d4792d4d1d2553901b6666d84ade13bba5ea7bc7db + is-docker: "npm:^2.0.0" + checksum: 10c0/a6fa2d370d21be487c0165c7a440d567274fbba1a817f2f0bfa41cc5e3af25041d84267baa22df66696956038a43973e72fca117918c91431920bdef490fa25e languageName: node linkType: hard -"is-stream@npm:^1.0.0, is-stream@npm:^1.1.0": - version: 1.1.0 - resolution: "is-stream@npm:1.1.0" - checksum: 10c0/b8ae7971e78d2e8488d15f804229c6eed7ed36a28f8807a1815938771f4adff0e705218b7dab968270433f67103e4fef98062a0beea55d64835f705ee72c7002 +"isarray@npm:^1.0.0": + version: 1.0.0 + resolution: "isarray@npm:1.0.0" + checksum: 10c0/18b5be6669be53425f0b84098732670ed4e727e3af33bc7f948aac01782110eb9a18b3b329c5323bcdd3acdaae547ee077d3951317e7f133bff7105264b3003d languageName: node linkType: hard -"is-string@npm:^1.1.1": - version: 1.1.1 - resolution: "is-string@npm:1.1.1" - dependencies: - call-bound: "npm:^1.0.3" - has-tostringtag: "npm:^1.0.2" - checksum: 10c0/2f518b4e47886bb81567faba6ffd0d8a8333cf84336e2e78bf160693972e32ad00fe84b0926491cc598dee576fdc55642c92e62d0cbe96bf36f643b6f956f94d +"isexe@npm:^2.0.0": + version: 2.0.0 + resolution: "isexe@npm:2.0.0" + checksum: 10c0/228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d languageName: node linkType: hard -"is-symbol@npm:^1.0.4, is-symbol@npm:^1.1.1": - version: 1.1.1 - resolution: "is-symbol@npm:1.1.1" - dependencies: - call-bound: "npm:^1.0.2" - has-symbols: "npm:^1.1.0" - safe-regex-test: "npm:^1.1.0" - checksum: 10c0/f08f3e255c12442e833f75a9e2b84b2d4882fdfd920513cf2a4a2324f0a5b076c8fd913778e3ea5d258d5183e9d92c0cd20e04b03ab3df05316b049b2670af1e +"isexe@npm:^4.0.0": + version: 4.0.0 + resolution: "isexe@npm:4.0.0" + checksum: 10c0/5884815115bceac452877659a9c7726382531592f43dc29e5d48b7c4100661aed54018cb90bd36cb2eaeba521092570769167acbb95c18d39afdccbcca06c5ce languageName: node linkType: hard -"is-typed-array@npm:^1.1.13, is-typed-array@npm:^1.1.14, is-typed-array@npm:^1.1.15": - version: 1.1.15 - resolution: "is-typed-array@npm:1.1.15" +"isomorphic-unfetch@npm:^3.0.0": + version: 3.1.0 + resolution: "isomorphic-unfetch@npm:3.1.0" dependencies: - which-typed-array: "npm:^1.1.16" - checksum: 10c0/415511da3669e36e002820584e264997ffe277ff136643a3126cc949197e6ca3334d0f12d084e83b1994af2e9c8141275c741cf2b7da5a2ff62dd0cac26f76c4 + node-fetch: "npm:^2.6.1" + unfetch: "npm:^4.2.0" + checksum: 10c0/d3b61fca06304db692b7f76bdfd3a00f410e42cfa7403c3b250546bf71589d18cf2f355922f57198e4cc4a9872d3647b20397a5c3edf1a347c90d57c83cf2a89 languageName: node linkType: hard -"is-typedarray@npm:^1.0.0, is-typedarray@npm:~1.0.0": - version: 1.0.0 - resolution: "is-typedarray@npm:1.0.0" - checksum: 10c0/4c096275ba041a17a13cca33ac21c16bc4fd2d7d7eb94525e7cd2c2f2c1a3ab956e37622290642501ff4310601e413b675cf399ad6db49855527d2163b3eeeec - languageName: node - linkType: hard - -"is-unicode-supported@npm:^0.1.0": - version: 0.1.0 - resolution: "is-unicode-supported@npm:0.1.0" - checksum: 10c0/00cbe3455c3756be68d2542c416cab888aebd5012781d6819749fefb15162ff23e38501fe681b3d751c73e8ff561ac09a5293eba6f58fdf0178462ce6dcb3453 - languageName: node - linkType: hard - -"is-weakmap@npm:^2.0.2": - version: 2.0.2 - resolution: "is-weakmap@npm:2.0.2" - checksum: 10c0/443c35bb86d5e6cc5929cd9c75a4024bb0fff9586ed50b092f94e700b89c43a33b186b76dbc6d54f3d3d09ece689ab38dcdc1af6a482cbe79c0f2da0a17f1299 - languageName: node - linkType: hard - -"is-weakref@npm:^1.0.2, is-weakref@npm:^1.1.1": - version: 1.1.1 - resolution: "is-weakref@npm:1.1.1" - dependencies: - call-bound: "npm:^1.0.3" - checksum: 10c0/8e0a9c07b0c780949a100e2cab2b5560a48ecd4c61726923c1a9b77b6ab0aa0046c9e7fb2206042296817045376dee2c8ab1dabe08c7c3dfbf195b01275a085b - languageName: node - linkType: hard - -"is-weakset@npm:^2.0.3": - version: 2.0.4 - resolution: "is-weakset@npm:2.0.4" - dependencies: - call-bound: "npm:^1.0.3" - get-intrinsic: "npm:^1.2.6" - checksum: 10c0/6491eba08acb8dc9532da23cb226b7d0192ede0b88f16199e592e4769db0a077119c1f5d2283d1e0d16d739115f70046e887e477eb0e66cd90e1bb29f28ba647 - languageName: node - linkType: hard - -"isarray@npm:^1.0.0, isarray@npm:~1.0.0": - version: 1.0.0 - resolution: "isarray@npm:1.0.0" - checksum: 10c0/18b5be6669be53425f0b84098732670ed4e727e3af33bc7f948aac01782110eb9a18b3b329c5323bcdd3acdaae547ee077d3951317e7f133bff7105264b3003d - languageName: node - linkType: hard - -"isarray@npm:^2.0.5": - version: 2.0.5 - resolution: "isarray@npm:2.0.5" - checksum: 10c0/4199f14a7a13da2177c66c31080008b7124331956f47bca57dd0b6ea9f11687aa25e565a2c7a2b519bc86988d10398e3049a1f5df13c9f6b7664154690ae79fd - languageName: node - linkType: hard - -"isexe@npm:^2.0.0": - version: 2.0.0 - resolution: "isexe@npm:2.0.0" - checksum: 10c0/228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d - languageName: node - linkType: hard - -"isexe@npm:^4.0.0": - version: 4.0.0 - resolution: "isexe@npm:4.0.0" - checksum: 10c0/5884815115bceac452877659a9c7726382531592f43dc29e5d48b7c4100661aed54018cb90bd36cb2eaeba521092570769167acbb95c18d39afdccbcca06c5ce - languageName: node - linkType: hard - -"isomorphic-unfetch@npm:^3.0.0": - version: 3.1.0 - resolution: "isomorphic-unfetch@npm:3.1.0" - dependencies: - node-fetch: "npm:^2.6.1" - unfetch: "npm:^4.2.0" - checksum: 10c0/d3b61fca06304db692b7f76bdfd3a00f410e42cfa7403c3b250546bf71589d18cf2f355922f57198e4cc4a9872d3647b20397a5c3edf1a347c90d57c83cf2a89 - languageName: node - linkType: hard - -"isows@npm:1.0.7": - version: 1.0.7 - resolution: "isows@npm:1.0.7" - peerDependencies: - ws: "*" - checksum: 10c0/43c41fe89c7c07258d0be3825f87e12da8ac9023c5b5ae6741ec00b2b8169675c04331ea73ef8c172d37a6747066f4dc93947b17cd369f92828a3b3e741afbda - languageName: node - linkType: hard - -"isstream@npm:~0.1.2": - version: 0.1.2 - resolution: "isstream@npm:0.1.2" - checksum: 10c0/a6686a878735ca0a48e0d674dd6d8ad31aedfaf70f07920da16ceadc7577b46d67179a60b313f2e6860cb097a2c2eb3cbd0b89e921ae89199a59a17c3273d66f - languageName: node - linkType: hard - -"isurl@npm:^1.0.0-alpha5": - version: 1.0.0 - resolution: "isurl@npm:1.0.0" - dependencies: - has-to-string-tag-x: "npm:^1.2.0" - is-object: "npm:^1.0.1" - checksum: 10c0/137e377cd72fefdbc950a226a08e7b35d53672c3b7173b03e72194c3e78a03109aa44c15390b26445b90b7708acb89ca89ed3cd7cc55a6afc7c37cbc88fc581a - languageName: node - linkType: hard - -"iterator.prototype@npm:^1.1.4": - version: 1.1.5 - resolution: "iterator.prototype@npm:1.1.5" - dependencies: - define-data-property: "npm:^1.1.4" - es-object-atoms: "npm:^1.0.0" - get-intrinsic: "npm:^1.2.6" - get-proto: "npm:^1.0.0" - has-symbols: "npm:^1.1.0" - set-function-name: "npm:^2.0.2" - checksum: 10c0/f7a262808e1b41049ab55f1e9c29af7ec1025a000d243b83edf34ce2416eedd56079b117fa59376bb4a724110690f13aa8427f2ee29a09eec63a7e72367626d0 +"isows@npm:1.0.7": + version: 1.0.7 + resolution: "isows@npm:1.0.7" + peerDependencies: + ws: "*" + checksum: 10c0/43c41fe89c7c07258d0be3825f87e12da8ac9023c5b5ae6741ec00b2b8169675c04331ea73ef8c172d37a6747066f4dc93947b17cd369f92828a3b3e741afbda languageName: node linkType: hard @@ -7528,10 +5718,10 @@ __metadata: languageName: node linkType: hard -"js-sha3@npm:0.5.7, js-sha3@npm:^0.5.7": - version: 0.5.7 - resolution: "js-sha3@npm:0.5.7" - checksum: 10c0/17b17d557f9d594ed36ba6c8cdc234bedd7b74ce4baf171e23a1f16b9a89b1527ae160e4eb1b836520acf5919b00732a22183fb00b7808702c36f646c1e9e973 +"js-cookie@npm:^3.0.7": + version: 3.0.8 + resolution: "js-cookie@npm:3.0.8" + checksum: 10c0/421912a4a55535bda32b3059835864e1182c3af5b4516df00a060edc1fa5a53d38bb8d5a91d5d305e396206f4fd11e829f17850aa5aa8164118c04d8ebf1ff5d languageName: node linkType: hard @@ -7542,25 +5732,13 @@ __metadata: languageName: node linkType: hard -"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": +"js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" checksum: 10c0/e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed languageName: node linkType: hard -"js-yaml@npm:^3.12.0, js-yaml@npm:^3.13.0, js-yaml@npm:^3.13.1, js-yaml@npm:^3.14.0": - version: 3.14.1 - resolution: "js-yaml@npm:3.14.1" - dependencies: - argparse: "npm:^1.0.7" - esprima: "npm:^4.0.0" - bin: - js-yaml: bin/js-yaml.js - checksum: 10c0/6746baaaeac312c4db8e75fa22331d9a04cccb7792d126ed8ce6a0bbcfef0cedaddd0c5098fade53db067c09fe00aa1c957674b4765610a8b06a5a189e46433b - languageName: node - linkType: hard - "js-yaml@npm:^4.1.0": version: 4.3.0 resolution: "js-yaml@npm:4.3.0" @@ -7572,24 +5750,17 @@ __metadata: languageName: node linkType: hard -"jsbn@npm:~0.1.0": - version: 0.1.1 - resolution: "jsbn@npm:0.1.1" - checksum: 10c0/e046e05c59ff880ee4ef68902dbdcb6d2f3c5d60c357d4d68647dc23add556c31c0e5f41bdb7e69e793dd63468bd9e085da3636341048ef577b18f5b713877c0 - languageName: node - linkType: hard - -"json-buffer@npm:3.0.0": - version: 3.0.0 - resolution: "json-buffer@npm:3.0.0" - checksum: 10c0/118c060d84430a8ad8376d0c60250830f350a6381bd56541a1ef257ce7ba82d109d1f71a4c4e92e0be0e7ab7da568fad8f7bf02905910a76e8e0aa338621b944 +"json-buffer@npm:3.0.1": + version: 3.0.1 + resolution: "json-buffer@npm:3.0.1" + checksum: 10c0/0d1c91569d9588e7eef2b49b59851f297f3ab93c7b35c7c221e288099322be6b562767d11e4821da500f3219542b9afd2e54c5dc573107c1126ed1080f8e96d7 languageName: node linkType: hard -"json-parse-better-errors@npm:^1.0.1": - version: 1.0.2 - resolution: "json-parse-better-errors@npm:1.0.2" - checksum: 10c0/2f1287a7c833e397c9ddd361a78638e828fc523038bb3441fd4fc144cfd2c6cd4963ffb9e207e648cf7b692600f1e1e524e965c32df5152120910e4903a47dcb +"json-parse-even-better-errors@npm:^2.3.0": + version: 2.3.1 + resolution: "json-parse-even-better-errors@npm:2.3.1" + checksum: 10c0/140932564c8f0b88455432e0f33c4cb4086b8868e37524e07e723f4eaedb9425bdc2bafd71bd1d9765bd15fd1e2d126972bc83990f55c467168c228c24d665f3 languageName: node linkType: hard @@ -7607,13 +5778,6 @@ __metadata: languageName: node linkType: hard -"json-schema@npm:0.4.0": - version: 0.4.0 - resolution: "json-schema@npm:0.4.0" - checksum: 10c0/d4a637ec1d83544857c1c163232f3da46912e971d5bf054ba44fdb88f07d8d359a462b4aec46f2745efbc57053365608d88bc1d7b1729f7b4fc3369765639ed3 - languageName: node - linkType: hard - "json-stable-stringify-without-jsonify@npm:^1.0.1": version: 1.0.1 resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" @@ -7628,33 +5792,6 @@ __metadata: languageName: node linkType: hard -"json-stringify-safe@npm:~5.0.1": - version: 5.0.1 - resolution: "json-stringify-safe@npm:5.0.1" - checksum: 10c0/7dbf35cd0411d1d648dceb6d59ce5857ec939e52e4afc37601aa3da611f0987d5cee5b38d58329ceddf3ed48bd7215229c8d52059ab01f2444a338bf24ed0f37 - languageName: node - linkType: hard - -"json-text-sequence@npm:^0.1": - version: 0.1.1 - resolution: "json-text-sequence@npm:0.1.1" - dependencies: - delimit-stream: "npm:0.1.0" - checksum: 10c0/5c436da4ab3d29f227eaefea2340a116eb62701007f5728c6a2369956d81903a53bbd970dde7e2dd6a9471043f48e97130c65adcc5a0bdd40461fda6d20eab20 - languageName: node - linkType: hard - -"json5@npm:^1.0.2": - version: 1.0.2 - resolution: "json5@npm:1.0.2" - dependencies: - minimist: "npm:^1.2.0" - bin: - json5: lib/cli.js - checksum: 10c0/9ee316bf21f000b00752e6c2a3b79ecf5324515a5c60ee88983a1910a45426b643a4f3461657586e8aeca87aaf96f0a519b0516d2ae527a6c3e7eed80f68717f - languageName: node - linkType: hard - "jsonfile@npm:^4.0.0": version: 4.0.0 resolution: "jsonfile@npm:4.0.0" @@ -7680,6 +5817,13 @@ __metadata: languageName: node linkType: hard +"jsonpointer@npm:^5.0.1": + version: 5.0.1 + resolution: "jsonpointer@npm:5.0.1" + checksum: 10c0/89929e58b400fcb96928c0504fcf4fc3f919d81e9543ceb055df125538470ee25290bb4984251e172e6ef8fcc55761eb998c118da763a82051ad89d4cb073fe7 + languageName: node + linkType: hard + "jsonschema@npm:^1.4.1": version: 1.5.0 resolution: "jsonschema@npm:1.5.0" @@ -7687,30 +5831,6 @@ __metadata: languageName: node linkType: hard -"jsprim@npm:^1.2.2": - version: 1.4.2 - resolution: "jsprim@npm:1.4.2" - dependencies: - assert-plus: "npm:1.0.0" - extsprintf: "npm:1.3.0" - json-schema: "npm:0.4.0" - verror: "npm:1.10.0" - checksum: 10c0/5e4bca99e90727c2040eb4c2190d0ef1fe51798ed5714e87b841d304526190d960f9772acc7108fa1416b61e1122bcd60e4460c91793dce0835df5852aab55af - languageName: node - linkType: hard - -"jsx-ast-utils@npm:^2.4.1 || ^3.0.0, jsx-ast-utils@npm:^3.3.5": - version: 3.3.5 - resolution: "jsx-ast-utils@npm:3.3.5" - dependencies: - array-includes: "npm:^3.1.6" - array.prototype.flat: "npm:^1.3.1" - object.assign: "npm:^4.1.4" - object.values: "npm:^1.1.6" - checksum: 10c0/a32679e9cb55469cb6d8bbc863f7d631b2c98b7fc7bf172629261751a6e7bc8da6ae374ddb74d5fbd8b06cf0eb4572287b259813d92b36e384024ed35e4c13e1 - languageName: node - linkType: hard - "keccak@npm:^3.0.0": version: 3.0.2 resolution: "keccak@npm:3.0.2" @@ -7735,38 +5855,44 @@ __metadata: languageName: node linkType: hard -"keyv@npm:^3.0.0": - version: 3.1.0 - resolution: "keyv@npm:3.1.0" +"keyv@npm:^4.5.3": + version: 4.5.4 + resolution: "keyv@npm:4.5.4" + dependencies: + json-buffer: "npm:3.0.1" + checksum: 10c0/aa52f3c5e18e16bb6324876bb8b59dd02acf782a4b789c7b2ae21107fab95fab3890ed448d4f8dba80ce05391eeac4bfabb4f02a20221342982f806fa2cf271e + languageName: node + linkType: hard + +"keyv@npm:^5.6.0": + version: 5.6.0 + resolution: "keyv@npm:5.6.0" dependencies: - json-buffer: "npm:3.0.0" - checksum: 10c0/6ad784361b4c0213333a8c5bc0bcc59cf46cb7cbbe21fb2f1539ffcc8fe18b8f1562ff913b40552278fdea5f152a15996dfa61ce24ce1a22222560c650be4a1b + "@keyv/serialize": "npm:^1.1.1" + checksum: 10c0/c3ea795b6e03593ca57c8f70928a69bad14c13389a7fb75649a115ff55615244b04d8902798d841c17f0bb4a8a8866c97133b543b93f151b440170bba09176db languageName: node linkType: hard -"language-subtag-registry@npm:^0.3.20": - version: 0.3.23 - resolution: "language-subtag-registry@npm:0.3.23" - checksum: 10c0/e9b05190421d2cd36dd6c95c28673019c927947cb6d94f40ba7e77a838629ee9675c94accf897fbebb07923187deb843b8fbb8935762df6edafe6c28dcb0b86c +"kleur@npm:^3.0.3": + version: 3.0.3 + resolution: "kleur@npm:3.0.3" + checksum: 10c0/cd3a0b8878e7d6d3799e54340efe3591ca787d9f95f109f28129bdd2915e37807bf8918bb295ab86afb8c82196beec5a1adcaf29042ce3f2bd932b038fe3aa4b languageName: node linkType: hard -"language-tags@npm:^1.0.9": - version: 1.0.9 - resolution: "language-tags@npm:1.0.9" +"latest-version@npm:^7.0.0": + version: 7.0.0 + resolution: "latest-version@npm:7.0.0" dependencies: - language-subtag-registry: "npm:^0.3.20" - checksum: 10c0/9ab911213c4bd8bd583c850201c17794e52cb0660d1ab6e32558aadc8324abebf6844e46f92b80a5d600d0fbba7eface2c207bfaf270a1c7fd539e4c3a880bff + package-json: "npm:^8.1.0" + checksum: 10c0/68045f5e419e005c12e595ae19687dd88317dd0108b83a8773197876622c7e9d164fe43aacca4f434b2cba105c92848b89277f658eabc5d50e81fb743bbcddb1 languageName: node linkType: hard -"levn@npm:^0.3.0, levn@npm:~0.3.0": - version: 0.3.0 - resolution: "levn@npm:0.3.0" - dependencies: - prelude-ls: "npm:~1.1.2" - type-check: "npm:~0.3.2" - checksum: 10c0/e440df9de4233da0b389cd55bd61f0f6aaff766400bebbccd1231b81801f6dbc1d816c676ebe8d70566394b749fa624b1ed1c68070e9c94999f0bdecc64cb676 +"leven@npm:^3.1.0 < 4": + version: 3.1.0 + resolution: "leven@npm:3.1.0" + checksum: 10c0/cd778ba3fbab0f4d0500b7e87d1f6e1f041507c56fdcd47e8256a3012c98aaee371d4c15e0a76e0386107af2d42e2b7466160a2d80688aaa03e66e49949f42df languageName: node linkType: hard @@ -7780,13 +5906,10 @@ __metadata: languageName: node linkType: hard -"locate-path@npm:^2.0.0": - version: 2.0.0 - resolution: "locate-path@npm:2.0.0" - dependencies: - p-locate: "npm:^2.0.0" - path-exists: "npm:^3.0.0" - checksum: 10c0/24efa0e589be6aa3c469b502f795126b26ab97afa378846cb508174211515633b770aa0ba610cab113caedab8d2a4902b061a08aaed5297c12ab6f5be4df0133 +"lines-and-columns@npm:^1.1.6": + version: 1.2.4 + resolution: "lines-and-columns@npm:1.2.4" + checksum: 10c0/3da6ee62d4cd9f03f5dc90b4df2540fb85b352081bee77fe4bbcd12c9000ead7f35e0a38b8d09a9bb99b13223446dd8689ff3c4959807620726d788701a83d2d languageName: node linkType: hard @@ -7813,10 +5936,10 @@ __metadata: languageName: node linkType: hard -"lodash.merge@npm:^4.6.2": - version: 4.6.2 - resolution: "lodash.merge@npm:4.6.2" - checksum: 10c0/402fa16a1edd7538de5b5903a90228aa48eb5533986ba7fa26606a49db2572bf414ff73a2c9f5d5fd36b31c46a5d5c7e1527749c07cbcf965ccff5fbdf32c506 +"lodash.isequal@npm:^4.5.0": + version: 4.5.0 + resolution: "lodash.isequal@npm:4.5.0" + checksum: 10c0/dfdb2356db19631a4b445d5f37868a095e2402292d59539a987f134a8778c62a2810c2452d11ae9e6dcac71fc9de40a6fedcb20e2952a15b431ad8b29e50e28f languageName: node linkType: hard @@ -7827,7 +5950,7 @@ __metadata: languageName: node linkType: hard -"lodash@npm:^4.17.11, lodash@npm:^4.17.12, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.19": +"lodash@npm:^4.17.11, lodash@npm:^4.17.15, lodash@npm:^4.17.19": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: 10c0/d8cbea072bb08655bb4c989da418994b073a608dffa608b09ac04b43a791b12aeae7cd7ad919aa4c925f33b48490b5cfe6c1f71d827956071dae2e7bb3a6b74c @@ -7851,28 +5974,10 @@ __metadata: languageName: node linkType: hard -"loose-envify@npm:^1.4.0": - version: 1.4.0 - resolution: "loose-envify@npm:1.4.0" - dependencies: - js-tokens: "npm:^3.0.0 || ^4.0.0" - bin: - loose-envify: cli.js - checksum: 10c0/655d110220983c1a4b9c0c679a2e8016d4b67f6e9c7b5435ff5979ecdb20d0813f4dec0a08674fcbdd4846a3f07edbb50a36811fd37930b94aaa0d9daceb017e - languageName: node - linkType: hard - -"lowercase-keys@npm:^1.0.0, lowercase-keys@npm:^1.0.1": - version: 1.0.1 - resolution: "lowercase-keys@npm:1.0.1" - checksum: 10c0/56776a8e1ef1aca98ecf6c19b30352ae1cf257b65b8ac858b7d8a0e8b348774d12a9b41aa7f59bfea51bff44bc7a198ab63ba4406bfba60dba008799618bef66 - languageName: node - linkType: hard - -"lowercase-keys@npm:^2.0.0": - version: 2.0.0 - resolution: "lowercase-keys@npm:2.0.0" - checksum: 10c0/f82a2b3568910509da4b7906362efa40f5b54ea14c2584778ddb313226f9cbf21020a5db35f9b9a0e95847a9b781d548601f31793d736b22a2b8ae8eb9ab1082 +"lowercase-keys@npm:^3.0.0": + version: 3.0.0 + resolution: "lowercase-keys@npm:3.0.0" + checksum: 10c0/ef62b9fa5690ab0a6e4ef40c94efce68e3ed124f583cc3be38b26ff871da0178a28b9a84ce0c209653bb25ca135520ab87fea7cd411a54ac4899cb2f30501430 languageName: node linkType: hard @@ -7906,15 +6011,6 @@ __metadata: languageName: node linkType: hard -"make-dir@npm:^1.0.0": - version: 1.3.0 - resolution: "make-dir@npm:1.3.0" - dependencies: - pify: "npm:^3.0.0" - checksum: 10c0/5eb94f47d7ef41d89d1b8eef6539b8950d5bd99eeba093a942bfd327faa37d2d62227526b88b73633243a2ec7972d21eb0f4e5d62ae4e02a79e389f4a7bb3022 - languageName: node - linkType: hard - "make-error@npm:^1.1.1": version: 1.3.6 resolution: "make-error@npm:1.3.6" @@ -7976,13 +6072,6 @@ __metadata: languageName: node linkType: hard -"media-typer@npm:0.3.0": - version: 0.3.0 - resolution: "media-typer@npm:0.3.0" - checksum: 10c0/d160f31246907e79fed398470285f21bafb45a62869dc469b1c8877f3f064f5eabc4bcc122f9479b8b605bc5c76187d7871cf84c4ee3ecd3e487da1993279928 - languageName: node - linkType: hard - "memorystream@npm:^0.3.1": version: 0.3.1 resolution: "memorystream@npm:0.3.1" @@ -7990,27 +6079,6 @@ __metadata: languageName: node linkType: hard -"merge-descriptors@npm:1.0.1": - version: 1.0.1 - resolution: "merge-descriptors@npm:1.0.1" - checksum: 10c0/b67d07bd44cfc45cebdec349bb6e1f7b077ee2fd5beb15d1f7af073849208cb6f144fe403e29a36571baf3f4e86469ac39acf13c318381e958e186b2766f54ec - languageName: node - linkType: hard - -"merge2@npm:^1.3.0, merge2@npm:^1.4.1": - version: 1.4.1 - resolution: "merge2@npm:1.4.1" - checksum: 10c0/254a8a4605b58f450308fc474c82ac9a094848081bf4c06778200207820e5193726dc563a0d2c16468810516a5c97d9d3ea0ca6585d23c58ccfff2403e8dbbeb - languageName: node - linkType: hard - -"methods@npm:~1.1.2": - version: 1.1.2 - resolution: "methods@npm:1.1.2" - checksum: 10c0/bdf7cc72ff0a33e3eede03708c08983c4d7a173f91348b4b1e4f47d4cdbf734433ad971e7d1e8c77247d9e5cd8adb81ea4c67b0a2db526b758b2233d7814b8b2 - languageName: node - linkType: hard - "micro-eth-signer@npm:^0.14.0": version: 0.14.0 resolution: "micro-eth-signer@npm:0.14.0" @@ -8031,28 +6099,6 @@ __metadata: languageName: node linkType: hard -"micromatch@npm:^4.0.8": - version: 4.0.8 - resolution: "micromatch@npm:4.0.8" - dependencies: - braces: "npm:^3.0.3" - picomatch: "npm:^2.3.1" - checksum: 10c0/166fa6eb926b9553f32ef81f5f531d27b4ce7da60e5baf8c021d043b27a388fb95e46a8038d5045877881e673f8134122b59624d5cecbd16eb50a42e7a6b5ca8 - languageName: node - linkType: hard - -"miller-rabin@npm:^4.0.0": - version: 4.0.1 - resolution: "miller-rabin@npm:4.0.1" - dependencies: - bn.js: "npm:^4.0.0" - brorand: "npm:^1.0.1" - bin: - miller-rabin: bin/miller-rabin - checksum: 10c0/26b2b96f6e49dbcff7faebb78708ed2f5f9ae27ac8cbbf1d7c08f83cf39bed3d418c0c11034dce997da70d135cc0ff6f3a4c15dc452f8e114c11986388a64346 - languageName: node - linkType: hard - "mime-db@npm:1.52.0": version: 1.52.0 resolution: "mime-db@npm:1.52.0" @@ -8060,7 +6106,7 @@ __metadata: languageName: node linkType: hard -"mime-types@npm:^2.1.12, mime-types@npm:^2.1.16, mime-types@npm:^2.1.35, mime-types@npm:~2.1.19, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": +"mime-types@npm:^2.1.12, mime-types@npm:^2.1.35": version: 2.1.35 resolution: "mime-types@npm:2.1.35" dependencies: @@ -8069,42 +6115,17 @@ __metadata: languageName: node linkType: hard -"mime@npm:1.6.0": - version: 1.6.0 - resolution: "mime@npm:1.6.0" - bin: - mime: cli.js - checksum: 10c0/b92cd0adc44888c7135a185bfd0dddc42c32606401c72896a842ae15da71eb88858f17669af41e498b463cd7eb998f7b48939a25b08374c7924a9c8a6f8a81b0 - languageName: node - linkType: hard - -"mimic-fn@npm:^1.0.0": - version: 1.2.0 - resolution: "mimic-fn@npm:1.2.0" - checksum: 10c0/ad55214aec6094c0af4c0beec1a13787556f8116ed88807cf3f05828500f21f93a9482326bcd5a077ae91e3e8795b4e76b5b4c8bb12237ff0e4043a365516cba - languageName: node - linkType: hard - -"mimic-fn@npm:^2.1.0": - version: 2.1.0 - resolution: "mimic-fn@npm:2.1.0" - checksum: 10c0/b26f5479d7ec6cc2bce275a08f146cf78f5e7b661b18114e2506dd91ec7ec47e7a25bf4360e5438094db0560bcc868079fb3b1fb3892b833c1ecbf63f80c95a4 - languageName: node - linkType: hard - -"mimic-response@npm:^1.0.0, mimic-response@npm:^1.0.1": - version: 1.0.1 - resolution: "mimic-response@npm:1.0.1" - checksum: 10c0/c5381a5eae997f1c3b5e90ca7f209ed58c3615caeee850e85329c598f0c000ae7bec40196580eef1781c60c709f47258131dab237cad8786f8f56750594f27fa +"mimic-response@npm:^3.1.0": + version: 3.1.0 + resolution: "mimic-response@npm:3.1.0" + checksum: 10c0/0d6f07ce6e03e9e4445bee655202153bdb8a98d67ee8dc965ac140900d7a2688343e6b4c9a72cfc9ef2f7944dfd76eef4ab2482eb7b293a68b84916bac735362 languageName: node linkType: hard -"min-document@npm:^2.19.0": - version: 2.19.0 - resolution: "min-document@npm:2.19.0" - dependencies: - dom-walk: "npm:^0.1.0" - checksum: 10c0/783724da716fc73a51c171865d7b29bf2b855518573f82ef61c40d214f6898d7b91b5c5419e4d22693cdb78d4615873ebc3b37d7639d3dd00ca283e5a07c7af9 +"mimic-response@npm:^4.0.0": + version: 4.0.0 + resolution: "mimic-response@npm:4.0.0" + checksum: 10c0/761d788d2668ae9292c489605ffd4fad220f442fbae6832adce5ebad086d691e906a6d5240c290293c7a11e99fbdbbef04abbbed498bf8699a4ee0f31315e3fb languageName: node linkType: hard @@ -8131,7 +6152,16 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^3.0.4, minimatch@npm:^3.1.2": +"minimatch@npm:^10.2.4, minimatch@npm:^10.2.5, minimatch@npm:^9.0.3 || ^10.1.2": + version: 10.2.6 + resolution: "minimatch@npm:10.2.6" + dependencies: + brace-expansion: "npm:^5.0.8" + checksum: 10c0/4559a836243b98bd4d17ea9f7edae698717c76399eea7be374f3737f33164e4907f19e9726891ddeb122f750a5a7fa80d2ac43e851d6e5984dc4ff42ec127d3a + languageName: node + linkType: hard + +"minimatch@npm:^3.0.4": version: 3.1.2 resolution: "minimatch@npm:3.1.2" dependencies: @@ -8158,20 +6188,20 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6": - version: 1.2.6 - resolution: "minimist@npm:1.2.6" - checksum: 10c0/d0b566204044481c4401abbd24cc75814e753b37268e7fe7ccc78612bf3e37bf1e45a6c43fb0b119445ea1c413c000bde013f320b7211974f2f49bcbec1d0dbf - languageName: node - linkType: hard - -"minimist@npm:^1.2.7": +"minimist@npm:^1.2.0, minimist@npm:^1.2.7": version: 1.2.8 resolution: "minimist@npm:1.2.8" checksum: 10c0/19d3fcdca050087b84c2029841a093691a91259a47def2f18222f41e7645a0b7c44ef4b40e88a1e58a40c84d2ef0ee6047c55594d298146d0eb3f6b737c20ce6 languageName: node linkType: hard +"minimist@npm:^1.2.5": + version: 1.2.6 + resolution: "minimist@npm:1.2.6" + checksum: 10c0/d0b566204044481c4401abbd24cc75814e753b37268e7fe7ccc78612bf3e37bf1e45a6c43fb0b119445ea1c413c000bde013f320b7211974f2f49bcbec1d0dbf + languageName: node + linkType: hard + "minipass-collect@npm:^2.0.1": version: 2.0.1 resolution: "minipass-collect@npm:2.0.1" @@ -8223,16 +6253,6 @@ __metadata: languageName: node linkType: hard -"minipass@npm:^2.6.0, minipass@npm:^2.9.0": - version: 2.9.0 - resolution: "minipass@npm:2.9.0" - dependencies: - safe-buffer: "npm:^5.1.2" - yallist: "npm:^3.0.0" - checksum: 10c0/307d8765ac3db9fcd6b486367e6f6c3e460f3a3e198d95d6c0005a2d95804c40c72959261cdebde3c8237cda0b03d4c01975e4581fe11abcf201f5005caafd2a - languageName: node - linkType: hard - "minipass@npm:^3.0.0": version: 3.3.6 resolution: "minipass@npm:3.3.6" @@ -8249,15 +6269,6 @@ __metadata: languageName: node linkType: hard -"minizlib@npm:^1.3.3": - version: 1.3.3 - resolution: "minizlib@npm:1.3.3" - dependencies: - minipass: "npm:^2.9.0" - checksum: 10c0/79798032bbaa6594fa517e5b7ff9977951984fc9548a421b28d3fb0add8ed7e98a33e41e262af53b944f9d860c1e00fc778b477ef692e7b38b1ba12b390ffb17 - languageName: node - linkType: hard - "minizlib@npm:^3.0.1, minizlib@npm:^3.1.0": version: 3.1.0 resolution: "minizlib@npm:3.1.0" @@ -8267,16 +6278,7 @@ __metadata: languageName: node linkType: hard -"mkdirp-promise@npm:^5.0.1": - version: 5.0.1 - resolution: "mkdirp-promise@npm:5.0.1" - dependencies: - mkdirp: "npm:*" - checksum: 10c0/c99007908866d65ebaa1fd7f0b0d090e577ac92f6cc5cb98b91a68a461fd9b973412447fb00be3bb2346f5535126667f1e27964abf390f2c1cd077e4fdb59e08 - languageName: node - linkType: hard - -"mkdirp@npm:*, mkdirp@npm:^1.0.4": +"mkdirp@npm:^1.0.4": version: 1.0.4 resolution: "mkdirp@npm:1.0.4" bin: @@ -8285,28 +6287,6 @@ __metadata: languageName: node linkType: hard -"mkdirp@npm:^0.5.1": - version: 0.5.5 - resolution: "mkdirp@npm:0.5.5" - dependencies: - minimist: "npm:^1.2.5" - bin: - mkdirp: bin/cmd.js - checksum: 10c0/4469faeeba703bc46b7cdbe3097d6373747a581eb8b556ce41c8fd25a826eb3254466c6522ba823c2edb0b6f0da7beb91cf71f040bc4e361534a3e67f0994bd0 - languageName: node - linkType: hard - -"mkdirp@npm:^0.5.5": - version: 0.5.6 - resolution: "mkdirp@npm:0.5.6" - dependencies: - minimist: "npm:^1.2.6" - bin: - mkdirp: bin/cmd.js - checksum: 10c0/e2e2be789218807b58abced04e7b49851d9e46e88a2f9539242cc8a92c9b5c3a0b9bab360bd3014e02a140fc4fbc58e31176c408b493f8a2a6f4986bd7527b01 - languageName: node - linkType: hard - "mnemonist@npm:^0.38.0": version: 0.38.5 resolution: "mnemonist@npm:0.38.5" @@ -8348,20 +6328,6 @@ __metadata: languageName: node linkType: hard -"mock-fs@npm:^4.1.0": - version: 4.14.0 - resolution: "mock-fs@npm:4.14.0" - checksum: 10c0/a23bc2ce74f2a01d02053fb20aecc2ea359e62580cd15b5e1029b55929802e2770bbd683ccdc5c1eabb5cecbf452196bb81a0ef61c4629dc819023e10d8303c6 - languageName: node - linkType: hard - -"ms@npm:2.0.0": - version: 2.0.0 - resolution: "ms@npm:2.0.0" - checksum: 10c0/f8fda810b39fd7255bbdc451c46286e549794fcc700dc9cd1d25658bbc4dc2563a5de6fe7c60f798a16a60c6ceb53f033cb353f493f0cf63e5199b702943159d - languageName: node - linkType: hard - "ms@npm:2.1.2": version: 2.1.2 resolution: "ms@npm:2.1.2" @@ -8369,7 +6335,7 @@ __metadata: languageName: node linkType: hard -"ms@npm:2.1.3, ms@npm:^2.1.1, ms@npm:^2.1.3": +"ms@npm:^2.1.3": version: 2.1.3 resolution: "ms@npm:2.1.3" checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 @@ -8387,47 +6353,19 @@ __metadata: languageName: node linkType: hard -"mute-stream@npm:0.0.7": - version: 0.0.7 - resolution: "mute-stream@npm:0.0.7" - checksum: 10c0/c687cfe99289166fe17dcbd0cf49612c5d267410a7819b654a82df45016967d7b2b0b18b35410edef86de6bb089a00413557dc0182c5e78a4af50ba5d61edb42 +"napi-postinstall@npm:^0.3.4": + version: 0.3.4 + resolution: "napi-postinstall@npm:0.3.4" + bin: + napi-postinstall: lib/cli.js + checksum: 10c0/b33d64150828bdade3a5d07368a8b30da22ee393f8dd8432f1b9e5486867be21c84ec443dd875dd3ef3c7401a079a7ab7e2aa9d3538a889abbcd96495d5104fe languageName: node linkType: hard -"mvdan-sh@npm:^0.5.0": - version: 0.5.0 - resolution: "mvdan-sh@npm:0.5.0" - checksum: 10c0/78cdf4f8b2a1a9595f52de99492c0d1a1a670846a300e6601b89e0dea6dcd7380170052f5ede78a8989ddb031f7f7e2fc29812e8385a369468dc66a70640913c - languageName: node - linkType: hard - -"nan@npm:^2.14.0": - version: 2.16.0 - resolution: "nan@npm:2.16.0" - dependencies: - node-gyp: "npm:latest" - checksum: 10c0/95204e4ed2970c0411735d866b0a71f30625e9ce598d2f7c2dfc2145dcd4e8e48dda26fda2587657f91e96973044353d300a9a6d259079b342fa4b30548aa8fa - languageName: node - linkType: hard - -"nano-json-stream-parser@npm:^0.1.2": - version: 0.1.2 - resolution: "nano-json-stream-parser@npm:0.1.2" - checksum: 10c0/c42df4cf2922a0b9771a6927df85bb10de01009ea0ea3d354eb3cd7f59d50cbe1350ebdfc78c0fb3dcb71adcdea2c4e3452e0210db8875b0d03f61210151a9a7 - languageName: node - linkType: hard - -"natural-compare@npm:^1.4.0": - version: 1.4.0 - resolution: "natural-compare@npm:1.4.0" - checksum: 10c0/f5f9a7974bfb28a91afafa254b197f0f22c684d4a1731763dda960d2c8e375b36c7d690e0d9dc8fba774c537af14a7e979129bca23d88d052fbeb9466955e447 - languageName: node - linkType: hard - -"negotiator@npm:0.6.3": - version: 0.6.3 - resolution: "negotiator@npm:0.6.3" - checksum: 10c0/3ec9fd413e7bf071c937ae60d572bc67155262068ed522cf4b3be5edbe6ddf67d095ec03a3a14ebf8fc8e95f8e1d61be4869db0dbb0de696f6b837358bd43fc2 +"natural-compare@npm:^1.4.0": + version: 1.4.0 + resolution: "natural-compare@npm:1.4.0" + checksum: 10c0/f5f9a7974bfb28a91afafa254b197f0f22c684d4a1731763dda960d2c8e375b36c7d690e0d9dc8fba774c537af14a7e979129bca23d88d052fbeb9466955e447 languageName: node linkType: hard @@ -8445,17 +6383,10 @@ __metadata: languageName: node linkType: hard -"next-tick@npm:^1.1.0": - version: 1.1.0 - resolution: "next-tick@npm:1.1.0" - checksum: 10c0/3ba80dd805fcb336b4f52e010992f3e6175869c8d88bf4ff0a81d5d66e6049f89993463b28211613e58a6b7fe93ff5ccbba0da18d4fa574b96289e8f0b577f28 - languageName: node - linkType: hard - -"nice-try@npm:^1.0.4": - version: 1.0.5 - resolution: "nice-try@npm:1.0.5" - checksum: 10c0/95568c1b73e1d0d4069a3e3061a2102d854513d37bcfda73300015b7ba4868d3b27c198d1dbbd8ebdef4112fc2ed9e895d4a0f2e1cce0bd334f2a1346dc9205f +"neoqs@npm:^6.13.0": + version: 6.13.0 + resolution: "neoqs@npm:6.13.0" + checksum: 10c0/646f4698b44e2479ca53be8530ebff704495db1db382b6a774ef621ef3456d17defad396d9256dd85c46b7ce5c7b7344e0231913e3b79ffbc84773efa8976810 languageName: node linkType: hard @@ -8527,13 +6458,6 @@ __metadata: languageName: node linkType: hard -"nofilter@npm:^1.0.3": - version: 1.0.4 - resolution: "nofilter@npm:1.0.4" - checksum: 10c0/fcee4ed627e18c8d66dda5afca79607e569e6997c08bd12dfb8a1578fe2674a1de7761b36ae207d6a10c545f27e236aae18f0c2b33e0ef8971507bda419793b7 - languageName: node - linkType: hard - "nofilter@npm:^3.0.2, nofilter@npm:^3.1.0": version: 3.1.0 resolution: "nofilter@npm:3.1.0" @@ -8559,34 +6483,10 @@ __metadata: languageName: node linkType: hard -"normalize-url@npm:^4.1.0": - version: 4.5.1 - resolution: "normalize-url@npm:4.5.1" - checksum: 10c0/6362e9274fdcc310f8b17e20de29754c94e1820d864114f03d3bfd6286a0028fc51705fb3fd4e475013357b5cd7421fc17f3aba93f2289056779a9bb23bccf59 - languageName: node - linkType: hard - -"number-to-bn@npm:1.7.0": - version: 1.7.0 - resolution: "number-to-bn@npm:1.7.0" - dependencies: - bn.js: "npm:4.11.6" - strip-hex-prefix: "npm:1.0.0" - checksum: 10c0/83d1540173c4fc60ef4e91e88ed17f2c38418c8e5e62f469d62404527efba48d9c40f364da5c5e6857234a6c1154ff32b3642d80f873ba6cb8d2dd05fb6bc303 - languageName: node - linkType: hard - -"oauth-sign@npm:~0.9.0": - version: 0.9.0 - resolution: "oauth-sign@npm:0.9.0" - checksum: 10c0/fc92a516f6ddbb2699089a2748b04f55c47b6ead55a77cd3a2cbbce5f7af86164cb9425f9ae19acfd066f1ad7d3a96a67b8928c6ea946426f6d6c29e448497c2 - languageName: node - linkType: hard - -"object-assign@npm:^4, object-assign@npm:^4.0.1, object-assign@npm:^4.1.0, object-assign@npm:^4.1.1": - version: 4.1.1 - resolution: "object-assign@npm:4.1.1" - checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414 +"normalize-url@npm:^8.0.0": + version: 8.1.1 + resolution: "normalize-url@npm:8.1.1" + checksum: 10c0/1beb700ce42acb2288f39453cdf8001eead55bbf046d407936a40404af420b8c1c6be97a869884ae9e659d7b1c744e40e905c875ac9290644eec2e3e6fb0b370 languageName: node linkType: hard @@ -8597,74 +6497,6 @@ __metadata: languageName: node linkType: hard -"object-keys@npm:^1.1.1": - version: 1.1.1 - resolution: "object-keys@npm:1.1.1" - checksum: 10c0/b11f7ccdbc6d406d1f186cdadb9d54738e347b2692a14439ca5ac70c225fa6db46db809711b78589866d47b25fc3e8dee0b4c722ac751e11180f9380e3d8601d - languageName: node - linkType: hard - -"object.assign@npm:^4.1.2, object.assign@npm:^4.1.4, object.assign@npm:^4.1.7": - version: 4.1.7 - resolution: "object.assign@npm:4.1.7" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.0.0" - has-symbols: "npm:^1.1.0" - object-keys: "npm:^1.1.1" - checksum: 10c0/3b2732bd860567ea2579d1567525168de925a8d852638612846bd8082b3a1602b7b89b67b09913cbb5b9bd6e95923b2ae73580baa9d99cb4e990564e8cbf5ddc - languageName: node - linkType: hard - -"object.entries@npm:^1.1.2, object.entries@npm:^1.1.9": - version: 1.1.9 - resolution: "object.entries@npm:1.1.9" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.4" - define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.1.1" - checksum: 10c0/d4b8c1e586650407da03370845f029aa14076caca4e4d4afadbc69cfb5b78035fd3ee7be417141abdb0258fa142e59b11923b4c44d8b1255b28f5ffcc50da7db - languageName: node - linkType: hard - -"object.fromentries@npm:^2.0.8": - version: 2.0.8 - resolution: "object.fromentries@npm:2.0.8" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.2" - es-object-atoms: "npm:^1.0.0" - checksum: 10c0/cd4327e6c3369cfa805deb4cbbe919bfb7d3aeebf0bcaba291bb568ea7169f8f8cdbcabe2f00b40db0c20cd20f08e11b5f3a5a36fb7dd3fe04850c50db3bf83b - languageName: node - linkType: hard - -"object.groupby@npm:^1.0.3": - version: 1.0.3 - resolution: "object.groupby@npm:1.0.3" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.2" - checksum: 10c0/60d0455c85c736fbfeda0217d1a77525956f76f7b2495edeca9e9bbf8168a45783199e77b894d30638837c654d0cc410e0e02cbfcf445bc8de71c3da1ede6a9c - languageName: node - linkType: hard - -"object.values@npm:^1.1.6, object.values@npm:^1.2.1": - version: 1.2.1 - resolution: "object.values@npm:1.2.1" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.0.0" - checksum: 10c0/3c47814fdc64842ae3d5a74bc9d06bdd8d21563c04d9939bf6716a9c00596a4ebc342552f8934013d1ec991c74e3671b26710a0c51815f0b603795605ab6b2c9 - languageName: node - linkType: hard - "obliterator@npm:^2.0.0": version: 2.0.1 resolution: "obliterator@npm:2.0.1" @@ -8672,25 +6504,7 @@ __metadata: languageName: node linkType: hard -"oboe@npm:2.1.4": - version: 2.1.4 - resolution: "oboe@npm:2.1.4" - dependencies: - http-https: "npm:^1.0.0" - checksum: 10c0/29bfbdc0cb995c56d03635dc4fa2bbcd2906ca0738a5b2b2a44548bd94c4299210f0e664f65d864f6b41c7360dabd06c203bd51dbd17e5909b0bac8ca57c4786 - languageName: node - linkType: hard - -"on-finished@npm:2.4.1": - version: 2.4.1 - resolution: "on-finished@npm:2.4.1" - dependencies: - ee-first: "npm:1.1.1" - checksum: 10c0/46fb11b9063782f2d9968863d9cbba33d77aa13c17f895f56129c274318b86500b22af3a160fe9995aa41317efcd22941b6eba747f718ced08d9a73afdb087b4 - languageName: node - linkType: hard - -"once@npm:^1.3.0, once@npm:^1.3.1, once@npm:^1.4.0": +"once@npm:^1.3.0": version: 1.4.0 resolution: "once@npm:1.4.0" dependencies: @@ -8699,56 +6513,28 @@ __metadata: languageName: node linkType: hard -"onetime@npm:^2.0.0": - version: 2.0.1 - resolution: "onetime@npm:2.0.1" - dependencies: - mimic-fn: "npm:^1.0.0" - checksum: 10c0/b4e44a8c34e70e02251bfb578a6e26d6de6eedbed106cd78211d2fd64d28b6281d54924696554e4e966559644243753ac5df73c87f283b0927533d3315696215 - languageName: node - linkType: hard - -"onetime@npm:^5.1.0": - version: 5.1.2 - resolution: "onetime@npm:5.1.2" - dependencies: - mimic-fn: "npm:^2.1.0" - checksum: 10c0/ffcef6fbb2692c3c40749f31ea2e22677a876daea92959b8a80b521d95cca7a668c884d8b2045d1d8ee7d56796aa405c405462af112a1477594cc63531baeb8f - languageName: node - linkType: hard - -"openzeppelin-solidity@npm:2.4.0": - version: 2.4.0 - resolution: "openzeppelin-solidity@npm:2.4.0" - checksum: 10c0/cb522a60c62b87dc7edce81aca5e36d19ef21dc33b10ba61958faf0cb7f52e126701b55aafcd55ef3bbe6ac971007cd161d74580d63bde6f66c6ea3a17c541af - languageName: node - linkType: hard - -"optionator@npm:^0.8.2": - version: 0.8.3 - resolution: "optionator@npm:0.8.3" +"open@npm:^8.4.0": + version: 8.4.2 + resolution: "open@npm:8.4.2" dependencies: - deep-is: "npm:~0.1.3" - fast-levenshtein: "npm:~2.0.6" - levn: "npm:~0.3.0" - prelude-ls: "npm:~1.1.2" - type-check: "npm:~0.3.2" - word-wrap: "npm:~1.2.3" - checksum: 10c0/ad7000ea661792b3ec5f8f86aac28895850988926f483b5f308f59f4607dfbe24c05df2d049532ee227c040081f39401a268cf7bbf3301512f74c4d760dc6dd8 + define-lazy-prop: "npm:^2.0.0" + is-docker: "npm:^2.1.1" + is-wsl: "npm:^2.2.0" + checksum: 10c0/bb6b3a58401dacdb0aad14360626faf3fb7fba4b77816b373495988b724fb48941cad80c1b65d62bb31a17609b2cd91c41a181602caea597ca80dfbcc27e84c9 languageName: node linkType: hard -"optionator@npm:^0.9.1": - version: 0.9.1 - resolution: "optionator@npm:0.9.1" +"optionator@npm:^0.9.3": + version: 0.9.4 + resolution: "optionator@npm:0.9.4" dependencies: deep-is: "npm:^0.1.3" fast-levenshtein: "npm:^2.0.6" levn: "npm:^0.4.1" prelude-ls: "npm:^1.2.1" type-check: "npm:^0.4.0" - word-wrap: "npm:^1.2.3" - checksum: 10c0/8b574d50b032f34713dc09bfacdc351824f713c3c80773ead3a05ab977364de88f2f3962a6f15437747b93a5e0636928253949970daea3aaeeefbd3a525da6a4 + word-wrap: "npm:^1.2.5" + checksum: 10c0/4afb687a059ee65b61df74dfe87d8d6815cd6883cb8b3d5883a910df72d0f5d029821f37025e4bccf4048873dbdb09acc6d303d27b8f76b1a80dd5a7d5334675 languageName: node linkType: hard @@ -8766,17 +6552,6 @@ __metadata: languageName: node linkType: hard -"own-keys@npm:^1.0.1": - version: 1.0.1 - resolution: "own-keys@npm:1.0.1" - dependencies: - get-intrinsic: "npm:^1.2.6" - object-keys: "npm:^1.1.1" - safe-push-apply: "npm:^1.0.0" - checksum: 10c0/6dfeb3455bff92ec3f16a982d4e3e65676345f6902d9f5ded1d8265a6318d0200ce461956d6d1c70053c7fe9f9fe65e552faac03f8140d37ef0fdd108e67013a - languageName: node - linkType: hard - "ox@npm:0.14.33": version: 0.14.33 resolution: "ox@npm:0.14.33" @@ -8798,33 +6573,10 @@ __metadata: languageName: node linkType: hard -"p-cancelable@npm:^0.3.0": - version: 0.3.0 - resolution: "p-cancelable@npm:0.3.0" - checksum: 10c0/b8b2c8425b3d284b72097f1b97081ff3f431fd5680f8dfc2344e4f8544f6d8d9f9b545a737bca6a32a319cca1921a44cfd234602e58911dc5d3e144cbe685ea6 - languageName: node - linkType: hard - -"p-cancelable@npm:^1.0.0": - version: 1.1.0 - resolution: "p-cancelable@npm:1.1.0" - checksum: 10c0/9f16d7d58897edb07b1a9234b2bfce3665c747f0f13886e25e2144ecab4595412017cc8cc3b0042f89864b997d6dba76c130724e1c0923fc41ff3c9399b87449 - languageName: node - linkType: hard - -"p-finally@npm:^1.0.0": - version: 1.0.0 - resolution: "p-finally@npm:1.0.0" - checksum: 10c0/6b8552339a71fe7bd424d01d8451eea92d379a711fc62f6b2fe64cad8a472c7259a236c9a22b4733abca0b5666ad503cb497792a0478c5af31ded793d00937e7 - languageName: node - linkType: hard - -"p-limit@npm:^1.1.0": - version: 1.3.0 - resolution: "p-limit@npm:1.3.0" - dependencies: - p-try: "npm:^1.0.0" - checksum: 10c0/5c1b1d53d180b2c7501efb04b7c817448e10efe1ba46f4783f8951994d5027e4cd88f36ad79af50546682594c4ebd11702ac4b9364c47f8074890e2acad0edee +"p-cancelable@npm:^3.0.0": + version: 3.0.0 + resolution: "p-cancelable@npm:3.0.0" + checksum: 10c0/948fd4f8e87b956d9afc2c6c7392de9113dac817cb1cecf4143f7a3d4c57ab5673614a80be3aba91ceec5e4b69fd8c869852d7e8048bc3d9273c4c36ce14b9aa languageName: node linkType: hard @@ -8837,15 +6589,6 @@ __metadata: languageName: node linkType: hard -"p-locate@npm:^2.0.0": - version: 2.0.0 - resolution: "p-locate@npm:2.0.0" - dependencies: - p-limit: "npm:^1.1.0" - checksum: 10c0/82da4be88fb02fd29175e66021610c881938d3cc97c813c71c1a605fac05617d57fd5d3b337494a6106c0edb2a37c860241430851411f1b265108cead34aee67 - languageName: node - linkType: hard - "p-locate@npm:^5.0.0": version: 5.0.0 resolution: "p-locate@npm:5.0.0" @@ -8871,22 +6614,6 @@ __metadata: languageName: node linkType: hard -"p-timeout@npm:^1.1.1": - version: 1.2.1 - resolution: "p-timeout@npm:1.2.1" - dependencies: - p-finally: "npm:^1.0.0" - checksum: 10c0/09177278c4bc060f9cc1d2f06bf0b8deac29acc53415c093dfd2cc7f4844526c5657a506eb7cd879b6a41c262742551dc2b0f3e90c047f2bd0354b7bd17a5d73 - languageName: node - linkType: hard - -"p-try@npm:^1.0.0": - version: 1.0.0 - resolution: "p-try@npm:1.0.0" - checksum: 10c0/757ba31de5819502b80c447826fac8be5f16d3cb4fbf9bc8bc4971dba0682e84ac33e4b24176ca7058c69e29f64f34d8d9e9b08e873b7b7bb0aa89d620fa224a - languageName: node - linkType: hard - "package-json-from-dist@npm:^1.0.0": version: 1.0.1 resolution: "package-json-from-dist@npm:1.0.1" @@ -8894,6 +6621,18 @@ __metadata: languageName: node linkType: hard +"package-json@npm:^8.1.0": + version: 8.1.1 + resolution: "package-json@npm:8.1.1" + dependencies: + got: "npm:^12.1.0" + registry-auth-token: "npm:^5.0.1" + registry-url: "npm:^6.0.0" + semver: "npm:^7.3.7" + checksum: 10c0/83b057878bca229033aefad4ef51569b484e63a65831ddf164dc31f0486817e17ffcb58c819c7af3ef3396042297096b3ffc04e107fd66f8f48756f6d2071c8f + languageName: node + linkType: hard + "parent-module@npm:^1.0.0": version: 1.0.1 resolution: "parent-module@npm:1.0.1" @@ -8903,47 +6642,15 @@ __metadata: languageName: node linkType: hard -"parse-asn1@npm:^5.0.0, parse-asn1@npm:^5.1.5": - version: 5.1.6 - resolution: "parse-asn1@npm:5.1.6" - dependencies: - asn1.js: "npm:^5.2.0" - browserify-aes: "npm:^1.0.0" - evp_bytestokey: "npm:^1.0.0" - pbkdf2: "npm:^3.0.3" - safe-buffer: "npm:^5.1.1" - checksum: 10c0/4ed1d9b9e120c5484d29d67bb90171aac0b73422bc016d6294160aea983275c28a27ab85d862059a36a86a97dd31b7ddd97486802ca9fac67115fe3409e9dcbd - languageName: node - linkType: hard - -"parse-headers@npm:^2.0.0": - version: 2.0.5 - resolution: "parse-headers@npm:2.0.5" - checksum: 10c0/950d75034f46be8b77c491754aefa61b32954e675200d9247ec60b2acaf85c0cc053c44e44b35feed9034a34cc696a5b6fda693b5a0b23daf3294959dd216124 - languageName: node - linkType: hard - -"parse-json@npm:^4.0.0": - version: 4.0.0 - resolution: "parse-json@npm:4.0.0" +"parse-json@npm:^5.2.0": + version: 5.2.0 + resolution: "parse-json@npm:5.2.0" dependencies: + "@babel/code-frame": "npm:^7.0.0" error-ex: "npm:^1.3.1" - json-parse-better-errors: "npm:^1.0.1" - checksum: 10c0/8d80790b772ccb1bcea4e09e2697555e519d83d04a77c2b4237389b813f82898943a93ffff7d0d2406203bdd0c30dcf95b1661e3a53f83d0e417f053957bef32 - languageName: node - linkType: hard - -"parseurl@npm:~1.3.3": - version: 1.3.3 - resolution: "parseurl@npm:1.3.3" - checksum: 10c0/90dd4760d6f6174adb9f20cf0965ae12e23879b5f5464f38e92fce8073354341e4b3b76fa3d878351efe7d01e617121955284cfd002ab087fba1a0726ec0b4f5 - languageName: node - linkType: hard - -"path-exists@npm:^3.0.0": - version: 3.0.0 - resolution: "path-exists@npm:3.0.0" - checksum: 10c0/17d6a5664bc0a11d48e2b2127d28a0e58822c6740bde30403f08013da599182289c56518bec89407e3f31d3c2b6b296a4220bc3f867f0911fee6952208b04167 + json-parse-even-better-errors: "npm:^2.3.0" + lines-and-columns: "npm:^1.1.6" + checksum: 10c0/77947f2253005be7a12d858aedbafa09c9ae39eb4863adf330f7b416ca4f4a08132e453e08de2db46459256fb66afaac5ee758b44fe6541b7cdaf9d252e59585 languageName: node linkType: hard @@ -8961,20 +6668,6 @@ __metadata: languageName: node linkType: hard -"path-is-inside@npm:^1.0.2": - version: 1.0.2 - resolution: "path-is-inside@npm:1.0.2" - checksum: 10c0/7fdd4b41672c70461cce734fc222b33e7b447fa489c7c4377c95e7e6852d83d69741f307d88ec0cc3b385b41cb4accc6efac3c7c511cd18512e95424f5fa980c - languageName: node - linkType: hard - -"path-key@npm:^2.0.1": - version: 2.0.1 - resolution: "path-key@npm:2.0.1" - checksum: 10c0/dd2044f029a8e58ac31d2bf34c34b93c3095c1481942960e84dd2faa95bbb71b9b762a106aead0646695330936414b31ca0bd862bf488a937ad17c8c5d73b32b - languageName: node - linkType: hard - "path-key@npm:^3.1.0": version: 3.1.1 resolution: "path-key@npm:3.1.1" @@ -8982,7 +6675,7 @@ __metadata: languageName: node linkType: hard -"path-parse@npm:^1.0.6, path-parse@npm:^1.0.7": +"path-parse@npm:^1.0.6": version: 1.0.7 resolution: "path-parse@npm:1.0.7" checksum: 10c0/11ce261f9d294cc7a58d6a574b7f1b935842355ec66fba3c3fd79e0f036462eaf07d0aa95bb74ff432f9afef97ce1926c720988c6a7451d8a584930ae7de86e1 @@ -9009,13 +6702,6 @@ __metadata: languageName: node linkType: hard -"path-to-regexp@npm:0.1.7": - version: 0.1.7 - resolution: "path-to-regexp@npm:0.1.7" - checksum: 10c0/50a1ddb1af41a9e68bd67ca8e331a705899d16fb720a1ea3a41e310480948387daf603abb14d7b0826c58f10146d49050a1291ba6a82b78a382d1c02c0b8f905 - languageName: node - linkType: hard - "path-type@npm:^4.0.0": version: 4.0.0 resolution: "path-type@npm:4.0.0" @@ -9030,7 +6716,7 @@ __metadata: languageName: node linkType: hard -"pbkdf2@npm:^3.0.17, pbkdf2@npm:^3.0.3": +"pbkdf2@npm:^3.0.17": version: 3.1.2 resolution: "pbkdf2@npm:3.1.2" dependencies: @@ -9043,20 +6729,6 @@ __metadata: languageName: node linkType: hard -"pend@npm:~1.2.0": - version: 1.2.0 - resolution: "pend@npm:1.2.0" - checksum: 10c0/8a87e63f7a4afcfb0f9f77b39bb92374afc723418b9cb716ee4257689224171002e07768eeade4ecd0e86f1fa3d8f022994219fb45634f2dbd78c6803e452458 - languageName: node - linkType: hard - -"performance-now@npm:^2.1.0": - version: 2.1.0 - resolution: "performance-now@npm:2.1.0" - checksum: 10c0/22c54de06f269e29f640e0e075207af57de5052a3d15e360c09b9a8663f393f6f45902006c1e71aa8a5a1cdfb1a47fe268826f8496d6425c362f00f5bc3e85d9 - languageName: node - linkType: hard - "picocolors@npm:^1.1.0, picocolors@npm:^1.1.1": version: 1.1.1 resolution: "picocolors@npm:1.1.1" @@ -9064,13 +6736,20 @@ __metadata: languageName: node linkType: hard -"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.3.1": +"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1": version: 2.3.1 resolution: "picomatch@npm:2.3.1" checksum: 10c0/26c02b8d06f03206fc2ab8d16f19960f2ff9e81a658f831ecb656d8f17d9edc799e8364b1f4a7873e89d9702dff96204be0fa26fe4181f6843f040f819dac4be languageName: node linkType: hard +"picomatch@npm:^4.0.3": + version: 4.0.7 + resolution: "picomatch@npm:4.0.7" + checksum: 10c0/beb6ae02c43ae44e84883b90830196d9046b1726ead292adcf7f57945e0bb0d992d68563d87e03b484b6f3c9a5c6defda7523477f047d7f0e663f126cc01787f + languageName: node + linkType: hard + "picomatch@npm:^4.0.4": version: 4.0.4 resolution: "picomatch@npm:4.0.4" @@ -9078,40 +6757,10 @@ __metadata: languageName: node linkType: hard -"pify@npm:^2.3.0": - version: 2.3.0 - resolution: "pify@npm:2.3.0" - checksum: 10c0/551ff8ab830b1052633f59cb8adc9ae8407a436e06b4a9718bcb27dc5844b83d535c3a8512b388b6062af65a98c49bdc0dd523d8b2617b188f7c8fee457158dc - languageName: node - linkType: hard - -"pify@npm:^3.0.0": - version: 3.0.0 - resolution: "pify@npm:3.0.0" - checksum: 10c0/fead19ed9d801f1b1fcd0638a1ac53eabbb0945bf615f2f8806a8b646565a04a1b0e7ef115c951d225f042cca388fdc1cd3add46d10d1ed6951c20bd2998af10 - languageName: node - linkType: hard - -"pinkie-promise@npm:^2.0.0": - version: 2.0.1 - resolution: "pinkie-promise@npm:2.0.1" - dependencies: - pinkie: "npm:^2.0.0" - checksum: 10c0/11b5e5ce2b090c573f8fad7b517cbca1bb9a247587306f05ae71aef6f9b2cd2b923c304aa9663c2409cfde27b367286179f1379bc4ec18a3fbf2bb0d473b160a - languageName: node - linkType: hard - -"pinkie@npm:^2.0.0": - version: 2.0.4 - resolution: "pinkie@npm:2.0.4" - checksum: 10c0/25228b08b5597da42dc384221aa0ce56ee0fbf32965db12ba838e2a9ca0193c2f0609c45551ee077ccd2060bf109137fdb185b00c6d7e0ed7e35006d20fdcbc6 - languageName: node - linkType: hard - -"possible-typed-array-names@npm:^1.0.0": - version: 1.1.0 - resolution: "possible-typed-array-names@npm:1.1.0" - checksum: 10c0/c810983414142071da1d644662ce4caebce890203eb2bc7bf119f37f3fe5796226e117e6cca146b521921fa6531072674174a3325066ac66fce089a53e1e5196 +"pluralize@npm:^8.0.0": + version: 8.0.0 + resolution: "pluralize@npm:8.0.0" + checksum: 10c0/2044cfc34b2e8c88b73379ea4a36fc577db04f651c2909041b054c981cd863dd5373ebd030123ab058d194ae615d3a97cfdac653991e499d10caf592e8b3dc33 languageName: node linkType: hard @@ -9122,78 +6771,46 @@ __metadata: languageName: node linkType: hard -"prelude-ls@npm:~1.1.2": - version: 1.1.2 - resolution: "prelude-ls@npm:1.1.2" - checksum: 10c0/7284270064f74e0bb7f04eb9bff7be677e4146417e599ccc9c1200f0f640f8b11e592d94eb1b18f7aa9518031913bb42bea9c86af07ba69902864e61005d6f18 - languageName: node - linkType: hard - -"prepend-http@npm:^1.0.1": - version: 1.0.4 - resolution: "prepend-http@npm:1.0.4" - checksum: 10c0/c6c173ca439e58163ba7bea7cbba52a1ed11e3e3da1c048da296f37d4b7654f78f7304e03f76d5923f4b83af7e2d55533e0f79064209c75b743ccddee13904f8 - languageName: node - linkType: hard - -"prepend-http@npm:^2.0.0": - version: 2.0.0 - resolution: "prepend-http@npm:2.0.0" - checksum: 10c0/b023721ffd967728e3a25e3a80dd73827e9444e586800ab90a21b3a8e67f362d28023085406ad53a36db1e4d98cb10e43eb37d45c6b733140a9165ead18a0987 - languageName: node - linkType: hard - -"prettier-linter-helpers@npm:^1.0.0": - version: 1.0.0 - resolution: "prettier-linter-helpers@npm:1.0.0" - dependencies: - fast-diff: "npm:^1.1.2" - checksum: 10c0/81e0027d731b7b3697ccd2129470ed9913ecb111e4ec175a12f0fcfab0096516373bf0af2fef132af50cafb0a905b74ff57996d615f59512bb9ac7378fcc64ab - languageName: node - linkType: hard - -"prettier-plugin-sh@npm:^0.8.1": - version: 0.8.1 - resolution: "prettier-plugin-sh@npm:0.8.1" +"prettier-plugin-sh@npm:^0.19.0": + version: 0.19.0 + resolution: "prettier-plugin-sh@npm:0.19.0" dependencies: - mvdan-sh: "npm:^0.5.0" + "@reteps/dockerfmt": "npm:^0.5.4" + sh-syntax: "npm:^0.6.0" peerDependencies: - prettier: ^2.0.0 - checksum: 10c0/9b9e983e2041244cdbde6847675ae8aed1bca2e5a67d23b62c402a0e233cf188d3214dedc1b9fae898e8bbb4ae5d31a9ba6d201d35080ab7ad0acbfb4666246d + prettier: ^3.6.0 + checksum: 10c0/47a152ea7049743d8080749eaeebc05ade1c224e27537b03aa1cb7d6680b28f5bd6d6539f4289fc724f52ea7baed22a4b027e8f7cd6ec28a60c24d9eaae7a79b languageName: node linkType: hard -"prettier-plugin-solidity@npm:^1.0.0-beta.19": - version: 1.0.0-beta.19 - resolution: "prettier-plugin-solidity@npm:1.0.0-beta.19" +"prettier-plugin-solidity@npm:^2.4.1": + version: 2.4.1 + resolution: "prettier-plugin-solidity@npm:2.4.1" dependencies: - "@solidity-parser/parser": "npm:^0.14.0" - emoji-regex: "npm:^10.0.0" - escape-string-regexp: "npm:^4.0.0" - semver: "npm:^7.3.5" - solidity-comments-extractor: "npm:^0.0.7" - string-width: "npm:^4.2.3" + "@nomicfoundation/slang": "npm:1.3.8" + "@solidity-parser/parser": "npm:^0.20.2" + semver: "npm:^7.8.5" peerDependencies: - prettier: ^2.3.0 - checksum: 10c0/f0fcfb61afeb3c9cda4bc0d49ddb81a730faa4398dd06459d39d1a93b345a2ab9eeb227b4f68c6278b19f053e4b4ac4ab239889691ac7924f620407ef698a426 + prettier: ">=3.0.0" + checksum: 10c0/20ea46e5e9e406d5eb6df50335b5c08be098afc6cc392d32b8bb0e140c2a41d02c8e83a8da79ce5a1223e361d7a497e86e95bfe6caf1eb8546c4f6ff3d085a76 languageName: node linkType: hard -"prettier@npm:^1.14.3": - version: 1.19.1 - resolution: "prettier@npm:1.19.1" +"prettier@npm:^2.3.1": + version: 2.8.8 + resolution: "prettier@npm:2.8.8" bin: - prettier: ./bin-prettier.js - checksum: 10c0/12efb4e486c1e1d006e9eadd3b6585fc6beb9481dc801080fc23d3e75ec599d88c6fea1b40aef167128069e8fe76b4205bb8306ad145575d1b051b8fa70cfaae + prettier: bin-prettier.js + checksum: 10c0/463ea8f9a0946cd5b828d8cf27bd8b567345cf02f56562d5ecde198b91f47a76b7ac9eae0facd247ace70e927143af6135e8cf411986b8cb8478784a4d6d724a languageName: node linkType: hard -"prettier@npm:^2.1.2, prettier@npm:^2.5.1": - version: 2.5.1 - resolution: "prettier@npm:2.5.1" +"prettier@npm:^3.0.0, prettier@npm:^3.9.6": + version: 3.9.6 + resolution: "prettier@npm:3.9.6" bin: - prettier: bin-prettier.js - checksum: 10c0/fa9750193b3fcdb4bd54ba4e57996d335de4cd492d277539b6ffb6d146c8b6d3c3dc264b75021914c99c91574643637f607da08ef4588ef30a7b78d14326f470 + prettier: bin/prettier.cjs + checksum: 10c0/9f7ddae234035868f3daab3dc34e6de7e54622185afb017378029f0c09a9c023248ccf6f34def0b17a0538e18c47aa1b3188bab72965d1bf735919baa0747e99 languageName: node linkType: hard @@ -9204,35 +6821,13 @@ __metadata: languageName: node linkType: hard -"process-nextick-args@npm:~2.0.0": - version: 2.0.1 - resolution: "process-nextick-args@npm:2.0.1" - checksum: 10c0/bec089239487833d46b59d80327a1605e1c5287eaad770a291add7f45fda1bb5e28b38e0e061add0a1d0ee0984788ce74fa394d345eed1c420cacf392c554367 - languageName: node - linkType: hard - -"process@npm:^0.11.10": - version: 0.11.10 - resolution: "process@npm:0.11.10" - checksum: 10c0/40c3ce4b7e6d4b8c3355479df77aeed46f81b279818ccdc500124e6a5ab882c0cc81ff7ea16384873a95a74c4570b01b120f287abbdd4c877931460eca6084b3 - languageName: node - linkType: hard - -"progress@npm:^2.0.0": - version: 2.0.3 - resolution: "progress@npm:2.0.3" - checksum: 10c0/1697e07cb1068055dbe9fe858d242368ff5d2073639e652b75a7eb1f2a1a8d4afd404d719de23c7b48481a6aa0040686310e2dac2f53d776daa2176d3f96369c - languageName: node - linkType: hard - -"prop-types@npm:^15.8.1": - version: 15.8.1 - resolution: "prop-types@npm:15.8.1" +"prompts@npm:^2.4.2": + version: 2.4.2 + resolution: "prompts@npm:2.4.2" dependencies: - loose-envify: "npm:^1.4.0" - object-assign: "npm:^4.1.1" - react-is: "npm:^16.13.1" - checksum: 10c0/59ece7ca2fb9838031d73a48d4becb9a7cc1ed10e610517c7d8f19a1e02fa47f7c27d557d8a5702bec3cfeccddc853579832b43f449e54635803f277b1c78077 + kleur: "npm:^3.0.3" + sisteransi: "npm:^1.0.5" + checksum: 10c0/16f1ac2977b19fe2cf53f8411cc98db7a3c8b115c479b2ca5c82b5527cd937aa405fa04f9a5960abeb9daef53191b53b4d13e35c1f5d50e8718c76917c5f1ea4 languageName: node linkType: hard @@ -9247,20 +6842,10 @@ __metadata: languageName: node linkType: hard -"proxy-addr@npm:~2.0.7": - version: 2.0.7 - resolution: "proxy-addr@npm:2.0.7" - dependencies: - forwarded: "npm:0.2.0" - ipaddr.js: "npm:1.9.1" - checksum: 10c0/c3eed999781a35f7fd935f398b6d8920b6fb00bbc14287bc6de78128ccc1a02c89b95b56742bf7cf0362cc333c61d138532049c7dedc7a328ef13343eff81210 - languageName: node - linkType: hard - -"proxy-from-env@npm:^1.1.0": - version: 1.1.0 - resolution: "proxy-from-env@npm:1.1.0" - checksum: 10c0/fe7dd8b1bdbbbea18d1459107729c3e4a2243ca870d26d34c2c1bcd3e4425b7bcc5112362df2d93cc7fb9746f6142b5e272fd1cc5c86ddf8580175186f6ad42b +"proto-list@npm:~1.2.1": + version: 1.2.4 + resolution: "proto-list@npm:1.2.4" + checksum: 10c0/b9179f99394ec8a68b8afc817690185f3b03933f7b46ce2e22c1930dc84b60d09f5ad222beab4e59e58c6c039c7f7fcf620397235ef441a356f31f9744010e12 languageName: node linkType: hard @@ -9271,120 +6856,45 @@ __metadata: languageName: node linkType: hard -"psl@npm:^1.1.28": - version: 1.9.0 - resolution: "psl@npm:1.9.0" - checksum: 10c0/6a3f805fdab9442f44de4ba23880c4eba26b20c8e8e0830eff1cb31007f6825dace61d17203c58bfe36946842140c97a1ba7f67bc63ca2d88a7ee052b65d97ab +"punycode@npm:^2.1.0": + version: 2.1.1 + resolution: "punycode@npm:2.1.1" + checksum: 10c0/83815ca9b9177f055771f31980cbec7ffaef10257d50a95ab99b4a30f0404846e85fa6887ee1bbc0aaddb7bad6d96e2fa150a016051ff0f6b92be4ad613ddca8 languageName: node linkType: hard -"public-encrypt@npm:^4.0.0": - version: 4.0.3 - resolution: "public-encrypt@npm:4.0.3" +"qified@npm:^0.10.1": + version: 0.10.1 + resolution: "qified@npm:0.10.1" dependencies: - bn.js: "npm:^4.1.0" - browserify-rsa: "npm:^4.0.0" - create-hash: "npm:^1.1.0" - parse-asn1: "npm:^5.0.0" - randombytes: "npm:^2.0.1" - safe-buffer: "npm:^5.1.2" - checksum: 10c0/6c2cc19fbb554449e47f2175065d6b32f828f9b3badbee4c76585ac28ae8641aafb9bb107afc430c33c5edd6b05dbe318df4f7d6d7712b1093407b11c4280700 + hookified: "npm:^2.1.1" + checksum: 10c0/4a39d45492c65a4b9795381acede1bd566028ce9764ead5b41d776b391a898bf0855dd2b59d724a6711fe253ba3cacf7c9a8832887cf9dc6d48a2c5e4997c82d languageName: node linkType: hard -"pump@npm:^3.0.0": - version: 3.0.0 - resolution: "pump@npm:3.0.0" +"qs@npm:^6.9.4": + version: 6.15.3 + resolution: "qs@npm:6.15.3" dependencies: - end-of-stream: "npm:^1.1.0" - once: "npm:^1.3.1" - checksum: 10c0/bbdeda4f747cdf47db97428f3a135728669e56a0ae5f354a9ac5b74556556f5446a46f720a8f14ca2ece5be9b4d5d23c346db02b555f46739934cc6c093a5478 + es-define-property: "npm:^1.0.1" + side-channel: "npm:^1.1.1" + checksum: 10c0/8f3f6e45ece255347d57696628401cde29e9ec649fff698b53bd3150dea7cefdf33036e1bc1826b9f110bfa7cb0ec4ab9f5297eca628ce216c55af82c304e08e + languageName: node + linkType: hard + +"quick-lru@npm:^5.1.1": + version: 5.1.1 + resolution: "quick-lru@npm:5.1.1" + checksum: 10c0/a24cba5da8cec30d70d2484be37622580f64765fb6390a928b17f60cd69e8dbd32a954b3ff9176fa1b86d86ff2ba05252fae55dc4d40d0291c60412b0ad096da languageName: node linkType: hard -"punycode@npm:2.1.0": +"randombytes@npm:^2.1.0": version: 2.1.0 - resolution: "punycode@npm:2.1.0" - checksum: 10c0/f427b54c0ce23da3eb07ef02f3f158a280bd0182cac7e409016390d2632d161fc759f99a2619e9f6dcdd9ea00e8640de844ffaffd9f9deb479494c3494ef5cfb - languageName: node - linkType: hard - -"punycode@npm:^2.1.0, punycode@npm:^2.1.1": - version: 2.1.1 - resolution: "punycode@npm:2.1.1" - checksum: 10c0/83815ca9b9177f055771f31980cbec7ffaef10257d50a95ab99b4a30f0404846e85fa6887ee1bbc0aaddb7bad6d96e2fa150a016051ff0f6b92be4ad613ddca8 - languageName: node - linkType: hard - -"qs@npm:6.10.3, qs@npm:^6.9.4": - version: 6.10.3 - resolution: "qs@npm:6.10.3" - dependencies: - side-channel: "npm:^1.0.4" - checksum: 10c0/c6684df925fd2c6f0940b8fbfe5d8b5a8634dc96c0908309655cbe61a3fbf94cedc6b11e669fca1971b53459b6f732cccd4eeb6484b5b77b405ad0cfb936e6fe - languageName: node - linkType: hard - -"qs@npm:~6.5.2": - version: 6.5.3 - resolution: "qs@npm:6.5.3" - checksum: 10c0/6631d4f2fa9d315e480662646745a4aa3a708817fbffe2cbdacec8ab9be130f92740c66191770fe9b704bc5fa9c1cc1f6596f55ad132fef7bd3ad1582f199eb0 - languageName: node - linkType: hard - -"query-string@npm:^5.0.1": - version: 5.1.1 - resolution: "query-string@npm:5.1.1" - dependencies: - decode-uri-component: "npm:^0.2.0" - object-assign: "npm:^4.1.0" - strict-uri-encode: "npm:^1.0.0" - checksum: 10c0/25adf37fe9a5b749da55ef91192d190163c44283826b425fa86eeb1fa567cf500a32afc2c602d4f661839d86ca49c2f8d49433b3c1b44b9129a37a5d3da55f89 - languageName: node - linkType: hard - -"queue-microtask@npm:^1.2.2": - version: 1.2.3 - resolution: "queue-microtask@npm:1.2.3" - checksum: 10c0/900a93d3cdae3acd7d16f642c29a642aea32c2026446151f0778c62ac089d4b8e6c986811076e1ae180a694cedf077d453a11b58ff0a865629a4f82ab558e102 - languageName: node - linkType: hard - -"randombytes@npm:^2.0.0, randombytes@npm:^2.0.1, randombytes@npm:^2.0.5, randombytes@npm:^2.1.0": - version: 2.1.0 - resolution: "randombytes@npm:2.1.0" - dependencies: - safe-buffer: "npm:^5.1.0" - checksum: 10c0/50395efda7a8c94f5dffab564f9ff89736064d32addf0cc7e8bf5e4166f09f8ded7a0849ca6c2d2a59478f7d90f78f20d8048bca3cdf8be09d8e8a10790388f3 - languageName: node - linkType: hard - -"randomfill@npm:^1.0.3": - version: 1.0.4 - resolution: "randomfill@npm:1.0.4" - dependencies: - randombytes: "npm:^2.0.5" - safe-buffer: "npm:^5.1.0" - checksum: 10c0/11aeed35515872e8f8a2edec306734e6b74c39c46653607f03c68385ab8030e2adcc4215f76b5e4598e028c4750d820afd5c65202527d831d2a5f207fe2bc87c - languageName: node - linkType: hard - -"range-parser@npm:~1.2.1": - version: 1.2.1 - resolution: "range-parser@npm:1.2.1" - checksum: 10c0/96c032ac2475c8027b7a4e9fe22dc0dfe0f6d90b85e496e0f016fbdb99d6d066de0112e680805075bd989905e2123b3b3d002765149294dce0c1f7f01fcc2ea0 - languageName: node - linkType: hard - -"raw-body@npm:2.5.1": - version: 2.5.1 - resolution: "raw-body@npm:2.5.1" - dependencies: - bytes: "npm:3.1.2" - http-errors: "npm:2.0.0" - iconv-lite: "npm:0.4.24" - unpipe: "npm:1.0.0" - checksum: 10c0/5dad5a3a64a023b894ad7ab4e5c7c1ce34d3497fc7138d02f8c88a3781e68d8a55aa7d4fd3a458616fa8647cc228be314a1c03fb430a07521de78b32c4dd09d2 + resolution: "randombytes@npm:2.1.0" + dependencies: + safe-buffer: "npm:^5.1.0" + checksum: 10c0/50395efda7a8c94f5dffab564f9ff89736064d32addf0cc7e8bf5e4166f09f8ded7a0849ca6c2d2a59478f7d90f78f20d8048bca3cdf8be09d8e8a10790388f3 languageName: node linkType: hard @@ -9400,25 +6910,17 @@ __metadata: languageName: node linkType: hard -"react-is@npm:^16.13.1": - version: 16.13.1 - resolution: "react-is@npm:16.13.1" - checksum: 10c0/33977da7a5f1a287936a0c85639fec6ca74f4f15ef1e59a6bc20338fc73dc69555381e211f7a3529b8150a1f71e4225525b41b60b52965bda53ce7d47377ada1 - languageName: node - linkType: hard - -"readable-stream@npm:^2.3.0, readable-stream@npm:^2.3.5": - version: 2.3.8 - resolution: "readable-stream@npm:2.3.8" +"rc@npm:1.2.8": + version: 1.2.8 + resolution: "rc@npm:1.2.8" dependencies: - core-util-is: "npm:~1.0.0" - inherits: "npm:~2.0.3" - isarray: "npm:~1.0.0" - process-nextick-args: "npm:~2.0.0" - safe-buffer: "npm:~5.1.1" - string_decoder: "npm:~1.1.1" - util-deprecate: "npm:~1.0.1" - checksum: 10c0/7efdb01f3853bc35ac62ea25493567bf588773213f5f4a79f9c365e1ad13bab845ac0dae7bc946270dc40c3929483228415e92a3fc600cc7e4548992f41ee3fa + deep-extend: "npm:^0.6.0" + ini: "npm:~1.3.0" + minimist: "npm:^1.2.0" + strip-json-comments: "npm:~2.0.1" + bin: + rc: ./cli.js + checksum: 10c0/24a07653150f0d9ac7168e52943cc3cb4b7a22c0e43c7dff3219977c2fdca5a2760a304a029c20811a0e79d351f57d46c9bde216193a0f73978496afc2b85b15 languageName: node linkType: hard @@ -9456,47 +6958,21 @@ __metadata: languageName: node linkType: hard -"reflect.getprototypeof@npm:^1.0.6, reflect.getprototypeof@npm:^1.0.9": - version: 1.0.10 - resolution: "reflect.getprototypeof@npm:1.0.10" +"registry-auth-token@npm:^5.0.1": + version: 5.1.1 + resolution: "registry-auth-token@npm:5.1.1" dependencies: - call-bind: "npm:^1.0.8" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.9" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.0.0" - get-intrinsic: "npm:^1.2.7" - get-proto: "npm:^1.0.1" - which-builtin-type: "npm:^1.2.1" - checksum: 10c0/7facec28c8008876f8ab98e80b7b9cb4b1e9224353fd4756dda5f2a4ab0d30fa0a5074777c6df24e1e0af463a2697513b0a11e548d99cf52f21f7bc6ba48d3ac + "@pnpm/npm-conf": "npm:^3.0.2" + checksum: 10c0/86b0f7fd87d327cb4177fee69bcf96563147ea72e206bc9c7a6a50a51c785a31b83a6c45956a489ed292d23b908b2755a075d0b2f7fec1ba91b1fb800b24cee3 languageName: node linkType: hard -"regexp.prototype.flags@npm:^1.5.3, regexp.prototype.flags@npm:^1.5.4": - version: 1.5.4 - resolution: "regexp.prototype.flags@npm:1.5.4" +"registry-url@npm:^6.0.0": + version: 6.0.1 + resolution: "registry-url@npm:6.0.1" dependencies: - call-bind: "npm:^1.0.8" - define-properties: "npm:^1.2.1" - es-errors: "npm:^1.3.0" - get-proto: "npm:^1.0.1" - gopd: "npm:^1.2.0" - set-function-name: "npm:^2.0.2" - checksum: 10c0/83b88e6115b4af1c537f8dabf5c3744032cb875d63bc05c288b1b8c0ef37cbe55353f95d8ca817e8843806e3e150b118bc624e4279b24b4776b4198232735a77 - languageName: node - linkType: hard - -"regexpp@npm:^2.0.1": - version: 2.0.1 - resolution: "regexpp@npm:2.0.1" - checksum: 10c0/4ac2cf4c68941728bffbba5a8f597a23385c2c05afc5bf5de74744ee048765ab84ea3ce3c6a5bdce102a3a54514b75b7add48b4c1abd925ca3afd40e537f2b5f - languageName: node - linkType: hard - -"regexpp@npm:^3.1.0": - version: 3.2.0 - resolution: "regexpp@npm:3.2.0" - checksum: 10c0/d1da82385c8754a1681416b90b9cca0e21b4a2babef159099b88f640637d789c69011d0bc94705dacab85b81133e929d027d85210e8b8b03f8035164dbc14710 + rc: "npm:1.2.8" + checksum: 10c0/66e2221c8113fc35ee9d23fe58cb516fc8d556a189fb8d6f1011a02efccc846c4c9b5075b4027b99a5d5c9ad1345ac37f297bea3c0ca30d607ec8084bf561b90 languageName: node linkType: hard @@ -9507,34 +6983,6 @@ __metadata: languageName: node linkType: hard -"request@npm:^2.79.0, request@npm:^2.85.0": - version: 2.88.2 - resolution: "request@npm:2.88.2" - dependencies: - aws-sign2: "npm:~0.7.0" - aws4: "npm:^1.8.0" - caseless: "npm:~0.12.0" - combined-stream: "npm:~1.0.6" - extend: "npm:~3.0.2" - forever-agent: "npm:~0.6.1" - form-data: "npm:~2.3.2" - har-validator: "npm:~5.1.3" - http-signature: "npm:~1.2.0" - is-typedarray: "npm:~1.0.0" - isstream: "npm:~0.1.2" - json-stringify-safe: "npm:~5.0.1" - mime-types: "npm:~2.1.19" - oauth-sign: "npm:~0.9.0" - performance-now: "npm:^2.1.0" - qs: "npm:~6.5.2" - safe-buffer: "npm:^5.1.2" - tough-cookie: "npm:~2.5.0" - tunnel-agent: "npm:^0.6.0" - uuid: "npm:^3.3.2" - checksum: 10c0/0ec66e7af1391e51ad231de3b1c6c6aef3ebd0a238aa50d4191c7a792dcdb14920eea8d570c702dc5682f276fe569d176f9b8ebc6031a3cf4a630a691a431a63 - languageName: node - linkType: hard - "require-directory@npm:^2.1.1": version: 2.1.1 resolution: "require-directory@npm:2.1.1" @@ -9549,10 +6997,10 @@ __metadata: languageName: node linkType: hard -"resolve-from@npm:^3.0.0": - version: 3.0.0 - resolution: "resolve-from@npm:3.0.0" - checksum: 10c0/24affcf8e81f4c62f0dcabc774afe0e19c1f38e34e43daac0ddb409d79435fc3037f612b0cc129178b8c220442c3babd673e88e870d27215c99454566e770ebc +"resolve-alpn@npm:^1.2.0": + version: 1.2.1 + resolution: "resolve-alpn@npm:1.2.1" + checksum: 10c0/b70b29c1843bc39781ef946c8cd4482e6d425976599c0f9c138cec8209e4e0736161bf39319b01676a847000085dfdaf63583c6fb4427bf751a10635bd2aa0c4 languageName: node linkType: hard @@ -9563,6 +7011,13 @@ __metadata: languageName: node linkType: hard +"resolve-pkg-maps@npm:^1.0.0": + version: 1.0.0 + resolution: "resolve-pkg-maps@npm:1.0.0" + checksum: 10c0/fb8f7bbe2ca281a73b7ef423a1cbc786fb244bd7a95cbe5c3fba25b27d327150beca8ba02f622baea65919a57e061eb5005204daa5f93ed590d9b77463a567ab + languageName: node + linkType: hard + "resolve@npm:1.17.0": version: 1.17.0 resolution: "resolve@npm:1.17.0" @@ -9572,32 +7027,6 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.22.4": - version: 1.22.10 - resolution: "resolve@npm:1.22.10" - dependencies: - is-core-module: "npm:^2.16.0" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10c0/8967e1f4e2cc40f79b7e080b4582b9a8c5ee36ffb46041dccb20e6461161adf69f843b43067b4a375de926a2cd669157e29a29578191def399dd5ef89a1b5203 - languageName: node - linkType: hard - -"resolve@npm:^2.0.0-next.5": - version: 2.0.0-next.5 - resolution: "resolve@npm:2.0.0-next.5" - dependencies: - is-core-module: "npm:^2.13.0" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10c0/a6c33555e3482ea2ec4c6e3d3bf0d78128abf69dca99ae468e64f1e30acaa318fd267fb66c8836b04d558d3e2d6ed875fe388067e7d8e0de647d3c21af21c43a - languageName: node - linkType: hard - "resolve@patch:resolve@npm%3A1.17.0#optional!builtin": version: 1.17.0 resolution: "resolve@patch:resolve@npm%3A1.17.0#optional!builtin::version=1.17.0&hash=c3c19d" @@ -9607,58 +7036,12 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": - version: 1.22.10 - resolution: "resolve@patch:resolve@npm%3A1.22.10#optional!builtin::version=1.22.10&hash=c3c19d" - dependencies: - is-core-module: "npm:^2.16.0" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10c0/52a4e505bbfc7925ac8f4cd91fd8c4e096b6a89728b9f46861d3b405ac9a1ccf4dcbf8befb4e89a2e11370dacd0160918163885cbc669369590f2f31f4c58939 - languageName: node - linkType: hard - -"resolve@patch:resolve@npm%3A^2.0.0-next.5#optional!builtin": - version: 2.0.0-next.5 - resolution: "resolve@patch:resolve@npm%3A2.0.0-next.5#optional!builtin::version=2.0.0-next.5&hash=c3c19d" - dependencies: - is-core-module: "npm:^2.13.0" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10c0/78ad6edb8309a2bfb720c2c1898f7907a37f858866ce11a5974643af1203a6a6e05b2fa9c53d8064a673a447b83d42569260c306d43628bff5bb101969708355 - languageName: node - linkType: hard - -"responselike@npm:^1.0.2": - version: 1.0.2 - resolution: "responselike@npm:1.0.2" - dependencies: - lowercase-keys: "npm:^1.0.0" - checksum: 10c0/1c2861d1950790da96159ca490eda645130eaf9ccc4d76db20f685ba944feaf30f45714b4318f550b8cd72990710ad68355ff15c41da43ed9a93c102c0ffa403 - languageName: node - linkType: hard - -"restore-cursor@npm:^2.0.0": - version: 2.0.0 - resolution: "restore-cursor@npm:2.0.0" - dependencies: - onetime: "npm:^2.0.0" - signal-exit: "npm:^3.0.2" - checksum: 10c0/f5b335bee06f440445e976a7031a3ef53691f9b7c4a9d42a469a0edaf8a5508158a0d561ff2b26a1f4f38783bcca2c0e5c3a44f927326f6694d5b44d7a4993e6 - languageName: node - linkType: hard - -"restore-cursor@npm:^3.1.0": - version: 3.1.0 - resolution: "restore-cursor@npm:3.1.0" +"responselike@npm:^3.0.0": + version: 3.0.0 + resolution: "responselike@npm:3.0.0" dependencies: - onetime: "npm:^5.1.0" - signal-exit: "npm:^3.0.2" - checksum: 10c0/8051a371d6aa67ff21625fa94e2357bd81ffdc96267f3fb0fc4aaf4534028343836548ef34c240ffa8c25b280ca35eb36be00b3cb2133fa4f51896d7e73c6b4f + lowercase-keys: "npm:^3.0.0" + checksum: 10c0/8af27153f7e47aa2c07a5f2d538cb1e5872995f0e9ff77def858ecce5c3fe677d42b824a62cde502e56d275ab832b0a8bd350d5cd6b467ac0425214ac12ae658 languageName: node linkType: hard @@ -9676,35 +7059,6 @@ __metadata: languageName: node linkType: hard -"reusify@npm:^1.0.4": - version: 1.1.0 - resolution: "reusify@npm:1.1.0" - checksum: 10c0/4eff0d4a5f9383566c7d7ec437b671cc51b25963bd61bf127c3f3d3f68e44a026d99b8d2f1ad344afff8d278a8fe70a8ea092650a716d22287e8bef7126bb2fa - languageName: node - linkType: hard - -"rimraf@npm:2.6.3": - version: 2.6.3 - resolution: "rimraf@npm:2.6.3" - dependencies: - glob: "npm:^7.1.3" - bin: - rimraf: ./bin.js - checksum: 10c0/f1e646f8c567795f2916aef7aadf685b543da6b9a53e482bb04b07472c7eef2b476045ba1e29f401c301c66b630b22b815ab31fdd60c5e1ae6566ff523debf45 - languageName: node - linkType: hard - -"rimraf@npm:^3.0.2": - version: 3.0.2 - resolution: "rimraf@npm:3.0.2" - dependencies: - glob: "npm:^7.1.3" - bin: - rimraf: bin.js - checksum: 10c0/9cb7757acb489bd83757ba1a274ab545eafd75598a9d817e0c3f8b164238dd90eba50d6b848bd4dcc5f3040912e882dc7ba71653e35af660d77b25c381d402e8 - languageName: node - linkType: hard - "ripemd160@npm:^2.0.0, ripemd160@npm:^2.0.1": version: 2.0.2 resolution: "ripemd160@npm:2.0.2" @@ -9715,7 +7069,7 @@ __metadata: languageName: node linkType: hard -"rlp@npm:^2.2.3, rlp@npm:^2.2.4": +"rlp@npm:^2.2.4": version: 2.2.7 resolution: "rlp@npm:2.2.7" dependencies: @@ -9726,100 +7080,20 @@ __metadata: languageName: node linkType: hard -"run-async@npm:^2.2.0": - version: 2.4.1 - resolution: "run-async@npm:2.4.1" - checksum: 10c0/35a68c8f1d9664f6c7c2e153877ca1d6e4f886e5ca067c25cdd895a6891ff3a1466ee07c63d6a9be306e9619ff7d509494e6d9c129516a36b9fd82263d579ee1 - languageName: node - linkType: hard - -"run-parallel@npm:^1.1.9": - version: 1.2.0 - resolution: "run-parallel@npm:1.2.0" - dependencies: - queue-microtask: "npm:^1.2.2" - checksum: 10c0/200b5ab25b5b8b7113f9901bfe3afc347e19bb7475b267d55ad0eb86a62a46d77510cb0f232507c9e5d497ebda569a08a9867d0d14f57a82ad5564d991588b39 - languageName: node - linkType: hard - -"rxjs@npm:^6.4.0": - version: 6.6.7 - resolution: "rxjs@npm:6.6.7" - dependencies: - tslib: "npm:^1.9.0" - checksum: 10c0/e556a13a9aa89395e5c9d825eabcfa325568d9c9990af720f3f29f04a888a3b854f25845c2b55875d875381abcae2d8100af9cacdc57576e7ed6be030a01d2fe - languageName: node - linkType: hard - -"safe-array-concat@npm:^1.1.3": - version: 1.1.3 - resolution: "safe-array-concat@npm:1.1.3" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.2" - get-intrinsic: "npm:^1.2.6" - has-symbols: "npm:^1.1.0" - isarray: "npm:^2.0.5" - checksum: 10c0/43c86ffdddc461fb17ff8a17c5324f392f4868f3c7dd2c6a5d9f5971713bc5fd755667212c80eab9567595f9a7509cc2f83e590ddaebd1bd19b780f9c79f9a8d - languageName: node - linkType: hard - -"safe-buffer@npm:5.2.1, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:^5.2.1, safe-buffer@npm:~5.2.0": +"safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:~5.2.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 languageName: node linkType: hard -"safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": - version: 5.1.2 - resolution: "safe-buffer@npm:5.1.2" - checksum: 10c0/780ba6b5d99cc9a40f7b951d47152297d0e260f0df01472a1b99d4889679a4b94a13d644f7dbc4f022572f09ae9005fa2fbb93bbbd83643316f365a3e9a45b21 - languageName: node - linkType: hard - -"safe-push-apply@npm:^1.0.0": - version: 1.0.0 - resolution: "safe-push-apply@npm:1.0.0" - dependencies: - es-errors: "npm:^1.3.0" - isarray: "npm:^2.0.5" - checksum: 10c0/831f1c9aae7436429e7862c7e46f847dfe490afac20d0ee61bae06108dbf5c745a0de3568ada30ccdd3eeb0864ca8331b2eef703abd69bfea0745b21fd320750 - languageName: node - linkType: hard - -"safe-regex-test@npm:^1.0.3, safe-regex-test@npm:^1.1.0": - version: 1.1.0 - resolution: "safe-regex-test@npm:1.1.0" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - is-regex: "npm:^1.2.1" - checksum: 10c0/f2c25281bbe5d39cddbbce7f86fca5ea9b3ce3354ea6cd7c81c31b006a5a9fff4286acc5450a3b9122c56c33eba69c56b9131ad751457b2b4a585825e6a10665 - languageName: node - linkType: hard - -"safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0, safer-buffer@npm:^2.0.2, safer-buffer@npm:^2.1.0, safer-buffer@npm:~2.1.0": +"safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0": version: 2.1.2 resolution: "safer-buffer@npm:2.1.2" checksum: 10c0/7e3c8b2e88a1841c9671094bbaeebd94448111dd90a81a1f606f3f67708a6ec57763b3b47f06da09fc6054193e0e6709e77325415dc8422b04497a8070fa02d4 languageName: node linkType: hard -"scrypt-js@npm:2.0.3": - version: 2.0.3 - resolution: "scrypt-js@npm:2.0.3" - checksum: 10c0/cd7768e104ff6752eb844813edccf5496d7b7c53ae43554695c59819247b1075d5993cbc9ffa0c36134b7401d77eda559e7895053235f416cfeb1f364245244e - languageName: node - linkType: hard - -"scrypt-js@npm:2.0.4": - version: 2.0.4 - resolution: "scrypt-js@npm:2.0.4" - checksum: 10c0/dc6df482f9befa395b577ea40c5cebe96df8fc5f376d23871c50800eacbec1b0d6a49a03f35e9d4405ceb96f43b8047a8f3f99ce7cda0c727cfc754d9e7060f8 - languageName: node - linkType: hard - "scrypt-js@npm:3.0.1, scrypt-js@npm:^3.0.0": version: 3.0.1 resolution: "scrypt-js@npm:3.0.1" @@ -9827,13 +7101,6 @@ __metadata: languageName: node linkType: hard -"scrypt-shim@github:web3-js/scrypt-shim": - version: 0.0.1-security - resolution: "scrypt-shim@npm:0.0.1-security" - checksum: 10c0/1ff7680429374fc1e00dafdc47e5c430e1898ee6f6ba6a4b12ad66219be5abd5097d00cec362334ca04025c617b44da8b3abe2011e7903faf33448592a246ec3 - languageName: node - linkType: hard - "secp256k1@npm:^4.0.1": version: 4.0.3 resolution: "secp256k1@npm:4.0.3" @@ -9846,19 +7113,7 @@ __metadata: languageName: node linkType: hard -"seek-bzip@npm:^1.0.5": - version: 1.0.6 - resolution: "seek-bzip@npm:1.0.6" - dependencies: - commander: "npm:^2.8.1" - bin: - seek-bunzip: bin/seek-bunzip - seek-table: bin/seek-bzip-table - checksum: 10c0/e4019e4498bb725ff855603595c4116ca003674b13d29cb9ed9891b2ceec884ccf7c1cb5dba0d6b50fe6ce760a011078f5744efb79823f4ddb9decb1571e9912 - languageName: node - linkType: hard - -"semver@npm:^5.5.0, semver@npm:^5.5.1": +"semver@npm:^5.5.0": version: 5.7.1 resolution: "semver@npm:5.7.1" bin: @@ -9867,7 +7122,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^6.3.0, semver@npm:^6.3.1": +"semver@npm:^6.3.0": version: 6.3.1 resolution: "semver@npm:6.3.1" bin: @@ -9876,7 +7131,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.2.1, semver@npm:^7.3.5": +"semver@npm:^7.3.5": version: 7.3.5 resolution: "semver@npm:7.3.5" dependencies: @@ -9887,24 +7142,12 @@ __metadata: languageName: node linkType: hard -"send@npm:0.18.0": - version: 0.18.0 - resolution: "send@npm:0.18.0" - dependencies: - debug: "npm:2.6.9" - depd: "npm:2.0.0" - destroy: "npm:1.2.0" - encodeurl: "npm:~1.0.2" - escape-html: "npm:~1.0.3" - etag: "npm:~1.8.1" - fresh: "npm:0.5.2" - http-errors: "npm:2.0.0" - mime: "npm:1.6.0" - ms: "npm:2.1.3" - on-finished: "npm:2.4.1" - range-parser: "npm:~1.2.1" - statuses: "npm:2.0.1" - checksum: 10c0/0eb134d6a51fc13bbcb976a1f4214ea1e33f242fae046efc311e80aff66c7a43603e26a79d9d06670283a13000e51be6e0a2cb80ff0942eaf9f1cd30b7ae736a +"semver@npm:^7.3.7, semver@npm:^7.5.2, semver@npm:^7.7.1, semver@npm:^7.7.2, semver@npm:^7.7.3, semver@npm:^7.8.5": + version: 7.8.5 + resolution: "semver@npm:7.8.5" + bin: + semver: bin/semver.js + checksum: 10c0/b1f3127a5be8125a94f37188b361c212466c292c6910adce3ec106cff5dc211ccaedc4739c11bb70fda59d6fc1f040a9bca289f4e093451521a2372e5231fe0c languageName: node linkType: hard @@ -9917,75 +7160,6 @@ __metadata: languageName: node linkType: hard -"serve-static@npm:1.15.0": - version: 1.15.0 - resolution: "serve-static@npm:1.15.0" - dependencies: - encodeurl: "npm:~1.0.2" - escape-html: "npm:~1.0.3" - parseurl: "npm:~1.3.3" - send: "npm:0.18.0" - checksum: 10c0/fa9f0e21a540a28f301258dfe1e57bb4f81cd460d28f0e973860477dd4acef946a1f41748b5bd41c73b621bea2029569c935faa38578fd34cd42a9b4947088ba - languageName: node - linkType: hard - -"servify@npm:^0.1.12": - version: 0.1.12 - resolution: "servify@npm:0.1.12" - dependencies: - body-parser: "npm:^1.16.0" - cors: "npm:^2.8.1" - express: "npm:^4.14.0" - request: "npm:^2.79.0" - xhr: "npm:^2.3.3" - checksum: 10c0/2a7af8ba9f79022325c1f1bfbcb02051c1e02252928c55028173d1ecbc5db49faebf3e8a865515b89cfd1e53eee7c2e5a9c47c264caaf98964708e5372b407c0 - languageName: node - linkType: hard - -"set-function-length@npm:^1.2.2": - version: 1.2.2 - resolution: "set-function-length@npm:1.2.2" - dependencies: - define-data-property: "npm:^1.1.4" - es-errors: "npm:^1.3.0" - function-bind: "npm:^1.1.2" - get-intrinsic: "npm:^1.2.4" - gopd: "npm:^1.0.1" - has-property-descriptors: "npm:^1.0.2" - checksum: 10c0/82850e62f412a258b71e123d4ed3873fa9377c216809551192bb6769329340176f109c2eeae8c22a8d386c76739855f78e8716515c818bcaef384b51110f0f3c - languageName: node - linkType: hard - -"set-function-name@npm:^2.0.2": - version: 2.0.2 - resolution: "set-function-name@npm:2.0.2" - dependencies: - define-data-property: "npm:^1.1.4" - es-errors: "npm:^1.3.0" - functions-have-names: "npm:^1.2.3" - has-property-descriptors: "npm:^1.0.2" - checksum: 10c0/fce59f90696c450a8523e754abb305e2b8c73586452619c2bad5f7bf38c7b6b4651895c9db895679c5bef9554339cf3ef1c329b66ece3eda7255785fbe299316 - languageName: node - linkType: hard - -"set-proto@npm:^1.0.0": - version: 1.0.0 - resolution: "set-proto@npm:1.0.0" - dependencies: - dunder-proto: "npm:^1.0.1" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.0.0" - checksum: 10c0/ca5c3ccbba479d07c30460e367e66337cec825560b11e8ba9c5ebe13a2a0d6021ae34eddf94ff3dfe17a3104dc1f191519cb6c48378b503e5c3f36393938776a - languageName: node - linkType: hard - -"setimmediate@npm:1.0.4": - version: 1.0.4 - resolution: "setimmediate@npm:1.0.4" - checksum: 10c0/78d1098320ac16a5500fc683491665333e16a6a99103c52d0550f0b31b680c6967d405b3d2b6284d99645c373e0d2ed7d2305c924f12de911a74ffb6c2c3eabe - languageName: node - linkType: hard - "setimmediate@npm:^1.0.5": version: 1.0.5 resolution: "setimmediate@npm:1.0.5" @@ -10000,6 +7174,13 @@ __metadata: languageName: node linkType: hard +"sh-syntax@npm:^0.6.0": + version: 0.6.0 + resolution: "sh-syntax@npm:0.6.0" + checksum: 10c0/495c660a23c67725cdee077b423ca974521ae580302ee62eda9309c84f6cf31722560cdf55bbea5ca98ba7dd7ac352d59f3eed61612d42b1f8a41cfc7673ba9f + languageName: node + linkType: hard + "sha.js@npm:^2.4.0, sha.js@npm:^2.4.8": version: 2.4.11 resolution: "sha.js@npm:2.4.11" @@ -10022,15 +7203,6 @@ __metadata: languageName: node linkType: hard -"shebang-command@npm:^1.2.0": - version: 1.2.0 - resolution: "shebang-command@npm:1.2.0" - dependencies: - shebang-regex: "npm:^1.0.0" - checksum: 10c0/7b20dbf04112c456b7fc258622dafd566553184ac9b6938dd30b943b065b21dabd3776460df534cc02480db5e1b6aec44700d985153a3da46e7db7f9bd21326d - languageName: node - linkType: hard - "shebang-command@npm:^2.0.0": version: 2.0.0 resolution: "shebang-command@npm:2.0.0" @@ -10040,13 +7212,6 @@ __metadata: languageName: node linkType: hard -"shebang-regex@npm:^1.0.0": - version: 1.0.0 - resolution: "shebang-regex@npm:1.0.0" - checksum: 10c0/9abc45dee35f554ae9453098a13fdc2f1730e525a5eb33c51f096cc31f6f10a4b38074c1ebf354ae7bffa7229506083844008dfc3bb7818228568c0b2dc1fff2 - languageName: node - linkType: hard - "shebang-regex@npm:^3.0.0": version: 3.0.0 resolution: "shebang-regex@npm:3.0.0" @@ -10054,13 +7219,13 @@ __metadata: languageName: node linkType: hard -"side-channel-list@npm:^1.0.0": - version: 1.0.0 - resolution: "side-channel-list@npm:1.0.0" +"side-channel-list@npm:^1.0.1": + version: 1.0.1 + resolution: "side-channel-list@npm:1.0.1" dependencies: es-errors: "npm:^1.3.0" - object-inspect: "npm:^1.13.3" - checksum: 10c0/644f4ac893456c9490ff388bf78aea9d333d5e5bfc64cfb84be8f04bf31ddc111a8d4b83b85d7e7e8a7b845bc185a9ad02c052d20e086983cf59f0be517d9b3d + object-inspect: "npm:^1.13.4" + checksum: 10c0/d346c787fd2f9f1c2fdea14f00e8250118db0e7596d85a6cb9faa75f105d31a73a8f7a341c93d7df2a2429098c3d37a77bd3be9e88c37094b8c01807bc77c7a2 languageName: node linkType: hard @@ -10089,16 +7254,16 @@ __metadata: languageName: node linkType: hard -"side-channel@npm:^1.0.4, side-channel@npm:^1.1.0": - version: 1.1.0 - resolution: "side-channel@npm:1.1.0" +"side-channel@npm:^1.1.1": + version: 1.1.1 + resolution: "side-channel@npm:1.1.1" dependencies: es-errors: "npm:^1.3.0" - object-inspect: "npm:^1.13.3" - side-channel-list: "npm:^1.0.0" + object-inspect: "npm:^1.13.4" + side-channel-list: "npm:^1.0.1" side-channel-map: "npm:^1.0.1" side-channel-weakmap: "npm:^1.0.2" - checksum: 10c0/cb20dad41eb032e6c24c0982e1e5a24963a28aa6122b4f05b3f3d6bf8ae7fd5474ef382c8f54a6a3ab86e0cac4d41a23bd64ede3970e5bfb50326ba02a7996e6 + checksum: 10c0/dc0ab81d67f61bda9247d053ce93f41c3fd8ad2bdcb9cf9d8d2f8540d488f26d87a5e99ebfc07eea49ec025867b2452b705442d974b1478f0395e69f6bfb3270 languageName: node linkType: hard @@ -10116,39 +7281,10 @@ __metadata: languageName: node linkType: hard -"simple-concat@npm:^1.0.0": - version: 1.0.1 - resolution: "simple-concat@npm:1.0.1" - checksum: 10c0/62f7508e674414008910b5397c1811941d457dfa0db4fd5aa7fa0409eb02c3609608dfcd7508cace75b3a0bf67a2a77990711e32cd213d2c76f4fd12ee86d776 - languageName: node - linkType: hard - -"simple-get@npm:^2.7.0": - version: 2.8.2 - resolution: "simple-get@npm:2.8.2" - dependencies: - decompress-response: "npm:^3.3.0" - once: "npm:^1.3.1" - simple-concat: "npm:^1.0.0" - checksum: 10c0/12747f008848e573a3d09c88d15fae37d4a359d1ef56a0bed36713952b1d236a3829cd77e862816cf32c7779f6800a0c4076ba7f71fe3684127eaccffb831aba - languageName: node - linkType: hard - -"slash@npm:^3.0.0": - version: 3.0.0 - resolution: "slash@npm:3.0.0" - checksum: 10c0/e18488c6a42bdfd4ac5be85b2ced3ccd0224773baae6ad42cfbb9ec74fc07f9fa8396bd35ee638084ead7a2a0818eb5e7151111544d4731ce843019dab4be47b - languageName: node - linkType: hard - -"slice-ansi@npm:^2.1.0": - version: 2.1.0 - resolution: "slice-ansi@npm:2.1.0" - dependencies: - ansi-styles: "npm:^3.2.0" - astral-regex: "npm:^1.0.0" - is-fullwidth-code-point: "npm:^2.0.0" - checksum: 10c0/c317b21ec9e3d3968f3d5b548cbfc2eae331f58a03f1352621020799cbe695b3611ee972726f8f32d4ca530065a5ec9c74c97fde711c1f41b4a1585876b2c191 +"sisteransi@npm:^1.0.5": + version: 1.0.5 + resolution: "sisteransi@npm:1.0.5" + checksum: 10c0/230ac975cca485b7f6fe2b96a711aa62a6a26ead3e6fb8ba17c5a00d61b8bed0d7adc21f5626b70d7c33c62ff4e63933017a6462942c719d1980bb0b1207ad46 languageName: node linkType: hard @@ -10208,40 +7344,34 @@ __metadata: languageName: node linkType: hard -"solhint-config-keep@https://codeload.github.com/keep-network/solhint-config-keep/tar.gz/5e1751e58c0f1c507305ffc8c7f6c58047657ada": - version: 0.1.0 - resolution: "solhint-config-keep@https://codeload.github.com/keep-network/solhint-config-keep/tar.gz/5e1751e58c0f1c507305ffc8c7f6c58047657ada" - peerDependencies: - solhint: ">=3.3.4" - checksum: 10c0/c4deed3efa00a6939042c8e94fdc7bb8abd18ddb3a3908688b3cd5bdf0d786594411809ad8527ee34a4b0c56413b161eeef9f3201942a3265537d9f37fa0919d - languageName: node - linkType: hard - -"solhint@npm:^3.3.6": - version: 3.3.6 - resolution: "solhint@npm:3.3.6" +"solhint@npm:^6.2.4": + version: 6.2.4 + resolution: "solhint@npm:6.2.4" dependencies: - "@solidity-parser/parser": "npm:^0.13.2" - ajv: "npm:^6.6.1" - antlr4: "npm:4.7.1" - ast-parents: "npm:0.0.1" - chalk: "npm:^2.4.2" - commander: "npm:2.18.0" - cosmiconfig: "npm:^5.0.7" - eslint: "npm:^5.6.0" - fast-diff: "npm:^1.1.2" - glob: "npm:^7.1.3" - ignore: "npm:^4.0.6" - js-yaml: "npm:^3.12.0" - lodash: "npm:^4.17.11" - prettier: "npm:^1.14.3" - semver: "npm:^6.3.0" + "@solidity-parser/parser": "npm:^0.20.2" + ajv: "npm:^8.18.0" + ast-parents: "npm:^0.0.1" + better-ajv-errors: "npm:^2.0.2" + chalk: "npm:^4.1.2" + commander: "npm:^10.0.0" + cosmiconfig: "npm:^8.0.0" + fast-diff: "npm:^1.2.0" + glob: "npm:^13.0.6" + ignore: "npm:^5.2.4" + js-yaml: "npm:^4.1.0" + latest-version: "npm:^7.0.0" + lodash: "npm:^4.17.21" + pluralize: "npm:^8.0.0" + prettier: "npm:^3.0.0" + semver: "npm:^7.5.2" + table: "npm:^6.8.1" + text-table: "npm:^0.2.0" dependenciesMeta: prettier: optional: true bin: solhint: solhint.js - checksum: 10c0/039dc509ba50971f299c8ad04792bec3f0402d8d12ff71a06e3abfd4a73b2321415eeaa00b457fd46ed46ef8534448c8d68fbaa9503db4bc6d9ba09d5aea926e + checksum: 10c0/7d30963faeb3a542904abdda722d50507314efea6d862169a6be8648b28572f02808c786014b84b039c02033f0096662c0f31428749565fb3f774c8cd173a384 languageName: node linkType: hard @@ -10252,17 +7382,10 @@ __metadata: languageName: node linkType: hard -"solidity-ast@npm:^0.4.51": - version: 0.4.59 - resolution: "solidity-ast@npm:0.4.59" - checksum: 10c0/d296ea890bfb026580b0b87623a1450d7de5be417395c1b017778b390e978c717e26c79fddcfb25d36134c425d4a4f813d60a1532ecc53c704ce5c9d4e322215 - languageName: node - linkType: hard - -"solidity-comments-extractor@npm:^0.0.7": - version: 0.0.7 - resolution: "solidity-comments-extractor@npm:0.0.7" - checksum: 10c0/57fb166ff71812404288ae1a386bb9bbb6330662aedc3b45d89f6f0ce51ee0e36c9f4b9d4fd363c2b37fbf607e42df088e734c532fb93e2f345601b429813d9e +"solidity-ast@npm:^0.4.60": + version: 0.4.62 + resolution: "solidity-ast@npm:0.4.62" + checksum: 10c0/8f9bfb41dddaa68e48d8620785cae43583a6711e79b132d3110f8cbf8f028a41004ca6ff8a3896f1e7f408932efb28b9f0390a67e729c12033ec95895430efeb languageName: node linkType: hard @@ -10295,45 +7418,6 @@ __metadata: languageName: node linkType: hard -"spinnies@npm:^0.4.2": - version: 0.4.3 - resolution: "spinnies@npm:0.4.3" - dependencies: - chalk: "npm:^2.4.2" - cli-cursor: "npm:^3.0.0" - strip-ansi: "npm:^5.2.0" - checksum: 10c0/0853c7e9eb825f9e490deb7ce33cc7ed0e1cd7bc504d88c5fd3ea1a93b733552a1e2c1dc8f87b2abb2c3b4aef0bb8d0671078805b1ebae3ee4d9f75a42721de6 - languageName: node - linkType: hard - -"sprintf-js@npm:~1.0.2": - version: 1.0.3 - resolution: "sprintf-js@npm:1.0.3" - checksum: 10c0/ecadcfe4c771890140da5023d43e190b7566d9cf8b2d238600f31bec0fc653f328da4450eb04bd59a431771a8e9cc0e118f0aa3974b683a4981b4e07abc2a5bb - languageName: node - linkType: hard - -"sshpk@npm:^1.7.0": - version: 1.17.0 - resolution: "sshpk@npm:1.17.0" - dependencies: - asn1: "npm:~0.2.3" - assert-plus: "npm:^1.0.0" - bcrypt-pbkdf: "npm:^1.0.0" - dashdash: "npm:^1.12.0" - ecc-jsbn: "npm:~0.1.1" - getpass: "npm:^0.1.1" - jsbn: "npm:~0.1.0" - safer-buffer: "npm:^2.0.2" - tweetnacl: "npm:~0.14.0" - bin: - sshpk-conv: bin/sshpk-conv - sshpk-sign: bin/sshpk-sign - sshpk-verify: bin/sshpk-verify - checksum: 10c0/cf5e7f4c72e8a505ef41daac9f9ca26da365cfe26ae265a01ce98a8868991943857a8526c1cf98a42ef0dc4edf1dbe4e77aeea378cfeb58054beb78505e85402 - languageName: node - linkType: hard - "ssri@npm:^13.0.0": version: 13.0.1 resolution: "ssri@npm:13.0.1" @@ -10343,6 +7427,13 @@ __metadata: languageName: node linkType: hard +"stable-hash-x@npm:^0.2.0": + version: 0.2.0 + resolution: "stable-hash-x@npm:0.2.0" + checksum: 10c0/c757df58366ee4bb266a9486b8932eab7c1ba730469eaf4b68d2dee404814e9f84089c44c9b5205f8c7d99a0ab036cce2af69139ce5ed44b635923c011a8aea8 + languageName: node + linkType: hard + "stacktrace-parser@npm:^0.1.10": version: 0.1.10 resolution: "stacktrace-parser@npm:0.1.10" @@ -10352,13 +7443,6 @@ __metadata: languageName: node linkType: hard -"statuses@npm:2.0.1": - version: 2.0.1 - resolution: "statuses@npm:2.0.1" - checksum: 10c0/34378b207a1620a24804ce8b5d230fea0c279f00b18a7209646d5d47e419d1cc23e7cbf33a25a1e51ac38973dc2ac2e1e9c647a8e481ef365f77668d72becfd0 - languageName: node - linkType: hard - "statuses@npm:>= 1.5.0 < 2": version: 1.5.0 resolution: "statuses@npm:1.5.0" @@ -10366,16 +7450,6 @@ __metadata: languageName: node linkType: hard -"stop-iteration-iterator@npm:^1.1.0": - version: 1.1.0 - resolution: "stop-iteration-iterator@npm:1.1.0" - dependencies: - es-errors: "npm:^1.3.0" - internal-slot: "npm:^1.1.0" - checksum: 10c0/de4e45706bb4c0354a4b1122a2b8cc45a639e86206807ce0baf390ee9218d3ef181923fa4d2b67443367c491aa255c5fbaa64bb74648e3c5b48299928af86c09 - languageName: node - linkType: hard - "streamsearch@npm:^1.1.0": version: 1.1.0 resolution: "streamsearch@npm:1.1.0" @@ -10383,13 +7457,6 @@ __metadata: languageName: node linkType: hard -"strict-uri-encode@npm:^1.0.0": - version: 1.1.0 - resolution: "strict-uri-encode@npm:1.1.0" - checksum: 10c0/eb8a4109ba2588239787389313ba58ec49e043d4c64a1d44716defe5821a68ae49abe0cdefed9946ca9fc2a4af7ecf321da92422b0a67258ec0a3638b053ae62 - languageName: node - linkType: hard - "string-format@npm:^2.0.0": version: 2.0.0 resolution: "string-format@npm:2.0.0" @@ -10408,27 +7475,6 @@ __metadata: languageName: node linkType: hard -"string-width@npm:^2.1.0": - version: 2.1.1 - resolution: "string-width@npm:2.1.1" - dependencies: - is-fullwidth-code-point: "npm:^2.0.0" - strip-ansi: "npm:^4.0.0" - checksum: 10c0/e5f2b169fcf8a4257a399f95d069522f056e92ec97dbdcb9b0cdf14d688b7ca0b1b1439a1c7b9773cd79446cbafd582727279d6bfdd9f8edd306ea5e90e5b610 - languageName: node - linkType: hard - -"string-width@npm:^3.0.0": - version: 3.1.0 - resolution: "string-width@npm:3.1.0" - dependencies: - emoji-regex: "npm:^7.0.1" - is-fullwidth-code-point: "npm:^2.0.0" - strip-ansi: "npm:^5.1.0" - checksum: 10c0/85fa0d4f106e7999bb68c1c640c76fa69fb8c069dab75b009e29c123914e2d3b532e6cfa4b9d1bd913176fc83dedd7a2d7bf40d21a81a8a1978432cedfb65b91 - languageName: node - linkType: hard - "string-width@npm:^5.0.1, string-width@npm:^5.1.2": version: 5.1.2 resolution: "string-width@npm:5.1.2" @@ -10440,86 +7486,6 @@ __metadata: languageName: node linkType: hard -"string.prototype.includes@npm:^2.0.1": - version: 2.0.1 - resolution: "string.prototype.includes@npm:2.0.1" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.3" - checksum: 10c0/25ce9c9b49128352a2618fbe8758b46f945817a58a4420f4799419e40a8d28f116e176c7590d767d5327a61e75c8f32c86171063f48e389b9fdd325f1bd04ee5 - languageName: node - linkType: hard - -"string.prototype.matchall@npm:^4.0.12": - version: 4.0.12 - resolution: "string.prototype.matchall@npm:4.0.12" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.6" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.0.0" - get-intrinsic: "npm:^1.2.6" - gopd: "npm:^1.2.0" - has-symbols: "npm:^1.1.0" - internal-slot: "npm:^1.1.0" - regexp.prototype.flags: "npm:^1.5.3" - set-function-name: "npm:^2.0.2" - side-channel: "npm:^1.1.0" - checksum: 10c0/1a53328ada73f4a77f1fdf1c79414700cf718d0a8ef6672af5603e709d26a24f2181208144aed7e858b1bcc1a0d08567a570abfb45567db4ae47637ed2c2f85c - languageName: node - linkType: hard - -"string.prototype.repeat@npm:^1.0.0": - version: 1.0.0 - resolution: "string.prototype.repeat@npm:1.0.0" - dependencies: - define-properties: "npm:^1.1.3" - es-abstract: "npm:^1.17.5" - checksum: 10c0/94c7978566cffa1327d470fd924366438af9b04b497c43a9805e476e2e908aa37a1fd34cc0911156c17556dab62159d12c7b92b3cc304c3e1281fe4c8e668f40 - languageName: node - linkType: hard - -"string.prototype.trim@npm:^1.2.10": - version: 1.2.10 - resolution: "string.prototype.trim@npm:1.2.10" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.2" - define-data-property: "npm:^1.1.4" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.5" - es-object-atoms: "npm:^1.0.0" - has-property-descriptors: "npm:^1.0.2" - checksum: 10c0/8a8854241c4b54a948e992eb7dd6b8b3a97185112deb0037a134f5ba57541d8248dd610c966311887b6c2fd1181a3877bffb14d873ce937a344535dabcc648f8 - languageName: node - linkType: hard - -"string.prototype.trimend@npm:^1.0.9": - version: 1.0.9 - resolution: "string.prototype.trimend@npm:1.0.9" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.2" - define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.0.0" - checksum: 10c0/59e1a70bf9414cb4c536a6e31bef5553c8ceb0cf44d8b4d0ed65c9653358d1c64dd0ec203b100df83d0413bbcde38b8c5d49e14bc4b86737d74adc593a0d35b6 - languageName: node - linkType: hard - -"string.prototype.trimstart@npm:^1.0.8": - version: 1.0.8 - resolution: "string.prototype.trimstart@npm:1.0.8" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.0.0" - checksum: 10c0/d53af1899959e53c83b64a5fd120be93e067da740e7e75acb433849aa640782fb6c7d4cd5b84c954c84413745a3764df135a8afeb22908b86a835290788d8366 - languageName: node - linkType: hard - "string_decoder@npm:^1.1.1": version: 1.3.0 resolution: "string_decoder@npm:1.3.0" @@ -10529,15 +7495,6 @@ __metadata: languageName: node linkType: hard -"string_decoder@npm:~1.1.1": - version: 1.1.1 - resolution: "string_decoder@npm:1.1.1" - dependencies: - safe-buffer: "npm:~5.1.0" - checksum: 10c0/b4f89f3a92fd101b5653ca3c99550e07bdf9e13b35037e9e2a1c7b47cec4e55e06ff3fc468e314a0b5e80bfbaf65c1ca5a84978764884ae9413bec1fc6ca924e - languageName: node - linkType: hard - "strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": version: 6.0.1 resolution: "strip-ansi@npm:6.0.1" @@ -10547,24 +7504,6 @@ __metadata: languageName: node linkType: hard -"strip-ansi@npm:^4.0.0": - version: 4.0.0 - resolution: "strip-ansi@npm:4.0.0" - dependencies: - ansi-regex: "npm:^3.0.0" - checksum: 10c0/d75d9681e0637ea316ddbd7d4d3be010b1895a17e885155e0ed6a39755ae0fd7ef46e14b22162e66a62db122d3a98ab7917794e255532ab461bb0a04feb03e7d - languageName: node - linkType: hard - -"strip-ansi@npm:^5.1.0, strip-ansi@npm:^5.2.0": - version: 5.2.0 - resolution: "strip-ansi@npm:5.2.0" - dependencies: - ansi-regex: "npm:^4.1.0" - checksum: 10c0/de4658c8a097ce3b15955bc6008f67c0790f85748bdc025b7bc8c52c7aee94bc4f9e50624516150ed173c3db72d851826cd57e7a85fe4e4bb6dbbebd5d297fdf - languageName: node - linkType: hard - "strip-ansi@npm:^7.0.1": version: 7.2.0 resolution: "strip-ansi@npm:7.2.0" @@ -10574,45 +7513,20 @@ __metadata: languageName: node linkType: hard -"strip-bom@npm:^3.0.0": - version: 3.0.0 - resolution: "strip-bom@npm:3.0.0" - checksum: 10c0/51201f50e021ef16672593d7434ca239441b7b760e905d9f33df6e4f3954ff54ec0e0a06f100d028af0982d6f25c35cd5cda2ce34eaebccd0250b8befb90d8f1 - languageName: node - linkType: hard - -"strip-dirs@npm:^2.0.0": - version: 2.1.0 - resolution: "strip-dirs@npm:2.1.0" - dependencies: - is-natural-number: "npm:^4.0.1" - checksum: 10c0/073d6d08331ec2e87afc2c2535d7336fee1d63797384045e4ecb9908a5ac6615022ee000cc278d6bbc94147bed7350f7cf4657b6d18c377813f37e7ae329fb52 - languageName: node - linkType: hard - -"strip-hex-prefix@npm:1.0.0": - version: 1.0.0 - resolution: "strip-hex-prefix@npm:1.0.0" - dependencies: - is-hex-prefixed: "npm:1.0.0" - checksum: 10c0/ec9a48c334c2ba4afff2e8efebb42c3ab5439f0e1ec2b8525e184eabef7fecade7aee444af802b1be55d2df6da5b58c55166c32f8461cc7559b401137ad51851 +"strip-json-comments@npm:^3.1.1": + version: 3.1.1 + resolution: "strip-json-comments@npm:3.1.1" + checksum: 10c0/9681a6257b925a7fa0f285851c0e613cc934a50661fa7bb41ca9cbbff89686bb4a0ee366e6ecedc4daafd01e83eee0720111ab294366fe7c185e935475ebcecd languageName: node linkType: hard -"strip-json-comments@npm:^2.0.1": +"strip-json-comments@npm:~2.0.1": version: 2.0.1 resolution: "strip-json-comments@npm:2.0.1" checksum: 10c0/b509231cbdee45064ff4f9fd73609e2bcc4e84a4d508e9dd0f31f70356473fde18abfb5838c17d56fb236f5a06b102ef115438de0600b749e818a35fbbc48c43 languageName: node linkType: hard -"strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1": - version: 3.1.1 - resolution: "strip-json-comments@npm:3.1.1" - checksum: 10c0/9681a6257b925a7fa0f285851c0e613cc934a50661fa7bb41ca9cbbff89686bb4a0ee366e6ecedc4daafd01e83eee0720111ab294366fe7c185e935475ebcecd - languageName: node - linkType: hard - "supports-color@npm:^5.3.0": version: 5.5.0 resolution: "supports-color@npm:5.5.0" @@ -10640,33 +7554,6 @@ __metadata: languageName: node linkType: hard -"supports-preserve-symlinks-flag@npm:^1.0.0": - version: 1.0.0 - resolution: "supports-preserve-symlinks-flag@npm:1.0.0" - checksum: 10c0/6c4032340701a9950865f7ae8ef38578d8d7053f5e10518076e6554a9381fa91bd9c6850193695c141f32b21f979c985db07265a758867bac95de05f7d8aeb39 - languageName: node - linkType: hard - -"swarm-js@npm:0.1.39": - version: 0.1.39 - resolution: "swarm-js@npm:0.1.39" - dependencies: - bluebird: "npm:^3.5.0" - buffer: "npm:^5.0.5" - decompress: "npm:^4.0.0" - eth-lib: "npm:^0.1.26" - fs-extra: "npm:^4.0.2" - got: "npm:^7.1.0" - mime-types: "npm:^2.1.16" - mkdirp-promise: "npm:^5.0.1" - mock-fs: "npm:^4.1.0" - setimmediate: "npm:^1.0.5" - tar: "npm:^4.0.2" - xhr-request-promise: "npm:^0.1.2" - checksum: 10c0/24849f3cdba95bca7364360553b56e8a203ae95bac74779d6836b4a2d02d6d38fbed9491f0ba19111175cffe949ca650a4817219e9f2458e73c8a73367172a93 - languageName: node - linkType: hard - "table-layout@npm:^1.0.1": version: 1.0.2 resolution: "table-layout@npm:1.0.2" @@ -10679,19 +7566,7 @@ __metadata: languageName: node linkType: hard -"table@npm:^5.2.3": - version: 5.4.6 - resolution: "table@npm:5.4.6" - dependencies: - ajv: "npm:^6.10.2" - lodash: "npm:^4.17.14" - slice-ansi: "npm:^2.1.0" - string-width: "npm:^3.0.0" - checksum: 10c0/87ad7b7cc926aa06e0e2a91a0fb4fcb8b365da87969bc5c74b54cae5d518a089245f44bf80f945ec1aa74c405782db15eeb1dd1926315d842cdc9dbb9371672e - languageName: node - linkType: hard - -"table@npm:^6.0.9, table@npm:^6.8.0": +"table@npm:^6.8.0": version: 6.8.0 resolution: "table@npm:6.8.0" dependencies: @@ -10704,33 +7579,16 @@ __metadata: languageName: node linkType: hard -"tar-stream@npm:^1.5.2": - version: 1.6.2 - resolution: "tar-stream@npm:1.6.2" - dependencies: - bl: "npm:^1.0.0" - buffer-alloc: "npm:^1.2.0" - end-of-stream: "npm:^1.0.0" - fs-constants: "npm:^1.0.0" - readable-stream: "npm:^2.3.0" - to-buffer: "npm:^1.1.1" - xtend: "npm:^4.0.0" - checksum: 10c0/ab8528d2cc9ccd0906d1ce6d8089030b2c92a578c57645ff4971452c8c5388b34c7152c04ed64b8510d22a66ffaf0fee58bada7d6ab41ad1e816e31993d59cf3 - languageName: node - linkType: hard - -"tar@npm:^4.0.2": - version: 4.4.19 - resolution: "tar@npm:4.4.19" +"table@npm:^6.8.1": + version: 6.9.0 + resolution: "table@npm:6.9.0" dependencies: - chownr: "npm:^1.1.4" - fs-minipass: "npm:^1.2.7" - minipass: "npm:^2.9.0" - minizlib: "npm:^1.3.3" - mkdirp: "npm:^0.5.5" - safe-buffer: "npm:^5.2.1" - yallist: "npm:^3.1.1" - checksum: 10c0/1a32a68feabd55e040f399f75fed37c35fd76202bb60e393986312cdee0175ff0dfd1aec9cc04ad2ade8a252d2a08c7d191fda877ce23f14a3da954d91d301d7 + ajv: "npm:^8.0.1" + lodash.truncate: "npm:^4.4.2" + slice-ansi: "npm:^4.0.0" + string-width: "npm:^4.2.3" + strip-ansi: "npm:^6.0.1" + checksum: 10c0/35646185712bb65985fbae5975dda46696325844b78735f95faefae83e86df0a265277819a3e67d189de6e858c509b54e66ca3958ffd51bde56ef1118d455bf4 languageName: node linkType: hard @@ -10747,6 +7605,29 @@ __metadata: languageName: node linkType: hard +"tenderly@npm:^0.8.0": + version: 0.8.0 + resolution: "tenderly@npm:0.8.0" + dependencies: + axios: "npm:^0.27.2" + cli-table3: "npm:^0.6.2" + commander: "npm:^9.4.0" + js-yaml: "npm:^4.1.0" + open: "npm:^8.4.0" + prompts: "npm:^2.4.2" + tslog: "npm:^4.4.0" + peerDependencies: + ts-node: "*" + typescript: "*" + peerDependenciesMeta: + ts-node: + optional: true + typescript: + optional: true + checksum: 10c0/090d3a526d9881968a1bb4f6d2fbe33db3a00677adfcf05ae54c7a585cab14760651982d0a5ded3caa9efdc3f6744cbf55abfcca74e4713941f2167be76cbfea + languageName: node + linkType: hard + "text-table@npm:^0.2.0": version: 0.2.0 resolution: "text-table@npm:0.2.0" @@ -10754,20 +7635,6 @@ __metadata: languageName: node linkType: hard -"through@npm:^2.3.6, through@npm:^2.3.8": - version: 2.3.8 - resolution: "through@npm:2.3.8" - checksum: 10c0/4b09f3774099de0d4df26d95c5821a62faee32c7e96fb1f4ebd54a2d7c11c57fe88b0a0d49cf375de5fee5ae6bf4eb56dbbf29d07366864e2ee805349970d3cc - languageName: node - linkType: hard - -"timed-out@npm:^4.0.0, timed-out@npm:^4.0.1": - version: 4.0.1 - resolution: "timed-out@npm:4.0.1" - checksum: 10c0/86f03ffce5b80c5a066e02e59e411d3fbbfcf242b19290ba76817b4180abd1b85558489586b6022b798fb1cf26fc644c0ce0efb9c271d67ec83fada4b9542a56 - languageName: node - linkType: hard - "tinyglobby@npm:^0.2.12": version: 0.2.16 resolution: "tinyglobby@npm:0.2.16" @@ -10778,7 +7645,7 @@ __metadata: languageName: node linkType: hard -"tinyglobby@npm:^0.2.6": +"tinyglobby@npm:^0.2.14, tinyglobby@npm:^0.2.15, tinyglobby@npm:^0.2.6": version: 0.2.17 resolution: "tinyglobby@npm:0.2.17" dependencies: @@ -10788,7 +7655,7 @@ __metadata: languageName: node linkType: hard -"tmp@npm:0.0.33, tmp@npm:^0.0.33": +"tmp@npm:0.0.33": version: 0.0.33 resolution: "tmp@npm:0.0.33" dependencies: @@ -10797,24 +7664,6 @@ __metadata: languageName: node linkType: hard -"to-buffer@npm:^1.1.1": - version: 1.2.2 - resolution: "to-buffer@npm:1.2.2" - dependencies: - isarray: "npm:^2.0.5" - safe-buffer: "npm:^5.2.1" - typed-array-buffer: "npm:^1.0.3" - checksum: 10c0/56bc56352f14a2c4a0ab6277c5fc19b51e9534882b98eb068b39e14146591e62fa5b06bf70f7fed1626230463d7e60dca81e815096656e5e01c195c593873d12 - languageName: node - linkType: hard - -"to-readable-stream@npm:^1.0.0": - version: 1.0.0 - resolution: "to-readable-stream@npm:1.0.0" - checksum: 10c0/79cb836e2fb4f2885745a8c212eab7ebc52e93758ff0737feceaed96df98e4d04b8903fe8c27f2e9f3f856a5068ac332918b235c5d801b3efe02a51a3fa0eb36 - languageName: node - linkType: hard - "to-regex-range@npm:^5.0.1": version: 5.0.1 resolution: "to-regex-range@npm:5.0.1" @@ -10831,16 +7680,6 @@ __metadata: languageName: node linkType: hard -"tough-cookie@npm:~2.5.0": - version: 2.5.0 - resolution: "tough-cookie@npm:2.5.0" - dependencies: - psl: "npm:^1.1.28" - punycode: "npm:^2.1.1" - checksum: 10c0/e1cadfb24d40d64ca16de05fa8192bc097b66aeeb2704199b055ff12f450e4f30c927ce250f53d01f39baad18e1c11d66f65e545c5c6269de4c366fafa4c0543 - languageName: node - linkType: hard - "tr46@npm:~0.0.3": version: 0.0.3 resolution: "tr46@npm:0.0.3" @@ -10848,18 +7687,12 @@ __metadata: languageName: node linkType: hard -"truffle-flattener@npm:^1.4.0": - version: 1.6.0 - resolution: "truffle-flattener@npm:1.6.0" - dependencies: - "@resolver-engine/imports-fs": "npm:^0.2.2" - "@solidity-parser/parser": "npm:^0.14.1" - find-up: "npm:^2.1.0" - mkdirp: "npm:^1.0.4" - tsort: "npm:0.0.1" - bin: - truffle-flattener: index.js - checksum: 10c0/422b4c6a5b9202f0d185258d795eb0efd07594300c074c23f671e20494864b87a2b2d9b10c3520635045b0f003d94696e7336fe2996fd9f53f7e854f5635b351 +"ts-api-utils@npm:^2.5.0": + version: 2.5.0 + resolution: "ts-api-utils@npm:2.5.0" + peerDependencies: + typescript: ">=4.8.4" + checksum: 10c0/767849383c114e7f1971fa976b20e73ac28fd0c70d8d65c0004790bf4d8f89888c7e4cf6d5949f9c1beae9bc3c64835bef77bbe27fddf45a3c7b60cebcf85c8c languageName: node linkType: hard @@ -10922,32 +7755,72 @@ __metadata: languageName: node linkType: hard -"tsconfig-paths@npm:^3.15.0": - version: 3.15.0 - resolution: "tsconfig-paths@npm:3.15.0" +"ts-node@npm:^10.9.1": + version: 10.9.2 + resolution: "ts-node@npm:10.9.2" dependencies: - "@types/json5": "npm:^0.0.29" - json5: "npm:^1.0.2" - minimist: "npm:^1.2.6" - strip-bom: "npm:^3.0.0" - checksum: 10c0/5b4f301a2b7a3766a986baf8fc0e177eb80bdba6e396792ff92dc23b5bca8bb279fc96517dcaaef63a3b49bebc6c4c833653ec58155780bc906bdbcf7dda0ef5 + "@cspotcode/source-map-support": "npm:^0.8.0" + "@tsconfig/node10": "npm:^1.0.7" + "@tsconfig/node12": "npm:^1.0.7" + "@tsconfig/node14": "npm:^1.0.0" + "@tsconfig/node16": "npm:^1.0.2" + acorn: "npm:^8.4.1" + acorn-walk: "npm:^8.1.1" + arg: "npm:^4.1.0" + create-require: "npm:^1.1.0" + diff: "npm:^4.0.1" + make-error: "npm:^1.1.1" + v8-compile-cache-lib: "npm:^3.0.1" + yn: "npm:3.1.1" + peerDependencies: + "@swc/core": ">=1.2.50" + "@swc/wasm": ">=1.2.50" + "@types/node": "*" + typescript: ">=2.7" + peerDependenciesMeta: + "@swc/core": + optional: true + "@swc/wasm": + optional: true + bin: + ts-node: dist/bin.js + ts-node-cwd: dist/bin-cwd.js + ts-node-esm: dist/bin-esm.js + ts-node-script: dist/bin-script.js + ts-node-transpile-only: dist/bin-transpile.js + ts-script: dist/bin-script-deprecated.js + checksum: 10c0/5f29938489f96982a25ba650b64218e83a3357d76f7bede80195c65ab44ad279c8357264639b7abdd5d7e75fc269a83daa0e9c62fd8637a3def67254ecc9ddc2 + languageName: node + linkType: hard + +"tslib@npm:2.7.0": + version: 2.7.0 + resolution: "tslib@npm:2.7.0" + checksum: 10c0/469e1d5bf1af585742128827000711efa61010b699cb040ab1800bcd3ccdd37f63ec30642c9e07c4439c1db6e46345582614275daca3e0f4abae29b0083f04a6 languageName: node linkType: hard -"tslib@npm:^1.11.1, tslib@npm:^1.8.1, tslib@npm:^1.9.0, tslib@npm:^1.9.3": +"tslib@npm:^1.11.1, tslib@npm:^1.9.3": version: 1.14.1 resolution: "tslib@npm:1.14.1" checksum: 10c0/69ae09c49eea644bc5ebe1bca4fa4cc2c82b7b3e02f43b84bd891504edf66dbc6b2ec0eef31a957042de2269139e4acff911e6d186a258fb14069cd7f6febce2 languageName: node linkType: hard -"tslib@npm:^2.3.1, tslib@npm:^2.6.2": +"tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:^2.6.2": version: 2.8.1 resolution: "tslib@npm:2.8.1" checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 languageName: node linkType: hard +"tslog@npm:^4.3.1, tslog@npm:^4.4.0": + version: 4.11.0 + resolution: "tslog@npm:4.11.0" + checksum: 10c0/1bf7aa08d110da69bfe34aadf24fd1e61d3823d5fe82986e35d3279f3dd11ce1c94430620d55dccc05c280351060b6cd0ef31944abf9320884e8572576f4d71d + languageName: node + linkType: hard + "tsort@npm:0.0.1": version: 0.0.1 resolution: "tsort@npm:0.0.1" @@ -10955,33 +7828,6 @@ __metadata: languageName: node linkType: hard -"tsutils@npm:^3.21.0": - version: 3.21.0 - resolution: "tsutils@npm:3.21.0" - dependencies: - tslib: "npm:^1.8.1" - peerDependencies: - typescript: ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - checksum: 10c0/02f19e458ec78ead8fffbf711f834ad8ecd2cc6ade4ec0320790713dccc0a412b99e7fd907c4cda2a1dc602c75db6f12e0108e87a5afad4b2f9e90a24cabd5a2 - languageName: node - linkType: hard - -"tunnel-agent@npm:^0.6.0": - version: 0.6.0 - resolution: "tunnel-agent@npm:0.6.0" - dependencies: - safe-buffer: "npm:^5.0.1" - checksum: 10c0/4c7a1b813e7beae66fdbf567a65ec6d46313643753d0beefb3c7973d66fcec3a1e7f39759f0a0b4465883499c6dc8b0750ab8b287399af2e583823e40410a17a - languageName: node - linkType: hard - -"tweetnacl@npm:^0.14.3, tweetnacl@npm:~0.14.0": - version: 0.14.5 - resolution: "tweetnacl@npm:0.14.5" - checksum: 10c0/4612772653512c7bc19e61923fbf42903f5e0389ec76a4a1f17195859d114671ea4aa3b734c2029ce7e1fa7e5cc8b80580f67b071ecf0b46b5636d030a0102a2 - languageName: node - linkType: hard - "type-check@npm:^0.4.0, type-check@npm:~0.4.0": version: 0.4.0 resolution: "type-check@npm:0.4.0" @@ -10991,15 +7837,6 @@ __metadata: languageName: node linkType: hard -"type-check@npm:~0.3.2": - version: 0.3.2 - resolution: "type-check@npm:0.3.2" - dependencies: - prelude-ls: "npm:~1.1.2" - checksum: 10c0/776217116b2b4e50e368c7ee0c22c0a85e982881c16965b90d52f216bc296d6a52ef74f9202d22158caacc092a7645b0b8d5fe529a96e3fe35d0fb393966c875 - languageName: node - linkType: hard - "type-detect@npm:^4.0.0, type-detect@npm:^4.0.5": version: 4.0.8 resolution: "type-detect@npm:4.0.8" @@ -11021,765 +7858,314 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^0.7.1": - version: 0.7.1 - resolution: "type-fest@npm:0.7.1" - checksum: 10c0/ce6b5ef806a76bf08d0daa78d65e61f24d9a0380bd1f1df36ffb61f84d14a0985c3a921923cf4b97831278cb6fa9bf1b89c751df09407e0510b14e8c081e4e0f - languageName: node - linkType: hard - -"type-is@npm:~1.6.18": - version: 1.6.18 - resolution: "type-is@npm:1.6.18" - dependencies: - media-typer: "npm:0.3.0" - mime-types: "npm:~2.1.24" - checksum: 10c0/a23daeb538591b7efbd61ecf06b6feb2501b683ffdc9a19c74ef5baba362b4347e42f1b4ed81f5882a8c96a3bfff7f93ce3ffaf0cbbc879b532b04c97a55db9d - languageName: node - linkType: hard - -"type@npm:^1.0.1": - version: 1.2.0 - resolution: "type@npm:1.2.0" - checksum: 10c0/444660849aaebef8cbb9bc43b28ec2068952064cfce6a646f88db97aaa2e2d6570c5629cd79238b71ba23aa3f75146a0b96e24e198210ee0089715a6f8889bf7 - languageName: node - linkType: hard - -"type@npm:^2.7.2": - version: 2.7.2 - resolution: "type@npm:2.7.2" - checksum: 10c0/84c2382788fe24e0bc3d64c0c181820048f672b0f06316aa9c7bdb373f8a09f8b5404f4e856bc4539fb931f2f08f2adc4c53f6c08c9c0314505d70c29a1289e1 - languageName: node - linkType: hard - -"typechain@npm:^6.1.0": - version: 6.1.0 - resolution: "typechain@npm:6.1.0" - dependencies: - "@types/prettier": "npm:^2.1.1" - debug: "npm:^4.1.1" - fs-extra: "npm:^7.0.0" - glob: "npm:^7.1.6" - js-sha3: "npm:^0.8.0" - lodash: "npm:^4.17.15" - mkdirp: "npm:^1.0.4" - prettier: "npm:^2.1.2" - ts-command-line-args: "npm:^2.2.0" - ts-essentials: "npm:^7.0.1" - peerDependencies: - typescript: ">=4.1.0" - bin: - typechain: dist/cli/cli.js - checksum: 10c0/85e6e00e169c95245d9acfc46143677ddac562c4ec853fa4c06b519f0509ec9e9dfc810c8537afb144366206909f9ed5e49e4292a7d34df949705f956c7abb9f - languageName: node - linkType: hard - -"typed-array-buffer@npm:^1.0.3": - version: 1.0.3 - resolution: "typed-array-buffer@npm:1.0.3" - dependencies: - call-bound: "npm:^1.0.3" - es-errors: "npm:^1.3.0" - is-typed-array: "npm:^1.1.14" - checksum: 10c0/1105071756eb248774bc71646bfe45b682efcad93b55532c6ffa4518969fb6241354e4aa62af679ae83899ec296d69ef88f1f3763657cdb3a4d29321f7b83079 - languageName: node - linkType: hard - -"typed-array-byte-length@npm:^1.0.3": - version: 1.0.3 - resolution: "typed-array-byte-length@npm:1.0.3" - dependencies: - call-bind: "npm:^1.0.8" - for-each: "npm:^0.3.3" - gopd: "npm:^1.2.0" - has-proto: "npm:^1.2.0" - is-typed-array: "npm:^1.1.14" - checksum: 10c0/6ae083c6f0354f1fce18b90b243343b9982affd8d839c57bbd2c174a5d5dc71be9eb7019ffd12628a96a4815e7afa85d718d6f1e758615151d5f35df841ffb3e - languageName: node - linkType: hard - -"typed-array-byte-offset@npm:^1.0.4": - version: 1.0.4 - resolution: "typed-array-byte-offset@npm:1.0.4" - dependencies: - available-typed-arrays: "npm:^1.0.7" - call-bind: "npm:^1.0.8" - for-each: "npm:^0.3.3" - gopd: "npm:^1.2.0" - has-proto: "npm:^1.2.0" - is-typed-array: "npm:^1.1.15" - reflect.getprototypeof: "npm:^1.0.9" - checksum: 10c0/3d805b050c0c33b51719ee52de17c1cd8e6a571abdf0fffb110e45e8dd87a657e8b56eee94b776b13006d3d347a0c18a730b903cf05293ab6d92e99ff8f77e53 - languageName: node - linkType: hard - -"typed-array-length@npm:^1.0.7": - version: 1.0.7 - resolution: "typed-array-length@npm:1.0.7" - dependencies: - call-bind: "npm:^1.0.7" - for-each: "npm:^0.3.3" - gopd: "npm:^1.0.1" - is-typed-array: "npm:^1.1.13" - possible-typed-array-names: "npm:^1.0.0" - reflect.getprototypeof: "npm:^1.0.6" - checksum: 10c0/e38f2ae3779584c138a2d8adfa8ecf749f494af3cd3cdafe4e688ce51418c7d2c5c88df1bd6be2bbea099c3f7cea58c02ca02ed438119e91f162a9de23f61295 - languageName: node - linkType: hard - -"typedarray-to-buffer@npm:^3.1.5": - version: 3.1.5 - resolution: "typedarray-to-buffer@npm:3.1.5" - dependencies: - is-typedarray: "npm:^1.0.0" - checksum: 10c0/4ac5b7a93d604edabf3ac58d3a2f7e07487e9f6e98195a080e81dbffdc4127817f470f219d794a843b87052cedef102b53ac9b539855380b8c2172054b7d5027 - languageName: node - linkType: hard - -"typescript@npm:^4.5.4": - version: 4.5.5 - resolution: "typescript@npm:4.5.5" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 10c0/ac15b92f3dcd9a4233cab288a913ccbd96729fc488181396fa93c0297ccef3cd3c2f9a7a63340efb0d07bff3d5026028fc81b9c1ef08076029e057081eb5884b - languageName: node - linkType: hard - -"typescript@patch:typescript@npm%3A^4.5.4#optional!builtin": - version: 4.5.5 - resolution: "typescript@patch:typescript@npm%3A4.5.5#optional!builtin::version=4.5.5&hash=f1b8ea" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 10c0/c699912602518eca36f101f61492608733da8305ba93a82291fbb29508da56e360b10f35f56fd9a53406db9ea2c261d30efd4ec1d9253ff45fdb5541b9d0381c - languageName: node - linkType: hard - -"typical@npm:^4.0.0": - version: 4.0.0 - resolution: "typical@npm:4.0.0" - checksum: 10c0/f300b198fb9fe743859b75ec761d53c382723dc178bbce4957d9cb754f2878a44ce17dc0b6a5156c52be1065449271f63754ba594dac225b80ce3aa39f9241ed - languageName: node - linkType: hard - -"typical@npm:^5.2.0": - version: 5.2.0 - resolution: "typical@npm:5.2.0" - checksum: 10c0/1cceaa20d4b77a02ab8eccfe4a20500729431aecc1e1b7dc70c0e726e7966efdca3bf0b4bee285555b751647e37818fd99154ea73f74b5c29adc95d3c13f5973 - languageName: node - linkType: hard - -"uglify-js@npm:^3.1.4": - version: 3.17.4 - resolution: "uglify-js@npm:3.17.4" - bin: - uglifyjs: bin/uglifyjs - checksum: 10c0/8b7fcdca69deb284fed7d2025b73eb747ce37f9aca6af53422844f46427152d5440601b6e2a033e77856a2f0591e4167153d5a21b68674ad11f662034ec13ced - languageName: node - linkType: hard - -"ultron@npm:~1.1.0": - version: 1.1.1 - resolution: "ultron@npm:1.1.1" - checksum: 10c0/527d7f687012898e3af8d646936ecba776a7099ef8d3d983f9b3ccd5e84e266af0f714d859be15090b55b93f331bb95e5798bce555d9bb08e2f4bf2faac16517 - languageName: node - linkType: hard - -"unbox-primitive@npm:^1.1.0": - version: 1.1.0 - resolution: "unbox-primitive@npm:1.1.0" - dependencies: - call-bound: "npm:^1.0.3" - has-bigints: "npm:^1.0.2" - has-symbols: "npm:^1.1.0" - which-boxed-primitive: "npm:^1.1.1" - checksum: 10c0/7dbd35ab02b0e05fe07136c72cb9355091242455473ec15057c11430129bab38b7b3624019b8778d02a881c13de44d63cd02d122ee782fb519e1de7775b5b982 - languageName: node - linkType: hard - -"unbzip2-stream@npm:^1.0.9": - version: 1.4.3 - resolution: "unbzip2-stream@npm:1.4.3" - dependencies: - buffer: "npm:^5.2.1" - through: "npm:^2.3.8" - checksum: 10c0/2ea2048f3c9db3499316ccc1d95ff757017ccb6f46c812d7c42466247e3b863fb178864267482f7f178254214247779daf68e85f50bd7736c3c97ba2d58b910a - languageName: node - linkType: hard - -"underscore@npm:1.9.1": - version: 1.9.1 - resolution: "underscore@npm:1.9.1" - checksum: 10c0/63415f33b1ba4d7f8a9c8bdd00d457ce7ebdfcb9b1bf9dd596d7550550a790986e5ce7f2319d5e5076dbd56c4a359ebd3c914dd98f6eb33122d41fd439fcb4fa - languageName: node - linkType: hard - -"undici@npm:^5.14.0": - version: 5.19.1 - resolution: "undici@npm:5.19.1" - dependencies: - busboy: "npm:^1.6.0" - checksum: 10c0/1a3d452532c4e8a668c66af69ed17fe6d4568b1745401eb814177f48b297d21cebdeaa07307aa9d07e629541e9dd71d0395b8c28bc7020dc61fa4fc0a1a4e336 - languageName: node - linkType: hard - -"unfetch@npm:^4.2.0": - version: 4.2.0 - resolution: "unfetch@npm:4.2.0" - checksum: 10c0/a5c0a896a6f09f278b868075aea65652ad185db30e827cb7df45826fe5ab850124bf9c44c4dafca4bf0c55a0844b17031e8243467fcc38dd7a7d435007151f1b - languageName: node - linkType: hard - -"universalify@npm:^0.1.0": - version: 0.1.2 - resolution: "universalify@npm:0.1.2" - checksum: 10c0/e70e0339f6b36f34c9816f6bf9662372bd241714dc77508d231d08386d94f2c4aa1ba1318614f92015f40d45aae1b9075cd30bd490efbe39387b60a76ca3f045 - languageName: node - linkType: hard - -"universalify@npm:^2.0.0": - version: 2.0.0 - resolution: "universalify@npm:2.0.0" - checksum: 10c0/07092b9f46df61b823d8ab5e57f0ee5120c178b39609a95e4a15a98c42f6b0b8e834e66fbb47ff92831786193be42f1fd36347169b88ce8639d0f9670af24a71 - languageName: node - linkType: hard - -"unpipe@npm:1.0.0, unpipe@npm:~1.0.0": - version: 1.0.0 - resolution: "unpipe@npm:1.0.0" - checksum: 10c0/193400255bd48968e5c5383730344fbb4fa114cdedfab26e329e50dd2d81b134244bb8a72c6ac1b10ab0281a58b363d06405632c9d49ca9dfd5e90cbd7d0f32c - languageName: node - linkType: hard - -"untildify@npm:^4.0.0": - version: 4.0.0 - resolution: "untildify@npm:4.0.0" - checksum: 10c0/d758e624c707d49f76f7511d75d09a8eda7f2020d231ec52b67ff4896bcf7013be3f9522d8375f57e586e9a2e827f5641c7e06ee46ab9c435fc2b2b2e9de517a - languageName: node - linkType: hard - -"uri-js@npm:^4.2.2": - version: 4.4.1 - resolution: "uri-js@npm:4.4.1" - dependencies: - punycode: "npm:^2.1.0" - checksum: 10c0/4ef57b45aa820d7ac6496e9208559986c665e49447cb072744c13b66925a362d96dd5a46c4530a6b8e203e5db5fe849369444440cb22ecfc26c679359e5dfa3c - languageName: node - linkType: hard - -"url-parse-lax@npm:^1.0.0": - version: 1.0.0 - resolution: "url-parse-lax@npm:1.0.0" - dependencies: - prepend-http: "npm:^1.0.1" - checksum: 10c0/7578d90d18297c0896ab3c98350b61b59be56211baad543ea55eb570dfbd403b0987e499a817abb55d755df6f47ec2e748a49bd09f8d39766066a6871853cea1 - languageName: node - linkType: hard - -"url-parse-lax@npm:^3.0.0": - version: 3.0.0 - resolution: "url-parse-lax@npm:3.0.0" - dependencies: - prepend-http: "npm:^2.0.0" - checksum: 10c0/16f918634d41a4fab9e03c5f9702968c9930f7c29aa1a8c19a6dc01f97d02d9b700ab9f47f8da0b9ace6e0c0e99c27848994de1465b494bced6940c653481e55 - languageName: node - linkType: hard - -"url-set-query@npm:^1.0.0": - version: 1.0.0 - resolution: "url-set-query@npm:1.0.0" - checksum: 10c0/88f52b16b213598763aafe1128f0b48d080d6b63b4f735c01b87effe4e21c463ba6df5c075499bc03c6af1357728b287d629c3d15b4a895c0c87dad8913fccef - languageName: node - linkType: hard - -"url-to-options@npm:^1.0.1": - version: 1.0.1 - resolution: "url-to-options@npm:1.0.1" - checksum: 10c0/3d8143bbc2ab0ead3cbc0c60803c274847bf69aa3ef8b2b77a7d58b1739de01efbfbcd7d7b15c8b6b540bb266ae10895a50a1477ce2d9895dfa2c67243e39c51 - languageName: node - linkType: hard - -"utf8@npm:3.0.0": - version: 3.0.0 - resolution: "utf8@npm:3.0.0" - checksum: 10c0/675d008bab65fc463ce718d5cae8fd4c063540f269e4f25afebce643098439d53e7164bb1f193e0c3852825c7e3e32fbd8641163d19a618dbb53f1f09acb0d5a - languageName: node - linkType: hard - -"util-deprecate@npm:^1.0.1, util-deprecate@npm:~1.0.1": - version: 1.0.2 - resolution: "util-deprecate@npm:1.0.2" - checksum: 10c0/41a5bdd214df2f6c3ecf8622745e4a366c4adced864bc3c833739791aeeeb1838119af7daed4ba36428114b5c67dcda034a79c882e97e43c03e66a4dd7389942 - languageName: node - linkType: hard - -"utils-merge@npm:1.0.1": - version: 1.0.1 - resolution: "utils-merge@npm:1.0.1" - checksum: 10c0/02ba649de1b7ca8854bfe20a82f1dfbdda3fb57a22ab4a8972a63a34553cf7aa51bc9081cf7e001b035b88186d23689d69e71b510e610a09a4c66f68aa95b672 - languageName: node - linkType: hard - -"uuid@npm:2.0.1": - version: 2.0.1 - resolution: "uuid@npm:2.0.1" - checksum: 10c0/8241e74e709bf0398a64c350ebdac8ba8340ee74858f239eee06972b7fbe09f2babd20df486692f68a695510df806f6bd17ffce3eadc4d3c13f2128b262d6f06 - languageName: node - linkType: hard - -"uuid@npm:3.3.2": - version: 3.3.2 - resolution: "uuid@npm:3.3.2" - bin: - uuid: ./bin/uuid - checksum: 10c0/847bd7b389f44d05cf5341134d52803116b616c7344f12c74040effd75280b58273ea3a2bee6ba6e5405688c5edbb0696f4adcbc89e1206dc1d8650bdaece7a6 - languageName: node - linkType: hard - -"uuid@npm:^3.3.2": - version: 3.4.0 - resolution: "uuid@npm:3.4.0" - bin: - uuid: ./bin/uuid - checksum: 10c0/1c13950df865c4f506ebfe0a24023571fa80edf2e62364297a537c80af09c618299797bbf2dbac6b1f8ae5ad182ba474b89db61e0e85839683991f7e08795347 - languageName: node - linkType: hard - -"uuid@npm:^8.3.2": - version: 8.3.2 - resolution: "uuid@npm:8.3.2" - bin: - uuid: dist/bin/uuid - checksum: 10c0/bcbb807a917d374a49f475fae2e87fdca7da5e5530820ef53f65ba1d12131bd81a92ecf259cc7ce317cbe0f289e7d79fdfebcef9bfa3087c8c8a2fa304c9be54 - languageName: node - linkType: hard - -"v8-compile-cache@npm:^2.0.3": - version: 2.3.0 - resolution: "v8-compile-cache@npm:2.3.0" - checksum: 10c0/b2d866febf943fbbf0b5e8d43ae9a9b0dacd11dd76e6a9c8e8032268f0136f081e894a2723774ae2d86befa994be4d4046b0717d82df4f3a10e067994ad5c688 - languageName: node - linkType: hard - -"vary@npm:^1, vary@npm:~1.1.2": - version: 1.1.2 - resolution: "vary@npm:1.1.2" - checksum: 10c0/f15d588d79f3675135ba783c91a4083dcd290a2a5be9fcb6514220a1634e23df116847b1cc51f66bfb0644cf9353b2abb7815ae499bab06e46dd33c1a6bf1f4f - languageName: node - linkType: hard - -"verror@npm:1.10.0": - version: 1.10.0 - resolution: "verror@npm:1.10.0" - dependencies: - assert-plus: "npm:^1.0.0" - core-util-is: "npm:1.0.2" - extsprintf: "npm:^1.2.0" - checksum: 10c0/37ccdf8542b5863c525128908ac80f2b476eed36a32cb944de930ca1e2e78584cc435c4b9b4c68d0fc13a47b45ff364b4be43aa74f8804f9050140f660fb660d - languageName: node - linkType: hard - -"viem@npm:^2.27.0": - version: 2.55.10 - resolution: "viem@npm:2.55.10" - dependencies: - "@noble/curves": "npm:1.9.1" - "@noble/hashes": "npm:1.8.0" - "@scure/bip32": "npm:1.7.0" - "@scure/bip39": "npm:1.6.0" - abitype: "npm:1.2.3" - isows: "npm:1.0.7" - ox: "npm:0.14.33" - ws: "npm:8.21.0" - peerDependencies: - typescript: ">=5.0.4" - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/8d77abf56da107a0fb41b81da82bf4e6f9c54ede8b3bf1bc6508ea324487c643b263adeea11049d10593ee80841c7f5fb876dab5837dafddeb34bfbe0cfd4a8a - languageName: node - linkType: hard - -"web3-bzz@npm:1.2.2": - version: 1.2.2 - resolution: "web3-bzz@npm:1.2.2" - dependencies: - "@types/node": "npm:^10.12.18" - got: "npm:9.6.0" - swarm-js: "npm:0.1.39" - underscore: "npm:1.9.1" - checksum: 10c0/d7ef18c1149223953b60c41b37478e609c9b373b9b91a64d8d2ee59b69870d4672e1bfa85a084a4bb26755dff40d6c64579c7cd2dd0d80e609af35b3eb54dba6 - languageName: node - linkType: hard - -"web3-core-helpers@npm:1.2.2": - version: 1.2.2 - resolution: "web3-core-helpers@npm:1.2.2" - dependencies: - underscore: "npm:1.9.1" - web3-eth-iban: "npm:1.2.2" - web3-utils: "npm:1.2.2" - checksum: 10c0/64dd51676dea138f239de5d64fd55edc516b6dfd4457f56331885f556f37f3a0eefa1112deda7d407239e8bad350078d1230b7bb0a4fe5300740fc4245e80765 - languageName: node - linkType: hard - -"web3-core-method@npm:1.2.2": - version: 1.2.2 - resolution: "web3-core-method@npm:1.2.2" - dependencies: - underscore: "npm:1.9.1" - web3-core-helpers: "npm:1.2.2" - web3-core-promievent: "npm:1.2.2" - web3-core-subscriptions: "npm:1.2.2" - web3-utils: "npm:1.2.2" - checksum: 10c0/207cec33beca1c04a09a33f634ca77bf49829671409045a803de1c3aa6971d44dbd0674ab7098c7f3329d566e3a5eb2ee477bea0356857919a13de56fd99cad6 +"type-fest@npm:^0.7.1": + version: 0.7.1 + resolution: "type-fest@npm:0.7.1" + checksum: 10c0/ce6b5ef806a76bf08d0daa78d65e61f24d9a0380bd1f1df36ffb61f84d14a0985c3a921923cf4b97831278cb6fa9bf1b89c751df09407e0510b14e8c081e4e0f languageName: node linkType: hard -"web3-core-promievent@npm:1.2.2": - version: 1.2.2 - resolution: "web3-core-promievent@npm:1.2.2" +"typechain@npm:^8.3.2": + version: 8.3.2 + resolution: "typechain@npm:8.3.2" dependencies: - any-promise: "npm:1.3.0" - eventemitter3: "npm:3.1.2" - checksum: 10c0/c2511583205cdc70afb0b1860f42264d749cae319904892f515332395909a25313206c79893fb2e1b6aa35d1b620e3438956a86bfcb894c0bf3972ceb2b8051f + "@types/prettier": "npm:^2.1.1" + debug: "npm:^4.3.1" + fs-extra: "npm:^7.0.0" + glob: "npm:7.1.7" + js-sha3: "npm:^0.8.0" + lodash: "npm:^4.17.15" + mkdirp: "npm:^1.0.4" + prettier: "npm:^2.3.1" + ts-command-line-args: "npm:^2.2.0" + ts-essentials: "npm:^7.0.1" + peerDependencies: + typescript: ">=4.3.0" + bin: + typechain: dist/cli/cli.js + checksum: 10c0/1ea660cc7c699c6ac68da67b76454eb4e9395c54666d924ca67f983ae8eb5b5e7dab0a576beb55dbfad75ea784a3f68cb1ca019d332293b7291731c156ead5b5 languageName: node linkType: hard -"web3-core-requestmanager@npm:1.2.2": - version: 1.2.2 - resolution: "web3-core-requestmanager@npm:1.2.2" +"typescript-eslint@npm:^8.70.0": + version: 8.70.0 + resolution: "typescript-eslint@npm:8.70.0" dependencies: - underscore: "npm:1.9.1" - web3-core-helpers: "npm:1.2.2" - web3-providers-http: "npm:1.2.2" - web3-providers-ipc: "npm:1.2.2" - web3-providers-ws: "npm:1.2.2" - checksum: 10c0/d5dda8509a6de3221ddce32efc9f3aaed9d77f8a3c381bb07fbb90d7004146416f63f82e67771c4736b71c08cebcc646b0841cfd30d2f55e4252ca37f5d8fde7 + "@typescript-eslint/eslint-plugin": "npm:8.70.0" + "@typescript-eslint/parser": "npm:8.70.0" + "@typescript-eslint/typescript-estree": "npm:8.70.0" + "@typescript-eslint/utils": "npm:8.70.0" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/bf6625631bfcc7392bb1403681ef934f4f428c41a6a090b081a77ed0d342326c31097956900d701d078ac0c8a599d53377b504455fa9ce7214365c4c8d4635a3 languageName: node linkType: hard -"web3-core-subscriptions@npm:1.2.2": - version: 1.2.2 - resolution: "web3-core-subscriptions@npm:1.2.2" - dependencies: - eventemitter3: "npm:3.1.2" - underscore: "npm:1.9.1" - web3-core-helpers: "npm:1.2.2" - checksum: 10c0/84a7f035c40a99216bd6157f795221fa6053aec75a55fa72faa2a9e328788757d3e7c4e1b5ea74616f1d56d9ffa6e601c0b881150a1508ce9719a1e8ad78cac2 +"typescript@npm:^5.2.2": + version: 5.9.3 + resolution: "typescript@npm:5.9.3" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/6bd7552ce39f97e711db5aa048f6f9995b53f1c52f7d8667c1abdc1700c68a76a308f579cd309ce6b53646deb4e9a1be7c813a93baaf0a28ccd536a30270e1c5 languageName: node linkType: hard -"web3-core@npm:1.2.2": - version: 1.2.2 - resolution: "web3-core@npm:1.2.2" - dependencies: - "@types/bn.js": "npm:^4.11.4" - "@types/node": "npm:^12.6.1" - web3-core-helpers: "npm:1.2.2" - web3-core-method: "npm:1.2.2" - web3-core-requestmanager: "npm:1.2.2" - web3-utils: "npm:1.2.2" - checksum: 10c0/5636ce39561423ee0f6b42c2de8f4f206b0c0f3c665ddb7e69d1d2d6cfba1c885c027ca6340ad01b5d1bfde7c838d94d4847b83cdd42534e9b53bbd9c47f7118 +"typescript@npm:^6.0.3": + version: 6.0.3 + resolution: "typescript@npm:6.0.3" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/4a25ff5045b984370f48f196b3a0120779b1b343d40b9a68d114ea5e5fff099809b2bb777576991a63a5cd59cf7bffd96ff6fe10afcefbcb8bd6fb96ad4b6606 languageName: node linkType: hard -"web3-eth-abi@npm:1.2.2": - version: 1.2.2 - resolution: "web3-eth-abi@npm:1.2.2" - dependencies: - ethers: "npm:4.0.0-beta.3" - underscore: "npm:1.9.1" - web3-utils: "npm:1.2.2" - checksum: 10c0/b70e2d39aaafa5e9072596ab3018f199bfe93b81bee05e0f6b559d218126652a8a74835b502814d8e25cb4b52a44b16f23f7790f1193a672dbbc901af71d6938 +"typescript@patch:typescript@npm%3A^5.2.2#optional!builtin": + version: 5.9.3 + resolution: "typescript@patch:typescript@npm%3A5.9.3#optional!builtin::version=5.9.3&hash=5786d5" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/ad09fdf7a756814dce65bc60c1657b40d44451346858eea230e10f2e95a289d9183b6e32e5c11e95acc0ccc214b4f36289dcad4bf1886b0adb84d711d336a430 languageName: node linkType: hard -"web3-eth-accounts@npm:1.2.2": - version: 1.2.2 - resolution: "web3-eth-accounts@npm:1.2.2" - dependencies: - any-promise: "npm:1.3.0" - crypto-browserify: "npm:3.12.0" - eth-lib: "npm:0.2.7" - ethereumjs-common: "npm:^1.3.2" - ethereumjs-tx: "npm:^2.1.1" - scrypt-shim: "github:web3-js/scrypt-shim" - underscore: "npm:1.9.1" - uuid: "npm:3.3.2" - web3-core: "npm:1.2.2" - web3-core-helpers: "npm:1.2.2" - web3-core-method: "npm:1.2.2" - web3-utils: "npm:1.2.2" - checksum: 10c0/e4538f08c227d98896e80861e3b5c2d5854aca63d9029f61bfb835106beba1194da01929fdf7c4c8529320493f642ef13f62993c7d325db9ecfbf4c329fd40be +"typescript@patch:typescript@npm%3A^6.0.3#optional!builtin": + version: 6.0.3 + resolution: "typescript@patch:typescript@npm%3A6.0.3#optional!builtin::version=6.0.3&hash=5786d5" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/2f25c74e65663c248fa1ade2b8459d9ce5372ff9dad07067310f132966ebec1d93f6c42f0baf77a6b6a7a91460463f708e6887013aaade22111037457c6b25df languageName: node linkType: hard -"web3-eth-contract@npm:1.2.2": - version: 1.2.2 - resolution: "web3-eth-contract@npm:1.2.2" - dependencies: - "@types/bn.js": "npm:^4.11.4" - underscore: "npm:1.9.1" - web3-core: "npm:1.2.2" - web3-core-helpers: "npm:1.2.2" - web3-core-method: "npm:1.2.2" - web3-core-promievent: "npm:1.2.2" - web3-core-subscriptions: "npm:1.2.2" - web3-eth-abi: "npm:1.2.2" - web3-utils: "npm:1.2.2" - checksum: 10c0/24199e7065406e21fbbf1ac12181bee9033b1be1421c154f06672b5b99be7762b17a60fd0224819c74c074bf0b1fe91f79c15deb3edf40a9b4a05bbe5a07feb3 +"typical@npm:^4.0.0": + version: 4.0.0 + resolution: "typical@npm:4.0.0" + checksum: 10c0/f300b198fb9fe743859b75ec761d53c382723dc178bbce4957d9cb754f2878a44ce17dc0b6a5156c52be1065449271f63754ba594dac225b80ce3aa39f9241ed languageName: node linkType: hard -"web3-eth-ens@npm:1.2.2": - version: 1.2.2 - resolution: "web3-eth-ens@npm:1.2.2" - dependencies: - eth-ens-namehash: "npm:2.0.8" - underscore: "npm:1.9.1" - web3-core: "npm:1.2.2" - web3-core-helpers: "npm:1.2.2" - web3-core-promievent: "npm:1.2.2" - web3-eth-abi: "npm:1.2.2" - web3-eth-contract: "npm:1.2.2" - web3-utils: "npm:1.2.2" - checksum: 10c0/33ea90542c32a2a4fc8e718504ed9fa190ab81668953d76a3293df619870f3eec8e4b30300ad67a4e3d5923c838071dd3913da014292e03fae7d4d357abcd74e +"typical@npm:^5.2.0": + version: 5.2.0 + resolution: "typical@npm:5.2.0" + checksum: 10c0/1cceaa20d4b77a02ab8eccfe4a20500729431aecc1e1b7dc70c0e726e7966efdca3bf0b4bee285555b751647e37818fd99154ea73f74b5c29adc95d3c13f5973 languageName: node linkType: hard -"web3-eth-iban@npm:1.2.2": - version: 1.2.2 - resolution: "web3-eth-iban@npm:1.2.2" - dependencies: - bn.js: "npm:4.11.8" - web3-utils: "npm:1.2.2" - checksum: 10c0/16da7d46821a3deec4f2123e8ffaca784a85544f54498cf3bf05841b0b68d1db48cc38adebe31b587b340b25a22981312bf83ac976974229db96a4c76164e8a2 +"uglify-js@npm:^3.1.4": + version: 3.17.4 + resolution: "uglify-js@npm:3.17.4" + bin: + uglifyjs: bin/uglifyjs + checksum: 10c0/8b7fcdca69deb284fed7d2025b73eb747ce37f9aca6af53422844f46427152d5440601b6e2a033e77856a2f0591e4167153d5a21b68674ad11f662034ec13ced languageName: node linkType: hard -"web3-eth-personal@npm:1.2.2": - version: 1.2.2 - resolution: "web3-eth-personal@npm:1.2.2" - dependencies: - "@types/node": "npm:^12.6.1" - web3-core: "npm:1.2.2" - web3-core-helpers: "npm:1.2.2" - web3-core-method: "npm:1.2.2" - web3-net: "npm:1.2.2" - web3-utils: "npm:1.2.2" - checksum: 10c0/2edc1fbcc50bcf7cad07a52824a4dd96b4b578a3a3decf244a12f0594f09e152a2b7ae047b408f473b6c700165c7253d622c289742d4de00f4eea6b459b6455e +"undici-types@npm:~6.19.2": + version: 6.19.8 + resolution: "undici-types@npm:6.19.8" + checksum: 10c0/078afa5990fba110f6824823ace86073b4638f1d5112ee26e790155f481f2a868cc3e0615505b6f4282bdf74a3d8caad715fd809e870c2bb0704e3ea6082f344 languageName: node linkType: hard -"web3-eth@npm:1.2.2": - version: 1.2.2 - resolution: "web3-eth@npm:1.2.2" - dependencies: - underscore: "npm:1.9.1" - web3-core: "npm:1.2.2" - web3-core-helpers: "npm:1.2.2" - web3-core-method: "npm:1.2.2" - web3-core-subscriptions: "npm:1.2.2" - web3-eth-abi: "npm:1.2.2" - web3-eth-accounts: "npm:1.2.2" - web3-eth-contract: "npm:1.2.2" - web3-eth-ens: "npm:1.2.2" - web3-eth-iban: "npm:1.2.2" - web3-eth-personal: "npm:1.2.2" - web3-net: "npm:1.2.2" - web3-utils: "npm:1.2.2" - checksum: 10c0/ed322028a7aa5d9ff3ef9da752c7f0593c592c3aaf2715c08c7e82a3ffba42405ccbe9d3c93ddf8142d2ed8990992d843809a4c4c95b977bf5bcda0d8d19ab39 - languageName: node - linkType: hard - -"web3-net@npm:1.2.2": - version: 1.2.2 - resolution: "web3-net@npm:1.2.2" - dependencies: - web3-core: "npm:1.2.2" - web3-core-method: "npm:1.2.2" - web3-utils: "npm:1.2.2" - checksum: 10c0/81bd2208fcab9f02faf908e07428896c71c3bfc56f9250bdee4da314dcc0c57cdbd621c533fa8af62ab9f11be24993a63c13f1c0b135f94caa49084300d55b1e +"undici-types@npm:~7.18.0": + version: 7.18.2 + resolution: "undici-types@npm:7.18.2" + checksum: 10c0/85a79189113a238959d7a647368e4f7c5559c3a404ebdb8fc4488145ce9426fcd82252a844a302798dfc0e37e6fb178ff481ed03bc4caf634c5757d9ef43521d languageName: node linkType: hard -"web3-providers-http@npm:1.2.2": - version: 1.2.2 - resolution: "web3-providers-http@npm:1.2.2" +"undici@npm:^5.14.0": + version: 5.19.1 + resolution: "undici@npm:5.19.1" dependencies: - web3-core-helpers: "npm:1.2.2" - xhr2-cookies: "npm:1.1.0" - checksum: 10c0/8baa690c07e088e8d6c96c70e32ccb17ff3e9bf1a78a820f1c25bb486735c05f27cff7c6c1bc96056ef414854361e6746753ebed9b95217e47808d2b7e3e5612 + busboy: "npm:^1.6.0" + checksum: 10c0/1a3d452532c4e8a668c66af69ed17fe6d4568b1745401eb814177f48b297d21cebdeaa07307aa9d07e629541e9dd71d0395b8c28bc7020dc61fa4fc0a1a4e336 languageName: node linkType: hard -"web3-providers-ipc@npm:1.2.2": - version: 1.2.2 - resolution: "web3-providers-ipc@npm:1.2.2" - dependencies: - oboe: "npm:2.1.4" - underscore: "npm:1.9.1" - web3-core-helpers: "npm:1.2.2" - checksum: 10c0/ef236685ba878bdeab3b18145652521e68af418e59f7cb44513466c10fcb97d0b616c729017511c9569a485f069734b843983e98066937f5243b0140345be2a2 +"unfetch@npm:^4.2.0": + version: 4.2.0 + resolution: "unfetch@npm:4.2.0" + checksum: 10c0/a5c0a896a6f09f278b868075aea65652ad185db30e827cb7df45826fe5ab850124bf9c44c4dafca4bf0c55a0844b17031e8243467fcc38dd7a7d435007151f1b languageName: node linkType: hard -"web3-providers-ws@npm:1.2.2": - version: 1.2.2 - resolution: "web3-providers-ws@npm:1.2.2" - dependencies: - underscore: "npm:1.9.1" - web3-core-helpers: "npm:1.2.2" - websocket: "github:web3-js/WebSocket-Node#polyfill/globalThis" - checksum: 10c0/408b73bbb9df051bcc698b0169cfd6d0d01eac90c63f7114ac72e3298de8539574774ab3501fb539d927c5006e51f9e02044ec7e342c8f0771f8eb26b15112c9 +"universalify@npm:^0.1.0": + version: 0.1.2 + resolution: "universalify@npm:0.1.2" + checksum: 10c0/e70e0339f6b36f34c9816f6bf9662372bd241714dc77508d231d08386d94f2c4aa1ba1318614f92015f40d45aae1b9075cd30bd490efbe39387b60a76ca3f045 languageName: node linkType: hard -"web3-shh@npm:1.2.2": - version: 1.2.2 - resolution: "web3-shh@npm:1.2.2" - dependencies: - web3-core: "npm:1.2.2" - web3-core-method: "npm:1.2.2" - web3-core-subscriptions: "npm:1.2.2" - web3-net: "npm:1.2.2" - checksum: 10c0/83b572f45393fba7da1deffea393f4f8d47cba665b8f95599f19077c57f9d5a1a2f803e7be213359fd7e850cac92fb223992fd3a99f75357f949d979b546d6fc +"universalify@npm:^2.0.0": + version: 2.0.0 + resolution: "universalify@npm:2.0.0" + checksum: 10c0/07092b9f46df61b823d8ab5e57f0ee5120c178b39609a95e4a15a98c42f6b0b8e834e66fbb47ff92831786193be42f1fd36347169b88ce8639d0f9670af24a71 languageName: node linkType: hard -"web3-utils@npm:1.2.2": - version: 1.2.2 - resolution: "web3-utils@npm:1.2.2" - dependencies: - bn.js: "npm:4.11.8" - eth-lib: "npm:0.2.7" - ethereum-bloom-filters: "npm:^1.0.6" - ethjs-unit: "npm:0.1.6" - number-to-bn: "npm:1.7.0" - randombytes: "npm:^2.1.0" - underscore: "npm:1.9.1" - utf8: "npm:3.0.0" - checksum: 10c0/aa86208ac1a22b0d62d3c0ee434f57863f5a9de87707e60f366fde889855f0b839bf7a1d8394e87a27e95ea405c7b51f6b9e0c967938467316a09ab4bf4ca6d2 +"unpipe@npm:1.0.0": + version: 1.0.0 + resolution: "unpipe@npm:1.0.0" + checksum: 10c0/193400255bd48968e5c5383730344fbb4fa114cdedfab26e329e50dd2d81b134244bb8a72c6ac1b10ab0281a58b363d06405632c9d49ca9dfd5e90cbd7d0f32c languageName: node linkType: hard -"web3@npm:1.2.2": - version: 1.2.2 - resolution: "web3@npm:1.2.2" - dependencies: - "@types/node": "npm:^12.6.1" - web3-bzz: "npm:1.2.2" - web3-core: "npm:1.2.2" - web3-eth: "npm:1.2.2" - web3-eth-personal: "npm:1.2.2" - web3-net: "npm:1.2.2" - web3-shh: "npm:1.2.2" - web3-utils: "npm:1.2.2" - checksum: 10c0/d4ca96687b5b66d6e41e226ffef848d29a2eb5a48fb1d998385e025948cea3182af42073a952cc49c2618c1eba9067014b3795af9a462fff680f5c4b374e3cf1 +"unrs-resolver@npm:^1.7.11, unrs-resolver@npm:^1.9.2": + version: 1.12.2 + resolution: "unrs-resolver@npm:1.12.2" + dependencies: + "@unrs/resolver-binding-android-arm-eabi": "npm:1.12.2" + "@unrs/resolver-binding-android-arm64": "npm:1.12.2" + "@unrs/resolver-binding-darwin-arm64": "npm:1.12.2" + "@unrs/resolver-binding-darwin-x64": "npm:1.12.2" + "@unrs/resolver-binding-freebsd-x64": "npm:1.12.2" + "@unrs/resolver-binding-linux-arm-gnueabihf": "npm:1.12.2" + "@unrs/resolver-binding-linux-arm-musleabihf": "npm:1.12.2" + "@unrs/resolver-binding-linux-arm64-gnu": "npm:1.12.2" + "@unrs/resolver-binding-linux-arm64-musl": "npm:1.12.2" + "@unrs/resolver-binding-linux-loong64-gnu": "npm:1.12.2" + "@unrs/resolver-binding-linux-loong64-musl": "npm:1.12.2" + "@unrs/resolver-binding-linux-ppc64-gnu": "npm:1.12.2" + "@unrs/resolver-binding-linux-riscv64-gnu": "npm:1.12.2" + "@unrs/resolver-binding-linux-riscv64-musl": "npm:1.12.2" + "@unrs/resolver-binding-linux-s390x-gnu": "npm:1.12.2" + "@unrs/resolver-binding-linux-x64-gnu": "npm:1.12.2" + "@unrs/resolver-binding-linux-x64-musl": "npm:1.12.2" + "@unrs/resolver-binding-openharmony-arm64": "npm:1.12.2" + "@unrs/resolver-binding-wasm32-wasi": "npm:1.12.2" + "@unrs/resolver-binding-win32-arm64-msvc": "npm:1.12.2" + "@unrs/resolver-binding-win32-ia32-msvc": "npm:1.12.2" + "@unrs/resolver-binding-win32-x64-msvc": "npm:1.12.2" + napi-postinstall: "npm:^0.3.4" + dependenciesMeta: + "@unrs/resolver-binding-android-arm-eabi": + optional: true + "@unrs/resolver-binding-android-arm64": + optional: true + "@unrs/resolver-binding-darwin-arm64": + optional: true + "@unrs/resolver-binding-darwin-x64": + optional: true + "@unrs/resolver-binding-freebsd-x64": + optional: true + "@unrs/resolver-binding-linux-arm-gnueabihf": + optional: true + "@unrs/resolver-binding-linux-arm-musleabihf": + optional: true + "@unrs/resolver-binding-linux-arm64-gnu": + optional: true + "@unrs/resolver-binding-linux-arm64-musl": + optional: true + "@unrs/resolver-binding-linux-loong64-gnu": + optional: true + "@unrs/resolver-binding-linux-loong64-musl": + optional: true + "@unrs/resolver-binding-linux-ppc64-gnu": + optional: true + "@unrs/resolver-binding-linux-riscv64-gnu": + optional: true + "@unrs/resolver-binding-linux-riscv64-musl": + optional: true + "@unrs/resolver-binding-linux-s390x-gnu": + optional: true + "@unrs/resolver-binding-linux-x64-gnu": + optional: true + "@unrs/resolver-binding-linux-x64-musl": + optional: true + "@unrs/resolver-binding-openharmony-arm64": + optional: true + "@unrs/resolver-binding-wasm32-wasi": + optional: true + "@unrs/resolver-binding-win32-arm64-msvc": + optional: true + "@unrs/resolver-binding-win32-ia32-msvc": + optional: true + "@unrs/resolver-binding-win32-x64-msvc": + optional: true + checksum: 10c0/ddc27f6d920eabdafeac0077ebff9fd799c895cea025751dc17b360bf9be7c93c471fafebf65f205eec476f90d7daa36aef889d47362b2dd4705d68852bcfea4 languageName: node linkType: hard -"webidl-conversions@npm:^3.0.0": - version: 3.0.1 - resolution: "webidl-conversions@npm:3.0.1" - checksum: 10c0/5612d5f3e54760a797052eb4927f0ddc01383550f542ccd33d5238cfd65aeed392a45ad38364970d0a0f4fea32e1f4d231b3d8dac4a3bdd385e5cf802ae097db +"untildify@npm:^4.0.0": + version: 4.0.0 + resolution: "untildify@npm:4.0.0" + checksum: 10c0/d758e624c707d49f76f7511d75d09a8eda7f2020d231ec52b67ff4896bcf7013be3f9522d8375f57e586e9a2e827f5641c7e06ee46ab9c435fc2b2b2e9de517a languageName: node linkType: hard -"websocket@github:web3-js/WebSocket-Node#polyfill/globalThis": - version: 1.0.29 - resolution: "websocket@https://github.com/web3-js/WebSocket-Node.git#commit=ef5ea2f41daf4a2113b80c9223df884b4d56c400" +"uri-js@npm:^4.2.2": + version: 4.4.1 + resolution: "uri-js@npm:4.4.1" dependencies: - debug: "npm:^2.2.0" - es5-ext: "npm:^0.10.50" - nan: "npm:^2.14.0" - typedarray-to-buffer: "npm:^3.1.5" - yaeti: "npm:^0.0.6" - checksum: 10c0/c3f19096589045c2710d48748fd954b68f52d91da0c2524600cdb0ff62d10f8a7f88e0977325e3a68ca0289ea78b4a4d3f24016309675496a88ca995262f36b5 + punycode: "npm:^2.1.0" + checksum: 10c0/4ef57b45aa820d7ac6496e9208559986c665e49447cb072744c13b66925a362d96dd5a46c4530a6b8e203e5db5fe849369444440cb22ecfc26c679359e5dfa3c languageName: node linkType: hard -"whatwg-url@npm:^5.0.0": - version: 5.0.0 - resolution: "whatwg-url@npm:5.0.0" - dependencies: - tr46: "npm:~0.0.3" - webidl-conversions: "npm:^3.0.0" - checksum: 10c0/1588bed84d10b72d5eec1d0faa0722ba1962f1821e7539c535558fb5398d223b0c50d8acab950b8c488b4ba69043fd833cc2697056b167d8ad46fac3995a55d5 +"util-deprecate@npm:^1.0.1": + version: 1.0.2 + resolution: "util-deprecate@npm:1.0.2" + checksum: 10c0/41a5bdd214df2f6c3ecf8622745e4a366c4adced864bc3c833739791aeeeb1838119af7daed4ba36428114b5c67dcda034a79c882e97e43c03e66a4dd7389942 languageName: node linkType: hard -"which-boxed-primitive@npm:^1.1.0, which-boxed-primitive@npm:^1.1.1": - version: 1.1.1 - resolution: "which-boxed-primitive@npm:1.1.1" - dependencies: - is-bigint: "npm:^1.1.0" - is-boolean-object: "npm:^1.2.1" - is-number-object: "npm:^1.1.1" - is-string: "npm:^1.1.1" - is-symbol: "npm:^1.1.1" - checksum: 10c0/aceea8ede3b08dede7dce168f3883323f7c62272b49801716e8332ff750e7ae59a511ae088840bc6874f16c1b7fd296c05c949b0e5b357bfe3c431b98c417abe +"uuid@npm:^8.3.2": + version: 8.3.2 + resolution: "uuid@npm:8.3.2" + bin: + uuid: dist/bin/uuid + checksum: 10c0/bcbb807a917d374a49f475fae2e87fdca7da5e5530820ef53f65ba1d12131bd81a92ecf259cc7ce317cbe0f289e7d79fdfebcef9bfa3087c8c8a2fa304c9be54 languageName: node linkType: hard -"which-builtin-type@npm:^1.2.1": - version: 1.2.1 - resolution: "which-builtin-type@npm:1.2.1" - dependencies: - call-bound: "npm:^1.0.2" - function.prototype.name: "npm:^1.1.6" - has-tostringtag: "npm:^1.0.2" - is-async-function: "npm:^2.0.0" - is-date-object: "npm:^1.1.0" - is-finalizationregistry: "npm:^1.1.0" - is-generator-function: "npm:^1.0.10" - is-regex: "npm:^1.2.1" - is-weakref: "npm:^1.0.2" - isarray: "npm:^2.0.5" - which-boxed-primitive: "npm:^1.1.0" - which-collection: "npm:^1.0.2" - which-typed-array: "npm:^1.1.16" - checksum: 10c0/8dcf323c45e5c27887800df42fbe0431d0b66b1163849bb7d46b5a730ad6a96ee8bfe827d078303f825537844ebf20c02459de41239a0a9805e2fcb3cae0d471 +"v8-compile-cache-lib@npm:^3.0.1": + version: 3.0.1 + resolution: "v8-compile-cache-lib@npm:3.0.1" + checksum: 10c0/bdc36fb8095d3b41df197f5fb6f11e3a26adf4059df3213e3baa93810d8f0cc76f9a74aaefc18b73e91fe7e19154ed6f134eda6fded2e0f1c8d2272ed2d2d391 languageName: node linkType: hard -"which-collection@npm:^1.0.2": - version: 1.0.2 - resolution: "which-collection@npm:1.0.2" +"viem@npm:^2.27.0": + version: 2.55.10 + resolution: "viem@npm:2.55.10" dependencies: - is-map: "npm:^2.0.3" - is-set: "npm:^2.0.3" - is-weakmap: "npm:^2.0.2" - is-weakset: "npm:^2.0.3" - checksum: 10c0/3345fde20964525a04cdf7c4a96821f85f0cc198f1b2ecb4576e08096746d129eb133571998fe121c77782ac8f21cbd67745a3d35ce100d26d4e684c142ea1f2 + "@noble/curves": "npm:1.9.1" + "@noble/hashes": "npm:1.8.0" + "@scure/bip32": "npm:1.7.0" + "@scure/bip39": "npm:1.6.0" + abitype: "npm:1.2.3" + isows: "npm:1.0.7" + ox: "npm:0.14.33" + ws: "npm:8.21.0" + peerDependencies: + typescript: ">=5.0.4" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/8d77abf56da107a0fb41b81da82bf4e6f9c54ede8b3bf1bc6508ea324487c643b263adeea11049d10593ee80841c7f5fb876dab5837dafddeb34bfbe0cfd4a8a languageName: node linkType: hard -"which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.19": - version: 1.1.19 - resolution: "which-typed-array@npm:1.1.19" - dependencies: - available-typed-arrays: "npm:^1.0.7" - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.4" - for-each: "npm:^0.3.5" - get-proto: "npm:^1.0.1" - gopd: "npm:^1.2.0" - has-tostringtag: "npm:^1.0.2" - checksum: 10c0/702b5dc878addafe6c6300c3d0af5983b175c75fcb4f2a72dfc3dd38d93cf9e89581e4b29c854b16ea37e50a7d7fca5ae42ece5c273d8060dcd603b2404bbb3f +"webidl-conversions@npm:^3.0.0": + version: 3.0.1 + resolution: "webidl-conversions@npm:3.0.1" + checksum: 10c0/5612d5f3e54760a797052eb4927f0ddc01383550f542ccd33d5238cfd65aeed392a45ad38364970d0a0f4fea32e1f4d231b3d8dac4a3bdd385e5cf802ae097db languageName: node linkType: hard -"which@npm:^1.2.9": - version: 1.3.1 - resolution: "which@npm:1.3.1" +"whatwg-url@npm:^5.0.0": + version: 5.0.0 + resolution: "whatwg-url@npm:5.0.0" dependencies: - isexe: "npm:^2.0.0" - bin: - which: ./bin/which - checksum: 10c0/e945a8b6bbf6821aaaef7f6e0c309d4b615ef35699576d5489b4261da9539f70393c6b2ce700ee4321c18f914ebe5644bc4631b15466ffbaad37d83151f6af59 + tr46: "npm:~0.0.3" + webidl-conversions: "npm:^3.0.0" + checksum: 10c0/1588bed84d10b72d5eec1d0faa0722ba1962f1821e7539c535558fb5398d223b0c50d8acab950b8c488b4ba69043fd833cc2697056b167d8ad46fac3995a55d5 languageName: node linkType: hard @@ -11814,10 +8200,10 @@ __metadata: languageName: node linkType: hard -"word-wrap@npm:^1.2.3, word-wrap@npm:~1.2.3": - version: 1.2.3 - resolution: "word-wrap@npm:1.2.3" - checksum: 10c0/1cb6558996deb22c909330db1f01d672feee41d7f0664492912de3de282da3f28ba2d49e87b723024e99d56ba2dac2f3ab28f8db07ac199f5e5d5e2e437833de +"word-wrap@npm:^1.2.5": + version: 1.2.5 + resolution: "word-wrap@npm:1.2.5" + checksum: 10c0/e0e4a1ca27599c92a6ca4c32260e8a92e8a44f4ef6ef93f803f8ed823f486e0889fc0b93be4db59c8d51b3064951d25e43d434e95dc8c960cc3a63d65d00ba20 languageName: node linkType: hard @@ -11874,15 +8260,6 @@ __metadata: languageName: node linkType: hard -"write@npm:1.0.3": - version: 1.0.3 - resolution: "write@npm:1.0.3" - dependencies: - mkdirp: "npm:^0.5.1" - checksum: 10c0/2ab5472e32ce2d25279a9d22365c5dd5b95fe40497ca43fa329aa61687fca56e36837615a1b6adfc4ca540389383185680a23497d75a1698b1dcbb52741d29a4 - languageName: node - linkType: hard - "ws@npm:7.4.6": version: 7.4.6 resolution: "ws@npm:7.4.6" @@ -11898,6 +8275,21 @@ __metadata: languageName: node linkType: hard +"ws@npm:8.18.0": + version: 8.18.0 + resolution: "ws@npm:8.18.0" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 10c0/25eb33aff17edcb90721ed6b0eb250976328533ad3cd1a28a274bd263682e7296a6591ff1436d6cbc50fa67463158b062f9d1122013b361cec99a05f84680e06 + languageName: node + linkType: hard + "ws@npm:8.21.0": version: 8.21.0 resolution: "ws@npm:8.21.0" @@ -11913,17 +8305,6 @@ __metadata: languageName: node linkType: hard -"ws@npm:^3.0.0": - version: 3.3.3 - resolution: "ws@npm:3.3.3" - dependencies: - async-limiter: "npm:~1.0.0" - safe-buffer: "npm:~5.1.0" - ultron: "npm:~1.1.0" - checksum: 10c0/bed856f4fd85388a78b80e5ea92c7a6ff8df09ece1621218c4e366faa1551b42b5a0b66a5dd1a47d7f0d97be21d1df528b6d54f04b327e5b94c9dbcab753c94c - languageName: node - linkType: hard - "ws@npm:^7.4.6": version: 7.5.6 resolution: "ws@npm:7.5.6" @@ -11939,65 +8320,6 @@ __metadata: languageName: node linkType: hard -"xhr-request-promise@npm:^0.1.2": - version: 0.1.3 - resolution: "xhr-request-promise@npm:0.1.3" - dependencies: - xhr-request: "npm:^1.1.0" - checksum: 10c0/c5674a395a75a2b788cc80ac9e7913b3a67ef924db51fa67c0958f986b2840583d44de179ac26cf45b872960766a4dd40b36cfab809b76dc80277ba163b75d44 - languageName: node - linkType: hard - -"xhr-request@npm:^1.1.0": - version: 1.1.0 - resolution: "xhr-request@npm:1.1.0" - dependencies: - buffer-to-arraybuffer: "npm:^0.0.5" - object-assign: "npm:^4.1.1" - query-string: "npm:^5.0.1" - simple-get: "npm:^2.7.0" - timed-out: "npm:^4.0.1" - url-set-query: "npm:^1.0.0" - xhr: "npm:^2.0.4" - checksum: 10c0/12bf79e11fa909c01058e654e954b0e3ed0638e6a62a42bd705251c920b39c3980720d0c2d8c2b97ceaeb8bf21bb08fd75c733a909b76555d252014bd3acbc79 - languageName: node - linkType: hard - -"xhr2-cookies@npm:1.1.0": - version: 1.1.0 - resolution: "xhr2-cookies@npm:1.1.0" - dependencies: - cookiejar: "npm:^2.1.1" - checksum: 10c0/38faf4ebecdc003559c58a19e389b51ea227c92d0d38f385e9b43f75df675eae9b7ac6335ecba813990af804d448f69109806e76b07eaf689ad863b303222a6c - languageName: node - linkType: hard - -"xhr@npm:^2.0.4, xhr@npm:^2.3.3": - version: 2.6.0 - resolution: "xhr@npm:2.6.0" - dependencies: - global: "npm:~4.4.0" - is-function: "npm:^1.0.1" - parse-headers: "npm:^2.0.0" - xtend: "npm:^4.0.0" - checksum: 10c0/b73b6413b678846c422559cbc0afb2acb34c3a75b4c3bbee1f258e984255a8b8d65c1749b51691278bbdc28781782950d77a759ef5a9adf7774bed2f5dabc954 - languageName: node - linkType: hard - -"xmlhttprequest@npm:1.8.0": - version: 1.8.0 - resolution: "xmlhttprequest@npm:1.8.0" - checksum: 10c0/c890661562e4cb6c36a126071e956047164296f58b0058ab28a9c9f1c3b46a65bf421a242d3449363a2aadc3d9769146160b10a501710d476a17d77d41a5c99e - languageName: node - linkType: hard - -"xtend@npm:^4.0.0": - version: 4.0.2 - resolution: "xtend@npm:4.0.2" - checksum: 10c0/366ae4783eec6100f8a02dff02ac907bf29f9a00b82ac0264b4d8b832ead18306797e283cf19de776538babfdcb2101375ec5646b59f08c52128ac4ab812ed0e - languageName: node - linkType: hard - "y18n@npm:^5.0.5": version: 5.0.8 resolution: "y18n@npm:5.0.8" @@ -12005,20 +8327,6 @@ __metadata: languageName: node linkType: hard -"yaeti@npm:^0.0.6": - version: 0.0.6 - resolution: "yaeti@npm:0.0.6" - checksum: 10c0/4e88702d8b34d7b61c1c4ec674422b835d453b8f8a6232be41e59fc98bc4d9ab6d5abd2da55bab75dfc07ae897fdc0c541f856ce3ab3b17de1630db6161aa3f6 - languageName: node - linkType: hard - -"yallist@npm:^3.0.0, yallist@npm:^3.1.1": - version: 3.1.1 - resolution: "yallist@npm:3.1.1" - checksum: 10c0/c66a5c46bc89af1625476f7f0f2ec3653c1a1791d2f9407cfb4c2ba812a1e1c9941416d71ba9719876530e3340a99925f697142989371b72d93b9ee628afd8c1 - languageName: node - linkType: hard - "yallist@npm:^4.0.0": version: 4.0.0 resolution: "yallist@npm:4.0.0" @@ -12067,16 +8375,6 @@ __metadata: languageName: node linkType: hard -"yauzl@npm:^2.4.2": - version: 2.10.0 - resolution: "yauzl@npm:2.10.0" - dependencies: - buffer-crc32: "npm:~0.2.3" - fd-slicer: "npm:~1.1.0" - checksum: 10c0/f265002af7541b9ec3589a27f5fb8f11cf348b53cc15e2751272e3c062cd73f3e715bc72d43257de71bbaecae446c3f1b14af7559e8ab0261625375541816422 - languageName: node - linkType: hard - "yn@npm:3.1.1": version: 3.1.1 resolution: "yn@npm:3.1.1" @@ -12091,20 +8389,22 @@ __metadata: languageName: node linkType: hard -"zksync-web3@npm:^0.7.8": - version: 0.7.9 - resolution: "zksync-web3@npm:0.7.9" +"zksync-ethers@npm:^5.0.0": + version: 5.11.2 + resolution: "zksync-ethers@npm:5.11.2" + dependencies: + ethers: "npm:~5.7.0" peerDependencies: - ethers: ~5.5.0 - checksum: 10c0/45b53ca34ff7ae4afe6a83c3ba28a0cd8ce9ad3a94f6b7fa635df274ece74404debfc5dc30525e42cbf0c8b165544055b9028eaf4105fe34178a8de648782e5d + ethers: ~5.7.0 + checksum: 10c0/a6065dcc484ac9bc96cc2163b939a26caf0f12619ea64d171dcac74d1ac37495d7e31a4a043f4adf51740a93a32f5d144b5e0092dd0df18386d9a46a9f0ce493 languageName: node linkType: hard -"zksync-web3@npm:^0.8.1": - version: 0.8.1 - resolution: "zksync-web3@npm:0.8.1" +"zksync-web3@npm:^0.14.3": + version: 0.14.4 + resolution: "zksync-web3@npm:0.14.4" peerDependencies: - ethers: ~5.7.0 - checksum: 10c0/064fed2a8cc0907e1c084f128d3098eed503dc49ee86b3f5e77922f899074ba44d5028a7fad19e017af21c5561cec2ab7c6c4a5c140050b20c6f281c9614a55d + ethers: ^5.7.0 + checksum: 10c0/1ee87dc33f2c45dfc5a93abb3ffda92f5e7190d90448aacb4859374975fd72bf269c72126ec06043e57e02c925273ecb936189ea2350a6ac4a620b95b86f7f97 languageName: node linkType: hard diff --git a/solidity/random-beacon/.dockerignore b/solidity/random-beacon/.dockerignore index 17165d83c9..1e58a46276 100644 --- a/solidity/random-beacon/.dockerignore +++ b/solidity/random-beacon/.dockerignore @@ -2,6 +2,12 @@ .* !.yarnrc.yml +# Include local dependency patches, but exclude Yarn caches and install state. +!.yarn +.yarn/** +!.yarn/patches +!.yarn/patches/** + # Documentation docs/ diff --git a/solidity/random-beacon/.eslintignore b/solidity/random-beacon/.eslintignore deleted file mode 100644 index 6604016c57..0000000000 --- a/solidity/random-beacon/.eslintignore +++ /dev/null @@ -1,8 +0,0 @@ -artifacts/ -build/ -cache/ -deployments/ -export/ -hardhat-dependency-compiler/ -typechain/ -export.json diff --git a/solidity/random-beacon/.eslintrc b/solidity/random-beacon/.eslintrc deleted file mode 100644 index 4fc3d1d346..0000000000 --- a/solidity/random-beacon/.eslintrc +++ /dev/null @@ -1,22 +0,0 @@ -{ - "root": true, - "extends": ["@thesis-co"], - "rules": { - "import/no-extraneous-dependencies": [ - "error", - { "devDependencies": ["./test/**/*.ts", "hardhat.config.ts", "./tasks/*.ts"] } - ], - "@typescript-eslint/no-use-before-define": "off", - "@typescript-eslint/no-explicit-any": "warn", - "no-plusplus": ["error", { "allowForLoopAfterthoughts": true }], - "@typescript-eslint/consistent-type-imports": "warn", - "import/order": [ - "warn", - { - "groups": ["builtin", "external", "parent", "sibling", "index", "type"], - "newlines-between": "always" - } - ], - "no-await-in-loop": "off" - } -} diff --git a/solidity/random-beacon/.nvmrc b/solidity/random-beacon/.nvmrc new file mode 100644 index 0000000000..9e2934aa34 --- /dev/null +++ b/solidity/random-beacon/.nvmrc @@ -0,0 +1 @@ +24.11.1 diff --git a/solidity/random-beacon/.prettierignore b/solidity/random-beacon/.prettierignore index 1dc21dc5dc..902c31f883 100644 --- a/solidity/random-beacon/.prettierignore +++ b/solidity/random-beacon/.prettierignore @@ -8,3 +8,6 @@ typechain/ docgen-templates/ export.json gasReporterOutput.json +contracts/legacy/ +export/ +.hardhat/ diff --git a/solidity/random-beacon/.prettierrc.js b/solidity/random-beacon/.prettierrc.js index 49faa7bb98..fe7b860f2b 100644 --- a/solidity/random-beacon/.prettierrc.js +++ b/solidity/random-beacon/.prettierrc.js @@ -1,5 +1,7 @@ module.exports = { - ...require("@thesis-co/prettier-config"), + semi: false, + trailingComma: "all", + plugins: ["prettier-plugin-solidity"], overrides: [ { files: "*.sol", diff --git a/solidity/random-beacon/.solhint.json b/solidity/random-beacon/.solhint.json index 0343773c2d..4b1a7f9a59 100644 --- a/solidity/random-beacon/.solhint.json +++ b/solidity/random-beacon/.solhint.json @@ -1,8 +1,42 @@ { - "extends": "keep", "plugins": [], "rules": { - "func-visibility": ["error", { "ignoreConstructors": true }], - "no-inline-assembly": "off" + "max-states-count": ["warn", 15], + "no-unused-vars": "error", + "payable-fallback": "warn", + "reason-string": [ + "error", + { + "maxLength": 250 + } + ], + "constructor-syntax": "error", + "quotes": ["error", "double"], + "event-name-capwords": "warn", + "func-name-mixedcase": "warn", + "use-forbidden-name": "error", + "imports-on-top": "error", + "ordering": "warn", + "visibility-modifier-order": "error", + "avoid-call-value": "error", + "avoid-low-level-calls": "error", + "avoid-sha3": "error", + "avoid-suicide": "error", + "avoid-throw": "error", + "avoid-tx-origin": "error", + "check-send-result": "error", + "func-visibility": [ + "error", + { + "ignoreConstructors": true + } + ], + "multiple-sends": "error", + "no-complex-fallback": "error", + "no-inline-assembly": "off", + "not-rely-on-block-hash": "error", + "not-rely-on-time": "error", + "reentrancy": "error", + "state-visibility": "error" } } diff --git a/solidity/random-beacon/.solhintignore b/solidity/random-beacon/.solhintignore index ef4020b604..17b3430392 100644 --- a/solidity/random-beacon/.solhintignore +++ b/solidity/random-beacon/.solhintignore @@ -1,2 +1,3 @@ hardhat-dependency-compiler/ node_modules/ +contracts/legacy/ diff --git a/solidity/random-beacon/.tsconfig-eslint.json b/solidity/random-beacon/.tsconfig-eslint.json deleted file mode 120000 index a46cad2975..0000000000 --- a/solidity/random-beacon/.tsconfig-eslint.json +++ /dev/null @@ -1 +0,0 @@ -./node_modules/@thesis-co/eslint-config/.tsconfig-eslint.json \ No newline at end of file diff --git a/solidity/random-beacon/.tsconfig-eslint.json b/solidity/random-beacon/.tsconfig-eslint.json new file mode 100644 index 0000000000..960aa2533d --- /dev/null +++ b/solidity/random-beacon/.tsconfig-eslint.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "include": ["**/*.ts"], + "exclude": [ + "node_modules", + "build", + "cache", + "export", + "external", + "typechain" + ] +} diff --git a/solidity/random-beacon/.yarn/patches/@keep-network-hardhat-helpers-npm-0.7.2-086cf3da54.patch b/solidity/random-beacon/.yarn/patches/@keep-network-hardhat-helpers-npm-0.7.2-086cf3da54.patch new file mode 100644 index 0000000000..3acb0a3521 --- /dev/null +++ b/solidity/random-beacon/.yarn/patches/@keep-network-hardhat-helpers-npm-0.7.2-086cf3da54.patch @@ -0,0 +1,520 @@ +diff --git a/dist/contracts.d.ts b/dist/contracts.d.ts +index e67607c..de33123 100644 +--- a/dist/contracts.d.ts ++++ b/dist/contracts.d.ts +@@ -1,7 +1,7 @@ +-import type { Contract } from "ethers"; ++import type { BaseContract, Contract } from "ethers"; + import type { HardhatRuntimeEnvironment } from "hardhat/types"; + export interface HardhatContractsHelpers { +- getContract(deploymentName: string): Promise; ++ getContract(deploymentName: string): Promise; + } + export default function (hre: HardhatRuntimeEnvironment): HardhatContractsHelpers; + //# sourceMappingURL=contracts.d.ts.map +\ No newline at end of file +diff --git a/dist/upgrades.d.ts b/dist/upgrades.d.ts +index 2eb5874..a07f2ae 100644 +--- a/dist/upgrades.d.ts ++++ b/dist/upgrades.d.ts +@@ -1,24 +1,24 @@ + import "@openzeppelin/hardhat-upgrades"; +-import type { Contract, ContractTransaction } from "ethers"; ++import type { BaseContract, Contract, ContractTransaction } from "ethers"; + import type { FactoryOptions, HardhatRuntimeEnvironment } from "hardhat/types"; + import type { Deployment } from "hardhat-deploy/dist/types"; + import type { DeployProxyOptions, UpgradeProxyOptions } from "@openzeppelin/hardhat-upgrades/src/utils/options"; + import { Libraries } from "hardhat-deploy/types"; + export interface HardhatUpgradesHelpers { +- deployProxy(name: string, opts?: UpgradesDeployOptions): Promise<[T, Deployment]>; +- upgradeProxy(currentContractName: string, newContractName: string, opts?: UpgradesUpgradeOptions): Promise<[T, Deployment]>; ++ deployProxy(name: string, opts?: UpgradesDeployOptions): Promise<[T, Deployment]>; ++ upgradeProxy(currentContractName: string, newContractName: string, opts?: UpgradesUpgradeOptions): Promise<[T, Deployment]>; + prepareProxyUpgrade(proxyDeploymentName: string, newContractName: string, opts?: UpgradesPrepareProxyUpgradeOptions): Promise<{ + newImplementationAddress: string; + preparedTransaction: ContractTransaction; + }>; + } + type CustomFactoryOptions = FactoryOptions & { + libraries?: Libraries; + }; + export interface UpgradesDeployOptions { + contractName?: string; + initializerArgs?: unknown[]; + factoryOpts?: CustomFactoryOptions; + proxyOpts?: DeployProxyOptions; + } + export interface UpgradesUpgradeOptions { +@@ -27,19 +27,19 @@ export interface UpgradesUpgradeOptions { + factoryOpts?: CustomFactoryOptions; + proxyOpts?: UpgradeProxyOptions; + } + export interface UpgradesPrepareProxyUpgradeOptions { + contractName?: string; + factoryOpts?: CustomFactoryOptions; + callData?: string; + } + /** + * Deploys contract as a TransparentProxy. + * + * @param {HardhatRuntimeEnvironment} hre Hardhat runtime environment. + * @param {string} name Contract Name + * @param {UpgradesDeployOptions} opts + */ +-export declare function deployProxy(hre: HardhatRuntimeEnvironment, name: string, opts?: UpgradesDeployOptions): Promise<[T, Deployment]>; ++export declare function deployProxy(hre: HardhatRuntimeEnvironment, name: string, opts?: UpgradesDeployOptions): Promise<[T, Deployment]>; + export default function (hre: HardhatRuntimeEnvironment): HardhatUpgradesHelpers; + export {}; + //# sourceMappingURL=upgrades.d.ts.map +\ No newline at end of file +diff --git a/dist/upgrades.js b/dist/upgrades.js +index 6367def..cfb0e32 100644 +--- a/dist/upgrades.js ++++ b/dist/upgrades.js +@@ -1,54 +1,85 @@ + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.deployProxy = void 0; + require("@openzeppelin/hardhat-upgrades"); +-const utils_1 = require("@openzeppelin/hardhat-upgrades/dist/utils"); ++const ProxyAdminV4 = require("@openzeppelin/upgrades-core/artifacts/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json"); ++const ProxyAdminV5 = require("@openzeppelin/upgrades-core/artifacts/@openzeppelin/contracts-v5/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json"); + const upgrades_core_1 = require("@openzeppelin/upgrades-core"); + /** + * Deploys contract as a TransparentProxy. + * + * @param {HardhatRuntimeEnvironment} hre Hardhat runtime environment. + * @param {string} name Contract Name + * @param {UpgradesDeployOptions} opts + */ ++// Preserve the receipt metadata published by hardhat-helpers 0.6. ++function toDeploymentReceipt(receipt) { ++ return { ++ to: receipt.to, ++ from: receipt.from, ++ contractAddress: receipt.contractAddress, ++ transactionIndex: receipt.index, ++ gasUsed: receipt.gasUsed.toString(), ++ logsBloom: receipt.logsBloom, ++ blockHash: receipt.blockHash, ++ transactionHash: receipt.hash, ++ logs: receipt.logs.map((log) => ({ ++ transactionIndex: log.transactionIndex, ++ blockNumber: log.blockNumber, ++ transactionHash: log.transactionHash, ++ address: log.address, ++ topics: [...log.topics], ++ data: log.data, ++ logIndex: log.index, ++ blockHash: log.blockHash, ++ // Mined receipt logs omit the removed field in the existing export format. ++ removed: undefined, ++ })), ++ blockNumber: receipt.blockNumber, ++ cumulativeGasUsed: receipt.cumulativeGasUsed.toString(), ++ status: receipt.status, ++ byzantium: receipt.status !== null, ++ } ++} + async function deployProxy(hre, name, opts) { + const { ethers, upgrades, deployments, artifacts } = hre; + const { log } = deployments; + const existingDeployment = await deployments.getOrNull(name); + if (existingDeployment) { + throw new Error(`${name} was already deployed at ${existingDeployment.address}`); + } + const contractFactory = await ethers.getContractFactory(opts?.contractName || name, opts?.factoryOpts); + const contractInstance = (await upgrades.deployProxy(contractFactory, opts?.initializerArgs, opts?.proxyOpts)); + const deploymentTransaction = contractInstance.deploymentTransaction(); + // Let the transaction propagate across the ethereum nodes. This is mostly to + // wait for all Alchemy nodes to catch up their state. + const transactionReceipt = await deploymentTransaction?.wait(1); + const contractAddress = await contractInstance.getAddress(); + const transactionHash = deploymentTransaction?.hash; + log(`Deployed ${name} as ${opts?.proxyOpts?.kind || "transparent"} proxy at ${contractAddress} (tx: ${transactionHash})`); + const artifact = artifacts.readArtifactSync(opts?.contractName || name); + const implementation = await upgrades.erc1967.getImplementationAddress(contractAddress); + if (!transactionReceipt || !transactionHash) { + throw new Error(`Could not find transaction receipt for transaction hash: ${transactionHash}`); + } + const deployment = { + address: contractAddress, + abi: artifact.abi, + transactionHash: transactionHash, + implementation: implementation, ++ receipt: toDeploymentReceipt(transactionReceipt), + libraries: opts?.factoryOpts?.libraries, + devdoc: "Contract deployed as upgradable proxy", + args: opts?.proxyOpts?.constructorArgs, + }; + await deployments.save(name, deployment); + return [contractInstance, deployment]; + } + exports.deployProxy = deployProxy; + /** + * Upgrades previously deployed contract. + * + * @param {HardhatRuntimeEnvironment} hre Hardhat runtime environment. + * @param {string} proxyDeploymentName Name of the proxy deployment that will be + * upgraded. + * @param {string} newContractName Name of the new implementation contract. +@@ -72,30 +103,31 @@ async function upgradeProxy(hre, proxyDeploymentName, newContractName, opts) { + const contractAddress = await newContractInstance.getAddress(); + const transactionHash = deploymentTransaction?.hash; + log(`Upgraded ${proxyDeploymentName} proxy contract (address: ${proxyDeployment.address}) ` + + `in tx: ${transactionHash}`); + const artifact = artifacts.readArtifactSync(opts?.contractName || newContractName); + const implementation = await upgrades.erc1967.getImplementationAddress(contractAddress); + log(`New ${proxyDeploymentName} proxy contract implementation address is: ${implementation}`); + if (!transactionReceipt || !transactionHash) { + throw new Error(`Could not find transaction receipt for transaction hash: ${transactionHash}`); + } + const deployment = { + address: contractAddress, + abi: artifact.abi, + transactionHash: transactionHash, + implementation: implementation, ++ receipt: toDeploymentReceipt(transactionReceipt), + libraries: opts?.factoryOpts?.libraries, + devdoc: "Contract deployed as upgradable proxy", + args: opts?.proxyOpts?.constructorArgs, + }; + await deployments.save(proxyDeploymentName, deployment); + return [newContractInstance, deployment]; + } + /** + * Prepare upgrade of deployed contract. + * It deploys new implementation contract and prepares transaction to upgrade + * the proxy contract to the new implementation thorough a Proxy Admin instance. + * The transaction has to be executed by the owner of the Proxy Admin. + * + * @param {HardhatRuntimeEnvironment} hre Hardhat runtime environment. + * @param {string} proxyDeploymentName Name of the proxy deployment that will be +@@ -108,40 +140,40 @@ async function prepareProxyUpgrade(hre, proxyDeploymentName, newContractName, op + const signer = await ethers.provider.getSigner(); + const { log } = deployments; + const proxyDeployment = await deployments.get(proxyDeploymentName); + const implementationContractFactory = await ethers.getContractFactory(opts?.contractName || newContractName, opts?.factoryOpts); + const newImplementationAddress = (await upgrades.prepareUpgrade(proxyDeployment.address, implementationContractFactory, { + kind: "transparent", + getTxResponse: false, + })); + log(`new implementation contract deployed at: ${newImplementationAddress}`); + const proxyAdminAddress = await hre.upgrades.erc1967.getAdminAddress(proxyDeployment.address); + let proxyAdmin; + let upgradeTxData; + const proxyInterfaceVersion = await (0, upgrades_core_1.getUpgradeInterfaceVersion)(hre.network.provider, proxyAdminAddress); + switch (proxyInterfaceVersion) { + case "5.0.0": { +- proxyAdmin = await (0, utils_1.attachProxyAdminV5)(hre, proxyAdminAddress, signer); ++ proxyAdmin = await hre.ethers.getContractAt(ProxyAdminV5.abi, proxyAdminAddress, signer); + upgradeTxData = proxyAdmin.interface.encodeFunctionData("upgradeAndCall", [ + proxyDeployment.address, + newImplementationAddress, + opts?.callData ?? "0x", + ]); + break; + } + default: { +- proxyAdmin = await (0, utils_1.attachProxyAdminV4)(hre, proxyAdminAddress, signer); ++ proxyAdmin = await hre.ethers.getContractAt(ProxyAdminV4.abi, proxyAdminAddress, signer); + if (opts?.callData) { + upgradeTxData = proxyAdmin.interface.encodeFunctionData("upgradeAndCall", [proxyDeployment.address, newImplementationAddress, opts?.callData]); + } + else { + upgradeTxData = proxyAdmin.interface.encodeFunctionData("upgrade", [ + proxyDeployment.address, + newImplementationAddress, + ]); + } + } + } + const preparedTransaction = { + from: (await proxyAdmin.owner()), + to: proxyAdminAddress, + data: upgradeTxData, +diff --git a/src/contracts.ts b/src/contracts.ts +index dc82311..b8f4d3a 100644 +--- a/src/contracts.ts ++++ b/src/contracts.ts +@@ -1,23 +1,23 @@ +-import type { Contract } from "ethers" ++import type { BaseContract, Contract } from "ethers" + import type { HardhatRuntimeEnvironment } from "hardhat/types" + + export interface HardhatContractsHelpers { +- getContract(deploymentName: string): Promise ++ getContract(deploymentName: string): Promise + } + +-async function getContract( ++async function getContract( + hre: HardhatRuntimeEnvironment, + deploymentName: string + ): Promise { + const deployment = await hre.deployments.get(deploymentName) + + return (await hre.ethers.getContractAt( + deployment.abi, + deployment.address + )) as T + } + + export default function ( + hre: HardhatRuntimeEnvironment + ): HardhatContractsHelpers { + return { +diff --git a/src/upgrades.ts b/src/upgrades.ts +index 22edb53..c7abdf3 100644 +--- a/src/upgrades.ts ++++ b/src/upgrades.ts +@@ -1,47 +1,77 @@ + import "@openzeppelin/hardhat-upgrades" + + import type { ++ BaseContract, + Contract, + ContractFactory, + ContractTransaction, + ContractTransactionResponse, ++ TransactionReceipt, + } from "ethers" + import type { + Artifact, + FactoryOptions, + HardhatRuntimeEnvironment, + } from "hardhat/types" +-import type { Deployment } from "hardhat-deploy/dist/types" ++import type { Deployment, Receipt } from "hardhat-deploy/dist/types" + import type { + DeployProxyOptions, + UpgradeProxyOptions, + } from "@openzeppelin/hardhat-upgrades/src/utils/options" + import { Libraries } from "hardhat-deploy/types" +-import { +- attachProxyAdminV4, +- attachProxyAdminV5, +-} from "@openzeppelin/hardhat-upgrades/dist/utils" ++import ProxyAdminV4 from "@openzeppelin/upgrades-core/artifacts/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json" ++import ProxyAdminV5 from "@openzeppelin/upgrades-core/artifacts/@openzeppelin/contracts-v5/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json" + + import { getUpgradeInterfaceVersion } from "@openzeppelin/upgrades-core" + ++// Preserve the receipt metadata published by hardhat-helpers 0.6. ++function toDeploymentReceipt(receipt: TransactionReceipt): Receipt { ++ return { ++ to: receipt.to, ++ from: receipt.from, ++ contractAddress: receipt.contractAddress, ++ transactionIndex: receipt.index, ++ gasUsed: receipt.gasUsed.toString(), ++ logsBloom: receipt.logsBloom, ++ blockHash: receipt.blockHash, ++ transactionHash: receipt.hash, ++ logs: receipt.logs.map((log) => ({ ++ transactionIndex: log.transactionIndex, ++ blockNumber: log.blockNumber, ++ transactionHash: log.transactionHash, ++ address: log.address, ++ topics: [...log.topics], ++ data: log.data, ++ logIndex: log.index, ++ blockHash: log.blockHash, ++ // Mined receipt logs omit the removed field in the existing export format. ++ removed: undefined, ++ })), ++ blockNumber: receipt.blockNumber, ++ cumulativeGasUsed: receipt.cumulativeGasUsed.toString(), ++ status: receipt.status, ++ byzantium: receipt.status !== null, ++ } ++} ++ + export interface HardhatUpgradesHelpers { +- deployProxy( ++ deployProxy( + name: string, + opts?: UpgradesDeployOptions + ): Promise<[T, Deployment]> +- upgradeProxy( ++ upgradeProxy( + currentContractName: string, + newContractName: string, + opts?: UpgradesUpgradeOptions + ): Promise<[T, Deployment]> + prepareProxyUpgrade( + proxyDeploymentName: string, + newContractName: string, + opts?: UpgradesPrepareProxyUpgradeOptions + ): Promise<{ + newImplementationAddress: string + preparedTransaction: ContractTransaction + }> + } + + type CustomFactoryOptions = FactoryOptions & { +@@ -63,31 +93,31 @@ export interface UpgradesUpgradeOptions { + } + + export interface UpgradesPrepareProxyUpgradeOptions { + contractName?: string + factoryOpts?: CustomFactoryOptions + callData?: string + } + + /** + * Deploys contract as a TransparentProxy. + * + * @param {HardhatRuntimeEnvironment} hre Hardhat runtime environment. + * @param {string} name Contract Name + * @param {UpgradesDeployOptions} opts + */ +-export async function deployProxy( ++export async function deployProxy( + hre: HardhatRuntimeEnvironment, + name: string, + opts?: UpgradesDeployOptions + ): Promise<[T, Deployment]> { + const { ethers, upgrades, deployments, artifacts } = hre + const { log } = deployments + + const existingDeployment = await deployments.getOrNull(name) + if (existingDeployment) { + throw new Error( + `${name} was already deployed at ${existingDeployment.address}` + ) + } + + const contractFactory: ContractFactory = await ethers.getContractFactory( +@@ -121,50 +151,51 @@ export async function deployProxy( + const implementation = await upgrades.erc1967.getImplementationAddress( + contractAddress + ) + + if (!transactionReceipt || !transactionHash) { + throw new Error( + `Could not find transaction receipt for transaction hash: ${transactionHash}` + ) + } + + const deployment: Deployment = { + address: contractAddress, + abi: artifact.abi, + transactionHash: transactionHash, + implementation: implementation, ++ receipt: toDeploymentReceipt(transactionReceipt), + libraries: opts?.factoryOpts?.libraries, + devdoc: "Contract deployed as upgradable proxy", + args: opts?.proxyOpts?.constructorArgs, + } + + await deployments.save(name, deployment) + + return [contractInstance, deployment] + } + + /** + * Upgrades previously deployed contract. + * + * @param {HardhatRuntimeEnvironment} hre Hardhat runtime environment. + * @param {string} proxyDeploymentName Name of the proxy deployment that will be + * upgraded. + * @param {string} newContractName Name of the new implementation contract. + * @param {UpgradesDeployOptions} opts + */ +-async function upgradeProxy( ++async function upgradeProxy( + hre: HardhatRuntimeEnvironment, + proxyDeploymentName: string, + newContractName: string, + opts?: UpgradesUpgradeOptions + ): Promise<[T, Deployment]> { + const { ethers, upgrades, deployments, artifacts } = hre + const { log } = deployments + + const proxyDeployment: Deployment = await deployments.get(proxyDeploymentName) + + const newContract: ContractFactory = await ethers.getContractFactory( + opts?.contractName || newContractName, + opts?.factoryOpts + ) + +@@ -205,30 +236,31 @@ async function upgradeProxy( + log( + `New ${proxyDeploymentName} proxy contract implementation address is: ${implementation}` + ) + + if (!transactionReceipt || !transactionHash) { + throw new Error( + `Could not find transaction receipt for transaction hash: ${transactionHash}` + ) + } + + const deployment: Deployment = { + address: contractAddress, + abi: artifact.abi, + transactionHash: transactionHash, + implementation: implementation, ++ receipt: toDeploymentReceipt(transactionReceipt), + libraries: opts?.factoryOpts?.libraries, + devdoc: "Contract deployed as upgradable proxy", + args: opts?.proxyOpts?.constructorArgs, + } + + await deployments.save(proxyDeploymentName, deployment) + + return [newContractInstance, deployment] + } + + /** + * Prepare upgrade of deployed contract. + * It deploys new implementation contract and prepares transaction to upgrade + * the proxy contract to the new implementation thorough a Proxy Admin instance. + * The transaction has to be executed by the owner of the Proxy Admin. +@@ -273,44 +305,44 @@ async function prepareProxyUpgrade( + + const proxyAdminAddress = await hre.upgrades.erc1967.getAdminAddress( + proxyDeployment.address + ) + + let proxyAdmin: Contract + let upgradeTxData: string + + const proxyInterfaceVersion = await getUpgradeInterfaceVersion( + hre.network.provider, + proxyAdminAddress + ) + + switch (proxyInterfaceVersion) { + case "5.0.0": { +- proxyAdmin = await attachProxyAdminV5(hre, proxyAdminAddress, signer) ++ proxyAdmin = await hre.ethers.getContractAt(ProxyAdminV5.abi, proxyAdminAddress, signer) + + upgradeTxData = proxyAdmin.interface.encodeFunctionData( + "upgradeAndCall", + [ + proxyDeployment.address, + newImplementationAddress, + opts?.callData ?? "0x", + ] + ) + break + } + default: { +- proxyAdmin = await attachProxyAdminV4(hre, proxyAdminAddress, signer) ++ proxyAdmin = await hre.ethers.getContractAt(ProxyAdminV4.abi, proxyAdminAddress, signer) + + if (opts?.callData) { + upgradeTxData = proxyAdmin.interface.encodeFunctionData( + "upgradeAndCall", + [proxyDeployment.address, newImplementationAddress, opts?.callData] + ) + } else { + upgradeTxData = proxyAdmin.interface.encodeFunctionData("upgrade", [ + proxyDeployment.address, + newImplementationAddress, + ]) + } + } + } + diff --git a/solidity/random-beacon/.yarn/patches/@openzeppelin-hardhat-upgrades-npm-2.5.1-etherscan-v2.patch b/solidity/random-beacon/.yarn/patches/@openzeppelin-hardhat-upgrades-npm-2.5.1-etherscan-v2.patch new file mode 100644 index 0000000000..06d2c0a560 --- /dev/null +++ b/solidity/random-beacon/.yarn/patches/@openzeppelin-hardhat-upgrades-npm-2.5.1-etherscan-v2.patch @@ -0,0 +1,85 @@ +diff --git a/src/utils/etherscan-api.ts b/src/utils/etherscan-api.ts +--- a/src/utils/etherscan-api.ts ++++ b/src/utils/etherscan-api.ts +@@ -2,36 +2,39 @@ + import { HardhatRuntimeEnvironment } from 'hardhat/types'; + + import { request } from 'undici'; + + import debug from './debug'; + import { Etherscan } from '@nomicfoundation/hardhat-verify/etherscan'; + + /** + * Call the configured Etherscan API with the given parameters. + * + * @param etherscan Etherscan instance + * @param params The API parameters to call with + * @returns The Etherscan API response + */ + export async function callEtherscanApi(etherscan: Etherscan, params: any): Promise { + const parameters = new URLSearchParams({ ...params, apikey: etherscan.apiKey }); ++ if (etherscan.chainId !== undefined) { ++ parameters.set('chainid', etherscan.chainId); ++ } + + const response = await request(etherscan.apiUrl, { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: parameters.toString(), + }); + + if (!(response.statusCode >= 200 && response.statusCode <= 299)) { + const responseBodyText = await response.body.text(); + throw new UpgradesError( + `Etherscan API call failed with status ${response.statusCode}, response: ${responseBodyText}`, + ); + } + + const responseBodyJson = await response.body.json(); + debug('Etherscan response', JSON.stringify(responseBodyJson)); + + return responseBodyJson; + } + +diff --git a/dist/utils/etherscan-api.js b/dist/utils/etherscan-api.js +--- a/dist/utils/etherscan-api.js ++++ b/dist/utils/etherscan-api.js +@@ -4,35 +4,38 @@ + }; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.verifyAndGetStatus = exports.RESPONSE_OK = exports.getEtherscanInstance = exports.callEtherscanApi = void 0; + const upgrades_core_1 = require("@openzeppelin/upgrades-core"); + const undici_1 = require("undici"); + const debug_1 = __importDefault(require("./debug")); + const etherscan_1 = require("@nomicfoundation/hardhat-verify/etherscan"); + /** + * Call the configured Etherscan API with the given parameters. + * + * @param etherscan Etherscan instance + * @param params The API parameters to call with + * @returns The Etherscan API response + */ + async function callEtherscanApi(etherscan, params) { + const parameters = new URLSearchParams({ ...params, apikey: etherscan.apiKey }); ++ if (etherscan.chainId !== undefined) { ++ parameters.set('chainid', etherscan.chainId); ++ } + const response = await (0, undici_1.request)(etherscan.apiUrl, { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: parameters.toString(), + }); + if (!(response.statusCode >= 200 && response.statusCode <= 299)) { + const responseBodyText = await response.body.text(); + throw new upgrades_core_1.UpgradesError(`Etherscan API call failed with status ${response.statusCode}, response: ${responseBodyText}`); + } + const responseBodyJson = await response.body.json(); + (0, debug_1.default)('Etherscan response', JSON.stringify(responseBodyJson)); + return responseBodyJson; + } + exports.callEtherscanApi = callEtherscanApi; + /** + * Gets an Etherscan instance based on Hardhat config. + * Throws an error if Etherscan API key is not present in config. + */ + async function getEtherscanInstance(hre) { diff --git a/solidity/random-beacon/.yarn/patches/@threshold-network-solidity-contracts-npm-1.3.0-dev.14-ethers-v6.patch b/solidity/random-beacon/.yarn/patches/@threshold-network-solidity-contracts-npm-1.3.0-dev.14-ethers-v6.patch new file mode 100644 index 0000000000..3e3b7c21ed --- /dev/null +++ b/solidity/random-beacon/.yarn/patches/@threshold-network-solidity-contracts-npm-1.3.0-dev.14-ethers-v6.patch @@ -0,0 +1,28 @@ +diff --git a/export/deploy/07_deploy_token_staking.js b/export/deploy/07_deploy_token_staking.js +--- a/export/deploy/07_deploy_token_staking.js ++++ b/export/deploy/07_deploy_token_staking.js +@@ -62,10 +62,10 @@ + })]; + case 4: + tokenStaking = _a.sent(); +- tokenStakingAddress = tokenStaking.address; ++ tokenStakingAddress = tokenStaking.target; + log("Deployed TokenStaking with TransparentProxy at ".concat(tokenStakingAddress)); + implementationInterface = tokenStaking.interface; +- jsonAbi = implementationInterface.format(hardhat_1.ethers.utils.FormatTypes.json); ++ jsonAbi = implementationInterface.formatJson(); + tokenStakingDeployment = { + address: tokenStakingAddress, + abi: JSON.parse(jsonAbi), +diff --git a/export/deploy/30_deploy_tokenholder_timelock.js b/export/deploy/30_deploy_tokenholder_timelock.js +--- a/export/deploy/30_deploy_tokenholder_timelock.js ++++ b/export/deploy/30_deploy_tokenholder_timelock.js +@@ -51,7 +51,7 @@ + case 1: + deployer = (_a.sent()).deployer; + proposers = []; +- executors = [ethers_1.ethers.constants.AddressZero]; ++ executors = [ethers_1.ethers.ZeroAddress]; + minDelay = 172800 // 2 days in seconds (2 * 24 * 60 * 60) + ; + return [4 /*yield*/, deployments.deploy("TokenholderTimelock", { diff --git a/solidity/random-beacon/.yarn/patches/@typechain-ethers-v6-npm-0.5.1-e825560376.patch b/solidity/random-beacon/.yarn/patches/@typechain-ethers-v6-npm-0.5.1-e825560376.patch new file mode 100644 index 0000000000..85cccd3381 --- /dev/null +++ b/solidity/random-beacon/.yarn/patches/@typechain-ethers-v6-npm-0.5.1-e825560376.patch @@ -0,0 +1,13 @@ +diff --git a/dist/codegen/reserved-keywords.js b/dist/codegen/reserved-keywords.js +index f5a47b105a31e5ae3a6e40da476a37f748d962d9..f05f5ec9582c56a264fe6a61f7a098e2008047a3 100644 +--- a/dist/codegen/reserved-keywords.js ++++ b/dist/codegen/reserved-keywords.js +@@ -1,7 +1,7 @@ + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.reservedKeywordsLabels = exports.reservedKeywords = void 0; +-exports.reservedKeywords = new Set(['signer', 'provider', 'deployTransaction', 'deployed', 'fallback', 'connect']); ++exports.reservedKeywords = new Set(['signer', 'provider', 'deployTransaction', 'deployed', 'fallback', 'connect', 'target']); + exports.reservedKeywordsLabels = new Set([ + 'class', + 'function', diff --git a/solidity/random-beacon/Dockerfile b/solidity/random-beacon/Dockerfile index dca524f86b..d95aa8789a 100644 --- a/solidity/random-beacon/Dockerfile +++ b/solidity/random-beacon/Dockerfile @@ -1,4 +1,4 @@ -FROM node:22.23.1-alpine +FROM node:24.11.1-alpine RUN apk add --update --no-cache \ git \ @@ -8,16 +8,32 @@ RUN apk add --update --no-cache \ rm -rf /usr/share/man ENV WORK_DIR=/random-beacon +ENV HOME=/home/node +ENV COREPACK_DEFAULT_TO_LATEST=0 -RUN mkdir -p $WORK_DIR +# `corepack enable` must run as root: it writes shims into root-owned +# /usr/local/bin. `corepack prepare` (below, after `USER node`) must run as +# node: it writes Corepack's per-user cache under $HOME. `chown` targets only +# $WORK_DIR here because `yarn install` creates node_modules inside it; +# dependency/source ownership is set later via `COPY --chown`. +# Native dependencies need a compiler while Yarn packs Git dependencies; the +# build tools are installed/removed as root since `apk` requires root. +RUN apk add --no-cache --virtual .build-deps python3 make g++ && \ + corepack enable && mkdir -p $WORK_DIR && chown node:node $WORK_DIR WORKDIR $WORK_DIR +USER node # Use `https://` instead of unauthenticated `git://` protocol. RUN git config --global url."https://".insteadOf git:// -COPY package*.json yarn.lock .yarnrc.yml ./ -RUN corepack enable && corepack prepare yarn@4.8.1 --activate && yarn install --immutable +COPY --chown=node:node package*.json yarn.lock .yarnrc.yml ./ +COPY --chown=node:node .yarn/patches/ ./.yarn/patches/ +RUN corepack prepare yarn@4.12.0 --activate && yarn install --immutable -COPY . ./ +USER root +RUN apk del .build-deps +USER node + +COPY --chown=node:node . ./ ENTRYPOINT ["npx", "hardhat"] diff --git a/solidity/random-beacon/README.adoc b/solidity/random-beacon/README.adoc index d1448f1f80..d4bd8b1251 100644 --- a/solidity/random-beacon/README.adoc +++ b/solidity/random-beacon/README.adoc @@ -485,8 +485,8 @@ presented below. Please make sure you have the following prerequisites installed on your machine: -- https://nodejs.org[Node.js] >=14.18.2 -- https://yarnpkg.com[Yarn] >=1.22.17 +- https://nodejs.org[Node.js] >=24.0.0 +- https://yarnpkg.com[Yarn] >=4.12.0 (via Corepack) === Build contracts diff --git a/solidity/random-beacon/contracts/BeaconDkgValidator.sol b/solidity/random-beacon/contracts/BeaconDkgValidator.sol index d69e76eb85..4f1606aa43 100644 --- a/solidity/random-beacon/contracts/BeaconDkgValidator.sol +++ b/solidity/random-beacon/contracts/BeaconDkgValidator.sol @@ -15,7 +15,7 @@ pragma solidity 0.8.17; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; -import "@keep-network/sortition-pools/contracts/SortitionPool.sol"; +import "./legacy/sortition/SortitionPool.sol"; import "./libraries/BytesLib.sol"; import {BeaconDkg as DKG} from "./libraries/BeaconDkg.sol"; @@ -101,11 +101,9 @@ contract BeaconDkgValidator { /// ranges, and order of arrays. /// @return isValid true if the result is valid, false otherwise /// @return errorMsg validation error message; empty for a valid result - function validateFields(DKG.Result calldata result) - public - pure - returns (bool isValid, string memory errorMsg) - { + function validateFields( + DKG.Result calldata result + ) public pure returns (bool isValid, string memory errorMsg) { // Group public key needs to be 128 bytes long. if (result.groupPubKey.length != 128) { return (false, "Malformed group public key"); @@ -123,7 +121,7 @@ contract BeaconDkgValidator { if ( misbehavedMembersIndices[0] < 1 || misbehavedMembersIndices[misbehavedMembersIndices.length - 1] > - groupSize + groupSize ) { return (false, "Corrupted misbehaved members indices"); } @@ -181,11 +179,10 @@ contract BeaconDkgValidator { /// result against group members selected by the sortition pool. /// @param seed seed used to start the DKG and select group members /// @return true if group members matches; false otherwise - function validateGroupMembers(DKG.Result calldata result, uint256 seed) - public - view - returns (bool) - { + function validateGroupMembers( + DKG.Result calldata result, + uint256 seed + ) public view returns (bool) { uint32[] calldata resultMembers = result.members; uint32[] memory actualGroupMembers = sortitionPool.selectGroup( groupSize, @@ -209,11 +206,10 @@ contract BeaconDkgValidator { /// together with `validateGroupMembers`. /// @param startBlock DKG start block /// @return true if group members matches; false otherwise - function validateSignatures(DKG.Result calldata result, uint256 startBlock) - public - view - returns (bool) - { + function validateSignatures( + DKG.Result calldata result, + uint256 startBlock + ) public view returns (bool) { bytes32 hash = keccak256( abi.encode( block.chainid, @@ -258,11 +254,9 @@ contract BeaconDkgValidator { /// @param result DKG result /// @return true if result's group members hash matches with the one that is /// challenged. - function validateMembersHash(DKG.Result calldata result) - public - pure - returns (bool) - { + function validateMembersHash( + DKG.Result calldata result + ) public pure returns (bool) { if (result.misbehavedMembersIndices.length > 0) { // members that generated a group signing key uint32[] memory groupMembers = new uint32[]( diff --git a/solidity/random-beacon/contracts/Governable.sol b/solidity/random-beacon/contracts/Governable.sol index 4a052c10c8..1c74a49fb9 100644 --- a/solidity/random-beacon/contracts/Governable.sol +++ b/solidity/random-beacon/contracts/Governable.sol @@ -38,11 +38,9 @@ abstract contract Governable { } /// @notice Transfers governance of the contract to `newGovernance`. - function transferGovernance(address newGovernance) - external - virtual - onlyGovernance - { + function transferGovernance( + address newGovernance + ) external virtual onlyGovernance { require( newGovernance != address(0), "New governance is the zero address" diff --git a/solidity/random-beacon/contracts/RandomBeacon.sol b/solidity/random-beacon/contracts/RandomBeacon.sol index 74e8dc11d8..244a2ed635 100644 --- a/solidity/random-beacon/contracts/RandomBeacon.sol +++ b/solidity/random-beacon/contracts/RandomBeacon.sol @@ -26,7 +26,7 @@ import {BeaconAuthorization as Authorization} from "./libraries/BeaconAuthorizat import {BeaconDkg as DKG} from "./libraries/BeaconDkg.sol"; import {BeaconDkgValidator as DKGValidator} from "./BeaconDkgValidator.sol"; -import "@keep-network/sortition-pools/contracts/SortitionPool.sol"; +import "./legacy/sortition/SortitionPool.sol"; import "@threshold-network/solidity-contracts/contracts/staking/IApplication.sol"; import "@threshold-network/solidity-contracts/contracts/staking/IStaking.sol"; @@ -594,9 +594,12 @@ contract RandomBeacon is IRandomBeacon, IApplication, Governable, Reimbursable { uint256 dkgMaliciousResultNotificationRewardMultiplier ) external onlyGovernance { _sortitionPoolRewardsBanDuration = sortitionPoolRewardsBanDuration; - _relayEntryTimeoutNotificationRewardMultiplier = relayEntryTimeoutNotificationRewardMultiplier; - _unauthorizedSigningNotificationRewardMultiplier = unauthorizedSigningNotificationRewardMultiplier; - _dkgMaliciousResultNotificationRewardMultiplier = dkgMaliciousResultNotificationRewardMultiplier; + _relayEntryTimeoutNotificationRewardMultiplier = + relayEntryTimeoutNotificationRewardMultiplier; + _unauthorizedSigningNotificationRewardMultiplier = + unauthorizedSigningNotificationRewardMultiplier; + _dkgMaliciousResultNotificationRewardMultiplier = + dkgMaliciousResultNotificationRewardMultiplier; emit RewardParametersUpdated( sortitionPoolRewardsBanDuration, relayEntryTimeoutNotificationRewardMultiplier, @@ -667,10 +670,10 @@ contract RandomBeacon is IRandomBeacon, IApplication, Governable, Reimbursable { /// random beacon governance contract. /// @param requester Requester, can be a contract or EOA /// @param isAuthorized True or false - function setRequesterAuthorization(address requester, bool isAuthorized) - external - onlyGovernance - { + function setRequesterAuthorization( + address requester, + bool isAuthorized + ) external onlyGovernance { authorizedRequesters[requester] = isAuthorized; emit RequesterAuthorizationUpdated(requester, isAuthorized); @@ -695,10 +698,9 @@ contract RandomBeacon is IRandomBeacon, IApplication, Governable, Reimbursable { /// @dev Can be called only by the contract guvnor, which should be the /// random beacon governance contract. /// @param recipient Recipient of withdrawn rewards. - function withdrawIneligibleRewards(address recipient) - external - onlyGovernance - { + function withdrawIneligibleRewards( + address recipient + ) external onlyGovernance { sortitionPool.withdrawIneligible(recipient); } @@ -986,19 +988,15 @@ contract RandomBeacon is IRandomBeacon, IApplication, Governable, Reimbursable { return groups.groupsRegistry; } - function getGroup(uint64 groupId) - external - view - returns (Groups.Group memory) - { + function getGroup( + uint64 groupId + ) external view returns (Groups.Group memory) { return groups.getGroup(groupId); } - function getGroup(bytes memory groupPubKey) - external - view - returns (Groups.Group memory) - { + function getGroup( + bytes memory groupPubKey + ) external view returns (Groups.Group memory) { return groups.getGroup(groupPubKey); } @@ -1007,9 +1005,9 @@ contract RandomBeacon is IRandomBeacon, IApplication, Governable, Reimbursable { /// random number). Requester must be previously authorized by the /// governance. /// @param callbackContract Beacon consumer callback contract. - function requestRelayEntry(IRandomBeaconConsumer callbackContract) - external - { + function requestRelayEntry( + IRandomBeaconConsumer callbackContract + ) external { require( authorizedRequesters[msg.sender], "Requester must be authorized" @@ -1348,22 +1346,18 @@ contract RandomBeacon is IRandomBeacon, IApplication, Governable, Reimbursable { /// is what is used for operator's weight in the sortition pool. /// If the authorized stake minus the pending authorization decrease /// is below the minimum authorization, eligible stake is 0. - function eligibleStake(address stakingProvider) - external - view - returns (uint96) - { + function eligibleStake( + address stakingProvider + ) external view returns (uint96) { return authorization.eligibleStake(staking, stakingProvider); } /// @notice Returns the amount of rewards available for withdrawal for the /// given staking provider. Reverts if staking provider has not /// registered the operator address. - function availableRewards(address stakingProvider) - external - view - returns (uint96) - { + function availableRewards( + address stakingProvider + ) external view returns (uint96) { address operator = stakingProviderToOperator(stakingProvider); require(operator != address(0), "Unknown operator"); return sortitionPool.getAvailableRewards(operator); @@ -1372,11 +1366,9 @@ contract RandomBeacon is IRandomBeacon, IApplication, Governable, Reimbursable { /// @notice Returns the amount of stake that is pending authorization /// decrease for the given staking provider. If no authorization /// decrease has been requested, returns zero. - function pendingAuthorizationDecrease(address stakingProvider) - external - view - returns (uint96) - { + function pendingAuthorizationDecrease( + address stakingProvider + ) external view returns (uint96) { return authorization.pendingAuthorizationDecrease(stakingProvider); } @@ -1385,30 +1377,24 @@ contract RandomBeacon is IRandomBeacon, IApplication, Governable, Reimbursable { /// If the sortition pool state was not updated yet by the operator /// after requesting the authorization decrease, returns /// `type(uint64).max`. - function remainingAuthorizationDecreaseDelay(address stakingProvider) - external - view - returns (uint64) - { + function remainingAuthorizationDecreaseDelay( + address stakingProvider + ) external view returns (uint64) { return authorization.remainingAuthorizationDecreaseDelay(stakingProvider); } /// @notice Returns operator registered for the given staking provider. - function stakingProviderToOperator(address stakingProvider) - public - view - returns (address) - { + function stakingProviderToOperator( + address stakingProvider + ) public view returns (address) { return authorization.stakingProviderToOperator[stakingProvider]; } /// @notice Returns staking provider of the given operator. - function operatorToStakingProvider(address operator) - public - view - returns (address) - { + function operatorToStakingProvider( + address operator + ) public view returns (address) { return authorization.operatorToStakingProvider[operator]; } diff --git a/solidity/random-beacon/contracts/RandomBeaconChaosnet.sol b/solidity/random-beacon/contracts/RandomBeaconChaosnet.sol index 9b44b1372a..2138237522 100644 --- a/solidity/random-beacon/contracts/RandomBeaconChaosnet.sol +++ b/solidity/random-beacon/contracts/RandomBeaconChaosnet.sol @@ -36,9 +36,9 @@ contract RandomBeaconChaosnet is IRandomBeacon, Ownable { /// @notice Executes the callback with an arbitrary relay entry number. /// @param callbackContract Beacon consumer callback contract - Wallet Registry /// @dev The caller must be an authorized requester. - function requestRelayEntry(IRandomBeaconConsumer callbackContract) - external - { + function requestRelayEntry( + IRandomBeaconConsumer callbackContract + ) external { require( authorizedRequesters[msg.sender], "Requester must be authorized" @@ -51,10 +51,10 @@ contract RandomBeaconChaosnet is IRandomBeacon, Ownable { } /// @notice Authorizes a requester of the relay entry. - function setRequesterAuthorization(address requester, bool isAuthorized) - external - onlyOwner - { + function setRequesterAuthorization( + address requester, + bool isAuthorized + ) external onlyOwner { authorizedRequesters[requester] = isAuthorized; emit RequesterAuthorizationUpdated(requester, isAuthorized); diff --git a/solidity/random-beacon/contracts/RandomBeaconGovernance.sol b/solidity/random-beacon/contracts/RandomBeaconGovernance.sol index 8e9fdf9f97..da4ecde863 100644 --- a/solidity/random-beacon/contracts/RandomBeaconGovernance.sol +++ b/solidity/random-beacon/contracts/RandomBeaconGovernance.sol @@ -300,10 +300,9 @@ contract RandomBeaconGovernance is Ownable { /// @notice Begins the governance delay update process. /// @dev Can be called only by the contract owner. /// @param _newGovernanceDelay New governance delay - function beginGovernanceDelayUpdate(uint256 _newGovernanceDelay) - external - onlyOwner - { + function beginGovernanceDelayUpdate( + uint256 _newGovernanceDelay + ) external onlyOwner { newGovernanceDelay = _newGovernanceDelay; /* solhint-disable not-rely-on-time */ governanceDelayChangeInitiated = block.timestamp; @@ -362,10 +361,9 @@ contract RandomBeaconGovernance is Ownable { /// @notice Begins the relay entry soft timeout update process. /// @dev Can be called only by the contract owner. /// @param _newRelayEntrySoftTimeout New relay entry submission timeout in blocks - function beginRelayEntrySoftTimeoutUpdate(uint256 _newRelayEntrySoftTimeout) - external - onlyOwner - { + function beginRelayEntrySoftTimeoutUpdate( + uint256 _newRelayEntrySoftTimeout + ) external onlyOwner { /* solhint-disable not-rely-on-time */ require( _newRelayEntrySoftTimeout > 0, @@ -407,10 +405,9 @@ contract RandomBeaconGovernance is Ownable { /// @notice Begins the relay entry hard timeout update process. /// @dev Can be called only by the contract owner. /// @param _newRelayEntryHardTimeout New relay entry hard timeout in blocks - function beginRelayEntryHardTimeoutUpdate(uint256 _newRelayEntryHardTimeout) - external - onlyOwner - { + function beginRelayEntryHardTimeoutUpdate( + uint256 _newRelayEntryHardTimeout + ) external onlyOwner { /* solhint-disable not-rely-on-time */ newRelayEntryHardTimeout = _newRelayEntryHardTimeout; relayEntryHardTimeoutChangeInitiated = block.timestamp; @@ -448,10 +445,9 @@ contract RandomBeaconGovernance is Ownable { /// @notice Begins the callback gas limit update process. /// @dev Can be called only by the contract owner. /// @param _newCallbackGasLimit New callback gas limit - function beginCallbackGasLimitUpdate(uint256 _newCallbackGasLimit) - external - onlyOwner - { + function beginCallbackGasLimitUpdate( + uint256 _newCallbackGasLimit + ) external onlyOwner { /* solhint-disable not-rely-on-time */ // slither-disable-next-line too-many-digits require( @@ -548,10 +544,9 @@ contract RandomBeaconGovernance is Ownable { /// time and authorization decrease delay which value is in seconds. /// @dev Can be called only by the contract owner. /// @param _newGroupLifetime New group lifetime in blocks - function beginGroupLifetimeUpdate(uint256 _newGroupLifetime) - external - onlyOwner - { + function beginGroupLifetimeUpdate( + uint256 _newGroupLifetime + ) external onlyOwner { require(_newGroupLifetime > 0, "Group lifetime must be greater than 0"); /* solhint-disable not-rely-on-time */ newGroupLifetime = _newGroupLifetime; @@ -754,7 +749,8 @@ contract RandomBeaconGovernance is Ownable { _newDkgSubmitterPrecedencePeriodLength > 0, "DKG submitter precedence period length must be > 0" ); - newDkgSubmitterPrecedencePeriodLength = _newDkgSubmitterPrecedencePeriodLength; + newDkgSubmitterPrecedencePeriodLength = + _newDkgSubmitterPrecedencePeriodLength; dkgSubmitterPrecedencePeriodLengthChangeInitiated = block.timestamp; emit DkgSubmitterPrecedencePeriodLengthUpdateStarted( _newDkgSubmitterPrecedencePeriodLength, @@ -805,7 +801,8 @@ contract RandomBeaconGovernance is Ownable { uint256 _newSortitionPoolRewardsBanDuration ) external onlyOwner { /* solhint-disable not-rely-on-time */ - newSortitionPoolRewardsBanDuration = _newSortitionPoolRewardsBanDuration; + newSortitionPoolRewardsBanDuration = + _newSortitionPoolRewardsBanDuration; sortitionPoolRewardsBanDurationChangeInitiated = block.timestamp; emit SortitionPoolRewardsBanDurationUpdateStarted( _newSortitionPoolRewardsBanDuration, @@ -856,7 +853,8 @@ contract RandomBeaconGovernance is Ownable { "Maximum value is 100" ); - newRelayEntryTimeoutNotificationRewardMultiplier = _newRelayEntryTimeoutNotificationRewardMultiplier; + newRelayEntryTimeoutNotificationRewardMultiplier = + _newRelayEntryTimeoutNotificationRewardMultiplier; relayEntryTimeoutNotificationRewardMultiplierChangeInitiated = block .timestamp; emit RelayEntryTimeoutNotificationRewardMultiplierUpdateStarted( @@ -880,7 +878,8 @@ contract RandomBeaconGovernance is Ownable { "Maximum value is 100" ); - newUnauthorizedSigningNotificationRewardMultiplier = _newUnauthorizedSigningNotificationRewardMultiplier; + newUnauthorizedSigningNotificationRewardMultiplier = + _newUnauthorizedSigningNotificationRewardMultiplier; unauthorizedSigningNotificationRewardMultiplierChangeInitiated = block .timestamp; emit UnauthorizedSigningNotificationRewardMultiplierUpdateStarted( @@ -966,7 +965,8 @@ contract RandomBeaconGovernance is Ownable { "Maximum value is 100" ); - newDkgMaliciousResultNotificationRewardMultiplier = _newDkgMaliciousResultNotificationRewardMultiplier; + newDkgMaliciousResultNotificationRewardMultiplier = + _newDkgMaliciousResultNotificationRewardMultiplier; dkgMaliciousResultNotificationRewardMultiplierChangeInitiated = block .timestamp; emit DkgMaliciousResultNotificationRewardMultiplierUpdateStarted( @@ -1016,7 +1016,8 @@ contract RandomBeaconGovernance is Ownable { uint96 _newRelayEntrySubmissionFailureSlashingAmount ) external onlyOwner { /* solhint-disable not-rely-on-time */ - newRelayEntrySubmissionFailureSlashingAmount = _newRelayEntrySubmissionFailureSlashingAmount; + newRelayEntrySubmissionFailureSlashingAmount = + _newRelayEntrySubmissionFailureSlashingAmount; relayEntrySubmissionFailureSlashingAmountChangeInitiated = block .timestamp; emit RelayEntrySubmissionFailureSlashingAmountUpdateStarted( @@ -1147,7 +1148,8 @@ contract RandomBeaconGovernance is Ownable { uint256 _newNotifyOperatorInactivityGasOffset ) external onlyOwner { /* solhint-disable not-rely-on-time */ - newNotifyOperatorInactivityGasOffset = _newNotifyOperatorInactivityGasOffset; + newNotifyOperatorInactivityGasOffset = + _newNotifyOperatorInactivityGasOffset; notifyOperatorInactivityGasOffsetChangeInitiated = block.timestamp; emit NotifyOperatorInactivityGasOffsetUpdateStarted( _newNotifyOperatorInactivityGasOffset, @@ -1238,7 +1240,8 @@ contract RandomBeaconGovernance is Ownable { uint96 _newMaliciousDkgResultSlashingAmount ) external onlyOwner { /* solhint-disable not-rely-on-time */ - newMaliciousDkgResultSlashingAmount = _newMaliciousDkgResultSlashingAmount; + newMaliciousDkgResultSlashingAmount = + _newMaliciousDkgResultSlashingAmount; maliciousDkgResultSlashingAmountChangeInitiated = block.timestamp; emit MaliciousDkgResultSlashingAmountUpdateStarted( _newMaliciousDkgResultSlashingAmount, @@ -1284,7 +1287,8 @@ contract RandomBeaconGovernance is Ownable { uint96 _newUnauthorizedSigningSlashingAmount ) external onlyOwner { /* solhint-disable not-rely-on-time */ - newUnauthorizedSigningSlashingAmount = _newUnauthorizedSigningSlashingAmount; + newUnauthorizedSigningSlashingAmount = + _newUnauthorizedSigningSlashingAmount; unauthorizedSigningSlashingAmountChangeInitiated = block.timestamp; emit UnauthorizedSigningSlashingAmountUpdateStarted( _newUnauthorizedSigningSlashingAmount, @@ -1325,10 +1329,9 @@ contract RandomBeaconGovernance is Ownable { /// @notice Begins the minimum authorization amount update process. /// @dev Can be called only by the contract owner. /// @param _newMinimumAuthorization New minimum authorization amount. - function beginMinimumAuthorizationUpdate(uint96 _newMinimumAuthorization) - external - onlyOwner - { + function beginMinimumAuthorizationUpdate( + uint96 _newMinimumAuthorization + ) external onlyOwner { /* solhint-disable not-rely-on-time */ newMinimumAuthorization = _newMinimumAuthorization; minimumAuthorizationChangeInitiated = block.timestamp; @@ -1410,7 +1413,8 @@ contract RandomBeaconGovernance is Ownable { uint64 _newAuthorizationDecreaseChangePeriod ) external onlyOwner { /* solhint-disable not-rely-on-time */ - newAuthorizationDecreaseChangePeriod = _newAuthorizationDecreaseChangePeriod; + newAuthorizationDecreaseChangePeriod = + _newAuthorizationDecreaseChangePeriod; authorizationDecreaseChangePeriodChangeInitiated = block.timestamp; emit AuthorizationDecreaseChangePeriodUpdateStarted( _newAuthorizationDecreaseChangePeriod, @@ -1451,10 +1455,10 @@ contract RandomBeaconGovernance is Ownable { /// entry. It can be done by the governance only. /// @param requester Requester, can be a contract or EOA /// @param isAuthorized True or false - function setRequesterAuthorization(address requester, bool isAuthorized) - external - onlyOwner - { + function setRequesterAuthorization( + address requester, + bool isAuthorized + ) external onlyOwner { randomBeacon.setRequesterAuthorization(requester, isAuthorized); } @@ -1782,11 +1786,9 @@ contract RandomBeaconGovernance is Ownable { /// can be committed. /// @param changeTimestamp Timestamp indicating the beginning of the change. /// @return Remaining time in seconds. - function getRemainingChangeTime(uint256 changeTimestamp) - internal - view - returns (uint256) - { + function getRemainingChangeTime( + uint256 changeTimestamp + ) internal view returns (uint256) { require(changeTimestamp > 0, "Change not initiated"); /* solhint-disable-next-line not-rely-on-time */ uint256 elapsed = block.timestamp - changeTimestamp; diff --git a/solidity/random-beacon/contracts/Reimbursable.sol b/solidity/random-beacon/contracts/Reimbursable.sol index 3fe4a663dc..c5bf85b5e9 100644 --- a/solidity/random-beacon/contracts/Reimbursable.sol +++ b/solidity/random-beacon/contracts/Reimbursable.sol @@ -39,10 +39,9 @@ abstract contract Reimbursable { _; } - function updateReimbursementPool(ReimbursementPool _reimbursementPool) - external - onlyReimbursableAdmin - { + function updateReimbursementPool( + ReimbursementPool _reimbursementPool + ) external onlyReimbursableAdmin { emit ReimbursementPoolUpdated(address(_reimbursementPool)); reimbursementPool = _reimbursementPool; diff --git a/solidity/random-beacon/contracts/ReimbursementPool.sol b/solidity/random-beacon/contracts/ReimbursementPool.sol index bf664254ab..7665e31c94 100644 --- a/solidity/random-beacon/contracts/ReimbursementPool.sol +++ b/solidity/random-beacon/contracts/ReimbursementPool.sol @@ -68,9 +68,8 @@ contract ReimbursementPool is Ownable, ReentrancyGuard { ); require(receiver != address(0), "Receiver's address cannot be zero"); - uint256 gasPrice = tx.gasprice < maxGasPrice - ? tx.gasprice - : maxGasPrice; + uint256 gasPrice = + tx.gasprice < maxGasPrice ? tx.gasprice : maxGasPrice; uint256 refundAmount = (gasSpent + staticGas) * gasPrice; diff --git a/solidity/random-beacon/contracts/legacy/sortition/Branch.sol b/solidity/random-beacon/contracts/legacy/sortition/Branch.sol new file mode 100644 index 0000000000..5f0178222c --- /dev/null +++ b/solidity/random-beacon/contracts/legacy/sortition/Branch.sol @@ -0,0 +1,141 @@ +pragma solidity 0.8.17; + +import "./Constants.sol"; + +/// @notice The implicit 8-ary trees of the sortition pool +/// rely on packing 8 "slots" of 32-bit values into each uint256. +/// The Branch library permits efficient calculations on these slots. +library Branch { + /// @notice Calculate the right shift required + /// to make the 32 least significant bits of an uint256 + /// be the bits of the `position`th slot + /// when treating the uint256 as a uint32[8]. + /// + /// @dev Not used for efficiency reasons, + /// but left to illustrate the meaning of a common pattern. + /// I wish solidity had macros, even C macros. + function slotShift(uint256 position) internal pure returns (uint256) { + unchecked { + return position * Constants.SLOT_WIDTH; + } + } + + /// @notice Return the `position`th slot of the `node`, + /// treating `node` as a uint32[32]. + function getSlot(uint256 node, uint256 position) + internal + pure + returns (uint256) + { + unchecked { + uint256 shiftBits = position * Constants.SLOT_WIDTH; + // Doing a bitwise AND with `SLOT_MAX` + // clears all but the 32 least significant bits. + // Because of the right shift by `slotShift(position)` bits, + // those 32 bits contain the 32 bits in the `position`th slot of `node`. + return (node >> shiftBits) & Constants.SLOT_MAX; + } + } + + /// @notice Return `node` with the `position`th slot set to zero. + function clearSlot(uint256 node, uint256 position) + internal + pure + returns (uint256) + { + unchecked { + uint256 shiftBits = position * Constants.SLOT_WIDTH; + // Shifting `SLOT_MAX` left by `slotShift(position)` bits + // gives us a number where all bits of the `position`th slot are set, + // and all other bits are unset. + // + // Using a bitwise NOT on this number, + // we get a uint256 where all bits are set + // except for those of the `position`th slot. + // + // Bitwise ANDing the original `node` with this number + // sets the bits of `position`th slot to zero, + // leaving all other bits unchanged. + return node & ~(Constants.SLOT_MAX << shiftBits); + } + } + + /// @notice Return `node` with the `position`th slot set to `weight`. + /// + /// @param weight The weight of of the node. + /// Safely truncated to a 32-bit number, + /// but this should never be called with an overflowing weight regardless. + function setSlot( + uint256 node, + uint256 position, + uint256 weight + ) internal pure returns (uint256) { + unchecked { + uint256 shiftBits = position * Constants.SLOT_WIDTH; + // Clear the `position`th slot like in `clearSlot()`. + uint256 clearedNode = node & ~(Constants.SLOT_MAX << shiftBits); + // Bitwise AND `weight` with `SLOT_MAX` + // to clear all but the 32 least significant bits. + // + // Shift this left by `slotShift(position)` bits + // to obtain a uint256 with all bits unset + // except in the `position`th slot + // which contains the 32-bit value of `weight`. + uint256 shiftedWeight = (weight & Constants.SLOT_MAX) << shiftBits; + // When we bitwise OR these together, + // all other slots except the `position`th one come from the left argument, + // and the `position`th gets filled with `weight` from the right argument. + return clearedNode | shiftedWeight; + } + } + + /// @notice Calculate the summed weight of all slots in the `node`. + function sumWeight(uint256 node) internal pure returns (uint256 sum) { + unchecked { + sum = node & Constants.SLOT_MAX; + // Iterate through each slot + // by shifting `node` right in increments of 32 bits, + // and adding the 32 least significant bits to the `sum`. + uint256 newNode = node >> Constants.SLOT_WIDTH; + while (newNode > 0) { + sum += (newNode & Constants.SLOT_MAX); + newNode = newNode >> Constants.SLOT_WIDTH; + } + return sum; + } + } + + /// @notice Pick a slot in `node` that corresponds to `index`. + /// Treats the node like an array of virtual stakers, + /// the number of virtual stakers in each slot corresponding to its weight, + /// and picks which slot contains the `index`th virtual staker. + /// + /// @dev Requires that `index` be lower than `sumWeight(node)`. + /// However, this is not enforced for performance reasons. + /// If `index` exceeds the permitted range, + /// `pickWeightedSlot()` returns the rightmost slot + /// and an excessively high `newIndex`. + /// + /// @return slot The slot of `node` containing the `index`th virtual staker. + /// + /// @return newIndex The index of the `index`th virtual staker of `node` + /// within the returned slot. + function pickWeightedSlot(uint256 node, uint256 index) + internal + pure + returns (uint256 slot, uint256 newIndex) + { + unchecked { + newIndex = index; + uint256 newNode = node; + uint256 currentSlotWeight = newNode & Constants.SLOT_MAX; + while (newIndex >= currentSlotWeight) { + newIndex -= currentSlotWeight; + slot++; + newNode = newNode >> Constants.SLOT_WIDTH; + currentSlotWeight = newNode & Constants.SLOT_MAX; + } + return (slot, newIndex); + } + } +} diff --git a/solidity/random-beacon/contracts/legacy/sortition/Chaosnet.sol b/solidity/random-beacon/contracts/legacy/sortition/Chaosnet.sol new file mode 100644 index 0000000000..237e88ce07 --- /dev/null +++ b/solidity/random-beacon/contracts/legacy/sortition/Chaosnet.sol @@ -0,0 +1,84 @@ +pragma solidity 0.8.17; + +/// @title Chaosnet +/// @notice This is a beta staker program for stakers willing to go the extra +/// mile with monitoring, share their logs with the dev team, and allow to more +/// carefully monitor the bootstrapping network. As the network matures, the +/// beta program will be ended. +contract Chaosnet { + /// @notice Indicates if the chaosnet is active. The chaosnet is active + /// after the contract deployment and can be ended with a call to + /// `deactivateChaosnet()`. Once deactivated chaosnet can not be activated + /// again. + bool public isChaosnetActive; + + /// @notice Indicates if the given operator is a beta operator for chaosnet. + mapping(address => bool) public isBetaOperator; + + /// @notice Address controlling chaosnet status and beta operator addresses. + address public chaosnetOwner; + + event BetaOperatorsAdded(address[] operators); + + event ChaosnetOwnerRoleTransferred( + address oldChaosnetOwner, + address newChaosnetOwner + ); + + event ChaosnetDeactivated(); + + constructor() { + _transferChaosnetOwner(msg.sender); + isChaosnetActive = true; + } + + modifier onlyChaosnetOwner() { + require(msg.sender == chaosnetOwner, "Not the chaosnet owner"); + _; + } + + modifier onlyOnChaosnet() { + require(isChaosnetActive, "Chaosnet is not active"); + _; + } + + /// @notice Adds beta operator to chaosnet. Can be called only by the + /// chaosnet owner when the chaosnet is active. Once the operator is added + /// as a beta operator, it can not be removed. + function addBetaOperators(address[] calldata operators) + public + onlyOnChaosnet + onlyChaosnetOwner + { + for (uint256 i = 0; i < operators.length; i++) { + isBetaOperator[operators[i]] = true; + } + + emit BetaOperatorsAdded(operators); + } + + /// @notice Deactivates the chaosnet. Can be called only by the chaosnet + /// owner. Once deactivated chaosnet can not be activated again. + function deactivateChaosnet() public onlyOnChaosnet onlyChaosnetOwner { + isChaosnetActive = false; + emit ChaosnetDeactivated(); + } + + /// @notice Transfers the chaosnet owner role to another non-zero address. + function transferChaosnetOwnerRole(address newChaosnetOwner) + public + onlyChaosnetOwner + { + require( + newChaosnetOwner != address(0), + "New chaosnet owner must not be zero address" + ); + _transferChaosnetOwner(newChaosnetOwner); + } + + function _transferChaosnetOwner(address newChaosnetOwner) internal { + address oldChaosnetOwner = chaosnetOwner; + chaosnetOwner = newChaosnetOwner; + emit ChaosnetOwnerRoleTransferred(oldChaosnetOwner, newChaosnetOwner); + } +} diff --git a/solidity/random-beacon/contracts/legacy/sortition/Constants.sol b/solidity/random-beacon/contracts/legacy/sortition/Constants.sol new file mode 100644 index 0000000000..ce1ba7dacc --- /dev/null +++ b/solidity/random-beacon/contracts/legacy/sortition/Constants.sol @@ -0,0 +1,32 @@ +pragma solidity 0.8.17; + +library Constants { + //////////////////////////////////////////////////////////////////////////// + // Parameters for configuration + + // How many bits a position uses per level of the tree; + // each branch of the tree contains 2**SLOT_BITS slots. + uint256 constant SLOT_BITS = 3; + uint256 constant LEVELS = 7; + //////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////// + // Derived constants, do not touch + uint256 constant SLOT_COUNT = 2**SLOT_BITS; + uint256 constant SLOT_WIDTH = 256 / SLOT_COUNT; + uint256 constant LAST_SLOT = SLOT_COUNT - 1; + uint256 constant SLOT_MAX = (2**SLOT_WIDTH) - 1; + uint256 constant POOL_CAPACITY = SLOT_COUNT**LEVELS; + + uint256 constant ID_WIDTH = SLOT_WIDTH; + uint256 constant ID_MAX = SLOT_MAX; + + uint256 constant BLOCKHEIGHT_WIDTH = 96 - ID_WIDTH; + uint256 constant BLOCKHEIGHT_MAX = (2**BLOCKHEIGHT_WIDTH) - 1; + + uint256 constant SLOT_POINTER_MAX = (2**SLOT_BITS) - 1; + uint256 constant LEAF_FLAG = 1 << 255; + + uint256 constant WEIGHT_WIDTH = 256 / SLOT_COUNT; + //////////////////////////////////////////////////////////////////////////// +} diff --git a/solidity/random-beacon/contracts/legacy/sortition/LICENSE b/solidity/random-beacon/contracts/legacy/sortition/LICENSE new file mode 100644 index 0000000000..3e7efefd1d --- /dev/null +++ b/solidity/random-beacon/contracts/legacy/sortition/LICENSE @@ -0,0 +1,17 @@ +ISC License + +The upstream @keep-network/sortition-pools package declares the ISC license. +It distributes no separate copyright notice or license file. The original +package manifest and source provenance are recorded in VENDOR.json. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/solidity/random-beacon/contracts/legacy/sortition/Leaf.sol b/solidity/random-beacon/contracts/legacy/sortition/Leaf.sol new file mode 100644 index 0000000000..4b15a72a7b --- /dev/null +++ b/solidity/random-beacon/contracts/legacy/sortition/Leaf.sol @@ -0,0 +1,44 @@ +pragma solidity 0.8.17; + +import "./Constants.sol"; + +library Leaf { + function make( + address _operator, + uint256 _creationBlock, + uint256 _id + ) internal pure returns (uint256) { + assert(_creationBlock <= type(uint64).max); + assert(_id <= type(uint32).max); + // Converting a bytesX type into a larger type + // adds zero bytes on the right. + uint256 op = uint256(bytes32(bytes20(_operator))); + // Bitwise AND the id to erase + // all but the 32 least significant bits + uint256 uid = _id & Constants.ID_MAX; + // Erase all but the 64 least significant bits, + // then shift left by 32 bits to make room for the id + uint256 cb = (_creationBlock & Constants.BLOCKHEIGHT_MAX) << + Constants.ID_WIDTH; + // Bitwise OR them all together to get + // [address operator || uint64 creationBlock || uint32 id] + return (op | cb | uid); + } + + function operator(uint256 leaf) internal pure returns (address) { + // Converting a bytesX type into a smaller type + // truncates it on the right. + return address(bytes20(bytes32(leaf))); + } + + /// @notice Return the block number the leaf was created in. + function creationBlock(uint256 leaf) internal pure returns (uint256) { + return ((leaf >> Constants.ID_WIDTH) & Constants.BLOCKHEIGHT_MAX); + } + + function id(uint256 leaf) internal pure returns (uint32) { + // Id is stored in the 32 least significant bits. + // Bitwise AND ensures that we only get the contents of those bits. + return uint32(leaf & Constants.ID_MAX); + } +} diff --git a/solidity/random-beacon/contracts/legacy/sortition/Position.sol b/solidity/random-beacon/contracts/legacy/sortition/Position.sol new file mode 100644 index 0000000000..0985a3777d --- /dev/null +++ b/solidity/random-beacon/contracts/legacy/sortition/Position.sol @@ -0,0 +1,39 @@ +pragma solidity 0.8.17; + +import "./Constants.sol"; + +library Position { + // Return the last 3 bits of a position number, + // corresponding to its slot in its parent + function slot(uint256 a) internal pure returns (uint256) { + return a & Constants.SLOT_POINTER_MAX; + } + + // Return the parent of a position number + function parent(uint256 a) internal pure returns (uint256) { + return a >> Constants.SLOT_BITS; + } + + // Return the location of the child of a at the given slot + function child(uint256 a, uint256 s) internal pure returns (uint256) { + return (a << Constants.SLOT_BITS) | (s & Constants.SLOT_POINTER_MAX); // slot(s) + } + + // Return the uint p as a flagged position uint: + // the least significant 21 bits contain the position + // and the 22nd bit is set as a flag + // to distinguish the position 0x000000 from an empty field. + function setFlag(uint256 p) internal pure returns (uint256) { + return p | Constants.LEAF_FLAG; + } + + // Turn a flagged position into an unflagged position + // by removing the flag at the 22nd least significant bit. + // + // We shouldn't _actually_ need this + // as all position-manipulating code should ignore non-position bits anyway + // but it's cheap to call so might as well do it. + function unsetFlag(uint256 p) internal pure returns (uint256) { + return p & (~Constants.LEAF_FLAG); + } +} diff --git a/solidity/random-beacon/contracts/legacy/sortition/README.md b/solidity/random-beacon/contracts/legacy/sortition/README.md new file mode 100644 index 0000000000..e1568d73f5 --- /dev/null +++ b/solidity/random-beacon/contracts/legacy/sortition/README.md @@ -0,0 +1,17 @@ +# Legacy sortition compatibility + +These are the frozen runtime sources from `@keep-network/sortition-pools@2.0.0`. +The runtime files are byte-identical in `2.0.0-pre.16`, previously locked by +Random Beacon. Only the two imports in SortitionPool point to local copies of +the Thesis interfaces; their transitive IApproveAndCall interface is retained too. +`VENDOR.json` records the source revision, package manifest, and original hashes. +Licenses and notices are retained alongside the components. + +The current source still needs this implementation for legacy ABI compatibility, +fixtures, and deployment replay. Its presence is not a statement about live +operator selection. Do not add new protocol features here or refresh from an +upstream branch. Retiring the implementation itself is a separate contract and +historical-deployment migration. + +Frozen legacy sources retain their prior dependency treatment in lint and Slither +filters; the original files were excluded under `node_modules/`. diff --git a/solidity/random-beacon/contracts/legacy/sortition/RNG.sol b/solidity/random-beacon/contracts/legacy/sortition/RNG.sol new file mode 100644 index 0000000000..3e02b4b9e0 --- /dev/null +++ b/solidity/random-beacon/contracts/legacy/sortition/RNG.sol @@ -0,0 +1,94 @@ +pragma solidity 0.8.17; + +import "./Leaf.sol"; +import "./Constants.sol"; + +library RNG { + /// @notice Get an index in the range `[0 .. range-1]` + /// and the new state of the RNG, + /// using the provided `state` of the RNG. + /// + /// @param range The upper bound of the index, exclusive. + /// + /// @param state The previous state of the RNG. + /// The initial state needs to be obtained + /// from a trusted randomness oracle (the random beacon), + /// or from a chain of earlier calls to `RNG.getIndex()` + /// on an originally trusted seed. + /// + /// @dev Calculates the number of bits required for the desired range, + /// takes the least significant bits of `state` + /// and checks if the obtained index is within the desired range. + /// The original state is hashed with `keccak256` to get a new state. + /// If the index is outside the range, + /// the function retries until it gets a suitable index. + /// + /// @return index A random integer between `0` and `range - 1`, inclusive. + /// + /// @return newState The new state of the RNG. + /// When `getIndex()` is called one or more times, + /// care must be taken to always use the output `state` + /// of the most recent call as the input `state` of a subsequent call. + /// At the end of a transaction calling `RNG.getIndex()`, + /// the previous stored state must be overwritten with the latest output. + function getIndex( + uint256 range, + bytes32 state, + uint256 bits + ) internal view returns (uint256, bytes32) { + bool found = false; + uint256 index = 0; + bytes32 newState = state; + while (!found) { + index = truncate(bits, uint256(newState)); + newState = keccak256(abi.encodePacked(newState, address(this))); + if (index < range) { + found = true; + } + } + return (index, newState); + } + + /// @notice Calculate how many bits are required + /// for an index in the range `[0 .. range-1]`. + /// + /// @param range The upper bound of the desired range, exclusive. + /// + /// @return uint The smallest number of bits + /// that can contain the number `range-1`. + function bitsRequired(uint256 range) internal pure returns (uint256) { + unchecked { + if (range == 1) { + return 0; + } + + uint256 bits = Constants.WEIGHT_WIDTH - 1; + + // Left shift by `bits`, + // so we have a 1 in the (bits + 1)th least significant bit + // and 0 in other bits. + // If this number is equal or greater than `range`, + // the range [0, range-1] fits in `bits` bits. + // + // Because we loop from high bits to low bits, + // we find the highest number of bits that doesn't fit the range, + // and return that number + 1. + while (1 << bits >= range) { + bits--; + } + + return bits + 1; + } + } + + /// @notice Truncate `input` to the `bits` least significant bits. + function truncate(uint256 bits, uint256 input) + internal + pure + returns (uint256) + { + unchecked { + return input & ((1 << bits) - 1); + } + } +} diff --git a/solidity/random-beacon/contracts/legacy/sortition/Rewards.sol b/solidity/random-beacon/contracts/legacy/sortition/Rewards.sol new file mode 100644 index 0000000000..2583e364aa --- /dev/null +++ b/solidity/random-beacon/contracts/legacy/sortition/Rewards.sol @@ -0,0 +1,218 @@ +pragma solidity 0.8.17; + +/// @title Rewards +/// @notice Rewards are allocated proportionally to operators +/// present in the pool at payout based on their weight in the pool. +/// +/// To facilitate this, we use a global accumulator value +/// to track the total rewards one unit of weight would've earned +/// since the creation of the pool. +/// +/// Whenever a reward is paid, the accumulator is increased +/// by the size of the reward divided by the total weight +/// of all eligible operators in the pool. +/// +/// Each operator has an individual accumulator value, +/// set to equal the global accumulator when the operator joins the pool. +/// This accumulator reflects the amount of rewards +/// that have already been accounted for with that operator. +/// +/// Whenever an operator's weight in the pool changes, +/// we can update the amount of rewards the operator has earned +/// by subtracting the operator's accumulator from the global accumulator. +/// This gives us the amount of rewards one unit of weight has earned +/// since the last time the operator's rewards have been updated. +/// Then we multiply that by the operator's previous (pre-change) weight +/// to determine how much rewards in total the operator has earned, +/// and add this to the operator's earned rewards. +/// Finally, we set the operator's accumulator to the global accumulator value. +contract Rewards { + struct OperatorRewards { + // The state of the global accumulator + // when the operator's rewards were last updated + uint96 accumulated; + // The amount of rewards collected by the operator after the latest update. + // The amount the operator could withdraw may equal `available` + // or it may be greater, if more rewards have been paid in since then. + // To evaulate the most recent amount including rewards potentially paid + // since the last update, use `availableRewards` function. + uint96 available; + // If nonzero, the operator is ineligible for rewards + // and may only re-enable rewards after the specified timestamp. + // XXX: unsigned 32-bit integer unix seconds, will break around 2106 + uint32 ineligibleUntil; + // Locally cached weight of the operator, + // used to reduce the cost of setting operators ineligible. + uint32 weight; + } + + // The global accumulator of how much rewards + // a hypothetical operator of weight 1 would have earned + // since the creation of the pool. + uint96 internal globalRewardAccumulator; + // If the amount of reward tokens paid in + // does not divide cleanly by pool weight, + // the difference is recorded as rounding dust + // and added to the next reward. + uint96 internal rewardRoundingDust; + + // The amount of rewards that would've been earned by ineligible operators + // had they not been ineligible. + uint96 public ineligibleEarnedRewards; + + // Ineligibility times are calculated from this offset, + // set at contract creation. + uint256 internal immutable ineligibleOffsetStart; + + mapping(uint32 => OperatorRewards) internal operatorRewards; + + constructor() { + // solhint-disable-next-line not-rely-on-time + ineligibleOffsetStart = block.timestamp; + } + + /// @notice Return whether the operator is eligible for rewards or not. + function isEligibleForRewards(uint32 operator) internal view returns (bool) { + return operatorRewards[operator].ineligibleUntil == 0; + } + + /// @notice Return the time the operator's reward eligibility can be restored. + function rewardsEligibilityRestorableAt(uint32 operator) + internal + view + returns (uint256) + { + uint32 until = operatorRewards[operator].ineligibleUntil; + require(until != 0, "Operator already eligible"); + return (uint256(until) + ineligibleOffsetStart); + } + + /// @notice Return whether the operator is able to restore their eligibility + /// for rewards right away. + function canRestoreRewardEligibility(uint32 operator) + internal + view + returns (bool) + { + // solhint-disable-next-line not-rely-on-time + return rewardsEligibilityRestorableAt(operator) <= block.timestamp; + } + + /// @notice Internal function for updating the global state of rewards. + function addRewards(uint96 rewardAmount, uint32 currentPoolWeight) internal { + require(currentPoolWeight > 0, "No recipients in pool"); + + uint96 totalAmount = rewardAmount + rewardRoundingDust; + uint96 perWeightReward = totalAmount / currentPoolWeight; + uint96 newRoundingDust = totalAmount % currentPoolWeight; + + globalRewardAccumulator += perWeightReward; + rewardRoundingDust = newRoundingDust; + } + + /// @notice Internal function for updating the operator's reward state. + function updateOperatorRewards(uint32 operator, uint32 newWeight) internal { + uint96 acc = globalRewardAccumulator; + OperatorRewards memory o = operatorRewards[operator]; + uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight); + if (o.ineligibleUntil == 0) { + // If operator is not ineligible, update their earned rewards + o.available += accruedRewards; + } else { + // If ineligible, put the rewards into the ineligible pot + ineligibleEarnedRewards += accruedRewards; + } + // In any case, update their accumulator and weight + o.accumulated = acc; + o.weight = newWeight; + operatorRewards[operator] = o; + } + + /// @notice Set the amount of withdrawable tokens to zero + /// and return the previous withdrawable amount. + /// @dev Does not update the withdrawable amount, + /// but should usually be accompanied by an update. + function withdrawOperatorRewards(uint32 operator) + internal + returns (uint96 withdrawable) + { + OperatorRewards storage o = operatorRewards[operator]; + withdrawable = o.available; + o.available = 0; + } + + /// @notice Set the amount of ineligible-earned tokens to zero + /// and return the previous amount. + function withdrawIneligibleRewards() internal returns (uint96 withdrawable) { + withdrawable = ineligibleEarnedRewards; + ineligibleEarnedRewards = 0; + } + + /// @notice Set the given operators as ineligible for rewards. + /// The operators can restore their eligibility at the given time. + function setIneligible(uint32[] memory operators, uint256 until) internal { + OperatorRewards memory o = OperatorRewards(0, 0, 0, 0); + uint96 globalAcc = globalRewardAccumulator; + uint96 accrued = 0; + // Record ineligibility as seconds after contract creation + uint32 _until = uint32(until - ineligibleOffsetStart); + + for (uint256 i = 0; i < operators.length; i++) { + uint32 operator = operators[i]; + OperatorRewards storage r = operatorRewards[operator]; + o.available = r.available; + o.accumulated = r.accumulated; + o.ineligibleUntil = r.ineligibleUntil; + o.weight = r.weight; + + if (o.ineligibleUntil != 0) { + // If operator is already ineligible, + // don't earn rewards or shorten its ineligibility + if (o.ineligibleUntil < _until) { + o.ineligibleUntil = _until; + } + } else { + // The operator becomes ineligible -> earn rewards + o.ineligibleUntil = _until; + accrued = (globalAcc - o.accumulated) * uint96(o.weight); + o.available += accrued; + } + o.accumulated = globalAcc; + + r.available = o.available; + r.accumulated = o.accumulated; + r.ineligibleUntil = o.ineligibleUntil; + r.weight = o.weight; + } + } + + /// @notice Restore the given operator's eligibility for rewards. + function restoreEligibility(uint32 operator) internal { + // solhint-disable-next-line not-rely-on-time + require(canRestoreRewardEligibility(operator), "Operator still ineligible"); + uint96 acc = globalRewardAccumulator; + OperatorRewards memory o = operatorRewards[operator]; + uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight); + ineligibleEarnedRewards += accruedRewards; + o.accumulated = acc; + o.ineligibleUntil = 0; + operatorRewards[operator] = o; + } + + /// @notice Returns the amount of rewards currently available for withdrawal + /// for the given operator. + function availableRewards(uint32 operator) internal view returns (uint96) { + uint96 acc = globalRewardAccumulator; + OperatorRewards memory o = operatorRewards[operator]; + if (o.ineligibleUntil == 0) { + // If operator is not ineligible, calculate newly accrued rewards and add + // them to the available ones, calculated during the last update. + uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight); + return o.available + accruedRewards; + } else { + // If ineligible, return only the rewards calculated during the last + // update. + return o.available; + } + } +} diff --git a/solidity/random-beacon/contracts/legacy/sortition/SortitionPool.sol b/solidity/random-beacon/contracts/legacy/sortition/SortitionPool.sol new file mode 100644 index 0000000000..fd35bc942b --- /dev/null +++ b/solidity/random-beacon/contracts/legacy/sortition/SortitionPool.sol @@ -0,0 +1,269 @@ +pragma solidity 0.8.17; + +import "./interfaces/IERC20WithPermit.sol"; +import "./interfaces/IReceiveApproval.sol"; + +import "@openzeppelin/contracts/access/Ownable.sol"; + +import "./RNG.sol"; +import "./SortitionTree.sol"; +import "./Rewards.sol"; +import "./Chaosnet.sol"; + +/// @title Sortition Pool +/// @notice A logarithmic data structure used to store the pool of eligible +/// operators weighted by their stakes. It allows to select a group of operators +/// based on the provided pseudo-random seed. +contract SortitionPool is + SortitionTree, + Rewards, + Ownable, + Chaosnet, + IReceiveApproval +{ + using Branch for uint256; + using Leaf for uint256; + using Position for uint256; + + IERC20WithPermit public immutable rewardToken; + + uint256 public immutable poolWeightDivisor; + + bool public isLocked; + + event IneligibleForRewards(uint32[] ids, uint256 until); + + event RewardEligibilityRestored(address indexed operator, uint32 indexed id); + + /// @notice Reverts if called while pool is locked. + modifier onlyUnlocked() { + require(!isLocked, "Sortition pool locked"); + _; + } + + /// @notice Reverts if called while pool is unlocked. + modifier onlyLocked() { + require(isLocked, "Sortition pool unlocked"); + _; + } + + constructor(IERC20WithPermit _rewardToken, uint256 _poolWeightDivisor) { + rewardToken = _rewardToken; + poolWeightDivisor = _poolWeightDivisor; + } + + function receiveApproval( + address sender, + uint256 amount, + address token, + bytes calldata + ) external override { + require(token == address(rewardToken), "Unsupported token"); + rewardToken.transferFrom(sender, address(this), amount); + Rewards.addRewards(uint96(amount), uint32(root.sumWeight())); + } + + /// @notice Withdraws all available rewards for the given operator to the + /// given beneficiary. + /// @dev Can be called only be the owner. Does not validate if the provided + /// beneficiary is associated with the provided operator - this needs to + /// be done by the owner calling this function. + /// @return The amount of rewards withdrawn in this call. + function withdrawRewards(address operator, address beneficiary) + public + onlyOwner + returns (uint96) + { + uint32 id = getOperatorID(operator); + Rewards.updateOperatorRewards(id, uint32(getPoolWeight(operator))); + uint96 earned = Rewards.withdrawOperatorRewards(id); + rewardToken.transfer(beneficiary, uint256(earned)); + return earned; + } + + /// @notice Withdraws rewards not allocated to operators marked as ineligible + /// to the given recipient address. + /// @dev Can be called only by the owner. + function withdrawIneligible(address recipient) public onlyOwner { + uint96 earned = Rewards.withdrawIneligibleRewards(); + rewardToken.transfer(recipient, uint256(earned)); + } + + /// @notice Locks the sortition pool. In locked state, members cannot be + /// inserted and removed from the pool. Members statuses cannot + /// be updated as well. + /// @dev Can be called only by the contract owner. + function lock() public onlyOwner { + isLocked = true; + } + + /// @notice Unlocks the sortition pool. Removes all restrictions set by + /// the `lock` method. + /// @dev Can be called only by the contract owner. + function unlock() public onlyOwner { + isLocked = false; + } + + /// @notice Inserts an operator to the pool. Reverts if the operator is + /// already present. Reverts if the operator is not eligible because of their + /// authorized stake. Reverts if the chaosnet is active and the operator is + /// not a beta operator. + /// @dev Can be called only by the contract owner. + /// @param operator Address of the inserted operator. + /// @param authorizedStake Inserted operator's authorized stake for the application. + function insertOperator(address operator, uint256 authorizedStake) + public + onlyOwner + onlyUnlocked + { + uint256 weight = getWeight(authorizedStake); + require(weight > 0, "Operator not eligible"); + + if (isChaosnetActive) { + require(isBetaOperator[operator], "Not beta operator for chaosnet"); + } + + _insertOperator(operator, weight); + uint32 id = getOperatorID(operator); + Rewards.updateOperatorRewards(id, uint32(weight)); + } + + /// @notice Update the operator's weight if present and eligible, + /// or remove from the pool if present and ineligible. + /// @dev Can be called only by the contract owner. + /// @param operator Address of the updated operator. + /// @param authorizedStake Operator's authorized stake for the application. + function updateOperatorStatus(address operator, uint256 authorizedStake) + public + onlyOwner + onlyUnlocked + { + uint256 weight = getWeight(authorizedStake); + + uint32 id = getOperatorID(operator); + Rewards.updateOperatorRewards(id, uint32(weight)); + + if (weight == 0) { + _removeOperator(operator); + } else { + updateOperator(operator, weight); + } + } + + /// @notice Set the given operators as ineligible for rewards. + /// The operators can restore their eligibility at the given time. + function setRewardIneligibility(uint32[] calldata operators, uint256 until) + public + onlyOwner + { + Rewards.setIneligible(operators, until); + emit IneligibleForRewards(operators, until); + } + + /// @notice Restores reward eligibility for the operator. + function restoreRewardEligibility(address operator) public { + uint32 id = getOperatorID(operator); + Rewards.restoreEligibility(id); + emit RewardEligibilityRestored(operator, id); + } + + /// @notice Returns whether the operator is eligible for rewards or not. + function isEligibleForRewards(address operator) public view returns (bool) { + uint32 id = getOperatorID(operator); + return Rewards.isEligibleForRewards(id); + } + + /// @notice Returns the time the operator's reward eligibility can be restored. + function rewardsEligibilityRestorableAt(address operator) + public + view + returns (uint256) + { + uint32 id = getOperatorID(operator); + return Rewards.rewardsEligibilityRestorableAt(id); + } + + /// @notice Returns whether the operator is able to restore their eligibility + /// for rewards right away. + function canRestoreRewardEligibility(address operator) + public + view + returns (bool) + { + uint32 id = getOperatorID(operator); + return Rewards.canRestoreRewardEligibility(id); + } + + /// @notice Returns the amount of rewards withdrawable for the given operator. + function getAvailableRewards(address operator) public view returns (uint96) { + uint32 id = getOperatorID(operator); + return availableRewards(id); + } + + /// @notice Return whether the operator is present in the pool. + function isOperatorInPool(address operator) public view returns (bool) { + return getFlaggedLeafPosition(operator) != 0; + } + + /// @notice Return whether the operator's weight in the pool + /// matches their eligible weight. + function isOperatorUpToDate(address operator, uint256 authorizedStake) + public + view + returns (bool) + { + return getWeight(authorizedStake) == getPoolWeight(operator); + } + + /// @notice Return the weight of the operator in the pool, + /// which may or may not be out of date. + function getPoolWeight(address operator) public view returns (uint256) { + uint256 flaggedPosition = getFlaggedLeafPosition(operator); + if (flaggedPosition == 0) { + return 0; + } else { + uint256 leafPosition = flaggedPosition.unsetFlag(); + uint256 leafWeight = getLeafWeight(leafPosition); + return leafWeight; + } + } + + /// @notice Selects a new group of operators of the provided size based on + /// the provided pseudo-random seed. At least one operator has to be + /// registered in the pool, otherwise the function fails reverting the + /// transaction. + /// @param groupSize Size of the requested group + /// @param seed Pseudo-random number used to select operators to group + /// @return selected Members of the selected group + function selectGroup(uint256 groupSize, bytes32 seed) + public + view + onlyLocked + returns (uint32[] memory) + { + uint256 _root = root; + + bytes32 rngState = seed; + uint256 rngRange = _root.sumWeight(); + require(rngRange > 0, "Not enough operators in pool"); + uint256 currentIndex; + + uint256 bits = RNG.bitsRequired(rngRange); + + uint32[] memory selected = new uint32[](groupSize); + + for (uint256 i = 0; i < groupSize; i++) { + (currentIndex, rngState) = RNG.getIndex(rngRange, rngState, bits); + + uint256 leafPosition = pickWeightedLeaf(currentIndex, _root); + + uint256 leaf = leaves[leafPosition]; + selected[i] = leaf.id(); + } + return selected; + } + + function getWeight(uint256 authorization) internal view returns (uint256) { + return authorization / poolWeightDivisor; + } +} diff --git a/solidity/random-beacon/contracts/legacy/sortition/SortitionTree.sol b/solidity/random-beacon/contracts/legacy/sortition/SortitionTree.sol new file mode 100644 index 0000000000..a4247b2821 --- /dev/null +++ b/solidity/random-beacon/contracts/legacy/sortition/SortitionTree.sol @@ -0,0 +1,368 @@ +pragma solidity 0.8.17; + +import "./Branch.sol"; +import "./Position.sol"; +import "./Leaf.sol"; +import "./Constants.sol"; + +contract SortitionTree { + using Branch for uint256; + using Position for uint256; + using Leaf for uint256; + + // implicit tree + // root 8 + // level2 64 + // level3 512 + // level4 4k + // level5 32k + // level6 256k + // level7 2M + uint256 internal root; + + // A 2-index mapping from layer => (index (0-index) => branch). For example, + // to access the 6th branch in the 2nd layer (right below the root node; the + // first branch layer), call branches[2][5]. Mappings are used in place of + // arrays for efficiency. The root is the first layer, the branches occupy + // layers 2 through 7, and layer 8 is for the leaves. Following this + // convention, the first index in `branches` is `2`, and the last index is + // `7`. + mapping(uint256 => mapping(uint256 => uint256)) internal branches; + + // A 0-index mapping from index => leaf, acting as an array. For example, to + // access the 42nd leaf, call leaves[41]. + mapping(uint256 => uint256) internal leaves; + + // the flagged (see setFlag() and unsetFlag() in Position.sol) positions + // of all operators present in the pool + mapping(address => uint256) internal flaggedLeafPosition; + + // the leaf after the rightmost occupied leaf of each stack + uint256 internal rightmostLeaf; + + // the empty leaves in each stack + // between 0 and the rightmost occupied leaf + uint256[] internal emptyLeaves; + + // Each operator has an uint32 ID number + // which is allocated when they first join the pool + // and remains unchanged even if they leave and rejoin the pool. + mapping(address => uint32) internal operatorID; + + // The idAddress array records the address corresponding to each ID number. + // The ID number 0 is initialized with a zero address and is not used. + address[] internal idAddress; + + constructor() { + root = 0; + rightmostLeaf = 0; + idAddress.push(); + } + + /// @notice Return the ID number of the given operator address. An ID number + /// of 0 means the operator has not been allocated an ID number yet. + /// @param operator Address of the operator. + /// @return the ID number of the given operator address + function getOperatorID(address operator) public view returns (uint32) { + return operatorID[operator]; + } + + /// @notice Get the operator address corresponding to the given ID number. A + /// zero address means the ID number has not been allocated yet. + /// @param id ID of the operator + /// @return the address of the operator + function getIDOperator(uint32 id) public view returns (address) { + return idAddress.length > id ? idAddress[id] : address(0); + } + + /// @notice Gets the operator addresses corresponding to the given ID + /// numbers. A zero address means the ID number has not been allocated yet. + /// This function works just like getIDOperator except that it allows to fetch + /// operator addresses for multiple IDs in one call. + /// @param ids the array of the operator ids + /// @return an array of the associated operator addresses + function getIDOperators(uint32[] calldata ids) + public + view + returns (address[] memory) + { + uint256 idCount = idAddress.length; + + address[] memory operators = new address[](ids.length); + for (uint256 i = 0; i < ids.length; i++) { + uint32 id = ids[i]; + operators[i] = idCount > id ? idAddress[id] : address(0); + } + return operators; + } + + /// @notice Checks if operator is already registered in the pool. + /// @param operator the address of the operator + /// @return whether or not the operator is already registered in the pool + function isOperatorRegistered(address operator) public view returns (bool) { + return getFlaggedLeafPosition(operator) != 0; + } + + /// @notice Sum the number of operators in each trunk. + /// @return the number of operators in the pool + function operatorsInPool() public view returns (uint256) { + // Get the number of leaves that might be occupied; + // if `rightmostLeaf` equals `firstLeaf()` the tree must be empty, + // otherwise the difference between these numbers + // gives the number of leaves that may be occupied. + uint256 nPossiblyUsedLeaves = rightmostLeaf; + // Get the number of empty leaves + // not accounted for by the `rightmostLeaf` + uint256 nEmptyLeaves = emptyLeaves.length; + + return (nPossiblyUsedLeaves - nEmptyLeaves); + } + + /// @notice Convenience method to return the total weight of the pool + /// @return the total weight of the pool + function totalWeight() public view returns (uint256) { + return root.sumWeight(); + } + + /// @notice Give the operator a new ID number. + /// Does not check if the operator already has an ID number. + /// @param operator the address of the operator + /// @return a new ID for that operator + function allocateOperatorID(address operator) internal returns (uint256) { + uint256 id = idAddress.length; + + require(id <= type(uint32).max, "Pool capacity exceeded"); + + operatorID[operator] = uint32(id); + idAddress.push(operator); + return id; + } + + /// @notice Inserts an operator into the sortition pool + /// @param operator the address of an operator to insert + /// @param weight how much weight that operator has in the pool + function _insertOperator(address operator, uint256 weight) internal { + require( + !isOperatorRegistered(operator), + "Operator is already registered in the pool" + ); + + // Fetch the operator's ID, and if they don't have one, allocate them one. + uint256 id = getOperatorID(operator); + if (id == 0) { + id = allocateOperatorID(operator); + } + + // Determine which leaf to insert them into + uint256 position = getEmptyLeafPosition(); + // Record the block the operator was inserted in + uint256 theLeaf = Leaf.make(operator, block.number, id); + + // Update the leaf, and propagate the weight changes all the way up to the + // root. + root = setLeaf(position, theLeaf, weight, root); + + // Without position flags, + // the position 0x000000 would be treated as empty + flaggedLeafPosition[operator] = position.setFlag(); + } + + /// @notice Remove an operator (and their weight) from the pool. + /// @param operator the address of the operator to remove + function _removeOperator(address operator) internal { + uint256 flaggedPosition = getFlaggedLeafPosition(operator); + require(flaggedPosition != 0, "Operator is not registered in the pool"); + uint256 unflaggedPosition = flaggedPosition.unsetFlag(); + + // Update the leaf, and propagate the weight changes all the way up to the + // root. + root = removeLeaf(unflaggedPosition, root); + removeLeafPositionRecord(operator); + } + + /// @notice Update an operator's weight in the pool. + /// @param operator the address of the operator to update + /// @param weight the new weight + function updateOperator(address operator, uint256 weight) internal { + require( + isOperatorRegistered(operator), + "Operator is not registered in the pool" + ); + + uint256 flaggedPosition = getFlaggedLeafPosition(operator); + uint256 unflaggedPosition = flaggedPosition.unsetFlag(); + root = updateLeaf(unflaggedPosition, weight, root); + } + + /// @notice Helper method to remove a leaf position record for an operator. + /// @param operator the address of the operator to remove the record for + function removeLeafPositionRecord(address operator) internal { + flaggedLeafPosition[operator] = 0; + } + + /// @notice Removes the data and weight from a particular leaf. + /// @param position the leaf index to remove + /// @param _root the root node containing the leaf + /// @return the updated root node + function removeLeaf(uint256 position, uint256 _root) + internal + returns (uint256) + { + uint256 rightmostSubOne = rightmostLeaf - 1; + bool isRightmost = position == rightmostSubOne; + + // Clears out the data in the leaf node, and then propagates the weight + // changes all the way up to the root. + uint256 newRoot = setLeaf(position, 0, 0, _root); + + // Infer if need to fall back on emptyLeaves yet + if (isRightmost) { + rightmostLeaf = rightmostSubOne; + } else { + emptyLeaves.push(position); + } + return newRoot; + } + + /// @notice Updates the tree to give a particular leaf a new weight. + /// @param position the index of the leaf to update + /// @param weight the new weight + /// @param _root the root node containing the leaf + /// @return the updated root node + function updateLeaf( + uint256 position, + uint256 weight, + uint256 _root + ) internal returns (uint256) { + if (getLeafWeight(position) != weight) { + return updateTree(position, weight, _root); + } else { + return _root; + } + } + + /// @notice Places a leaf into a particular position, with a given weight and + /// propagates that change. + /// @param position the index to place the leaf in + /// @param theLeaf the new leaf to place in the position + /// @param leafWeight the weight of the leaf + /// @param _root the root containing the new leaf + /// @return the updated root node + function setLeaf( + uint256 position, + uint256 theLeaf, + uint256 leafWeight, + uint256 _root + ) internal returns (uint256) { + // set leaf + leaves[position] = theLeaf; + + return (updateTree(position, leafWeight, _root)); + } + + /// @notice Propagates a weight change at a position through the tree, + /// eventually returning the updated root. + /// @param position the index of leaf to update + /// @param weight the new weight of the leaf + /// @param _root the root node containing the leaf + /// @return the updated root node + function updateTree( + uint256 position, + uint256 weight, + uint256 _root + ) internal returns (uint256) { + uint256 childSlot; + uint256 treeNode; + uint256 newNode; + uint256 nodeWeight = weight; + + uint256 parent = position; + // set levels 7 to 2 + for (uint256 level = Constants.LEVELS; level >= 2; level--) { + childSlot = parent.slot(); + parent = parent.parent(); + treeNode = branches[level][parent]; + newNode = treeNode.setSlot(childSlot, nodeWeight); + branches[level][parent] = newNode; + nodeWeight = newNode.sumWeight(); + } + + // set level Root + childSlot = parent.slot(); + return _root.setSlot(childSlot, nodeWeight); + } + + /// @notice Retrieves the next available empty leaf position. Tries to fill + /// left to right first, ignoring leaf removals, and then fills + /// most-recent-removals first. + /// @return the position of the empty leaf + function getEmptyLeafPosition() internal returns (uint256) { + uint256 rLeaf = rightmostLeaf; + bool spaceOnRight = (rLeaf + 1) < Constants.POOL_CAPACITY; + if (spaceOnRight) { + rightmostLeaf = rLeaf + 1; + return rLeaf; + } else { + uint256 emptyLeafCount = emptyLeaves.length; + require(emptyLeafCount > 0, "Pool is full"); + uint256 emptyLeaf = emptyLeaves[emptyLeafCount - 1]; + emptyLeaves.pop(); + return emptyLeaf; + } + } + + /// @notice Gets the flagged leaf position for an operator. + /// @param operator the address of the operator + /// @return the leaf position of that operator + function getFlaggedLeafPosition(address operator) + internal + view + returns (uint256) + { + return flaggedLeafPosition[operator]; + } + + /// @notice Gets the weight of a leaf at a particular position. + /// @param position the index of the leaf + /// @return the weight of the leaf at that position + function getLeafWeight(uint256 position) internal view returns (uint256) { + uint256 slot = position.slot(); + uint256 parent = position.parent(); + + // A leaf's weight information is stored a 32-bit slot in the branch layer + // directly above the leaf layer. To access it, we calculate that slot and + // parent position, and always know the hard-coded layer index. + uint256 node = branches[Constants.LEVELS][parent]; + return node.getSlot(slot); + } + + /// @notice Picks a leaf given a random index. + /// @param index a number in `[0, _root.totalWeight())` used to decide + /// between leaves + /// @param _root the root of the tree + function pickWeightedLeaf(uint256 index, uint256 _root) + internal + view + returns (uint256 leafPosition) + { + uint256 currentIndex = index; + uint256 currentNode = _root; + uint256 currentPosition = 0; + uint256 currentSlot; + + require(index < currentNode.sumWeight(), "Index exceeds weight"); + + // get root slot + (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex); + + // get slots from levels 2 to 7 + for (uint256 level = 2; level <= Constants.LEVELS; level++) { + currentPosition = currentPosition.child(currentSlot); + currentNode = branches[level][currentPosition]; + (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex); + } + + // get leaf position + leafPosition = currentPosition.child(currentSlot); + } +} diff --git a/solidity/random-beacon/contracts/legacy/sortition/VENDOR.json b/solidity/random-beacon/contracts/legacy/sortition/VENDOR.json new file mode 100644 index 0000000000..6aa1aa0d58 --- /dev/null +++ b/solidity/random-beacon/contracts/legacy/sortition/VENDOR.json @@ -0,0 +1,101 @@ +{ + "package": "@keep-network/sortition-pools", + "version": "2.0.0", + "upstreamCommit": "8048806a05826785075a926485e0320a7bb75745", + "upstreamPackageManifest": { + "name": "@keep-network/sortition-pools", + "version": "2.0.0", + "description": "", + "main": "truffle-config.js", + "directories": { + "test": "test" + }, + "files": [ + "contracts/**/*.sol", + "migrations/scripts" + ], + "scripts": { + "build": "hardhat compile", + "ganache": "echo 'GANACHE IS NO LONGER USED; use buidler-vm script instead'", + "test": "hardhat test", + "lint": "npm run lint:js && npm run lint:sol", + "lint:fix": "npm run lint:fix:js && npm run lint:fix:sol", + "lint:js": "eslint ${npm_package_config_eslintPaths}", + "lint:fix:js": "eslint --fix ${npm_package_config_eslintPaths}", + "lint:sol": "solhint 'contracts/**/*.sol' && prettier --list-different **/*.sol", + "lint:fix:sol": "solhint 'contracts/**/*.sol' --fix && prettier --write **/*.sol" + }, + "config": { + "eslintPaths": "test/ migrations/" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/keep-network/sortition-pools.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/keep-network/sortition-pools/issues" + }, + "homepage": "https://github.com/keep-network/sortition-pools#readme", + "dependencies": { + "@openzeppelin/contracts": "^4.3.2", + "@thesis/solidity-contracts": "github:thesis/solidity-contracts#4985bcf" + }, + "devDependencies": { + "@keep-network/hardhat-helpers": "^0.2.0-pre", + "@keep-network/hardhat-local-networks-config": "0.1.0-pre.0", + "@keep-network/prettier-config-keep": "github:keep-network/prettier-config-keep#d6ec02e", + "@nomiclabs/hardhat-ethers": "^2.0.2", + "@nomiclabs/hardhat-etherscan": "^2.1.6", + "@nomiclabs/hardhat-waffle": "^2.0.1", + "@nomiclabs/buidler": "^1.4.5", + "@openzeppelin/test-helpers": "^0.5.4", + "@types/chai": "^4.2.20", + "@types/mocha": "^8.2.3", + "@types/node": "^16.0.1", + "bn-chai": "^1.0.1", + "chai": "^4.2.0", + "eslint": "^6.8.0", + "eslint-config-keep": "github:keep-network/eslint-config-keep#0.3.0", + "ethereum-waffle": "^3.4.0", + "ethers": "^5.0.32", + "ethlint": "^1.2.5", + "hardhat": "^2.6.4", + "hardhat-deploy": "^0.9.1", + "hardhat-gas-reporter": "^1.0.8", + "prettier": "^2.3.2", + "prettier-plugin-solidity": "^1.0.0-beta.14", + "solc": "0.8.6", + "solhint": "^3.3.6", + "solhint-config-keep": "github:keep-network/solhint-config-keep", + "truffle": "^5.4.14", + "ts-node": "^10.0.0", + "typescript": "^4.3.5" + } + }, + "sourceSha256": { + "package/contracts/Branch.sol": "0aec2214f3ff1f8c4494baa95eba565644ab1eb6b6688ac20c55ca5da0ef1363", + "package/contracts/Chaosnet.sol": "5400c070de2b775d222ebf0a8633a05d237509b050399ad3468d853f7de2c750", + "package/contracts/Constants.sol": "1e7897b3beaff2b6ae99a214c363d6844e90aff6ef6fdf752b5ed3f6f294e9d1", + "package/contracts/Leaf.sol": "362f02f24d0a4429bea86051b881fe34ae75d6fbb7af29322cc87e324397a659", + "package/contracts/Position.sol": "8bb4ad218deb3a3faafeddc63e4186a27cc550c1c527a3b62751685fd0b97cf6", + "package/contracts/Rewards.sol": "6068ce09b1831411a47b3c25a0ac91725d44057b7c3cb3c5689b6627c191a6d8", + "package/contracts/RNG.sol": "005d1a3beab5b49083ad8dfad1f85baea08cd7119512977d91187bc42b9b22f5", + "package/contracts/SortitionPool.sol": "d81d8cad798e53745bec0b71c0bfd0b2a32c0f8678165048eb9142d9c8114221", + "package/contracts/SortitionTree.sol": "ca43b3e7c8ee362d787f0d12262d397fe916973d9015d738e534751fb1025521" + }, + "interfaceSha256": { + "IApproveAndCall.sol": "211e50c2984546d5ad4ff78991beb2ce344c0573d203fb505132903715991597", + "IERC20WithPermit.sol": "8fa746c4fa1820230c91eec5689c1026bb6369e0ec9ed01976be1b8cdf09bb47", + "IReceiveApproval.sol": "158a8fe35674f1edf2e58223ae9dc7da58b317cc2be3f4cf8e7996ccfcafad6e" + }, + "changes": [ + "Only the two Thesis interface import paths were made local." + ], + "interfaces": { + "repository": "https://github.com/thesis/solidity-contracts", + "revision": "4985bcf" + }, + "compatibility": "Runtime Solidity sources are identical in 2.0.0 and 2.0.0-pre.16." +} diff --git a/solidity/random-beacon/contracts/legacy/sortition/interfaces/IApproveAndCall.sol b/solidity/random-beacon/contracts/legacy/sortition/interfaces/IApproveAndCall.sol new file mode 100644 index 0000000000..bccb1ac658 --- /dev/null +++ b/solidity/random-beacon/contracts/legacy/sortition/interfaces/IApproveAndCall.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.4; + +/// @notice An interface that should be implemented by tokens supporting +/// `approveAndCall`/`receiveApproval` pattern. +interface IApproveAndCall { + /// @notice Executes `receiveApproval` function on spender as specified in + /// `IReceiveApproval` interface. Approves spender to withdraw from + /// the caller multiple times, up to the `amount`. If this + /// function is called again, it overwrites the current allowance + /// with `amount`. Reverts if the approval reverted or if + /// `receiveApproval` call on the spender reverted. + function approveAndCall( + address spender, + uint256 amount, + bytes memory extraData + ) external returns (bool); +} diff --git a/solidity/random-beacon/contracts/legacy/sortition/interfaces/IERC20WithPermit.sol b/solidity/random-beacon/contracts/legacy/sortition/interfaces/IERC20WithPermit.sol new file mode 100644 index 0000000000..80693f9543 --- /dev/null +++ b/solidity/random-beacon/contracts/legacy/sortition/interfaces/IERC20WithPermit.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.4; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; + +import "./IApproveAndCall.sol"; + +/// @title IERC20WithPermit +/// @notice Burnable ERC20 token with EIP2612 permit functionality. User can +/// authorize a transfer of their token with a signature conforming +/// EIP712 standard instead of an on-chain transaction from their +/// address. Anyone can submit this signature on the user's behalf by +/// calling the permit function, as specified in EIP2612 standard, +/// paying gas fees, and possibly performing other actions in the same +/// transaction. +interface IERC20WithPermit is IERC20, IERC20Metadata, IApproveAndCall { + /// @notice EIP2612 approval made with secp256k1 signature. + /// Users can authorize a transfer of their tokens with a signature + /// conforming EIP712 standard, rather than an on-chain transaction + /// from their address. Anyone can submit this signature on the + /// user's behalf by calling the permit function, paying gas fees, + /// and possibly performing other actions in the same transaction. + /// @dev The deadline argument can be set to `type(uint256).max to create + /// permits that effectively never expire. + function permit( + address owner, + address spender, + uint256 amount, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + /// @notice Destroys `amount` tokens from the caller. + function burn(uint256 amount) external; + + /// @notice Destroys `amount` of tokens from `account`, deducting the amount + /// from caller's allowance. + function burnFrom(address account, uint256 amount) external; + + /// @notice Returns hash of EIP712 Domain struct with the token name as + /// a signing domain and token contract as a verifying contract. + /// Used to construct EIP2612 signature provided to `permit` + /// function. + /* solhint-disable-next-line func-name-mixedcase */ + function DOMAIN_SEPARATOR() external view returns (bytes32); + + /// @notice Returns the current nonce for EIP2612 permission for the + /// provided token owner for a replay protection. Used to construct + /// EIP2612 signature provided to `permit` function. + function nonce(address owner) external view returns (uint256); + + /// @notice Returns EIP2612 Permit message hash. Used to construct EIP2612 + /// signature provided to `permit` function. + /* solhint-disable-next-line func-name-mixedcase */ + function PERMIT_TYPEHASH() external pure returns (bytes32); +} diff --git a/solidity/random-beacon/contracts/legacy/sortition/interfaces/IReceiveApproval.sol b/solidity/random-beacon/contracts/legacy/sortition/interfaces/IReceiveApproval.sol new file mode 100644 index 0000000000..0aa4c01d1b --- /dev/null +++ b/solidity/random-beacon/contracts/legacy/sortition/interfaces/IReceiveApproval.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.4; + +/// @notice An interface that should be implemented by contracts supporting +/// `approveAndCall`/`receiveApproval` pattern. +interface IReceiveApproval { + /// @notice Receives approval to spend tokens. Called as a result of + /// `approveAndCall` call on the token. + function receiveApproval( + address from, + uint256 amount, + address token, + bytes calldata extraData + ) external; +} diff --git a/solidity/random-beacon/contracts/legacy/sortition/interfaces/LICENSE b/solidity/random-beacon/contracts/legacy/sortition/interfaces/LICENSE new file mode 100644 index 0000000000..e1cd72518a --- /dev/null +++ b/solidity/random-beacon/contracts/legacy/sortition/interfaces/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Thesis + +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/solidity/random-beacon/contracts/libraries/AltBn128.sol b/solidity/random-beacon/contracts/libraries/AltBn128.sol index ef71bfe910..3091211edb 100644 --- a/solidity/random-beacon/contracts/libraries/AltBn128.sol +++ b/solidity/random-beacon/contracts/libraries/AltBn128.sol @@ -89,11 +89,9 @@ library AltBn128 { /// point on G1. Note that this approach was chosen for its simplicity /// and lower gas cost on the EVM, rather than good distribution of /// points on G1. - function g1HashToPoint(bytes memory m) - internal - view - returns (G1Point memory) - { + function g1HashToPoint( + bytes memory m + ) internal view returns (G1Point memory) { unchecked { bytes32 h = sha256(m); uint256 x = uint256(h) % p; @@ -137,11 +135,10 @@ library AltBn128 { /// @dev Wraps the point addition pre-compile introduced in Byzantium. /// Returns the sum of two points on G1. Revert if the provided points /// are not on the curve. - function g1Add(G1Point memory a, G1Point memory b) - internal - view - returns (G1Point memory c) - { + function g1Add( + G1Point memory a, + G1Point memory b + ) internal view returns (G1Point memory c) { assembly { let arg := mload(0x40) mstore(arg, mload(a)) @@ -156,11 +153,9 @@ library AltBn128 { } /// @dev Returns true if G1 point is on the curve. - function isG1PointOnCurve(G1Point memory point) - internal - view - returns (bool) - { + function isG1PointOnCurve( + G1Point memory point + ) internal view returns (bool) { return point.y.modExp(2, p) == (point.x.modExp(3, p) + 3) % p; } @@ -168,11 +163,10 @@ library AltBn128 { /// Byzantium. The result of a point from G1 multiplied by a scalar /// should match the point added to itself the same number of times. /// Revert if the provided point isn't on the curve. - function scalarMultiply(G1Point memory p_1, uint256 scalar) - internal - view - returns (G1Point memory p_2) - { + function scalarMultiply( + G1Point memory p_1, + uint256 scalar + ) internal view returns (G1Point memory p_2) { assembly { let arg := mload(0x40) mstore(arg, mload(p_1)) @@ -252,8 +246,10 @@ library AltBn128 { // Using formula y = x ^ (p^2 + 15) / 32 from // https://github.com/ethereum/beacon_chain/blob/master/beacon_chain/utils/bls.py // (p^2 + 15) / 32 results into a big 512bit value, so breaking it to two uint256 as (a * a + b) - uint256 a = 3869331240733915743250440106392954448556483137451914450067252501901456824595; - uint256 b = 146360017852723390495514512480590656176144969185739259173561346299185050597; + uint256 a = + 3869331240733915743250440106392954448556483137451914450067252501901456824595; + uint256 b = + 146360017852723390495514512480590656176144969185739259173561346299185050597; (uint256 xbx, uint256 xby) = _gfP2Pow(xx, xy, b); (uint256 yax, uint256 yay) = _gfP2Pow(xx, xy, a); @@ -279,11 +275,9 @@ library AltBn128 { } /// @dev Compress a point on G2 to a pair of uint256 for serialization. - function g2Compress(G2Point memory point) - internal - pure - returns (bytes memory) - { + function g2Compress( + G2Point memory point + ) internal pure returns (bytes memory) { bytes32 m = bytes32(point.x.x); bytes1 leadM = m[0] | (parity(point.y.x) << 7); @@ -295,11 +289,9 @@ library AltBn128 { } /// @dev Unmarshals a point on G1 from bytes in an uncompressed form. - function g1Unmarshal(bytes memory m) - internal - pure - returns (G1Point memory) - { + function g1Unmarshal( + bytes memory m + ) internal pure returns (G1Point memory) { require(m.length == 64, "Invalid G1 bytes length"); bytes32 x; @@ -314,11 +306,9 @@ library AltBn128 { } /// @dev Marshals a point on G1 to bytes form. - function g1Marshal(G1Point memory point) - internal - pure - returns (bytes memory) - { + function g1Marshal( + G1Point memory point + ) internal pure returns (bytes memory) { bytes memory m = new bytes(64); bytes32 x = bytes32(point.x); bytes32 y = bytes32(point.y); @@ -332,11 +322,9 @@ library AltBn128 { } /// @dev Unmarshals a point on G2 from bytes in an uncompressed form. - function g2Unmarshal(bytes memory m) - internal - pure - returns (G2Point memory) - { + function g2Unmarshal( + bytes memory m + ) internal pure returns (G2Point memory) { require(m.length == 128, "Invalid G2 bytes length"); uint256 xx; @@ -355,11 +343,9 @@ library AltBn128 { } /// @dev Decompress a point on G2 from a pair of uint256. - function g2Decompress(bytes memory m) - internal - pure - returns (G2Point memory) - { + function g2Decompress( + bytes memory m + ) internal pure returns (G2Point memory) { require(m.length == 64, "Invalid G2 compressed bytes length"); bytes32 x1; @@ -392,20 +378,18 @@ library AltBn128 { } /// @dev Returns the sum of two gfP2 field elements. - function gfP2Add(gfP2 memory a, gfP2 memory b) - internal - pure - returns (gfP2 memory) - { + function gfP2Add( + gfP2 memory a, + gfP2 memory b + ) internal pure returns (gfP2 memory) { return gfP2(addmod(a.x, b.x, p), addmod(a.y, b.y, p)); } /// @dev Returns multiplication of two gfP2 field elements. - function gfP2Multiply(gfP2 memory a, gfP2 memory b) - internal - pure - returns (gfP2 memory) - { + function gfP2Multiply( + gfP2 memory a, + gfP2 memory b + ) internal pure returns (gfP2 memory) { return gfP2( addmod(mulmod(a.x, b.y, p), mulmod(b.x, a.y, p), p), @@ -414,11 +398,10 @@ library AltBn128 { } /// @dev Returns gfP2 element to the power of the provided exponent. - function gfP2Pow(gfP2 memory _a, uint256 _exp) - internal - pure - returns (gfP2 memory result) - { + function gfP2Pow( + gfP2 memory _a, + uint256 _exp + ) internal pure returns (gfP2 memory result) { (uint256 x, uint256 y) = _gfP2Pow(_a.x, _a.y, _exp); return gfP2(x, y); } @@ -431,11 +414,9 @@ library AltBn128 { return gfP2Multiply(a, gfP2Square(a)); } - function gfP2CubeAddTwistB(gfP2 memory a) - internal - pure - returns (gfP2 memory) - { + function gfP2CubeAddTwistB( + gfP2 memory a + ) internal pure returns (gfP2 memory) { (uint256 x, uint256 y) = _gfP2CubeAddTwistB(a.x, a.y); return gfP2(x, y); } @@ -449,11 +430,9 @@ library AltBn128 { } /// @dev Returns true if G2 point is on the curve. - function isG2PointOnCurve(G2Point memory point) - internal - pure - returns (bool) - { + function isG2PointOnCurve( + G2Point memory point + ) internal pure returns (bool) { (uint256 y2x, uint256 y2y) = _gfP2Square(point.y.x, point.y.y); (uint256 x3x, uint256 x3y) = _gfP2CubeAddTwistB(point.x.x, point.x.y); @@ -494,11 +473,10 @@ library AltBn128 { y = addmod(mulmod(ay, by, p), p - mulmod(ax, bx, p), p); } - function _gfP2CubeAddTwistB(uint256 ax, uint256 ay) - private - pure - returns (uint256 x, uint256 y) - { + function _gfP2CubeAddTwistB( + uint256 ax, + uint256 ay + ) private pure returns (uint256 x, uint256 y) { (uint256 a3x, uint256 a3y) = _gfP2Cube(ax, ay); return _gfP2Add(a3x, a3y, twistBx, twistBy); } @@ -528,19 +506,17 @@ library AltBn128 { } } - function _gfP2Square(uint256 _ax, uint256 _ay) - private - pure - returns (uint256 x, uint256 y) - { + function _gfP2Square( + uint256 _ax, + uint256 _ay + ) private pure returns (uint256 x, uint256 y) { return _gfP2Multiply(_ax, _ay, _ax, _ay); } - function _gfP2Cube(uint256 _ax, uint256 _ay) - private - pure - returns (uint256 x, uint256 y) - { + function _gfP2Cube( + uint256 _ax, + uint256 _ay + ) private pure returns (uint256 x, uint256 y) { (uint256 _bx, uint256 _by) = _gfP2Square(_ax, _ay); return _gfP2Multiply(_ax, _ay, _bx, _by); } diff --git a/solidity/random-beacon/contracts/libraries/BLS.sol b/solidity/random-beacon/contracts/libraries/BLS.sol index 72564d1087..b4da2952ca 100644 --- a/solidity/random-beacon/contracts/libraries/BLS.sol +++ b/solidity/random-beacon/contracts/libraries/BLS.sol @@ -22,11 +22,10 @@ import "./AltBn128.sol"; /// using the AltBn128 curve. library BLS { /// @dev Creates a signature over message using the provided secret key. - function sign(bytes memory message, uint256 secretKey) - external - view - returns (bytes memory) - { + function sign( + bytes memory message, + uint256 secretKey + ) external view returns (bytes memory) { AltBn128.G1Point memory p_1 = AltBn128.g1HashToPoint(message); AltBn128.G1Point memory p_2 = AltBn128.scalarMultiply(p_1, secretKey); diff --git a/solidity/random-beacon/contracts/libraries/BeaconAuthorization.sol b/solidity/random-beacon/contracts/libraries/BeaconAuthorization.sol index 3689a6e9d1..b56d55f122 100644 --- a/solidity/random-beacon/contracts/libraries/BeaconAuthorization.sol +++ b/solidity/random-beacon/contracts/libraries/BeaconAuthorization.sol @@ -22,7 +22,7 @@ pragma solidity 0.8.17; -import "@keep-network/sortition-pools/contracts/SortitionPool.sol"; +import "../legacy/sortition/SortitionPool.sol"; import "@threshold-network/solidity-contracts/contracts/staking/IStaking.sol"; /// @notice Library managing the state of stake authorizations for the operator @@ -156,12 +156,10 @@ library BeaconAuthorization { uint64 _authorizationDecreaseChangePeriod ) external { self.parameters.minimumAuthorization = _minimumAuthorization; - self - .parameters - .authorizationDecreaseDelay = _authorizationDecreaseDelay; - self - .parameters - .authorizationDecreaseChangePeriod = _authorizationDecreaseChangePeriod; + self.parameters.authorizationDecreaseDelay = + _authorizationDecreaseDelay; + self.parameters.authorizationDecreaseChangePeriod = + _authorizationDecreaseChangePeriod; } /// @notice Used by staking provider to set operator address that will @@ -619,9 +617,8 @@ library BeaconAuthorization { address(this) ); - uint96 _eligibleStake = authorizedStake > decreasingBy - ? authorizedStake - decreasingBy - : 0; + uint96 _eligibleStake = + authorizedStake > decreasingBy ? authorizedStake - decreasingBy : 0; if (_eligibleStake < self.parameters.minimumAuthorization) { return 0; diff --git a/solidity/random-beacon/contracts/libraries/BeaconDkg.sol b/solidity/random-beacon/contracts/libraries/BeaconDkg.sol index 636c7ded50..15192f2d37 100644 --- a/solidity/random-beacon/contracts/libraries/BeaconDkg.sol +++ b/solidity/random-beacon/contracts/libraries/BeaconDkg.sol @@ -15,7 +15,7 @@ pragma solidity 0.8.17; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; -import "@keep-network/sortition-pools/contracts/SortitionPool.sol"; +import "../legacy/sortition/SortitionPool.sol"; import "./BytesLib.sol"; import {BeaconDkgValidator as DKGValidator} from "../BeaconDkgValidator.sol"; @@ -172,11 +172,9 @@ library BeaconDkg { /// @notice Determines the current state of group creation. It doesn't take /// timeouts into consideration. The timeouts should be tracked and /// notified separately. - function currentState(Data storage self) - internal - view - returns (State state) - { + function currentState( + Data storage self + ) internal view returns (State state) { state = State.IDLE; if (self.sortitionPool.isLocked()) { @@ -264,10 +262,10 @@ library BeaconDkg { return currentState(self) == State.AWAITING_RESULT && block.number > - (self.startBlock + - offchainDkgTime + - self.resultSubmissionStartBlockOffset + - self.parameters.resultSubmissionTimeout); + (self.startBlock + + offchainDkgTime + + self.resultSubmissionStartBlockOffset + + self.parameters.resultSubmissionTimeout); } /// @notice Notifies about DKG timeout. @@ -302,17 +300,18 @@ library BeaconDkg { /// @param result Result to approve. Must match the submitted result stored /// during `submitResult`. /// @return misbehavedMembers Identifiers of members who misbehaved during DKG. - function approveResult(Data storage self, Result calldata result) - external - returns (uint32[] memory misbehavedMembers) - { + function approveResult( + Data storage self, + Result calldata result + ) external returns (uint32[] memory misbehavedMembers) { require( currentState(self) == State.CHALLENGE, "Current state is not CHALLENGE" ); - uint256 challengePeriodEnd = self.submittedResultBlock + - self.parameters.resultChallengePeriodLength; + uint256 challengePeriodEnd = + self.submittedResultBlock + + self.parameters.resultChallengePeriodLength; require( block.number > challengePeriodEnd, @@ -334,8 +333,8 @@ library BeaconDkg { require( msg.sender == submitterMember || block.number > - challengePeriodEnd + - self.parameters.submitterPrecedencePeriodLength, + challengePeriodEnd + + self.parameters.submitterPrecedencePeriodLength, "Only the DKG result submitter can approve the result at this moment" ); @@ -363,7 +362,10 @@ library BeaconDkg { /// stored during `submitResult`. /// @return maliciousResultHash Hash of the malicious result. /// @return maliciousSubmitter Identifier of the malicious submitter. - function challengeResult(Data storage self, Result calldata result) + function challengeResult( + Data storage self, + Result calldata result + ) external returns (bytes32 maliciousResultHash, uint32 maliciousSubmitter) { @@ -481,14 +483,12 @@ library BeaconDkg { "Submitter precedence period length should be less than the result submission timeout" ); - self - .parameters - .resultChallengePeriodLength = _resultChallengePeriodLength; + self.parameters.resultChallengePeriodLength = + _resultChallengePeriodLength; self.parameters.resultChallengeExtraGas = _resultChallengeExtraGas; self.parameters.resultSubmissionTimeout = _resultSubmissionTimeout; - self - .parameters - .submitterPrecedencePeriodLength = _submitterPrecedencePeriodLength; + self.parameters.submitterPrecedencePeriodLength = + _submitterPrecedencePeriodLength; } /// @notice Completes DKG by cleaning up state. diff --git a/solidity/random-beacon/contracts/libraries/BeaconInactivity.sol b/solidity/random-beacon/contracts/libraries/BeaconInactivity.sol index 88ee0b34fb..c8e1d9cf0a 100644 --- a/solidity/random-beacon/contracts/libraries/BeaconInactivity.sol +++ b/solidity/random-beacon/contracts/libraries/BeaconInactivity.sol @@ -17,7 +17,7 @@ pragma solidity 0.8.17; import "./BytesLib.sol"; import "./Groups.sol"; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; -import "@keep-network/sortition-pools/contracts/SortitionPool.sol"; +import "../legacy/sortition/SortitionPool.sol"; library BeaconInactivity { using BytesLib for bytes; diff --git a/solidity/random-beacon/contracts/libraries/BytesLib.sol b/solidity/random-beacon/contracts/libraries/BytesLib.sol index 9d9f975c82..85515c01ad 100644 --- a/solidity/random-beacon/contracts/libraries/BytesLib.sol +++ b/solidity/random-beacon/contracts/libraries/BytesLib.sol @@ -49,9 +49,10 @@ For more information, please refer to /** @author https://github.com/GNSPS **/ library BytesLib { - function concatStorage(bytes storage _preBytes, bytes memory _postBytes) - internal - { + function concatStorage( + bytes storage _preBytes, + bytes memory _postBytes + ) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot @@ -190,11 +191,10 @@ library BytesLib { } } - function equalStorage(bytes storage _preBytes, bytes memory _postBytes) - internal - view - returns (bool) - { + function equalStorage( + bytes storage _preBytes, + bytes memory _postBytes + ) internal view returns (bool) { bool success = true; assembly { @@ -240,9 +240,7 @@ library BytesLib { // the next line is the loop condition: // while(uint(mc < end) + cb == 2) - for { - - } eq(add(lt(mc, end), cb), 2) { + for {} eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { @@ -264,11 +262,10 @@ library BytesLib { return success; } - function concat(bytes memory _preBytes, bytes memory _postBytes) - internal - pure - returns (bytes memory) - { + function concat( + bytes memory _preBytes, + bytes memory _postBytes + ) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { @@ -370,11 +367,10 @@ library BytesLib { } } - function toAddress(bytes memory _bytes, uint256 _start) - internal - pure - returns (address) - { + function toAddress( + bytes memory _bytes, + uint256 _start + ) internal pure returns (address) { uint256 _totalLen = _start + 20; require( _totalLen > _start && _bytes.length >= _totalLen, @@ -392,11 +388,10 @@ library BytesLib { return tempAddress; } - function toUint8(bytes memory _bytes, uint256 _start) - internal - pure - returns (uint8) - { + function toUint8( + bytes memory _bytes, + uint256 _start + ) internal pure returns (uint8) { require( _bytes.length >= (_start + 1), "Uint8 conversion out of bounds." @@ -410,11 +405,10 @@ library BytesLib { return tempUint; } - function toUint(bytes memory _bytes, uint256 _start) - internal - pure - returns (uint256) - { + function toUint( + bytes memory _bytes, + uint256 _start + ) internal pure returns (uint256) { uint256 _totalLen = _start + 32; require( _totalLen > _start && _bytes.length >= _totalLen, @@ -429,11 +423,10 @@ library BytesLib { return tempUint; } - function equal(bytes memory _preBytes, bytes memory _postBytes) - internal - pure - returns (bool) - { + function equal( + bytes memory _preBytes, + bytes memory _postBytes + ) internal pure returns (bool) { bool success = true; assembly { @@ -453,9 +446,9 @@ library BytesLib { for { let cc := add(_postBytes, 0x20) + } eq(add(lt(mc, end), cb), 2) { // the next line is the loop condition: // while(uint(mc < end) + cb == 2) - } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { @@ -476,11 +469,9 @@ library BytesLib { return success; } - function toBytes32(bytes memory _source) - internal - pure - returns (bytes32 result) - { + function toBytes32( + bytes memory _source + ) internal pure returns (bytes32 result) { if (_source.length == 0) { return 0x0; } diff --git a/solidity/random-beacon/contracts/libraries/Groups.sol b/solidity/random-beacon/contracts/libraries/Groups.sol index 0c9d6e64d9..0853f27311 100644 --- a/solidity/random-beacon/contracts/libraries/Groups.sol +++ b/solidity/random-beacon/contracts/libraries/Groups.sol @@ -57,10 +57,10 @@ library Groups { /// must be called first for a public key of a group added with /// `addGroup` function. /// @param groupPubKey Candidate group public key - function validatePublicKey(Data storage self, bytes calldata groupPubKey) - internal - view - { + function validatePublicKey( + Data storage self, + bytes calldata groupPubKey + ) internal view { require(groupPubKey.length == 128, "Invalid length of the public key"); bytes32 groupPubKeyHash = keccak256(groupPubKey); @@ -117,7 +117,7 @@ library Groups { self, self.groupsRegistry[self.expiredGroupOffset] ) < - block.number + block.number ) { self.expiredGroupOffset++; } @@ -185,10 +185,10 @@ library Groups { /// is updated. At least one active group needs to be present for this /// function to succeed. /// @param seed Random number used as a group selection seed. - function selectGroup(Data storage self, uint256 seed) - internal - returns (uint64) - { + function selectGroup( + Data storage self, + uint256 seed + ) internal returns (uint64) { expireOldGroups(self); require(numberOfActiveGroups(self) > 0, "No active groups"); @@ -208,89 +208,81 @@ library Groups { } /// @notice Checks if group with the given index is terminated. - function isGroupTerminated(Data storage self, uint64 groupId) - internal - view - returns (bool) - { + function isGroupTerminated( + Data storage self, + uint64 groupId + ) internal view returns (bool) { return self.groupsData[self.groupsRegistry[groupId]].terminated; } /// @notice Gets the cutoff time until which the given group is considered /// to be active assuming it hasn't been terminated before. - function groupLifetimeOf(Data storage self, bytes32 groupPubKeyHash) - internal - view - returns (uint256) - { + function groupLifetimeOf( + Data storage self, + bytes32 groupPubKeyHash + ) internal view returns (uint256) { return self.groupsData[groupPubKeyHash].registrationBlockNumber + self.groupLifetime; } /// @notice Checks if group with the given index is active and non-terminated. - function isGroupActive(Data storage self, uint64 groupId) - internal - view - returns (bool) - { + function isGroupActive( + Data storage self, + uint64 groupId + ) internal view returns (bool) { return groupLifetimeOf(self, self.groupsRegistry[groupId]) >= - block.number && + block.number && !isGroupTerminated(self, groupId); } - function getGroup(Data storage self, uint64 groupId) - internal - view - returns (Group storage) - { + function getGroup( + Data storage self, + uint64 groupId + ) internal view returns (Group storage) { return self.groupsData[self.groupsRegistry[groupId]]; } - function getGroup(Data storage self, bytes memory groupPubKey) - internal - view - returns (Group storage) - { + function getGroup( + Data storage self, + bytes memory groupPubKey + ) internal view returns (Group storage) { return self.groupsData[keccak256(groupPubKey)]; } /// @notice Gets the number of active groups. Expired and terminated /// groups are not counted as active. - function numberOfActiveGroups(Data storage self) - internal - view - returns (uint64) - { + function numberOfActiveGroups( + Data storage self + ) internal view returns (uint64) { if (self.groupsRegistry.length == 0) { return 0; } - uint256 activeGroups = self.groupsRegistry.length - - self.expiredGroupOffset - - self.activeTerminatedGroups.length; + uint256 activeGroups = + self.groupsRegistry.length - + self.expiredGroupOffset - + self.activeTerminatedGroups.length; return uint64(activeGroups); } /// @notice Evaluates the shift of a selected group index based on the number /// of expired groups. - function shiftByExpiredGroups(Data storage self, uint64 selectedIndex) - internal - view - returns (uint64) - { + function shiftByExpiredGroups( + Data storage self, + uint64 selectedIndex + ) internal view returns (uint64) { return self.expiredGroupOffset + selectedIndex; } /// @notice Evaluates the shift of a selected group index based on the number /// of non-expired but terminated groups. - function shiftByTerminatedGroups(Data storage self, uint64 selectedIndex) - internal - view - returns (uint64) - { + function shiftByTerminatedGroups( + Data storage self, + uint64 selectedIndex + ) internal view returns (uint64) { uint64 shiftedIndex = selectedIndex; for (uint64 i = 0; i < self.activeTerminatedGroups.length; i++) { if (self.activeTerminatedGroups[i] <= shiftedIndex) { diff --git a/solidity/random-beacon/contracts/libraries/ModUtils.sol b/solidity/random-beacon/contracts/libraries/ModUtils.sol index 51f0173fe0..713690c379 100644 --- a/solidity/random-beacon/contracts/libraries/ModUtils.sol +++ b/solidity/random-beacon/contracts/libraries/ModUtils.sol @@ -97,7 +97,7 @@ library ModUtils { return x; } - gs = modExp(g, uint256(2)**(r - m - 1), p); + gs = modExp(g, uint256(2) ** (r - m - 1), p); g = (gs * gs) % p; x = (x * gs) % p; b = (b * g) % p; diff --git a/solidity/random-beacon/contracts/libraries/Relay.sol b/solidity/random-beacon/contracts/libraries/Relay.sol index c589f854dc..daed3eebd4 100644 --- a/solidity/random-beacon/contracts/libraries/Relay.sol +++ b/solidity/random-beacon/contracts/libraries/Relay.sol @@ -168,11 +168,9 @@ library Relay { /// @dev Must be used when a soft timeout was hit. /// @return Amount by which group members should be slashed /// in case the relay entry was submitted after the soft timeout. - function calculateSlashingAmount(Data storage self) - internal - view - returns (uint96) - { + function calculateSlashingAmount( + Data storage self + ) internal view returns (uint96) { uint256 softTimeout = softTimeoutBlock(self); if (block.number > softTimeout) { @@ -222,16 +220,17 @@ library Relay { ) internal { require(!isRequestInProgress(self), "Relay request in progress"); - self - .relayEntrySubmissionFailureSlashingAmount = newRelayEntrySubmissionFailureSlashingAmount; + self.relayEntrySubmissionFailureSlashingAmount = + newRelayEntrySubmissionFailureSlashingAmount; } /// @notice Retries the current relay request in case a relay entry /// timeout was reported. /// @param newGroupId ID of the group chosen to retry the current request. - function retryOnEntryTimeout(Data storage self, uint64 newGroupId) - internal - { + function retryOnEntryTimeout( + Data storage self, + uint64 newGroupId + ) internal { require(hasRequestTimedOut(self), "Relay request did not time out"); uint64 currentRequestId = self.currentRequestID; @@ -266,23 +265,19 @@ library Relay { /// @notice Returns whether a relay entry request is currently in progress. /// @return True if there is a request in progress. False otherwise. - function isRequestInProgress(Data storage self) - internal - view - returns (bool) - { + function isRequestInProgress( + Data storage self + ) internal view returns (bool) { return self.currentRequestID != 0; } /// @notice Returns whether the current relay request has timed out. /// @return True if the request timed out. False otherwise. - function hasRequestTimedOut(Data storage self) - internal - view - returns (bool) - { - uint256 _relayEntryTimeout = self.relayEntrySoftTimeout + - self.relayEntryHardTimeout; + function hasRequestTimedOut( + Data storage self + ) internal view returns (bool) { + uint256 _relayEntryTimeout = + self.relayEntrySoftTimeout + self.relayEntryHardTimeout; return isRequestInProgress(self) && @@ -291,11 +286,9 @@ library Relay { /// @notice Calculates soft timeout block for the pending relay request. /// @return The soft timeout block - function softTimeoutBlock(Data storage self) - internal - view - returns (uint256) - { + function softTimeoutBlock( + Data storage self + ) internal view returns (uint256) { return self.currentRequestStartBlock + self.relayEntrySoftTimeout; } } diff --git a/solidity/random-beacon/contracts/test/CallbackContractStub.sol b/solidity/random-beacon/contracts/test/CallbackContractStub.sol index 322a5cac68..37fdf49192 100644 --- a/solidity/random-beacon/contracts/test/CallbackContractStub.sol +++ b/solidity/random-beacon/contracts/test/CallbackContractStub.sol @@ -10,10 +10,10 @@ contract CallbackContractStub is IRandomBeaconConsumer { uint256 public blockNumber; bool public shouldFail; - function __beaconCallback(uint256 _lastEntry, uint256 _blockNumber) - external - override - { + function __beaconCallback( + uint256 _lastEntry, + uint256 _blockNumber + ) external override { if (shouldFail) { revert("error"); } diff --git a/solidity/random-beacon/contracts/test/GroupsStub.sol b/solidity/random-beacon/contracts/test/GroupsStub.sol index 773c0e2e57..23acace457 100644 --- a/solidity/random-beacon/contracts/test/GroupsStub.sol +++ b/solidity/random-beacon/contracts/test/GroupsStub.sol @@ -14,9 +14,10 @@ contract GroupsStub { groups.validatePublicKey(groupPubKey); } - function addGroup(bytes calldata groupPubKey, bytes32 membersHash) - external - { + function addGroup( + bytes calldata groupPubKey, + bytes32 membersHash + ) external { groups.addGroup(groupPubKey, membersHash); } @@ -40,20 +41,16 @@ contract GroupsStub { return groups.numberOfActiveGroups(); } - function getGroup(bytes memory groupPubKey) - external - view - returns (Groups.Group memory) - { + function getGroup( + bytes memory groupPubKey + ) external view returns (Groups.Group memory) { return groups.getGroup(groupPubKey); } // group id is an index in the groups.groupsRegistry array - function getGroupById(uint64 groupId) - external - view - returns (Groups.Group memory) - { + function getGroupById( + uint64 groupId + ) external view returns (Groups.Group memory) { return groups.getGroup(groupId); } diff --git a/solidity/random-beacon/contracts/test/MockContract.sol b/solidity/random-beacon/contracts/test/MockContract.sol index 97bf06c1f9..3b5e8b3085 100644 --- a/solidity/random-beacon/contracts/test/MockContract.sol +++ b/solidity/random-beacon/contracts/test/MockContract.sol @@ -272,20 +272,18 @@ contract MockContract { /// @notice Marks selectors that must never be recorded. The helper calls /// this once with every `view` and `pure` function of the mocked /// ABI. - function __mock__setNonRecordingSelectors(bytes4[] calldata selectors) - external - { + function __mock__setNonRecordingSelectors( + bytes4[] calldata selectors + ) external { for (uint256 i = 0; i < selectors.length; i++) { _state().nonRecording[selectors[i]] = true; } } /// @notice Whether a selector is excluded from recording. - function __mock__isNonRecording(bytes4 selector) - external - view - returns (bool) - { + function __mock__isNonRecording( + bytes4 selector + ) external view returns (bool) { return _state().nonRecording[selector]; } @@ -324,20 +322,16 @@ contract MockContract { } /// @notice Raw calldata of the i-th call recorded, across all selectors. - function __mock__callAt(uint256 index) - external - view - returns (bytes memory) - { + function __mock__callAt( + uint256 index + ) external view returns (bytes memory) { return _state().receivedCalls[index]; } /// @notice Number of calls recorded for one selector. - function __mock__callCountForSelector(bytes4 selector) - external - view - returns (uint256 count) - { + function __mock__callCountForSelector( + bytes4 selector + ) external view returns (uint256 count) { uint256 total = _state().receivedCalls.length; for (uint256 i = 0; i < total; i++) { if (__mock__selectorOf(_state().receivedCalls[i]) == selector) { @@ -348,11 +342,10 @@ contract MockContract { /// @notice Raw calldata of the i-th call recorded for one selector. /// @notice msg.value of the i-th call recorded for one selector. - function __mock__callValueForSelectorAt(bytes4 selector, uint256 index) - external - view - returns (uint256) - { + function __mock__callValueForSelectorAt( + bytes4 selector, + uint256 index + ) external view returns (uint256) { uint256 seen = 0; uint256 total = _state().receivedCalls.length; @@ -368,11 +361,10 @@ contract MockContract { revert("MockContract: call index out of range"); } - function __mock__callForSelectorAt(bytes4 selector, uint256 index) - external - view - returns (bytes memory) - { + function __mock__callForSelectorAt( + bytes4 selector, + uint256 index + ) external view returns (bytes memory) { uint256 seen = 0; uint256 total = _state().receivedCalls.length; @@ -389,11 +381,9 @@ contract MockContract { } /// @dev Leading four bytes of `callData`, or zero if it is shorter. - function __mock__selectorOf(bytes memory callData) - public - pure - returns (bytes4 selector) - { + function __mock__selectorOf( + bytes memory callData + ) public pure returns (bytes4 selector) { if (callData.length < 4) { return bytes4(0); } @@ -445,11 +435,9 @@ contract MockContract { /// @dev Resolves an incoming call against the three layers, most specific /// first. Reverts here if the matched response is a configured revert. - function __mock__responseFor(bytes memory callData) - private - view - returns (bytes memory) - { + function __mock__responseFor( + bytes memory callData + ) private view returns (bytes memory) { Response storage exact = _state().responseByCalldata[ keccak256(callData) ]; @@ -499,11 +487,9 @@ contract MockContract { } } - function __mock__respond(Response storage response) - private - view - returns (bytes memory) - { + function __mock__respond( + Response storage response + ) private view returns (bytes memory) { if (response.behaviour == Behaviour.Revert) { bytes memory revertData = response.data; diff --git a/solidity/random-beacon/contracts/test/MockTargetConsumer.sol b/solidity/random-beacon/contracts/test/MockTargetConsumer.sol index 45c30efae4..eb1232ad4a 100644 --- a/solidity/random-beacon/contracts/test/MockTargetConsumer.sol +++ b/solidity/random-beacon/contracts/test/MockTargetConsumer.sol @@ -33,27 +33,21 @@ contract MockTargetConsumer { } /// @dev STATICCALL: `readValue` is `view` on the interface. - function readValueThroughStaticCall(uint256 key) - external - view - returns (uint256) - { + function readValueThroughStaticCall( + uint256 key + ) external view returns (uint256) { return target.readValue(key); } - function readInfoThroughStaticCall(uint256 key) - external - view - returns (IMockTarget.Info memory) - { + function readInfoThroughStaticCall( + uint256 key + ) external view returns (IMockTarget.Info memory) { return target.readInfo(key); } - function readPairThroughStaticCall(uint256 key) - external - view - returns (uint32, uint32) - { + function readPairThroughStaticCall( + uint256 key + ) external view returns (uint32, uint32) { return target.readPair(key); } } diff --git a/solidity/random-beacon/contracts/test/RandomBeaconStub.sol b/solidity/random-beacon/contracts/test/RandomBeaconStub.sol index 21554d7dbc..70432ef62e 100644 --- a/solidity/random-beacon/contracts/test/RandomBeaconStub.sol +++ b/solidity/random-beacon/contracts/test/RandomBeaconStub.sol @@ -1,7 +1,7 @@ pragma solidity ^0.8.6; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@keep-network/sortition-pools/contracts/SortitionPool.sol"; +import "../legacy/sortition/SortitionPool.sol"; import "../RandomBeacon.sol"; import "../libraries/Callback.sol"; import "../libraries/Groups.sol"; diff --git a/solidity/random-beacon/contracts/test/TestAltBn128.sol b/solidity/random-beacon/contracts/test/TestAltBn128.sol index c71f81aa8a..991afbb5e1 100644 --- a/solidity/random-beacon/contracts/test/TestAltBn128.sol +++ b/solidity/random-beacon/contracts/test/TestAltBn128.sol @@ -284,33 +284,29 @@ contract TestAltBn128 { function runVerifySignatureTest() public view { // "hello!" message hashed to G1 point using G1HashToPoint from keep-core/pkg/bls/altbn128.go AltBn128.G1Point memory message; - message - .x = 5634139805531803244211629196316241342481813136353842610045004964364565232495; - message - .y = 12935759374343796368049060881302766596646163398265176009268480404372697203641; + message.x = + 5634139805531803244211629196316241342481813136353842610045004964364565232495; + message.y = + 12935759374343796368049060881302766596646163398265176009268480404372697203641; // G1 point hashed message above signed with private key = 123 using ScalarMult // from go-ethereum/crypto/bn256/cloudflare library AltBn128.G1Point memory signature; - signature - .x = 656647519899395589093611455851658769732922739162315270379466002146796568126; - signature - .y = 5296675831567268847773497112983742440203412208935796410329912816023128374551; + signature.x = + 656647519899395589093611455851658769732922739162315270379466002146796568126; + signature.y = + 5296675831567268847773497112983742440203412208935796410329912816023128374551; // G2 point representing public key for private key = 123 AltBn128.G2Point memory publicKey; - publicKey - .x - .x = 14066454060412929535985836631817650877381034334390275410072431082437297539867; - publicKey - .x - .y = 19276105129625393659655050515259006463014579919681138299520812914148935621072; - publicKey - .y - .x = 10109651107942685361120988628892759706059655669161016107907096760613704453218; - publicKey - .y - .y = 12642665914920339463975152321804664028480770144655934937445922690262428344269; + publicKey.x.x = + 14066454060412929535985836631817650877381034334390275410072431082437297539867; + publicKey.x.y = + 19276105129625393659655050515259006463014579919681138299520812914148935621072; + publicKey.y.x = + 10109651107942685361120988628892759706059655669161016107907096760613704453218; + publicKey.y.y = + 12642665914920339463975152321804664028480770144655934937445922690262428344269; bool result = AltBn128.pairing( signature, @@ -402,36 +398,30 @@ contract TestAltBn128 { } } - function publicG1Unmarshal(bytes memory m) - public - pure - returns (AltBn128.G1Point memory) - { + function publicG1Unmarshal( + bytes memory m + ) public pure returns (AltBn128.G1Point memory) { return AltBn128.g1Unmarshal(m); } - function publicG2Unmarshal(bytes memory m) - public - pure - returns (AltBn128.G2Point memory) - { + function publicG2Unmarshal( + bytes memory m + ) public pure returns (AltBn128.G2Point memory) { return AltBn128.g2Unmarshal(m); } - function publicG2Decompress(bytes memory m) - public - pure - returns (AltBn128.G2Point memory) - { + function publicG2Decompress( + bytes memory m + ) public pure returns (AltBn128.G2Point memory) { return AltBn128.g2Decompress(m); } function runG1PointMarshalingTest() public pure { AltBn128.G1Point memory point; - point - .x = 656647519899395589093611455851658769732922739162315270379466002146796568126; - point - .y = 5296675831567268847773497112983742440203412208935796410329912816023128374551; + point.x = + 656647519899395589093611455851658769732922739162315270379466002146796568126; + point.y = + 5296675831567268847773497112983742440203412208935796410329912816023128374551; bytes memory marshaledPoint = AltBn128.g1Marshal(point); AltBn128.G1Point memory actual = AltBn128.g1Unmarshal(marshaledPoint); diff --git a/solidity/random-beacon/contracts/test/TestModUtils.sol b/solidity/random-beacon/contracts/test/TestModUtils.sol index b4bec62ed0..c07d85fbaf 100644 --- a/solidity/random-beacon/contracts/test/TestModUtils.sol +++ b/solidity/random-beacon/contracts/test/TestModUtils.sol @@ -82,7 +82,7 @@ contract TestModUtils { // a simple test require(a.modExp(2, 5) == 1, ""); // test for overflow - (2 ^ 256 - 1) ^ 2 % alt_bn128_P - uint256 almostOverflow = (2**256 - 1); + uint256 almostOverflow = (2 ** 256 - 1); uint256 result = almostOverflow.modExp( 2, 21888242871839275222246405745257275088696311157297823662689037894645226208583 diff --git a/solidity/random-beacon/deploy/01_deploy_reimbursement_pool.ts b/solidity/random-beacon/deploy/01_deploy_reimbursement_pool.ts index 9832d42288..eb328e5a46 100644 --- a/solidity/random-beacon/deploy/01_deploy_reimbursement_pool.ts +++ b/solidity/random-beacon/deploy/01_deploy_reimbursement_pool.ts @@ -1,3 +1,5 @@ +import waitForConfirmations from "../utils/wait-for-confirmations" + import type { HardhatRuntimeEnvironment } from "hardhat/types" import type { DeployFunction } from "hardhat-deploy/types" @@ -16,11 +18,14 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { }) if (hre.network.tags.etherscan) { - await hre.ethers.provider.waitForTransaction( - ReimbursementPool.transactionHash, - 2, - 300000 - ) + if (ReimbursementPool.transactionHash) { + await waitForConfirmations( + hre.ethers.provider, + ReimbursementPool.transactionHash, + 2, + 300000, + ) + } await helpers.etherscan.verify(ReimbursementPool) } diff --git a/solidity/random-beacon/deploy/02_deploy_beacon_sortition_pool.ts b/solidity/random-beacon/deploy/02_deploy_beacon_sortition_pool.ts index 12ce503e42..5417b40c0e 100644 --- a/solidity/random-beacon/deploy/02_deploy_beacon_sortition_pool.ts +++ b/solidity/random-beacon/deploy/02_deploy_beacon_sortition_pool.ts @@ -1,3 +1,5 @@ +import waitForConfirmations from "../utils/wait-for-confirmations" + import type { HardhatRuntimeEnvironment } from "hardhat/types" import type { DeployFunction } from "hardhat-deploy/types" @@ -23,15 +25,18 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { "BeaconSortitionPool", { from: deployer, log: true, waitConfirmations: 1 }, "transferChaosnetOwnerRole", - chaosnetOwner + chaosnetOwner, ) if (hre.network.tags.etherscan) { - await hre.ethers.provider.waitForTransaction( - BeaconSortitionPool.transactionHash, - 2, - 300000 - ) + if (BeaconSortitionPool.transactionHash) { + await waitForConfirmations( + hre.ethers.provider, + BeaconSortitionPool.transactionHash, + 2, + 300000, + ) + } await helpers.etherscan.verify(BeaconSortitionPool) } diff --git a/solidity/random-beacon/deploy/03_deploy_beacon_dkg_validator.ts b/solidity/random-beacon/deploy/03_deploy_beacon_dkg_validator.ts index ae34ed752a..e4af9bcec3 100644 --- a/solidity/random-beacon/deploy/03_deploy_beacon_dkg_validator.ts +++ b/solidity/random-beacon/deploy/03_deploy_beacon_dkg_validator.ts @@ -1,3 +1,5 @@ +import waitForConfirmations from "../utils/wait-for-confirmations" + import type { HardhatRuntimeEnvironment } from "hardhat/types" import type { DeployFunction } from "hardhat-deploy/types" @@ -15,11 +17,14 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { }) if (hre.network.tags.etherscan) { - await hre.ethers.provider.waitForTransaction( - BeaconDkgValidator.transactionHash, - 2, - 300000 - ) + if (BeaconDkgValidator.transactionHash) { + await waitForConfirmations( + hre.ethers.provider, + BeaconDkgValidator.transactionHash, + 2, + 300000, + ) + } await helpers.etherscan.verify(BeaconDkgValidator) } diff --git a/solidity/random-beacon/deploy/04_deploy_random_beacon.ts b/solidity/random-beacon/deploy/04_deploy_random_beacon.ts index 9ff3a57b6f..77ff2c7a58 100644 --- a/solidity/random-beacon/deploy/04_deploy_random_beacon.ts +++ b/solidity/random-beacon/deploy/04_deploy_random_beacon.ts @@ -1,3 +1,5 @@ +import waitForConfirmations from "../utils/wait-for-confirmations" + import type { HardhatRuntimeEnvironment } from "hardhat/types" import type { DeployFunction, DeployOptions } from "hardhat-deploy/types" @@ -21,14 +23,14 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const BeaconAuthorization = await deployments.deploy( "BeaconAuthorization", - deployOptions + deployOptions, ) const BeaconDkg = await deployments.deploy("BeaconDkg", deployOptions) const BeaconInactivity = await deployments.deploy( "BeaconInactivity", - deployOptions + deployOptions, ) const RandomBeacon = await deployments.deploy("RandomBeacon", { @@ -55,15 +57,18 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { await helpers.ownable.transferOwnership( "BeaconSortitionPool", RandomBeacon.address, - deployer + deployer, ) if (hre.network.tags.etherscan) { - await hre.ethers.provider.waitForTransaction( - RandomBeacon.transactionHash, - 2, - 300000 - ) + if (RandomBeacon.transactionHash) { + await waitForConfirmations( + hre.ethers.provider, + RandomBeacon.transactionHash, + 2, + 300000, + ) + } await helpers.etherscan.verify(BLS) await helpers.etherscan.verify(BeaconAuthorization) await helpers.etherscan.verify(BeaconDkg) diff --git a/solidity/random-beacon/deploy/05_approve_random_beacon_in_token_staking.ts b/solidity/random-beacon/deploy/05_approve_random_beacon_in_token_staking.ts index 6209a8567a..0095c21ad9 100644 --- a/solidity/random-beacon/deploy/05_approve_random_beacon_in_token_staking.ts +++ b/solidity/random-beacon/deploy/05_approve_random_beacon_in_token_staking.ts @@ -1,14 +1,13 @@ import type { HardhatRuntimeEnvironment } from "hardhat/types" import type { DeployFunction } from "hardhat-deploy/types" -import type { utils } from "ethers" +import type { Interface } from "ethers" // ApplicationStatus enum: NOT_APPROVED=0, APPROVED=1, PAUSED=2, DISABLED=3 -const APPLICATION_STATUS_APPROVED = 1 +const APPLICATION_STATUS_APPROVED = 1n -function ifaceHasFunction(iface: utils.Interface, name: string): boolean { +function ifaceHasFunction(iface: Interface, name: string): boolean { try { - iface.getFunction(name) - return true + return iface.getFunction(name) !== null } catch { return false } @@ -22,10 +21,10 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const RandomBeacon = await deployments.get("RandomBeacon") const TokenStaking = await get("TokenStaking") - const iface = new ethers.utils.Interface(TokenStaking.abi) + const iface = new ethers.Interface(TokenStaking.abi) if (!ifaceHasFunction(iface, "approveApplication")) { hre.deployments.log( - "TokenStaking does not have approveApplication (Threshold TokenStaking); skipping" + "TokenStaking does not have approveApplication (Threshold TokenStaking); skipping", ) return } @@ -34,22 +33,22 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { try { const tokenStakingContract = await ethers.getContractAt( TokenStaking.abi, - TokenStaking.address + TokenStaking.address, ) if (ifaceHasFunction(iface, "applicationInfo")) { const appInfo = await tokenStakingContract.applicationInfo( - RandomBeacon.address + RandomBeacon.address, ) if (appInfo.status === APPLICATION_STATUS_APPROVED) { hre.deployments.log( - "RandomBeacon already approved in TokenStaking; skipping" + "RandomBeacon already approved in TokenStaking; skipping", ) return } } } catch (e) { hre.deployments.log( - `Could not read TokenStaking application status (continuing): ${e}` + `Could not read TokenStaking application status (continuing): ${e}`, ) } @@ -57,7 +56,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { "TokenStaking", { from: deployer, log: true, waitConfirmations: 1 }, "approveApplication", - RandomBeacon.address + RandomBeacon.address, ) } diff --git a/solidity/random-beacon/deploy/06_authorize_random_beacon_in_reimbursement_pool.ts b/solidity/random-beacon/deploy/06_authorize_random_beacon_in_reimbursement_pool.ts index af9b3df3c5..a81c28569a 100644 --- a/solidity/random-beacon/deploy/06_authorize_random_beacon_in_reimbursement_pool.ts +++ b/solidity/random-beacon/deploy/06_authorize_random_beacon_in_reimbursement_pool.ts @@ -12,7 +12,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { "ReimbursementPool", { from: deployer, log: true, waitConfirmations: 1 }, "authorize", - RandomBeacon.address + RandomBeacon.address, ) } diff --git a/solidity/random-beacon/deploy/07_deploy_random_beacon_governance.ts b/solidity/random-beacon/deploy/07_deploy_random_beacon_governance.ts index 95e2b41815..b38064c867 100644 --- a/solidity/random-beacon/deploy/07_deploy_random_beacon_governance.ts +++ b/solidity/random-beacon/deploy/07_deploy_random_beacon_governance.ts @@ -1,3 +1,5 @@ +import waitForConfirmations from "../utils/wait-for-confirmations" + import type { HardhatRuntimeEnvironment } from "hardhat/types" import type { DeployFunction } from "hardhat-deploy/types" @@ -16,15 +18,18 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { args: [RandomBeacon.address, GOVERNANCE_DELAY], log: true, waitConfirmations: 1, - } + }, ) if (hre.network.tags.etherscan) { - await hre.ethers.provider.waitForTransaction( - RandomBeaconGovernance.transactionHash, - 2, - 300000 - ) + if (RandomBeaconGovernance.transactionHash) { + await waitForConfirmations( + hre.ethers.provider, + RandomBeaconGovernance.transactionHash, + 2, + 300000, + ) + } await helpers.etherscan.verify(RandomBeaconGovernance) } diff --git a/solidity/random-beacon/deploy/08_transfer_governance.ts b/solidity/random-beacon/deploy/08_transfer_governance.ts index 31ff6f98a0..b435a5fea6 100644 --- a/solidity/random-beacon/deploy/08_transfer_governance.ts +++ b/solidity/random-beacon/deploy/08_transfer_governance.ts @@ -10,14 +10,14 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { await helpers.ownable.transferOwnership( "RandomBeaconGovernance", governance, - deployer + deployer, ) await deployments.execute( "RandomBeacon", { from: deployer, log: true, waitConfirmations: 1 }, "transferGovernance", - RandomBeaconGovernance.address + RandomBeaconGovernance.address, ) } diff --git a/solidity/random-beacon/deploy/09_deploy_random_beacon_chaosnet.ts b/solidity/random-beacon/deploy/09_deploy_random_beacon_chaosnet.ts index 9828554555..02009e92e7 100644 --- a/solidity/random-beacon/deploy/09_deploy_random_beacon_chaosnet.ts +++ b/solidity/random-beacon/deploy/09_deploy_random_beacon_chaosnet.ts @@ -1,3 +1,5 @@ +import waitForConfirmations from "../utils/wait-for-confirmations" + import type { HardhatRuntimeEnvironment } from "hardhat/types" import type { DeployFunction, DeployOptions } from "hardhat-deploy/types" @@ -15,15 +17,18 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { "RandomBeaconChaosnet", { ...deployOptions, - } + }, ) if (hre.network.tags.etherscan) { - await hre.ethers.provider.waitForTransaction( - RandomBeaconChaosnet.transactionHash, - 2, - 300000 - ) + if (RandomBeaconChaosnet.transactionHash) { + await waitForConfirmations( + hre.ethers.provider, + RandomBeaconChaosnet.transactionHash, + 2, + 300000, + ) + } await helpers.etherscan.verify(RandomBeaconChaosnet) } diff --git a/solidity/random-beacon/eslint.config.mjs b/solidity/random-beacon/eslint.config.mjs new file mode 100644 index 0000000000..bb101bdc8a --- /dev/null +++ b/solidity/random-beacon/eslint.config.mjs @@ -0,0 +1,545 @@ +// Preserve the active non-React rules from the former Thesis/Airbnb config. +// Formatting is checked by Prettier; generated code is excluded below. +import tseslint from "typescript-eslint" +import importPlugin from "eslint-plugin-import-x" +import noOnlyTests from "eslint-plugin-no-only-tests" +import stylistic from "@stylistic/eslint-plugin" +import globals from "globals" + +export default [ + { + ignores: [ + "**/.hardhat/**", + "**/artifacts/**", + "**/build/**", + "**/cache/**", + "**/deployments/**", + "**/export/**", + "**/external/**", + "**/hardhat-dependency-compiler/**", + "**/typechain/**", + "**/export.json", + ], + }, + { + files: ["**/*.{js,cjs,mjs,ts}"], + languageOptions: { ecmaVersion: "latest", globals: globals.node }, + plugins: { + import: importPlugin, + "no-only-tests": noOnlyTests, + "@stylistic": stylistic, + }, + settings: { + "import-x/resolver": { + typescript: { project: "./tsconfig.json" }, + node: true, + }, + "import-x/parsers": { "@typescript-eslint/parser": [".ts"] }, + }, + rules: { + "import/no-extraneous-dependencies": [ + "error", + { + devDependencies: [ + "test/**/*.ts", + "tasks/**/*.ts", + "hardhat.config.ts", + "*.config.mjs", + ".prettierrc.js", + ], + }, + ], + "no-plusplus": [ + "error", + { + allowForLoopAfterthoughts: true, + }, + ], + "import/order": [ + "warn", + { + groups: ["builtin", "external", "parent", "sibling", "index", "type"], + "newlines-between": "always", + warnOnUnassignedImports: false, + }, + ], + "no-param-reassign": [ + "error", + { + props: true, + ignorePropertyModificationsFor: [ + "acc", + "accumulator", + "e", + "ctx", + "context", + "req", + "request", + "res", + "response", + "$scope", + "staticContext", + ], + ignorePropertyModificationsForRegex: ["^immer"], + }, + ], + "no-only-tests/no-only-tests": ["error"], + "no-var": ["error"], + "prefer-const": [ + "error", + { + destructuring: "any", + ignoreReadBeforeAssign: true, + }, + ], + "prefer-rest-params": ["error"], + "prefer-spread": ["error"], + "import/no-unresolved": [ + "error", + { + commonjs: true, + caseSensitive: true, + }, + ], + "import/namespace": ["error"], + "import/default": ["error"], + "import/export": ["error"], + "import/no-named-as-default": ["warn"], + "import/no-named-as-default-member": ["warn"], + "import/no-duplicates": ["warn"], + "import/extensions": [ + "error", + "ignorePackages", + { + js: "never", + mjs: "never", + jsx: "never", + ts: "never", + tsx: "never", + }, + ], + "no-underscore-dangle": [ + "error", + { + allow: ["__REDUX_DEVTOOLS_EXTENSION_COMPOSE__"], + allowAfterThis: false, + allowAfterSuper: false, + enforceInMethodNames: true, + allowAfterThisConstructor: false, + allowFunctionParams: true, + }, + ], + "class-methods-use-this": ["error"], + strict: ["error", "never"], + "import/no-mutable-exports": ["error"], + "import/no-amd": ["error"], + "import/first": ["error"], + "import/newline-after-import": ["error"], + "import/prefer-default-export": ["error"], + "import/no-absolute-path": ["error"], + "import/no-dynamic-require": ["error"], + "import/no-webpack-loader-syntax": ["error"], + "import/no-named-default": ["error"], + "import/no-self-import": ["error"], + "import/no-cycle": [ + "error", + { + ignoreExternal: false, + }, + ], + "import/no-useless-path-segments": [ + "error", + { + commonjs: true, + }, + ], + "arrow-body-style": [ + "error", + "as-needed", + { + requireReturnForObjectLiteral: false, + }, + ], + "no-class-assign": ["error"], + "no-useless-computed-key": ["error"], + "no-useless-rename": [ + "error", + { + ignoreDestructuring: false, + ignoreImport: false, + ignoreExport: false, + }, + ], + "object-shorthand": [ + "error", + "always", + { + ignoreConstructors: false, + avoidQuotes: true, + }, + ], + "prefer-arrow-callback": [ + "error", + { + allowNamedFunctions: false, + allowUnboundThis: true, + }, + ], + "prefer-destructuring": [ + "error", + { + VariableDeclarator: { + array: false, + object: true, + }, + AssignmentExpression: { + array: true, + object: false, + }, + }, + { + enforceForRenamedProperties: false, + }, + ], + "prefer-numeric-literals": ["error"], + "prefer-template": ["error"], + "require-yield": ["error"], + "symbol-description": ["error"], + "no-delete-var": ["error"], + "no-label-var": ["error"], + "no-restricted-globals": ["error", "isFinite", "isNaN"], + "no-shadow-restricted-names": ["error"], + "no-undef-init": ["error"], + "func-names": ["warn"], + "new-cap": [ + "error", + { + newIsCap: true, + newIsCapExceptions: [], + capIsNew: false, + capIsNewExceptions: [ + "Immutable.Map", + "Immutable.Set", + "Immutable.List", + ], + properties: true, + }, + ], + "no-bitwise": ["error"], + "no-continue": ["error"], + "no-lonely-if": ["error"], + "no-multi-assign": ["error"], + "no-nested-ternary": ["error"], + "no-restricted-syntax": [ + "error", + { + selector: "ForInStatement", + }, + { + selector: "ForOfStatement", + }, + { + selector: "LabeledStatement", + }, + { + selector: "WithStatement", + }, + ], + "no-unneeded-ternary": [ + "error", + { + defaultAssignment: false, + }, + ], + "one-var": ["error", "never"], + "operator-assignment": ["error", "always"], + "prefer-object-spread": ["error"], + "global-require": ["error"], + "no-buffer-constructor": ["error"], + "no-new-require": ["error"], + "no-path-concat": ["error"], + "for-direction": ["error"], + "no-async-promise-executor": ["error"], + // ecdsa uses ["error"]; this package intentionally keeps it off + "no-await-in-loop": "off", + "grouped-accessor-pairs": ["error"], + "no-constructor-return": ["error"], + "no-dupe-else-if": ["error"], + "no-new-func": ["error"], + "no-promise-executor-return": ["error"], + "no-unreachable-loop": ["error"], + "no-unsafe-optional-chaining": [ + "error", + { disallowArithmeticOperators: true }, + ], + "no-useless-backreference": ["error"], + "no-compare-neg-zero": ["error"], + "no-cond-assign": ["error", "always"], + "no-console": ["warn"], + "no-constant-condition": ["warn"], + "no-control-regex": ["error"], + "no-debugger": ["error"], + "no-duplicate-case": ["error"], + "no-empty": ["error"], + "no-empty-character-class": ["error"], + "no-ex-assign": ["error"], + "no-extra-boolean-cast": ["error"], + "no-inner-declarations": ["error"], + "no-invalid-regexp": ["error"], + "no-irregular-whitespace": ["error"], + "no-misleading-character-class": ["error"], + "no-prototype-builtins": ["error"], + "no-regex-spaces": ["error"], + "no-sparse-arrays": ["error"], + "no-template-curly-in-string": ["error"], + "no-unsafe-finally": ["error"], + "use-isnan": ["error"], + "array-callback-return": [ + "error", + { + allowImplicit: true, + checkForEach: false, + }, + ], + "block-scoped-var": ["error"], + "consistent-return": ["error"], + "default-case": [ + "error", + { + commentPattern: "^no default$", + }, + ], + eqeqeq: [ + "error", + "always", + { + null: "ignore", + }, + ], + "guard-for-in": ["error"], + "max-classes-per-file": ["error", 1], + "no-alert": ["warn"], + "no-caller": ["error"], + "no-case-declarations": ["error"], + "no-else-return": [ + "error", + { + allowElseIf: false, + }, + ], + "no-empty-pattern": ["error"], + "no-eval": ["error"], + "no-extend-native": ["error"], + "no-extra-bind": ["error"], + "no-extra-label": ["error"], + "no-fallthrough": ["error"], + "no-global-assign": [ + "error", + { + exceptions: [], + }, + ], + "no-iterator": ["error"], + "no-labels": [ + "error", + { + allowLoop: false, + allowSwitch: false, + }, + ], + "no-lone-blocks": ["error"], + "no-multi-str": ["error"], + "no-new": ["error"], + "no-new-wrappers": ["error"], + "no-octal": ["error"], + "no-octal-escape": ["error"], + "no-proto": ["error"], + "no-restricted-properties": [ + "error", + { + object: "arguments", + property: "callee", + }, + { + object: "global", + property: "isFinite", + }, + { + object: "self", + property: "isFinite", + }, + { + object: "window", + property: "isFinite", + }, + { + object: "global", + property: "isNaN", + }, + { + object: "self", + property: "isNaN", + }, + { + object: "window", + property: "isNaN", + }, + { + property: "__defineGetter__", + }, + { + property: "__defineSetter__", + }, + { + object: "Math", + property: "pow", + }, + ], + "no-return-assign": ["error", "always"], + "no-script-url": ["error"], + "no-self-assign": [ + "error", + { + props: true, + }, + ], + "no-self-compare": ["error"], + "no-sequences": ["error"], + "no-unused-labels": ["error"], + "no-useless-catch": ["error"], + "no-useless-concat": ["error"], + "no-useless-escape": ["error"], + "no-useless-return": ["error"], + "no-void": ["error"], + "no-with": ["error"], + "prefer-promise-reject-errors": [ + "error", + { + allowEmptyReject: true, + }, + ], + radix: ["error"], + "vars-on-top": ["error"], + yoda: ["error"], + "no-object-constructor": ["error"], + "@stylistic/spaced-comment": [ + "error", + "always", + { + line: { + exceptions: ["-", "+"], + markers: ["=", "!", "/"], + }, + block: { + exceptions: ["-", "+"], + markers: ["=", "!", ":", "::"], + balanced: true, + }, + }, + ], + "@stylistic/lines-between-class-members": [ + "error", + "always", + { + exceptAfterSingleLine: false, + }, + ], + }, + }, + { + files: ["**/*.ts"], + languageOptions: { + parser: tseslint.parser, + sourceType: "module", + parserOptions: { + project: "./.tsconfig-eslint.json", + tsconfigRootDir: import.meta.dirname, + }, + }, + plugins: { "@typescript-eslint": tseslint.plugin }, + rules: { + "@typescript-eslint/no-explicit-any": ["warn"], + "@typescript-eslint/consistent-type-imports": ["warn"], + "@typescript-eslint/adjacent-overload-signatures": ["error"], + "@typescript-eslint/ban-ts-comment": ["error"], + "@typescript-eslint/explicit-module-boundary-types": ["warn"], + "@typescript-eslint/no-array-constructor": ["error"], + "@typescript-eslint/no-empty-function": [ + "error", + { + allow: ["arrowFunctions", "functions", "methods"], + }, + ], + "@typescript-eslint/no-extra-non-null-assertion": ["error"], + "@typescript-eslint/no-inferrable-types": ["error"], + "@typescript-eslint/no-misused-new": ["error"], + "@typescript-eslint/no-namespace": ["error"], + "@typescript-eslint/no-non-null-asserted-optional-chain": ["error"], + "@typescript-eslint/no-non-null-assertion": ["warn"], + "@typescript-eslint/no-this-alias": ["error"], + "@typescript-eslint/no-unused-vars": [ + "warn", + { + vars: "all", + args: "after-used", + ignoreRestSiblings: true, + }, + ], + "@typescript-eslint/prefer-as-const": ["error"], + "@typescript-eslint/prefer-namespace-keyword": ["error"], + "@typescript-eslint/triple-slash-reference": ["error"], + "@typescript-eslint/naming-convention": [ + "error", + { + selector: "variable", + format: ["camelCase", "PascalCase", "UPPER_CASE"], + }, + { + selector: "function", + format: ["camelCase", "PascalCase"], + }, + { + selector: "typeLike", + format: ["PascalCase"], + }, + ], + "@typescript-eslint/dot-notation": [ + "error", + { + allowKeywords: true, + allowPattern: "", + allowPrivateClassPropertyAccess: false, + allowProtectedClassPropertyAccess: false, + allowIndexSignaturePropertyAccess: false, + }, + ], + "@typescript-eslint/no-dupe-class-members": ["error"], + "@typescript-eslint/no-implied-eval": ["error"], + "@typescript-eslint/no-loop-func": ["error"], + "@typescript-eslint/no-redeclare": ["error"], + "@typescript-eslint/no-shadow": ["error"], + "@typescript-eslint/no-unused-expressions": [ + "error", + { + allowShortCircuit: false, + allowTernary: false, + allowTaggedTemplates: false, + enforceForJSX: false, + }, + ], + "@typescript-eslint/no-useless-constructor": ["error"], + "@typescript-eslint/return-await": ["error"], + "@typescript-eslint/no-empty-object-type": ["error"], + "@typescript-eslint/only-throw-error": ["error"], + "@typescript-eslint/no-require-imports": [ + "error", + { allowAsImport: true }, + ], + "@typescript-eslint/no-unsafe-function-type": ["error"], + "@typescript-eslint/no-wrapper-object-types": ["error"], + "@typescript-eslint/default-param-last": ["error"], + }, + }, + { files: ["test/**/*.ts"], languageOptions: { globals: globals.mocha } }, + { files: ["**/*.{js,cjs}"], languageOptions: { sourceType: "commonjs" } }, +] diff --git a/solidity/random-beacon/export-baseline.sha256 b/solidity/random-beacon/export-baseline.sha256 new file mode 100644 index 0000000000..a9c97f1254 --- /dev/null +++ b/solidity/random-beacon/export-baseline.sha256 @@ -0,0 +1,76 @@ +a7fe677b015af93102a99a276263bb1e8cbc84a06055c6dc98a636b681750083 export.json +802ed29e9e11d143f0999aa9307dd5f3be7b4a066b816fe888fcc65f1b70f602 export/artifacts/@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol/SafeERC20Upgradeable.json +612d312256c5262e9f7ce30990de06bfad985505e87224ee5f5bef63087e3e83 export/artifacts/@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol/AddressUpgradeable.json +cd5090034284cbc291e950b41efcef746e81b75eafcc254a41e8585eb2833ec2 export/artifacts/@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol/MathUpgradeable.json +8e4979afd0be42bb1df3f0b168944dc25bb5c0b4c2c849718ea59a16dec96c59 export/artifacts/@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol/SafeCastUpgradeable.json +dec8ea0c4388915e8d0955fcae01c17dcbafa4e1efcfa237732313f0ceefb731 export/artifacts/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol/SafeERC20.json +6828bb03da91dd2a1b87e8517047e293691661bc78993b5cec4b49eb8f22cd39 export/artifacts/@openzeppelin/contracts/utils/Address.sol/Address.json +28ef2255b53165bb9881e5399b8863719c031a4d13a91c3e2d97214821875eca export/artifacts/@openzeppelin/contracts/utils/Strings.sol/Strings.json +ea4a07de9c2160d22d919282e2f971c0ca8ff239efbf5a4d3bdbe730d97d64f2 export/artifacts/@openzeppelin/contracts/utils/cryptography/ECDSA.sol/ECDSA.json +3a118189746049dffeb6041d40207779ef42bf290e3da8406dceaef073abc071 export/artifacts/@openzeppelin/contracts/utils/math/Math.sol/Math.json +792de70975851edca99112b4c7b6cde7ee4c9c2cc8d3f3ce2fc8e77b542090b2 export/artifacts/@openzeppelin/contracts/utils/math/SafeCast.sol/SafeCast.json +50e8b3885973aa92ab30767ffe3f5d4aa366ed1cbb4fea246600e0d622cd7c11 export/artifacts/@thesis/solidity-contracts/contracts/token/ERC20WithPermit.sol/ERC20WithPermit.json +b8dbac68eeec0bf0d07130faf5d9bf80da643d0bbcad739839c1546d931a7090 export/artifacts/@thesis/solidity-contracts/contracts/token/MisfundRecovery.sol/MisfundRecovery.json +b09e63de02efc682ed9a0f71056bc79b5e338fb24df2cf48e082f7dbefb9bb3d export/artifacts/@threshold-network/solidity-contracts/contracts/staking/TokenStaking.sol/TokenStaking.json +a8e61fa781f4c99024ba7ca6b40552b0a00d4aa22930963968b7c5d16dc90af3 export/artifacts/@threshold-network/solidity-contracts/contracts/token/T.sol/T.json +74a7677ccb441fcbdf1086f8b6ff4c946a262cf66175b4e8fd5b7de5c2156b50 export/artifacts/@threshold-network/solidity-contracts/contracts/utils/PercentUtils.sol/PercentUtils.json +920396ad3fd010c3e007c615a640e18fdd2a0eddb1be89ca5bfc76c7c2a41b2a export/artifacts/@threshold-network/solidity-contracts/contracts/utils/SafeTUpgradeable.sol/SafeTUpgradeable.json +c245e3639475035311102190c2c478a4aeacca43eb8e8b290603948de6cebf60 export/artifacts/@threshold-network/solidity-contracts/contracts/vending/VendingMachine.sol/VendingMachine.json +37eab0e35378b2a79038118aa0936b414229aa29d019e30daea18605d5507a2b export/artifacts/contracts/BeaconDkgValidator.sol/BeaconDkgValidator.json +a6cc16898efe699bca4f1456fd8388992aac5d6a50abc48990b15d8e39fb1d30 export/artifacts/contracts/RandomBeacon.sol/RandomBeacon.json +8287a728027969bdfb6acb819b564e014effe7b9e38665a4851548bbff6b0fb3 export/artifacts/contracts/RandomBeaconChaosnet.sol/RandomBeaconChaosnet.json +a6a706fc9e3409b6c722417fe76099b31f550fc47eb135ee288ad40f841ea560 export/artifacts/contracts/RandomBeaconGovernance.sol/RandomBeaconGovernance.json +093990b5b34c375c8d3c334f8336a5374a33bc41c03c2dd4da9e8afdfd239634 export/artifacts/contracts/ReimbursementPool.sol/ReimbursementPool.json +f5289f22b9da0669b876491b48be2910da2b50044865bb4b46b06c39c89d0602 export/artifacts/contracts/legacy/sortition/Branch.sol/Branch.json +0afaa3fa0747ef9486caaf71b59e0f3c2256f840b19a6c9c91e44e5dc2491ff3 export/artifacts/contracts/legacy/sortition/Chaosnet.sol/Chaosnet.json +0891cbb02e3c46b8fea392260a0d8f2be342631af522b7ceae5dea2a970ea488 export/artifacts/contracts/legacy/sortition/Constants.sol/Constants.json +4a47b22da0c79565fe4baf4cc9d9c6ad01476cc9e5d1ae48b14841d28409946d export/artifacts/contracts/legacy/sortition/Leaf.sol/Leaf.json +e5c1929cde13ae43cfa40aab45bf926083e8aee12af2ca537b5207cdf27d0785 export/artifacts/contracts/legacy/sortition/Position.sol/Position.json +9530ee6826e7457889e2c84e0968754c6822013b07db457941fe36c8c6406db5 export/artifacts/contracts/legacy/sortition/RNG.sol/RNG.json +c15ff840f489e417cd0109e66daa43255e7bc0c96b871c4e40da129ad01c42b5 export/artifacts/contracts/legacy/sortition/Rewards.sol/Rewards.json +f78324912bfc02f4f4168a1017d1633165dde406f937a0f4c712059c41fb70d3 export/artifacts/contracts/legacy/sortition/SortitionPool.sol/SortitionPool.json +82d09d5da0d92cc2c499474ab56e623c60ef9f4b39868dc66bf35ecc4043e8c8 export/artifacts/contracts/legacy/sortition/SortitionTree.sol/SortitionTree.json +2944c6710fcecb5dab79b11136783a8c0591801923d008fce49984b611fc663c export/artifacts/contracts/libraries/AltBn128.sol/AltBn128.json +f0c4fa589219d84e75726ffdbd45fedb111f033ff8ac5d45e48d20c1631e6afa export/artifacts/contracts/libraries/BLS.sol/BLS.json +caf277952b6e49f3464cde3ad6515335e8142d5c6b642621be3478519cf5d613 export/artifacts/contracts/libraries/BeaconAuthorization.sol/BeaconAuthorization.json +6bd4697e2c274d547f791741f3f9ec9419310d3c2844b2972abfe9afc2c94f76 export/artifacts/contracts/libraries/BeaconDkg.sol/BeaconDkg.json +6a8a42a991d024bd50365944ad1c8c498af4140f5e9784ddc00f5a7fb69abf03 export/artifacts/contracts/libraries/BeaconInactivity.sol/BeaconInactivity.json +5a699bcfd1c69316961797cca54e61eaa25315365a78b3a3fb53ed1b04bf5270 export/artifacts/contracts/libraries/BytesLib.sol/BytesLib.json +d79b5916898368a5a24b97b1706bc4b2fbfcb62cc5063cdf287e5109567af4c9 export/artifacts/contracts/libraries/Callback.sol/Callback.json +5c9e18f50ddfa8902f07e0d6433d2ae3df116da9c396ac26514c21f53e2ead9d export/artifacts/contracts/libraries/Groups.sol/Groups.json +ad41985b9a641228fec3dc51ae50cedbdbba1728cd7fe0158a6384dde92ec0eb export/artifacts/contracts/libraries/ModUtils.sol/ModUtils.json +77f951764cccb629c8b9af2c094b2e005f1713f548c2e1e22d5cb2630769c8ca export/artifacts/contracts/libraries/Relay.sol/Relay.json +566c4b53867d3743d3b1008dd236d599506f60e2ef3250c809b62b6b916b166b export/artifacts/contracts/test/CallbackContractStub.sol/CallbackContractStub.json +dee054e800ab4712b368679ea548300572c66d5ec42b6754f07e7f34b2898ce0 export/artifacts/contracts/test/GovernableImpl.sol/GovernableImpl.json +1c81ab0fe70c1a98c39fe0e4ee1a67924361ed260f43a6c068943d4abd40c3ac export/artifacts/contracts/test/GroupsStub.sol/GroupsStub.json +340bd22b624d8428089ec9507403f80f5f480d0220d205ff634fdecbfcd332a4 export/artifacts/contracts/test/MockContract.sol/MockContract.json +cc241444be9df2be5397bb73f6b84981c4dde662736e426941311a57e0f9bd12 export/artifacts/contracts/test/MockTargetConsumer.sol/MockTargetConsumer.json +db5257e70860e84445bc753c0239345633419da953dd936a30f9e071ce6e19a9 export/artifacts/contracts/test/RandomBeaconStub.sol/RandomBeaconStub.json +133ceb64cbb2a4f0dfa8739b9b81483da7cc7adee2f05555ca5b6ff75fc2bf96 export/artifacts/contracts/test/ReimbursableImplStub.sol/ReimbursableImplStub.json +feed0e511ab2ff54866cdcb109eba376a5be2801a8c058ccd6e0ba591584af0d export/artifacts/contracts/test/RelayStub.sol/RelayStub.json +0dc0992320c646605be36eaf03abea889b2754765a0f3674b441f2b3c0a6ca61 export/artifacts/contracts/test/TestAltBn128.sol/TestAltBn128.json +8477a67093395d3969e6393f9c8c22b81a448136d73d2756980c170340e7aa58 export/artifacts/contracts/test/TestModUtils.sol/TestModUtils.json +a8ca0d41130c14c7644e1dc71110fc07138f4341c2993aafd4aeee5cbdd39173 export/deploy/01_deploy_reimbursement_pool.js +abc3259ad23e6a59e15255c6048f71456c5dca6166c7b03e9b8efb4909a541e3 export/deploy/02_deploy_beacon_sortition_pool.js +72cbcb2a9a3b18b50f1e2d71ab35b89d452ddfa09b560a290449ad3f7473503c export/deploy/03_deploy_beacon_dkg_validator.js +f720c254e218bd2a2dc3dd36921c6cd460cab202a609c71665a7cb85fd4f5311 export/deploy/04_deploy_random_beacon.js +dc4beb5cabe48f3fb18a1465cc85a34a9d20a0049189d7cf5b665ba9f4c1bd78 export/deploy/05_approve_random_beacon_in_token_staking.js +470005455547dcb19ffe6e023202659a6ba41d2875c98469a7e11e9a216d9ac3 export/deploy/06_authorize_random_beacon_in_reimbursement_pool.js +1668d54172cc24b9af6be627914a84923e0d9102d741d0b0c631e2b3e280c5ff export/deploy/07_deploy_random_beacon_governance.js +70206a22d3784195128c4138fcc661ea2fdde7f636935f18be46e67ebd605883 export/deploy/08_transfer_governance.js +af570a509d46452a69cbf6974ee527193f6975ccda181aa150621026d6107570 export/deploy/09_deploy_random_beacon_chaosnet.js +148c81cd0ba5a4fd2d84a7ea474ec20337644a813cb33909154e95e25cb515b6 export/hardhat.config.js +bbfa690e72cae56c992ed6755a1e505211fed8e675726bf792abafa74a1e3157 export/tasks/ensure-eth-balance.js +760337573ef1fcddc7e84a0685564fb19ba7bef2ddf133ff2a8067b7e2be68e8 export/tasks/genesis.js +02c4969955c262cf674f578430c360c9c659a9ed4a1da71e28831b93df17eb94 export/tasks/index.js +313df6ab058fb3fc561e8dd62476c8fdf5d4d12f037647fffd554f029548036e export/tasks/initialize.js +d5391cfac7a359721f5fd7f247165607e1fc57bca7b9f80f18f63b0cb86fb582 export/tasks/send-eth.js +6c638999c74e89a3f0b6d260e7c77e8450c2426762059f79f41923f8fb5d4a3b export/tasks/unlock-eth-accounts.js +05f78656bda56e2f012198eadd00a8b5557aba5944465a9b5e4de4c62d052fd1 export/tasks/utils/add_beta_operator.js +1934377c80a43005e2144d4b2e4417e68ebcfa3ef614f1edef635b3877442828 export/tasks/utils/authorize.js +aeec915daa6d27c4b6615a766b121009d5416a5f4f385a4c571dd0f134ba5a5b export/tasks/utils/ether.js +1ca808e3ccad8dbdb882f7545892ae4e690f1d349501baadcbf087ea5c655078 export/tasks/utils/index.js +8a1f59568550491baad027eca95ca39ab21afb3939dabc28b0f4a4dae6c08f5e export/tasks/utils/mint.js +d509094d66bb589e43fccf4df5caed7062de0aca8377ac319e1a2fce1a0eb4f6 export/tasks/utils/register.js +b89f0927e05341a48587ac54f7658a52b4c10febff6615730fe9df0f2e8c92c6 export/tasks/utils/stake.js +1e6cefa2d8eb6f09d61abf2744797bc88d241fb3e45fa955038281e1038c92fb export/utils/wait-for-confirmations.js diff --git a/solidity/random-beacon/hardhat.config.ts b/solidity/random-beacon/hardhat.config.ts index 74c685e616..db65c37170 100644 --- a/solidity/random-beacon/hardhat.config.ts +++ b/solidity/random-beacon/hardhat.config.ts @@ -1,10 +1,10 @@ -import "@nomiclabs/hardhat-etherscan" +import "@nomicfoundation/hardhat-verify" import "@keep-network/hardhat-local-networks-config" import "@keep-network/hardhat-helpers" -import "@nomiclabs/hardhat-ethers" +import "@nomicfoundation/hardhat-ethers" import "hardhat-deploy" -import "@tenderly/hardhat-tenderly" -import "@nomiclabs/hardhat-waffle" +import { setup as setupTenderly } from "@tenderly/hardhat-tenderly" +import "@nomicfoundation/hardhat-chai-matchers" import "hardhat-gas-reporter" import "hardhat-contract-sizer" import "@typechain/hardhat" @@ -16,6 +16,8 @@ import { task } from "hardhat/config" import type { HardhatUserConfig } from "hardhat/config" +setupTenderly({ automaticVerifications: false }) + const thresholdSolidityCompilerConfig = { version: "0.8.9", settings: { @@ -52,7 +54,7 @@ if ( (!Number.isInteger(gasPriceGwei) || gasPriceGwei <= 0) ) { throw new Error( - `Invalid GAS_PRICE_GWEI "${process.env.GAS_PRICE_GWEI}": expected a positive integer (gwei)` + `Invalid GAS_PRICE_GWEI "${process.env.GAS_PRICE_GWEI}": expected a positive integer (gwei)`, ) } @@ -230,14 +232,14 @@ const config: HardhatUserConfig = { } task("check-accounts-count", "Checks accounts count").setAction(async () => { - // eslint-disable-next-line @typescript-eslint/no-var-requires,global-require + // eslint-disable-next-line @typescript-eslint/no-require-imports,global-require const { constants } = require("./test/fixtures") if (testConfig.operatorsCount < constants.groupSize) { throw new Error( "not enough accounts predefined for configured group size: " + `expected group size: ${constants.groupSize} ` + - `number of predefined accounts: ${testConfig.operatorsCount}` + `number of predefined accounts: ${testConfig.operatorsCount}`, ) } }) diff --git a/solidity/random-beacon/package.json b/solidity/random-beacon/package.json index abe71b7bac..b9d56cefed 100644 --- a/solidity/random-beacon/package.json +++ b/solidity/random-beacon/package.json @@ -11,10 +11,11 @@ "deploy/", "export/", "tasks/", + "utils/", "export.json" ], "scripts": { - "install:deps": "corepack enable && corepack prepare yarn@4.8.1 --activate && yarn install", + "install:deps": "corepack enable && corepack prepare yarn@4.12.0 --activate && yarn install", "clean": "hardhat clean && rm -rf cache/ export/ external/npm typechain/ export.json", "build": "hardhat compile", "test": "hardhat typechain && hardhat check-accounts-count && USE_EXTERNAL_DEPLOY=true TEST_USE_STUBS_BEACON=true hardhat test", @@ -22,61 +23,68 @@ "deploy:test": "USE_EXTERNAL_DEPLOY=true hardhat deploy", "format": "npm run lint", "format:fix": "npm run lint:fix", - "lint": "npm run lint:eslint && npm run lint:sol && npm run lint:config", - "lint:fix": "npm run lint:fix:eslint && npm run lint:fix:sol && npm run lint:config:fix", - "lint:eslint": "eslint .", - "lint:fix:eslint": "eslint . --fix", + "lint": "npm run lint:ts && npm run lint:sol && npm run lint:config", + "lint:fix": "npm run lint:fix:ts && npm run lint:fix:sol && npm run lint:config:fix", + "lint:ts": "eslint . && prettier --check '**/*.@(js|ts|mjs|cjs)' && npm run lint:eslint-policy", + "lint:fix:ts": "eslint . --fix && prettier --write '**/*.@(js|ts|mjs|cjs)'", + "lint:eslint-policy": "node scripts/test-eslint-policy.mjs", "lint:sol": "solhint 'contracts/**/*.sol' && prettier --check '**/*.sol'", "lint:fix:sol": "solhint 'contracts/**/*.sol' --fix && prettier --write '**/*.sol'", "lint:config": "prettier --check '**/*.@(json|yaml)'", "lint:config:fix": "prettier --write '**/*.@(json|yaml)'", + "typecheck": "tsc --noEmit -p tsconfig.json", "prepack": "tsc -p tsconfig.export.json && hardhat export-artifacts --including-no-public-functions export/artifacts", - "prepublishOnly": "hardhat prepare-artifacts --network $npm_config_network" + "prepublishOnly": "hardhat export-deployment-artifacts --network \"${npm_config_network:-hardhat}\"" }, "dependencies": { - "@keep-network/sortition-pools": "^2.0.0-pre.16", "@openzeppelin/contracts": "4.7.3", - "@thesis/solidity-contracts": "github:thesis/solidity-contracts#4985bcf", "@threshold-network/solidity-contracts": "1.3.0-dev.14" }, "devDependencies": { - "@keep-network/hardhat-helpers": "^0.6.0-pre.15", - "@keep-network/hardhat-local-networks-config": "^0.1.0-pre.0", - "@nomiclabs/hardhat-ethers": "^2.0.6", - "@nomiclabs/hardhat-etherscan": "^3.1.0", - "@nomiclabs/hardhat-waffle": "^2.0.1", - "@openzeppelin/hardhat-upgrades": "^1.20.0", - "@tenderly/hardhat-tenderly": "1.0.12", - "@thesis-co/eslint-config": "https://codeload.github.com/thesis/eslint-config/tar.gz/e63608fab2a1ad5c8fe89873bf0d4d4f9ef4a081", - "@typechain/ethers-v5": "^9.0.0", - "@typechain/hardhat": "^4.0.0", - "@types/chai": "^4.2.22", - "@types/mocha": "^9.0.0", - "@types/node": "^16.10.5", + "@keep-network/hardhat-helpers": "patch:@keep-network/hardhat-helpers@npm%3A0.7.2#~/.yarn/patches/@keep-network-hardhat-helpers-npm-0.7.2-086cf3da54.patch", + "@keep-network/hardhat-local-networks-config": "github:threshold-network/hardhat-local-networks-config#6dff5bc8648127ca5d8696c321076bddb6d4142a", + "@nomicfoundation/hardhat-chai-matchers": "^2.1.2", + "@nomicfoundation/hardhat-ethers": "^3.1.3", + "@nomicfoundation/hardhat-network-helpers": "^1.1.2", + "@nomicfoundation/hardhat-verify": "^2.1.3", + "@openzeppelin/hardhat-upgrades": "patch:@openzeppelin/hardhat-upgrades@npm%3A2.5.1#~/.yarn/patches/@openzeppelin-hardhat-upgrades-npm-2.5.1-etherscan-v2.patch", + "@stylistic/eslint-plugin": "^5.10.0", + "@tenderly/hardhat-tenderly": "2.1.1", + "@typechain/ethers-v6": "patch:@typechain/ethers-v6@npm%3A0.5.1#~/.yarn/patches/@typechain-ethers-v6-npm-0.5.1-e825560376.patch", + "@typechain/hardhat": "^9.1.0", + "@types/chai": "^4.3.20", + "@types/mocha": "^10.0.10", + "@types/node": "^24.13.3", "chai": "^4.3.4", - "eslint": "^7.32.0", - "ethereum-waffle": "^3.4.0", - "ethers": "^5.4.7", + "eslint": "^10.10.0", + "eslint-import-resolver-typescript": "^4.4.5", + "eslint-plugin-import-x": "^4.17.1", + "eslint-plugin-no-only-tests": "^3.4.0", + "ethers": "^6.17.0", "fs-extra": "^11.2.0", + "globals": "^17.12.0", "hardhat": "2.29.0", "hardhat-contract-sizer": "^2.5.1", "hardhat-dependency-compiler": "^1.1.2", - "hardhat-deploy": "^0.11.11", + "hardhat-deploy": "^1.0.4", "hardhat-gas-reporter": "^2.3.0", - "prettier": "^2.4.1", - "prettier-plugin-solidity": "^1.0.0-beta.18", - "solhint": "^3.3.6", - "solhint-config-keep": "https://codeload.github.com/keep-network/solhint-config-keep/tar.gz/5e1751e58c0f1c507305ffc8c7f6c58047657ada", + "prettier": "^3.9.6", + "prettier-plugin-solidity": "^2.4.1", + "solhint": "^6.2.4", "solidity-docgen": "^0.6.0-beta.35", "ts-node": "^10.2.1", - "typechain": "^7.0.0", - "typescript": "^4.4.3" + "typechain": "^8.3.2", + "typescript": "^6.0.3", + "typescript-eslint": "^8.70.0" }, "engines": { - "node": ">=22.0.0" + "node": ">=24.0.0" }, "resolutions": { - "ethereumjs-abi": "npm:0.6.8" + "axios": "^1.8.4", + "ethereumjs-abi": "npm:0.6.8", + "@ethersproject/abstract-provider": "5.8.0", + "@threshold-network/solidity-contracts@npm:1.3.0-dev.14": "patch:@threshold-network/solidity-contracts@npm%3A1.3.0-dev.14#./.yarn/patches/@threshold-network-solidity-contracts-npm-1.3.0-dev.14-ethers-v6.patch" }, - "packageManager": "yarn@4.8.1+sha512.bc946f2a022d7a1a38adfc15b36a66a3807a67629789496c3714dd1703d2e6c6b1c69ff9ec3b43141ac7a1dd853b7685638eb0074300386a59c18df351ef8ff6" + "packageManager": "yarn@4.12.0+sha512.f45ab632439a67f8bc759bf32ead036a1f413287b9042726b7cc4818b7b49e14e9423ba49b18f9e06ea4941c1ad062385b1d8760a8d5091a1a31e5f6219afca8" } diff --git a/solidity/random-beacon/scripts/test-eslint-policy.mjs b/solidity/random-beacon/scripts/test-eslint-policy.mjs new file mode 100644 index 0000000000..96043080bd --- /dev/null +++ b/solidity/random-beacon/scripts/test-eslint-policy.mjs @@ -0,0 +1,89 @@ +// Lightweight policy test: lints small fixtures against the real +// eslint.config.mjs to confirm no-only-tests enforcement, ignore-pattern +// behavior, and that test/**/*.ts files are actually linted. +// Run with: node scripts/test-eslint-policy.mjs +// +// Fixtures are written as real, temporary files directly under this package's +// test/ and typechain/ directories (then deleted) so ESLint's `files`/`ignores` +// globs and the type-aware TS project both see a real, in-project path. +// The two test/-scoped checks deliberately reuse the SAME path, overwritten in +// place: typescript-eslint's project-based parser resolves its TS program +// once per process and never discovers a brand-new path added afterward +// (it fatal-errors "file was not found in any of the provided project(s)"), +// but it does correctly re-lint a path it has already resolved once its +// content changes - confirmed empirically before relying on it here. + +/* eslint-disable import/no-extraneous-dependencies -- eslint is a legitimate devDependency used + here to smoke-test this package's own lint config; it is not a runtime dependency. */ +import { mkdirSync, rmSync, writeFileSync } from "node:fs" +import { dirname, join } from "node:path" +import { ESLint } from "eslint" + +const pkgRoot = join(import.meta.dirname, "..") + +let failures = 0 + +function assert(condition, message) { + if (!condition) { + failures += 1 + console.error(`FAIL: ${message}`) + } else { + console.log(`PASS: ${message}`) + } +} + +async function lintFixture(relativePath, code) { + const fullPath = join(pkgRoot, relativePath) + mkdirSync(dirname(fullPath), { recursive: true }) + writeFileSync(fullPath, code, "utf8") + const eslint = new ESLint({ cwd: pkgRoot, errorOnUnmatchedPattern: false }) + const results = await eslint.lintFiles([fullPath]) + const messages = results[0]?.messages ?? [] + // Exclude ESLint's own synthetic "file ignored" notice (ruleId: null) so a + // genuinely-ignored path with zero rule violations reads as zero messages. + return messages.filter((m) => m.ruleId !== null) +} + +const sharedTestFixture = "test/policy-fixture.ts" +const ignoredFixture = "typechain/policy-fixture-ignored.ts" + +try { + // Fixture (a): it.only in a test file should trigger no-only-tests + const onlyMessages = await lintFixture( + sharedTestFixture, + 'it.only("x", () => {})\n', + ) + assert( + onlyMessages.some((m) => m.ruleId === "no-only-tests/no-only-tests"), + "it.only() in test/**/*.ts triggers no-only-tests/no-only-tests", + ) + + // Fixture (c): an ordinary test file should be linted (at least one rule evaluated). + // Reuses sharedTestFixture's already-resolved path, overwritten with new content. + const lintedMessages = await lintFixture(sharedTestFixture, "var y = 1\n") + assert( + lintedMessages.length > 0, + "ordinary test/**/*.ts fixture is actually linted (not silently skipped)", + ) + + // Fixture (b): file matching an ignores glob (typechain/**) should have zero messages + const ignoredMessages = await lintFixture( + ignoredFixture, + "const x: any = 1\n", + ) + assert( + ignoredMessages.length === 0, + "typechain/**/*.ts fixture produces zero lint messages (ignored)", + ) +} finally { + rmSync(join(pkgRoot, sharedTestFixture), { force: true }) + rmSync(join(pkgRoot, ignoredFixture), { force: true }) +} + +if (failures > 0) { + console.error(`\n${failures} policy assertion(s) failed.`) + process.exit(1) +} else { + console.log("\nAll ESLint policy assertions passed.") + process.exit(0) +} diff --git a/solidity/random-beacon/slither.config.json b/solidity/random-beacon/slither.config.json index 8655859bad..90b5af4be6 100644 --- a/solidity/random-beacon/slither.config.json +++ b/solidity/random-beacon/slither.config.json @@ -1,5 +1,5 @@ { "detectors_to_exclude": "assembly,timestamp,solc-version,naming-convention", "hardhat_artifacts_directory": "./build", - "filter_paths": "test|node_modules|BytesLib.sol|ModUtils.sol|AltBn128.sol" + "filter_paths": "test|node_modules|BytesLib.sol|ModUtils.sol|AltBn128.sol|contracts/legacy/" } diff --git a/solidity/random-beacon/tasks/ensure-eth-balance.ts b/solidity/random-beacon/tasks/ensure-eth-balance.ts index 79a924f1cd..150a548664 100644 --- a/solidity/random-beacon/tasks/ensure-eth-balance.ts +++ b/solidity/random-beacon/tasks/ensure-eth-balance.ts @@ -7,55 +7,60 @@ const TASK_ENSURE_ETH_BALANCE = "ensure-eth-balance" task( TASK_ENSURE_ETH_BALANCE, - "Ensure addresses hold a minimum ether balance, top-up if needed" + "Ensure addresses hold a minimum ether balance, top-up if needed", ) .addOptionalParam( "from", "Address to send the ether from", undefined, - types.string + types.string, ) .addParam( "targetBalance", 'Expected target balances of the addresses, e.g. "0.5 ether", "100 gwei"', undefined, - types.string + types.string, ) .addVariadicPositionalParam( "addresses", "Addresses for which balance should be validated", undefined, - types.string + types.string, ) - .setAction(async (args, hre) => { - const { ethers } = hre + .setAction( + async ( + args: { from?: string; targetBalance: string; addresses: string[] }, + hre, + ) => { + const { ethers } = hre - // FIXME: `validate` will fail for badly checksummed addresses - // see: https://github.com/ethers-io/ethers.js/discussions/3261 - const addresses: Set = new Set( - Array.from(args.addresses).map(hre.helpers.address.validate) - ) + // FIXME: `validate` will fail for badly checksummed addresses + // see: https://github.com/ethers-io/ethers.js/discussions/3261 + const addresses: Set = new Set( + Array.from(args.addresses).map(hre.helpers.address.validate), + ) - const expectedBalance = parseValue(args.targetBalance, hre) + const expectedBalance = parseValue(args.targetBalance, hre) - // eslint-disable-next-line no-restricted-syntax - for (const address of addresses) { - const currentBalance = await ethers.provider.getBalance(address) + // eslint-disable-next-line no-restricted-syntax + for (const address of addresses) { + const currentBalance = await ethers.provider.getBalance(address) - console.log( - `current balance of ${address} is ${ethers.utils.formatEther( - currentBalance - )} ether` - ) + console.log( + `current balance of ${address} is ${ethers.formatEther( + currentBalance, + )} ether`, + ) - if (currentBalance.lt(expectedBalance)) { - const topUpAmount = expectedBalance.sub(currentBalance) + if (currentBalance < expectedBalance) { + const topUpAmount = expectedBalance - currentBalance - await hre.run(TASK_SEND_ETH, { - from: args.from, - amount: topUpAmount.toString(), - to: address, - }) + await hre.run(TASK_SEND_ETH, { + from: args.from, + amount: topUpAmount.toString(), + to: address, + }) + } } - } - }) + }, + ) diff --git a/solidity/random-beacon/tasks/genesis.ts b/solidity/random-beacon/tasks/genesis.ts index eabf212282..7851eed46f 100644 --- a/solidity/random-beacon/tasks/genesis.ts +++ b/solidity/random-beacon/tasks/genesis.ts @@ -5,7 +5,7 @@ import type { HardhatRuntimeEnvironment } from "hardhat/types" task("genesis", "Triggers the Random Beacon genesis").setAction( async (args, hre) => { await genesis(hre) - } + }, ) async function genesis(hre: HardhatRuntimeEnvironment) { @@ -14,7 +14,9 @@ async function genesis(hre: HardhatRuntimeEnvironment) { const randomBeacon = await helpers.contracts.getContract("RandomBeacon") - const genesisTx = await randomBeacon.connect(governance).genesis() + const genesisTx = await randomBeacon + .connect(governance) + .getFunction("genesis")() await genesisTx.wait() console.log("Genesis was triggered successfully") diff --git a/solidity/random-beacon/tasks/index.ts b/solidity/random-beacon/tasks/index.ts index 2a852992bb..d0fbe98cca 100644 --- a/solidity/random-beacon/tasks/index.ts +++ b/solidity/random-beacon/tasks/index.ts @@ -1,6 +1,5 @@ -// eslint-disable-next-line global-require -require("./unlock-eth-accounts") -require("./initialize") -require("./genesis") -require("./send-eth") -require("./ensure-eth-balance") +import "./unlock-eth-accounts" +import "./initialize" +import "./genesis" +import "./send-eth" +import "./ensure-eth-balance" diff --git a/solidity/random-beacon/tasks/initialize.ts b/solidity/random-beacon/tasks/initialize.ts index 07cc32f520..bc05368bac 100644 --- a/solidity/random-beacon/tasks/initialize.ts +++ b/solidity/random-beacon/tasks/initialize.ts @@ -1,3 +1,4 @@ +import { getNumber } from "ethers" import { task, types } from "hardhat/config" import { @@ -29,7 +30,7 @@ const TASK_ADD_BETA_OPERATOR_BEACON = `${TASK_ADD_BETA_OPERATOR}:beacon` task( TASK_INITIALIZE, - "Initializes staking and the Random Beacon application for a staking provider and an operator" + "Initializes staking and the Random Beacon application for a staking provider and an operator", ) .addParam("owner", "Stake Owner address", undefined, types.string) .addParam("provider", "Staking Provider", undefined, types.string) @@ -41,7 +42,7 @@ task( "authorization", "Authorization amount (default: minimumAuthorization)", undefined, - types.int + types.int, ) .setAction(async (args, hre) => { // Initialize staking @@ -62,11 +63,11 @@ task(TASK_INITIALIZE_STAKING, "Initializes staking for a service provider") const tokensToMint = await calculateTokensNeededForStake( hre, args.provider, - args.amount + args.amount, ) - if (!tokensToMint.isZero()) { - await hre.run(TASK_MINT, { ...args, amount: tokensToMint.toNumber() }) + if (tokensToMint !== 0n) { + await hre.run(TASK_MINT, { ...args, amount: getNumber(tokensToMint) }) } await hre.run(TASK_STAKE, args) @@ -92,7 +93,7 @@ task(TASK_STAKE, "Stakes T tokens") args.provider, args.amount, args.beneficiary, - args.authorizer + args.authorizer, ) }) @@ -100,7 +101,7 @@ task(TASK_INITIALIZE_BEACON, "Initializes operator for Beacon").setAction( async (args, hre) => { await hre.run(TASK_AUTHORIZE_BEACON, args) await hre.run(TASK_REGISTER_BEACON, args) - } + }, ) task(TASK_AUTHORIZE_BEACON, "Sets authorization for Beacon") @@ -111,7 +112,7 @@ task(TASK_AUTHORIZE_BEACON, "Sets authorization for Beacon") "authorization", "Authorization amount (default: minimumAuthorization)", undefined, - types.int + types.int, ) .setAction(async (args, hre) => { await authorize( @@ -120,13 +121,13 @@ task(TASK_AUTHORIZE_BEACON, "Sets authorization for Beacon") args.owner, args.provider, args.authorizer, - args.authorization + args.authorization, ) }) task( TASK_REGISTER_BEACON, - "Registers an operator for a staking provider in Beacon" + "Registers an operator for a staking provider in Beacon", ) .addParam("provider", "Staking Provider", undefined, types.string) .addParam("operator", "Operator Address", undefined, types.string) @@ -136,7 +137,7 @@ task( task( TASK_ADD_BETA_OPERATOR_BEACON, - "Adds an operator to the set of beta operators in Beacon" + "Adds an operator to the set of beta operators in Beacon", ) .addParam("operator", "Operator Address", undefined, types.string) .setAction(async (args, hre) => { diff --git a/solidity/random-beacon/tasks/send-eth.ts b/solidity/random-beacon/tasks/send-eth.ts index 177f8c184b..844eb055fb 100644 --- a/solidity/random-beacon/tasks/send-eth.ts +++ b/solidity/random-beacon/tasks/send-eth.ts @@ -2,9 +2,8 @@ import { task, types } from "hardhat/config" import { parseValue } from "./utils" -import type { BigNumber } from "ethers" -import type { TransactionResponse } from "@ethersproject/abstract-provider" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import type { TransactionResponse } from "ethers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" // eslint-disable-next-line import/prefer-default-export export const TASK_SEND_ETH = "send-eth" @@ -14,13 +13,13 @@ task(TASK_SEND_ETH, "Send ether to an address") "from", "Address to send value from", undefined, - types.string + types.string, ) .addParam( "amount", 'Amount to transfer with unit, e.g. "0.5 ether", "100 gwei"', undefined, - types.string + types.string, ) .addParam("to", "Transfer receiver address", undefined, types.string) .setAction(async (args, hre) => { @@ -28,7 +27,7 @@ task(TASK_SEND_ETH, "Send ether to an address") ? await hre.ethers.getSigner(args.from) : (await hre.ethers.getSigners())[0] - const amount: BigNumber = parseValue(args.amount, hre) + const amount: bigint = parseValue(args.amount, hre) // FIXME: `validate` will fail for badly checksummed addresses // see: https://github.com/ethers-io/ethers.js/discussions/3261 @@ -42,7 +41,7 @@ task(TASK_SEND_ETH, "Send ether to an address") console.log( `sending ${amount} wei from ${await from.getAddress()} to ${to} in tx ${ tx.hash - }...` + }...`, ) await tx.wait() diff --git a/solidity/random-beacon/tasks/unlock-eth-accounts.ts b/solidity/random-beacon/tasks/unlock-eth-accounts.ts index 6f357fe46a..53c8eb341f 100644 --- a/solidity/random-beacon/tasks/unlock-eth-accounts.ts +++ b/solidity/random-beacon/tasks/unlock-eth-accounts.ts @@ -9,8 +9,8 @@ task("unlock-accounts", "Unlock ethereum accounts").setAction( if (hre.network.name === "development") { const password = process.env.KEEP_ETHEREUM_PASSWORD || "password" - const provider = new ethers.providers.JsonRpcProvider( - (hre.network.config as HttpNetworkConfig).url + const provider = new ethers.JsonRpcProvider( + (hre.network.config as HttpNetworkConfig).url, ) const accounts = await provider.listAccounts() @@ -18,7 +18,7 @@ task("unlock-accounts", "Unlock ethereum accounts").setAction( console.log("---------------------------------") for (let i = 0; i < accounts.length; i++) { - const account = accounts[i] + const account = await accounts[i].getAddress() try { console.log(`\nUnlocking account: ${account}`) @@ -36,5 +36,5 @@ task("unlock-accounts", "Unlock ethereum accounts").setAction( console.log("\n---------------------------------") } } - } + }, ) diff --git a/solidity/random-beacon/tasks/utils/add_beta_operator.ts b/solidity/random-beacon/tasks/utils/add_beta_operator.ts index 6f5ee8c971..bc5ae752ed 100644 --- a/solidity/random-beacon/tasks/utils/add_beta_operator.ts +++ b/solidity/random-beacon/tasks/utils/add_beta_operator.ts @@ -5,18 +5,23 @@ import type { HardhatRuntimeEnvironment } from "hardhat/types" export async function addBetaOperator( hre: HardhatRuntimeEnvironment, sortitionPoolDeploymentName: string, - operator: string + operator: string, ): Promise { const { ethers, helpers } = hre const sortitionPool = await helpers.contracts.getContract( - sortitionPoolDeploymentName + sortitionPoolDeploymentName, ) const chaosnetOwner = await sortitionPool.chaosnetOwner() + if (await sortitionPool.isBetaOperator(operator)) { + console.log(`Operator ${operator} is already a beta operator`) + return + } + console.log(`Adding ${operator} to the set of beta operators...`) await ( await sortitionPool .connect(await ethers.getSigner(chaosnetOwner)) - .addBetaOperators([operator]) + .getFunction("addBetaOperators")([operator]) ).wait() } diff --git a/solidity/random-beacon/tasks/utils/authorize.ts b/solidity/random-beacon/tasks/utils/authorize.ts index eee4836179..f11a93517d 100644 --- a/solidity/random-beacon/tasks/utils/authorize.ts +++ b/solidity/random-beacon/tasks/utils/authorize.ts @@ -1,5 +1,5 @@ /* eslint-disable no-console */ -import type { BigNumber, BigNumberish } from "ethers" +import type { BigNumberish } from "ethers" import type { HardhatRuntimeEnvironment } from "hardhat/types" // eslint-disable-next-line import/prefer-default-export @@ -9,58 +9,58 @@ export async function authorize( owner: string, provider: string, authorizer?: string, - authorization?: BigNumberish + authorization?: BigNumberish, ): Promise { const { ethers, helpers } = hre - const ownerAddress = ethers.utils.getAddress(owner) - const providerAddress = ethers.utils.getAddress(provider) + const ownerAddress = ethers.getAddress(owner) + const providerAddress = ethers.getAddress(provider) const application = await helpers.contracts.getContract(deploymentName) console.log( - `Authorizing provider's ${providerAddress} stake in ${deploymentName} application (${application.address})` + `Authorizing provider's ${providerAddress} stake in ${deploymentName} application (${await application.getAddress()})`, ) // Authorizer can equal to the owner if not set otherwise. This simplification // is used for development purposes. const authorizerAddress = authorizer - ? ethers.utils.getAddress(authorizer) + ? ethers.getAddress(authorizer) : ownerAddress const { to1e18, from1e18 } = helpers.number const staking = await helpers.contracts.getContract("TokenStaking") - const authorizationBN: BigNumber = authorization + const authorizationBN: bigint = authorization ? to1e18(authorization) : await application.minimumAuthorization() - const currentAuthorization = await staking.authorizedStake( + const currentAuthorization: bigint = await staking.authorizedStake( providerAddress, - application.address + await application.getAddress(), ) - if (currentAuthorization.gte(authorizationBN)) { + if (currentAuthorization >= authorizationBN) { console.log( - `Authorized stake is already ${from1e18(currentAuthorization)} T` + `Authorized stake is already ${from1e18(currentAuthorization)} T`, ) return } - const increaseAmount: BigNumber = authorizationBN.sub(currentAuthorization) + const increaseAmount: bigint = authorizationBN - currentAuthorization console.log( `Increasing authorization by ${from1e18(increaseAmount)} T to ${from1e18( - authorizationBN - )} T...` + authorizationBN, + )} T...`, ) await ( await staking .connect(await ethers.getSigner(authorizerAddress)) - .increaseAuthorization( - providerAddress, - application.address, - increaseAmount - ) + .getFunction("increaseAuthorization")( + providerAddress, + await application.getAddress(), + increaseAmount, + ) ).wait() } diff --git a/solidity/random-beacon/tasks/utils/ether.ts b/solidity/random-beacon/tasks/utils/ether.ts index d71893d7c5..a63ed7decf 100644 --- a/solidity/random-beacon/tasks/utils/ether.ts +++ b/solidity/random-beacon/tasks/utils/ether.ts @@ -1,16 +1,15 @@ -import type { BigNumber } from "ethers" import type { HardhatRuntimeEnvironment } from "hardhat/types" // eslint-disable-next-line import/prefer-default-export export function parseValue( value: string, - hre: HardhatRuntimeEnvironment -): BigNumber { + hre: HardhatRuntimeEnvironment, +): bigint { const parsed = String(value).trim().split(" ") if (parsed.length === 0 || parsed.length > 2) { throw new Error(`invalid value: ${value}`) } - return hre.ethers.utils.parseUnits(parsed[0], parsed[1] || "wei") + return hre.ethers.parseUnits(parsed[0], parsed[1] || "wei") } diff --git a/solidity/random-beacon/tasks/utils/mint.ts b/solidity/random-beacon/tasks/utils/mint.ts index 7089ea8fd3..01f9d844b4 100644 --- a/solidity/random-beacon/tasks/utils/mint.ts +++ b/solidity/random-beacon/tasks/utils/mint.ts @@ -1,16 +1,16 @@ /* eslint-disable no-console */ -import type { BigNumberish, BigNumber } from "ethers" +import type { BigNumberish } from "ethers" import type { HardhatRuntimeEnvironment } from "hardhat/types" // eslint-disable-next-line import/prefer-default-export export async function mint( hre: HardhatRuntimeEnvironment, owner: string, - amount: BigNumberish + amount: BigNumberish, ): Promise { const { ethers, helpers } = hre const { to1e18, from1e18 } = helpers.number - const ownerAddress = ethers.utils.getAddress(owner) + const ownerAddress = ethers.getAddress(owner) const stakeAmount = to1e18(amount) const t = await helpers.contracts.getContract("T") @@ -18,43 +18,43 @@ export async function mint( const tokenContractOwner = await t.owner() - const currentBalance: BigNumber = await t.balanceOf(ownerAddress) + const currentBalance: bigint = await t.balanceOf(ownerAddress) console.log( - `Account ${ownerAddress} balance is ${from1e18(currentBalance)} T` + `Account ${ownerAddress} balance is ${from1e18(currentBalance)} T`, ) - if (currentBalance.lt(stakeAmount)) { - const mintAmount = stakeAmount.sub(currentBalance) + if (currentBalance < stakeAmount) { + const mintAmount = stakeAmount - currentBalance console.log(`Minting ${from1e18(mintAmount)} T for ${ownerAddress}...`) await ( await t .connect(await ethers.getSigner(tokenContractOwner)) - .mint(ownerAddress, mintAmount) + .getFunction("mint")(ownerAddress, mintAmount) ).wait() } - const currentAllowance: BigNumber = await t.allowance( + const currentAllowance: bigint = await t.allowance( ownerAddress, - staking.address + await staking.getAddress(), ) console.log( - `Account ${ownerAddress} allowance for ${staking.address} is ${from1e18( - currentAllowance - )} T` + `Account ${ownerAddress} allowance for ${await staking.getAddress()} is ${from1e18( + currentAllowance, + )} T`, ) - if (currentAllowance.lt(stakeAmount)) { + if (currentAllowance < stakeAmount) { console.log( - `Approving ${from1e18(stakeAmount)} T for ${staking.address}...` + `Approving ${from1e18(stakeAmount)} T for ${await staking.getAddress()}...`, ) await ( await t .connect(await ethers.getSigner(ownerAddress)) - .approve(staking.address, stakeAmount) + .getFunction("approve")(await staking.getAddress(), stakeAmount) ).wait() } } diff --git a/solidity/random-beacon/tasks/utils/register.ts b/solidity/random-beacon/tasks/utils/register.ts index 2413f44443..4207930481 100644 --- a/solidity/random-beacon/tasks/utils/register.ts +++ b/solidity/random-beacon/tasks/utils/register.ts @@ -6,46 +6,46 @@ export async function register( hre: HardhatRuntimeEnvironment, deploymentName: string, provider: string, - operator: string + operator: string, ): Promise { const { ethers, helpers } = hre - const providerAddress = ethers.utils.getAddress(provider) - const operatorAddress = ethers.utils.getAddress(operator) + const providerAddress = ethers.getAddress(provider) + const operatorAddress = ethers.getAddress(operator) const application = await helpers.contracts.getContract(deploymentName) console.log( - `Registering operator ${operatorAddress} in ${deploymentName} application (${application.address})` + `Registering operator ${operatorAddress} in ${deploymentName} application (${await application.getAddress()})`, ) - const currentProvider = ethers.utils.getAddress( - await application.callStatic.operatorToStakingProvider(operatorAddress) + const currentProvider = ethers.getAddress( + await application.operatorToStakingProvider.staticCall(operatorAddress), ) switch (currentProvider) { case providerAddress: { console.log( - `Current staking provider for operator ${operatorAddress} is ${currentProvider}` + `Current staking provider for operator ${operatorAddress} is ${currentProvider}`, ) return } - case ethers.constants.AddressZero: { + case ethers.ZeroAddress: { console.log( - `Registering operator ${operatorAddress} for a staking provider ${providerAddress}...` + `Registering operator ${operatorAddress} for a staking provider ${providerAddress}...`, ) await ( await application .connect(await ethers.getSigner(providerAddress)) - .registerOperator(operatorAddress) + .getFunction("registerOperator")(operatorAddress) ).wait() break } default: { throw new Error( - `Operator [${operatorAddress}] has already been registered for another staking provider [${currentProvider}]` + `Operator [${operatorAddress}] has already been registered for another staking provider [${currentProvider}]`, ) } } diff --git a/solidity/random-beacon/tasks/utils/stake.ts b/solidity/random-beacon/tasks/utils/stake.ts index b467568dab..3c1e772921 100644 --- a/solidity/random-beacon/tasks/utils/stake.ts +++ b/solidity/random-beacon/tasks/utils/stake.ts @@ -1,5 +1,5 @@ /* eslint-disable no-console */ -import type { BigNumberish, BigNumber } from "ethers" +import type { BigNumberish } from "ethers" import type { HardhatRuntimeEnvironment } from "hardhat/types" export async function stake( @@ -8,66 +8,65 @@ export async function stake( provider: string, amount: BigNumberish, beneficiary?: string, - authorizer?: string + authorizer?: string, ): Promise { const { ethers, helpers } = hre const { to1e18, from1e18 } = helpers.number - const ownerAddress = ethers.utils.getAddress(owner) - const providerAddress = ethers.utils.getAddress(provider) + const ownerAddress = ethers.getAddress(owner) + const providerAddress = ethers.getAddress(provider) const stakeAmount = to1e18(amount) // Beneficiary can equal to the owner if not set otherwise. This simplification // is used for development purposes. const beneficiaryAddress = beneficiary - ? ethers.utils.getAddress(beneficiary) + ? ethers.getAddress(beneficiary) : ownerAddress // Authorizer can equal to the owner if not set otherwise. This simplification // is used for development purposes. const authorizerAddress = authorizer - ? ethers.utils.getAddress(authorizer) + ? ethers.getAddress(authorizer) : ownerAddress const staking = await helpers.contracts.getContract("TokenStaking") - const { tStake: currentStake } = await staking.callStatic.stakes( - providerAddress - ) + const { tStake: currentStake }: { tStake: bigint } = + await staking.stakes.staticCall(providerAddress) console.log( - `Current stake for ${providerAddress} is ${from1e18(currentStake)} T` + `Current stake for ${providerAddress} is ${from1e18(currentStake)} T`, ) - if (currentStake.eq(0)) { + if (currentStake === 0n) { console.log( `Staking ${from1e18( - stakeAmount - )} T to the staking provider ${providerAddress}...` + stakeAmount, + )} T to the staking provider ${providerAddress}...`, ) await ( await staking .connect(await ethers.getSigner(ownerAddress)) - .stake( - providerAddress, - beneficiaryAddress, - authorizerAddress, - stakeAmount - ) + .getFunction("stake")( + providerAddress, + beneficiaryAddress, + authorizerAddress, + stakeAmount, + ) ).wait() - } else if (currentStake.lt(stakeAmount)) { - const topUpAmount = stakeAmount.sub(currentStake) + } else if (currentStake < stakeAmount) { + const topUpAmount = stakeAmount - currentStake console.log( `Topping up ${from1e18( - topUpAmount - )} T to the staking provider ${providerAddress}...` + topUpAmount, + )} T to the staking provider ${providerAddress}...`, ) await ( await staking .connect(await ethers.getSigner(ownerAddress)) - .topUp(providerAddress, topUpAmount) + .getFunction("topUp")(providerAddress, topUpAmount) ).wait() } } @@ -75,8 +74,8 @@ export async function stake( export async function calculateTokensNeededForStake( hre: HardhatRuntimeEnvironment, provider: string, - amount: BigNumberish -): Promise { + amount: BigNumberish, +): Promise { const { ethers, helpers } = hre const { to1e18, from1e18 } = helpers.number @@ -84,11 +83,12 @@ export async function calculateTokensNeededForStake( const staking = await helpers.contracts.getContract("TokenStaking") - const { tStake: currentStake } = await staking.callStatic.stakes(provider) + const { tStake: currentStake }: { tStake: bigint } = + await staking.stakes.staticCall(provider) - if (currentStake.lt(stakeAmount)) { - return ethers.BigNumber.from(from1e18(stakeAmount.sub(currentStake))) + if (currentStake < stakeAmount) { + return BigInt(from1e18(stakeAmount - currentStake)) } - return ethers.constants.Zero + return 0n } diff --git a/solidity/random-beacon/test/AltBn128.test.ts b/solidity/random-beacon/test/AltBn128.test.ts index 5fa8c09a9e..082a2d8883 100644 --- a/solidity/random-beacon/test/AltBn128.test.ts +++ b/solidity/random-beacon/test/AltBn128.test.ts @@ -1,4 +1,5 @@ -import { ethers, waffle } from "hardhat" +import { ethers } from "hardhat" +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" import { expect } from "chai" import type { TestAltBn128 } from "../typechain" @@ -16,19 +17,19 @@ describe("AltBn128", () => { const fixture = async () => { const TestAltBn128 = await ethers.getContractFactory("TestAltBn128") testAltBn128 = await TestAltBn128.deploy() - await testAltBn128.deployed() + await testAltBn128.waitForDeployment() return testAltBn128 } beforeEach("load test fixture", async () => { - testAltBn128 = await waffle.loadFixture(fixture) + testAltBn128 = await loadFixture(fixture) }) describe("g1Unmarshal", async () => { it("should not accept less than 64 bytes", async () => { await expect( - testAltBn128.publicG1Unmarshal(g1.slice(0, -2)) + testAltBn128.publicG1Unmarshal(g1.slice(0, -2)), ).to.be.revertedWith("Invalid G1 bytes length") }) @@ -39,7 +40,7 @@ describe("AltBn128", () => { it("should not accept more than 64 bytes", async () => { await expect( - testAltBn128.publicG1Unmarshal(`${g1}ff`) + testAltBn128.publicG1Unmarshal(`${g1}ff`), ).to.be.revertedWith("Invalid G1 bytes length") }) }) @@ -47,7 +48,7 @@ describe("AltBn128", () => { describe("g2Unmarshal", async () => { it("should not accept less than 128 bytes", async () => { await expect( - testAltBn128.publicG2Unmarshal(g2.slice(0, -2)) + testAltBn128.publicG2Unmarshal(g2.slice(0, -2)), ).to.be.revertedWith("Invalid G2 bytes length") }) @@ -58,7 +59,7 @@ describe("AltBn128", () => { it("should not accept more than 128 bytes", async () => { await expect( - testAltBn128.publicG2Unmarshal(`${g2}ff`) + testAltBn128.publicG2Unmarshal(`${g2}ff`), ).to.be.revertedWith("Invalid G2 bytes length") }) }) @@ -66,7 +67,7 @@ describe("AltBn128", () => { describe("g2Decompress", async () => { it("should not accept less than 64 bytes", async () => { await expect( - testAltBn128.publicG2Decompress(g2Compressed.slice(0, -2)) + testAltBn128.publicG2Decompress(g2Compressed.slice(0, -2)), ).to.be.revertedWith("Invalid G2 compressed bytes length") }) @@ -77,7 +78,7 @@ describe("AltBn128", () => { it("should not accept more than 64 bytes", async () => { await expect( - testAltBn128.publicG2Decompress(`${g2Compressed}ff`) + testAltBn128.publicG2Decompress(`${g2Compressed}ff`), ).to.be.revertedWith("Invalid G2 compressed bytes length") }) }) diff --git a/solidity/random-beacon/test/BLS.test.ts b/solidity/random-beacon/test/BLS.test.ts index 88711fd95f..c5860a3866 100644 --- a/solidity/random-beacon/test/BLS.test.ts +++ b/solidity/random-beacon/test/BLS.test.ts @@ -1,4 +1,4 @@ -import { waffle } from "hardhat" +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" import { expect } from "chai" import blsData from "./data/bls" @@ -10,7 +10,7 @@ describe("BLS", () => { let bls: BLS beforeEach("load test fixture", async () => { - const contracts = await waffle.loadFixture(blsDeployment) + const contracts = await loadFixture(blsDeployment) bls = contracts.bls as BLS }) @@ -20,7 +20,7 @@ describe("BLS", () => { const result = await bls.verify( "0x1f1954b33144db2b5c90da089e8bde287ec7089d5d6433f3b6becaefdb678b1b2a9de38d14bef2cf9afc3c698a4211fa7ada7b4f036a2dfef0dc122b423259d01659dc18b57722ecf6a4beb4d04dfe780a660c4c3bb2b165ab8486114c464c621bf37ecdba226629c20908c7f475c5b3a7628ce26d696436eab0b0148034dfcd", "0x15c30f4b6cf6dbbcbdcc10fe22f54c8170aea44e198139b776d512d8f027319a1b9e8bfaf1383978231ce98e42bafc8129f473fc993cf60ce327f7d223460663", - "0x112d462728e89432b0fe40251eeb6608aed4560f3dc833a9877f5010ace9b1312006dbbe2f30c6e0e3e7ec47dc078b7b6b773379d44d64e44ec4e017bfa7375c" + "0x112d462728e89432b0fe40251eeb6608aed4560f3dc833a9877f5010ace9b1312006dbbe2f30c6e0e3e7ec47dc078b7b6b773379d44d64e44ec4e017bfa7375c", ) await expect(result).to.be.true }) @@ -30,22 +30,22 @@ describe("BLS", () => { const result = await bls.verify( "0x1644bcbb604e3608225d1826bab0b926f2df4fb506e1aa3641d5ab350ebceb5825c7df94f3a87e9dd6e11865dfdbdd3db69eab4951c8bc2250fb51da5f813009131e0c9e6d90d91741458b522b57ca99b597dd922dd31f61a2f69412ce3220d31a1ec4b09ef2ea1d6ba7cad98386f6049b5eec5fb3a40408229dc75c5759f184", "0x15c30f4b6cf6dbbcbdcc10fe22f54c8170aea44e198139b776d512d8f027319a1b9e8bfaf1383978231ce98e42bafc8129f473fc993cf60ce327f7d223460663", - "0x23cbfa4b2fcbf43a44d8a4b2a9aa1a9123f183794fa7b53c633c2de7ada5b5ca174f81900dc4ca5672768d51c12dfcb0eac2aafba0a66ac54b76f689dc1fe321" + "0x23cbfa4b2fcbf43a44d8a4b2a9aa1a9123f183794fa7b53c633c2de7ada5b5ca174f81900dc4ca5672768d51c12dfcb0eac2aafba0a66ac54b76f689dc1fe321", ) await expect(result).to.be.true }) it("should use reasonable amount of gas", async () => { // Corresponding test in Go library: bls_test.go TestThresholdBLS - const gasEstimate = await bls.estimateGas.verify( + const gasEstimate = await bls.verify.estimateGas( "0x1644bcbb604e3608225d1826bab0b926f2df4fb506e1aa3641d5ab350ebceb5825c7df94f3a87e9dd6e11865dfdbdd3db69eab4951c8bc2250fb51da5f813009131e0c9e6d90d91741458b522b57ca99b597dd922dd31f61a2f69412ce3220d31a1ec4b09ef2ea1d6ba7cad98386f6049b5eec5fb3a40408229dc75c5759f184", "0x15c30f4b6cf6dbbcbdcc10fe22f54c8170aea44e198139b776d512d8f027319a1b9e8bfaf1383978231ce98e42bafc8129f473fc993cf60ce327f7d223460663", - "0x23cbfa4b2fcbf43a44d8a4b2a9aa1a9123f183794fa7b53c633c2de7ada5b5ca174f81900dc4ca5672768d51c12dfcb0eac2aafba0a66ac54b76f689dc1fe321" + "0x23cbfa4b2fcbf43a44d8a4b2a9aa1a9123f183794fa7b53c633c2de7ada5b5ca174f81900dc4ca5672768d51c12dfcb0eac2aafba0a66ac54b76f689dc1fe321", ) // make sure no change will make the verification more expensive than it is now - await expect(gasEstimate.toNumber()).to.be.lessThan( + await expect(Number(gasEstimate)).to.be.lessThan( 306682, - "BLS verification is too expensive" + "BLS verification is too expensive", ) }) @@ -54,7 +54,7 @@ describe("BLS", () => { const result = await bls.verify( "0x04ab0e5862ecdffda6bab4465c4ee88a3b71a86f178c1ac6e89a4827464c618215f83a353b5ba5126f7fdfb21998fb36d1169db87ea4042ac0d60106c98c9b8122c158a3411a0ea19841c60bcc1da84cf94f5959f1783d7ee751a48d909f58f10bbcfc4acb66b369e61c91b3a5620167ab861a80c639d1fd14b2414cd386853b", "0x15c30f4b6cf6dbbcbdcc10fe22f54c8170aea44e198139b776d512d8f027319a1b9e8bfaf1383978231ce98e42bafc8129f473fc993cf60ce327f7d223460663", - "0x0855a2afab929270bd423e0d4069250519a45e4c3bcb33f53531f5b6988bb87b14301047405783a8d52311f4dfebe6a8f5acc7f299cf576c38cf726bc9fc0a1a" + "0x0855a2afab929270bd423e0d4069250519a45e4c3bcb33f53531f5b6988bb87b14301047405783a8d52311f4dfebe6a8f5acc7f299cf576c38cf726bc9fc0a1a", ) await expect(result).to.be.true }) @@ -63,7 +63,7 @@ describe("BLS", () => { const result = await bls.verify( "0x1f1954b33144db2b5c90da089e8bde287ec7089d5d6433f3b6becaefdb678b1b2a9de38d14bef2cf9afc3c698a4211fa7ada7b4f036a2dfef0dc122b423259d01659dc18b57722ecf6a4beb4d04dfe780a660c4c3bb2b165ab8486114c464c621bf37ecdba226629c20908c7f475c5b3a7628ce26d696436eab0b0148034dfcd", "0x15c30f4b6cf6dbbcbdcc10fe22f54c8170aea44e198139b776d512d8f027319a1b9e8bfaf1383978231ce98e42bafc8129f473fc993cf60ce327f7d223460663", - "0x0855a2afab929270bd423e0d4069250519a45e4c3bcb33f53531f5b6988bb87b14301047405783a8d52311f4dfebe6a8f5acc7f299cf576c38cf726bc9fc0a1a" + "0x0855a2afab929270bd423e0d4069250519a45e4c3bcb33f53531f5b6988bb87b14301047405783a8d52311f4dfebe6a8f5acc7f299cf576c38cf726bc9fc0a1a", ) await expect(result).to.be.false }) @@ -72,7 +72,7 @@ describe("BLS", () => { const result = await bls.verify( "0x1f1954b33144db2b5c90da089e8bde287ec7089d5d6433f3b6becaefdb678b1b2a9de38d14bef2cf9afc3c698a4211fa7ada7b4f036a2dfef0dc122b423259d01659dc18b57722ecf6a4beb4d04dfe780a660c4c3bb2b165ab8486114c464c621bf37ecdba226629c20908c7f475c5b3a7628ce26d696436eab0b0148034dfcd", "0x1a01114fce4c287d8beb49616ca8f2c2be211820b73340c79bd4aada0c4f66af1bcbbb9c398c87dc504e9d275b6f5f97215a081a85d3161910158b4ab331f7bc", - "0x112d462728e89432b0fe40251eeb6608aed4560f3dc833a9877f5010ace9b1312006dbbe2f30c6e0e3e7ec47dc078b7b6b773379d44d64e44ec4e017bfa7375c" + "0x112d462728e89432b0fe40251eeb6608aed4560f3dc833a9877f5010ace9b1312006dbbe2f30c6e0e3e7ec47dc078b7b6b773379d44d64e44ec4e017bfa7375c", ) await expect(result).to.be.false }) @@ -81,7 +81,7 @@ describe("BLS", () => { const result = await bls.verify( "0x1644bcbb604e3608225d1826bab0b926f2df4fb506e1aa3641d5ab350ebceb5825c7df94f3a87e9dd6e11865dfdbdd3db69eab4951c8bc2250fb51da5f813009131e0c9e6d90d91741458b522b57ca99b597dd922dd31f61a2f69412ce3220d31a1ec4b09ef2ea1d6ba7cad98386f6049b5eec5fb3a40408229dc75c5759f184", "0x15c30f4b6cf6dbbcbdcc10fe22f54c8170aea44e198139b776d512d8f027319a1b9e8bfaf1383978231ce98e42bafc8129f473fc993cf60ce327f7d223460663", - "0x112d462728e89432b0fe40251eeb6608aed4560f3dc833a9877f5010ace9b1312006dbbe2f30c6e0e3e7ec47dc078b7b6b773379d44d64e44ec4e017bfa7375c" + "0x112d462728e89432b0fe40251eeb6608aed4560f3dc833a9877f5010ace9b1312006dbbe2f30c6e0e3e7ec47dc078b7b6b773379d44d64e44ec4e017bfa7375c", ) await expect(result).to.be.false }) @@ -95,7 +95,7 @@ describe("BLS", () => { const actual = await bls.verifyBytes( blsData.groupPubKey, message, - signature + signature, ) await expect(actual).to.be.true }) @@ -106,8 +106,8 @@ describe("BLS", () => { bls.verify( "0x1f1954b33144db2b5c90da089e8bde287ec7089d5d6433f3b6becaefdb678b1b2a9de38d14bef2cf9afc3c698a4211fa7ada7b4f036a2dfef0dc122b423259d01659dc18b57722ecf6a4beb4d04dfe780a660c4c3bb2b165ab8486114c464c621bf37ecdba226629c20908c7f475c5b3a7628ce26d696436eab0b0148034df", "0x15c30f4b6cf6dbbcbdcc10fe22f54c8170aea44e198139b776d512d8f027319a1b9e8bfaf1383978231ce98e42bafc8129f473fc993cf60ce327f7d223460663", - "0x112d462728e89432b0fe40251eeb6608aed4560f3dc833a9877f5010ace9b1312006dbbe2f30c6e0e3e7ec47dc078b7b6b773379d44d64e44ec4e017bfa7375c" - ) + "0x112d462728e89432b0fe40251eeb6608aed4560f3dc833a9877f5010ace9b1312006dbbe2f30c6e0e3e7ec47dc078b7b6b773379d44d64e44ec4e017bfa7375c", + ), // TODO: The exact message should be "Invalid G2 bytes length" but due to // https://github.com/nomiclabs/hardhat/issues/1873 the message // is "library was called directly". Until it's resolved, we don't @@ -120,8 +120,8 @@ describe("BLS", () => { bls.verify( "0x1f1954b33144db2b5c90da089e8bde287ec7089d5d6433f3b6becaefdb678b1b2a9de38d14bef2cf9afc3c698a4211fa7ada7b4f036a2dfef0dc122b423259d01659dc18b57722ecf6a4beb4d04dfe780a660c4c3bb2b165ab8486114c464c621bf37ecdba226629c20908c7f475c5b3a7628ce26d696436eab0b0148034dfcdcd", "0x15c30f4b6cf6dbbcbdcc10fe22f54c8170aea44e198139b776d512d8f027319a1b9e8bfaf1383978231ce98e42bafc8129f473fc993cf60ce327f7d223460663", - "0x112d462728e89432b0fe40251eeb6608aed4560f3dc833a9877f5010ace9b1312006dbbe2f30c6e0e3e7ec47dc078b7b6b773379d44d64e44ec4e017bfa7375c" - ) + "0x112d462728e89432b0fe40251eeb6608aed4560f3dc833a9877f5010ace9b1312006dbbe2f30c6e0e3e7ec47dc078b7b6b773379d44d64e44ec4e017bfa7375c", + ), // TODO: The exact message should be "Invalid G2 bytes length" but due to // https://github.com/nomiclabs/hardhat/issues/1873 the message // is "library was called directly". Until it's resolved, we don't @@ -134,8 +134,8 @@ describe("BLS", () => { bls.verify( "0x1f1954b33144db2b5c90da089e8bde287ec7089d5d6433f3b6becaefdb678b1b2a9de38d14bef2cf9afc3c698a4211fa7ada7b4f036a2dfef0dc122b423259d01659dc18b57722ecf6a4beb4d04dfe780a660c4c3bb2b165ab8486114c464c621bf37ecdba226629c20908c7f475c5b3a7628ce26d696436eab0b0148034dfcd", "0x15c30f4b6cf6dbbcbdcc10fe22f54c8170aea44e198139b776d512d8f027319a1b9e8bfaf1383978231ce98e42bafc8129f473fc993cf60ce327f7d2234606", - "0x112d462728e89432b0fe40251eeb6608aed4560f3dc833a9877f5010ace9b1312006dbbe2f30c6e0e3e7ec47dc078b7b6b773379d44d64e44ec4e017bfa7375c" - ) + "0x112d462728e89432b0fe40251eeb6608aed4560f3dc833a9877f5010ace9b1312006dbbe2f30c6e0e3e7ec47dc078b7b6b773379d44d64e44ec4e017bfa7375c", + ), // TODO: The exact message should be "Invalid G1 bytes length" but due to // https://github.com/nomiclabs/hardhat/issues/1873 the message // is "library was called directly". Until it's resolved, we don't @@ -148,8 +148,8 @@ describe("BLS", () => { bls.verify( "0x1f1954b33144db2b5c90da089e8bde287ec7089d5d6433f3b6becaefdb678b1b2a9de38d14bef2cf9afc3c698a4211fa7ada7b4f036a2dfef0dc122b423259d01659dc18b57722ecf6a4beb4d04dfe780a660c4c3bb2b165ab8486114c464c621bf37ecdba226629c20908c7f475c5b3a7628ce26d696436eab0b0148034dfcd", "0x15c30f4b6cf6dbbcbdcc10fe22f54c8170aea44e198139b776d512d8f027319a1b9e8bfaf1383978231ce98e42bafc8129f473fc993cf60ce327f7d22346066363", - "0x112d462728e89432b0fe40251eeb6608aed4560f3dc833a9877f5010ace9b1312006dbbe2f30c6e0e3e7ec47dc078b7b6b773379d44d64e44ec4e017bfa7375c" - ) + "0x112d462728e89432b0fe40251eeb6608aed4560f3dc833a9877f5010ace9b1312006dbbe2f30c6e0e3e7ec47dc078b7b6b773379d44d64e44ec4e017bfa7375c", + ), // TODO: The exact message should be "Invalid G1 bytes length" but due to // https://github.com/nomiclabs/hardhat/issues/1873 the message // is "library was called directly". Until it's resolved, we don't @@ -162,8 +162,8 @@ describe("BLS", () => { bls.verify( "0x1f1954b33144db2b5c90da089e8bde287ec7089d5d6433f3b6becaefdb678b1b2a9de38d14bef2cf9afc3c698a4211fa7ada7b4f036a2dfef0dc122b423259d01659dc18b57722ecf6a4beb4d04dfe780a660c4c3bb2b165ab8486114c464c621bf37ecdba226629c20908c7f475c5b3a7628ce26d696436eab0b0148034dfcd", "0x15c30f4b6cf6dbbcbdcc10fe22f54c8170aea44e198139b776d512d8f027319a1b9e8bfaf1383978231ce98e42bafc8129f473fc993cf60ce327f7d223460663", - "0x112d462728e89432b0fe40251eeb6608aed4560f3dc833a9877f5010ace9b1312006dbbe2f30c6e0e3e7ec47dc078b7b6b773379d44d64e44ec4e017bfa737" - ) + "0x112d462728e89432b0fe40251eeb6608aed4560f3dc833a9877f5010ace9b1312006dbbe2f30c6e0e3e7ec47dc078b7b6b773379d44d64e44ec4e017bfa737", + ), // TODO: The exact message should be "Invalid G1 bytes length" but due to // https://github.com/nomiclabs/hardhat/issues/1873 the message // is "library was called directly". Until it's resolved, we don't @@ -176,8 +176,8 @@ describe("BLS", () => { bls.verify( "0x1f1954b33144db2b5c90da089e8bde287ec7089d5d6433f3b6becaefdb678b1b2a9de38d14bef2cf9afc3c698a4211fa7ada7b4f036a2dfef0dc122b423259d01659dc18b57722ecf6a4beb4d04dfe780a660c4c3bb2b165ab8486114c464c621bf37ecdba226629c20908c7f475c5b3a7628ce26d696436eab0b0148034dfcd", "0x15c30f4b6cf6dbbcbdcc10fe22f54c8170aea44e198139b776d512d8f027319a1b9e8bfaf1383978231ce98e42bafc8129f473fc993cf60ce327f7d223460663", - "0x112d462728e89432b0fe40251eeb6608aed4560f3dc833a9877f5010ace9b1312006dbbe2f30c6e0e3e7ec47dc078b7b6b773379d44d64e44ec4e017bfa7375c5c" - ) + "0x112d462728e89432b0fe40251eeb6608aed4560f3dc833a9877f5010ace9b1312006dbbe2f30c6e0e3e7ec47dc078b7b6b773379d44d64e44ec4e017bfa7375c5c", + ), // TODO: The exact message should be "Invalid G1 bytes length" but due to // https://github.com/nomiclabs/hardhat/issues/1873 the message // is "library was called directly". Until it's resolved, we don't diff --git a/solidity/random-beacon/test/BeaconDkgValidator.test.ts b/solidity/random-beacon/test/BeaconDkgValidator.test.ts index 8a33b32cc8..444c5ef089 100644 --- a/solidity/random-beacon/test/BeaconDkgValidator.test.ts +++ b/solidity/random-beacon/test/BeaconDkgValidator.test.ts @@ -1,13 +1,7 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions, no-await-in-loop */ +/* eslint-disable @typescript-eslint/no-unused-expressions */ -import { BigNumber } from "ethers" -import { - ethers, - helpers, - getUnnamedAccounts, - waffle, - deployments, -} from "hardhat" +import { ethers, helpers, getUnnamedAccounts, deployments } from "hardhat" +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" import { expect } from "chai" import blsData from "./data/bls" @@ -38,17 +32,17 @@ const fixture = async () => { const SortitionPool = await ethers.getContractFactory("SortitionPool") const sortitionPool = (await SortitionPool.deploy( - t.address, - constants.poolWeightDivisor + await t.getAddress(), + constants.poolWeightDivisor, )) as SortitionPool await sortitionPool.deactivateChaosnet() const DKGValidator = await ethers.getContractFactory("BeaconDkgValidator") const dkgValidator = (await DKGValidator.deploy( - sortitionPool.address + await sortitionPool.getAddress(), )) as DKGValidator - await dkgValidator.deployed() + await dkgValidator.waitForDeployment() return { sortitionPool, @@ -57,11 +51,11 @@ const fixture = async () => { } describe("BeaconDkgValidator", () => { - const dkgSeed: BigNumber = BigNumber.from( - "31415926535897932384626433832795028841971693993751058209749445923078164062862" + const dkgSeed = BigInt( + "31415926535897932384626433832795028841971693993751058209749445923078164062862", ) const dkgStartBlock = 1337 - const groupPublicKey: string = ethers.utils.hexValue(blsData.groupPubKey) + const groupPublicKey: string = ethers.toQuantity(blsData.groupPubKey) let selectedOperators: Operator[] @@ -72,13 +66,13 @@ describe("BeaconDkgValidator", () => { _misbehaved: number[], _startBlock: number, _numberOfSignatures?: number, - _submitterIndex?: number + _submitterIndex?: number, ) => Promise let validator: DKGValidator before("load test fixture", async () => { - const contracts = await waffle.loadFixture(fixture) + const contracts = await loadFixture(fixture) const { sortitionPool } = contracts validator = contracts.dkgValidator @@ -98,14 +92,14 @@ describe("BeaconDkgValidator", () => { _misbehaved: number[], _startBlock: number, _numberOfSignatures = 33, - _submitterIndex = 1 + _submitterIndex = 1, ): Promise => { const { signingMembersIndices, signaturesBytes } = await signDkgResult( _signers, _groupPublicKey, _misbehaved, _startBlock, - _numberOfSignatures + _numberOfSignatures, ) const dkgResult: DKG.ResultStruct = { @@ -117,7 +111,7 @@ describe("BeaconDkgValidator", () => { members: _groupMembers.map((m) => m.id), membersHash: hashDKGMembers( _groupMembers.map((m) => m.id), - _misbehaved + _misbehaved, ), } @@ -131,14 +125,14 @@ describe("BeaconDkgValidator", () => { _signers: Operator[], _groupPublicKey: string, _misbehaved: number[], - _membersHash?: string + _membersHash?: string, ) => { const dkgResult = await prepareDkgResult( _groupMembers, _signers, _groupPublicKey, _misbehaved, - dkgStartBlock + dkgStartBlock, ) if (_membersHash) { @@ -176,7 +170,7 @@ describe("BeaconDkgValidator", () => { selectedOperators, selectedOperators, groupPublicKey, - misbehavedMemberIds + misbehavedMemberIds, ) expect(result.isValid).to.be.true @@ -196,7 +190,7 @@ describe("BeaconDkgValidator", () => { selectedOperators, selectedOperators, groupPublicKey, - misbehavedMemberIds + misbehavedMemberIds, ) expect(result.isValid).to.be.true @@ -214,7 +208,7 @@ describe("BeaconDkgValidator", () => { selectedOperators, selectedOperators, groupPublicKey, - misbehavedMemberIds + misbehavedMemberIds, ) expect(result.isValid).to.be.true @@ -234,7 +228,7 @@ describe("BeaconDkgValidator", () => { selectedOperators, groupPublicKey, misbehavedMemberIds, - hashUint32Array(expectedMembersIds) + hashUint32Array(expectedMembersIds), ) expect(result.isValid).to.be.false @@ -249,7 +243,7 @@ describe("BeaconDkgValidator", () => { selectedOperators, selectedOperators, groupPublicKey, - noMisbehaved + noMisbehaved, ) expect(result.isValid).to.be.true @@ -268,7 +262,7 @@ describe("BeaconDkgValidator", () => { shuffledOperators, shuffledOperators, groupPublicKey, - noMisbehaved + noMisbehaved, ) expect(result.isValid).to.be.false @@ -287,7 +281,7 @@ describe("BeaconDkgValidator", () => { selectedOperators, shuffledOperators, groupPublicKey, - noMisbehaved + noMisbehaved, ) expect(result.isValid).to.be.false @@ -301,7 +295,7 @@ describe("BeaconDkgValidator", () => { _groupMembers: Operator[], _groupPublicKey: string, _misbehaved: number[], - _numberOfSignatures = 33 + _numberOfSignatures = 33, ) => { const dkgResult = await prepareDkgResult( _groupMembers, @@ -309,7 +303,7 @@ describe("BeaconDkgValidator", () => { _groupPublicKey, _misbehaved, dkgStartBlock, - _numberOfSignatures + _numberOfSignatures, ) const result = await validator.validateFields(dkgResult) @@ -325,7 +319,7 @@ describe("BeaconDkgValidator", () => { const result = await testValidateFields( selectedOperators, groupPublicKey, - noMisbehaved + noMisbehaved, ) expect(result.isValid).to.be.true @@ -340,7 +334,7 @@ describe("BeaconDkgValidator", () => { const result = await testValidateFields( selectedOperators, empty, - noMisbehaved + noMisbehaved, ) expect(result.isValid).to.be.false @@ -352,12 +346,12 @@ describe("BeaconDkgValidator", () => { it("should return validation error", async () => { const tooShort = groupPublicKey.substring( 0, - groupPublicKey.length - 2 + groupPublicKey.length - 2, ) const result = await testValidateFields( selectedOperators, tooShort, - noMisbehaved + noMisbehaved, ) expect(result.isValid).to.be.false @@ -371,7 +365,7 @@ describe("BeaconDkgValidator", () => { const result = await testValidateFields( selectedOperators, tooLong, - noMisbehaved + noMisbehaved, ) expect(result.isValid).to.be.false @@ -387,12 +381,12 @@ describe("BeaconDkgValidator", () => { const result = await testValidateFields( selectedOperators, groupPublicKey, - lessThanOne + lessThanOne, ) expect(result.isValid).to.be.false expect(result.errorMsg).to.equal( - "Corrupted misbehaved members indices" + "Corrupted misbehaved members indices", ) }) }) @@ -403,12 +397,12 @@ describe("BeaconDkgValidator", () => { const result = await testValidateFields( selectedOperators, groupPublicKey, - higherThanGroupSize + higherThanGroupSize, ) expect(result.isValid).to.be.false expect(result.errorMsg).to.equal( - "Corrupted misbehaved members indices" + "Corrupted misbehaved members indices", ) }) }) @@ -419,12 +413,12 @@ describe("BeaconDkgValidator", () => { const result = await testValidateFields( selectedOperators, groupPublicKey, - unsorted + unsorted, ) expect(result.isValid).to.be.false expect(result.errorMsg).to.equal( - "Corrupted misbehaved members indices" + "Corrupted misbehaved members indices", ) }) }) @@ -435,12 +429,12 @@ describe("BeaconDkgValidator", () => { const result = await testValidateFields( selectedOperators, groupPublicKey, - tooMany + tooMany, ) expect(result.isValid).to.be.false expect(result.errorMsg).to.equal( - "Too many members misbehaving during DKG" + "Too many members misbehaving during DKG", ) }) }) @@ -454,7 +448,7 @@ describe("BeaconDkgValidator", () => { selectedOperators, groupPublicKey, noMisbehaved, - noSignatures + noSignatures, ) expect(result.isValid).to.be.false @@ -469,7 +463,7 @@ describe("BeaconDkgValidator", () => { selectedOperators, groupPublicKey, noMisbehaved, - dkgStartBlock + dkgStartBlock, ) dkgResult.signatures += "ff" const result = await validator.validateFields(dkgResult) @@ -487,7 +481,7 @@ describe("BeaconDkgValidator", () => { selectedOperators, groupPublicKey, noMisbehaved, - dkgStartBlock + dkgStartBlock, ) dkgResult.signatures += "f".repeat(signatureHexStrLength) const result = await validator.validateFields(dkgResult) @@ -504,7 +498,7 @@ describe("BeaconDkgValidator", () => { selectedOperators, groupPublicKey, noMisbehaved, - tooFewSignatures + tooFewSignatures, ) expect(result.isValid).to.be.false @@ -522,7 +516,7 @@ describe("BeaconDkgValidator", () => { groupPublicKey, noMisbehaved, dkgStartBlock, - maxSignatures + maxSignatures, ) dkgResult.signatures += "f".repeat(signatureHexStrLength) dkgResult.signingMembersIndices.push(65) @@ -536,14 +530,14 @@ describe("BeaconDkgValidator", () => { context("when signing members indices array is malformed", async () => { const testSigningMembers = async ( - _signingMembersIndices: BigNumberish[] + _signingMembersIndices: BigNumberish[], ) => { const dkgResult = await prepareDkgResult( selectedOperators, selectedOperators, groupPublicKey, noMisbehaved, - dkgStartBlock + dkgStartBlock, ) dkgResult.signingMembersIndices = _signingMembersIndices @@ -603,7 +597,7 @@ describe("BeaconDkgValidator", () => { _groupMembers, groupPublicKey, noMisbehaved, - dkgStartBlock + dkgStartBlock, ) return validator.validateGroupMembers(dkgResult, dkgSeed) @@ -619,7 +613,7 @@ describe("BeaconDkgValidator", () => { context("when there are operators other then selected", () => { it("should fail the validation", async () => { const isValid = await testValidateGroupMembers( - shuffle(selectedOperators) + shuffle(selectedOperators), ) expect(isValid).to.be.false }) @@ -629,14 +623,14 @@ describe("BeaconDkgValidator", () => { describe("validateSignatures", () => { const testValidateSignatures = async ( _groupMembers: Operator[], - _signers: Operator[] + _signers: Operator[], ) => { const dkgResult = await prepareDkgResult( _groupMembers, _signers, groupPublicKey, noMisbehaved, - dkgStartBlock + dkgStartBlock, ) return validator.validateSignatures(dkgResult, dkgStartBlock) @@ -646,7 +640,7 @@ describe("BeaconDkgValidator", () => { it("should pass", async () => { const isValid = await testValidateSignatures( selectedOperators, - selectedOperators + selectedOperators, ) expect(isValid).to.be.true @@ -658,16 +652,16 @@ describe("BeaconDkgValidator", () => { () => { it("should fail the validation", async () => { const maliciousSigners = Array(constants.groupSize).fill( - selectedOperators[0] + selectedOperators[0], ) const isValid = await testValidateSignatures( selectedOperators, - maliciousSigners + maliciousSigners, ) expect(isValid).to.be.false }) - } + }, ) context("when signatures do not matching signers", () => { @@ -677,7 +671,7 @@ describe("BeaconDkgValidator", () => { selectedOperators, groupPublicKey, noMisbehaved, - dkgStartBlock + dkgStartBlock, ) // reverse order of signers ;[ @@ -689,7 +683,7 @@ describe("BeaconDkgValidator", () => { ] const isValid = await validator.validateSignatures( dkgResult, - dkgStartBlock + dkgStartBlock, ) expect(isValid).to.be.false @@ -698,26 +692,26 @@ describe("BeaconDkgValidator", () => { context("when signatures contain wrong result hash", () => { const signWithWrongResultHash = async (signingOperators: Operator[]) => { - const wrongResultHash = ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode( + const wrongResultHash = ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( ["uint256", "bytes", "uint8[]", "uint256"], [ hardhatNetworkId, groupPublicKey, noMisbehaved, dkgStartBlock + 12345, - ] - ) + ], + ), ) const signatures = [] for (let i = 0; i < signingOperators.length; i++) { const { signer: ethersSigner } = signingOperators[i] const signature = await ethersSigner.signMessage( - ethers.utils.arrayify(wrongResultHash) + ethers.getBytes(wrongResultHash), ) signatures.push(signature) } - const signaturesBytes = ethers.utils.hexConcat(signatures) + const signaturesBytes = ethers.concat(signatures) return signaturesBytes } @@ -729,14 +723,14 @@ describe("BeaconDkgValidator", () => { groupPublicKey, noMisbehaved, dkgStartBlock, - numberOfSignatures + numberOfSignatures, ) dkgResult.signatures = await signWithWrongResultHash( - selectedOperators.slice(numberOfSignatures - 1) + selectedOperators.slice(numberOfSignatures - 1), ) const isValid = await validator.validateSignatures( dkgResult, - dkgStartBlock + dkgStartBlock, ) expect(isValid).to.be.false @@ -753,15 +747,15 @@ describe("BeaconDkgValidator", () => { groupPublicKey, noMisbehaved, dkgStartBlock, - numberOfSignatures + numberOfSignatures, ) const wrongSignatures = `0x${"a".repeat( - signatureHexStrLength * numberOfSignatures + signatureHexStrLength * numberOfSignatures, )}` dkgResult.signatures = wrongSignatures await expect( - validator.validateSignatures(dkgResult, dkgStartBlock) + validator.validateSignatures(dkgResult, dkgStartBlock), ).to.be.revertedWith("ECDSA: invalid signature 's' value") }) }) diff --git a/solidity/random-beacon/test/Governable.test.ts b/solidity/random-beacon/test/Governable.test.ts index 7592980a74..a9a44453a2 100644 --- a/solidity/random-beacon/test/Governable.test.ts +++ b/solidity/random-beacon/test/Governable.test.ts @@ -2,8 +2,8 @@ import { expect } from "chai" import { ethers, helpers } from "hardhat" -import type { ContractTransaction } from "ethers" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import type { ContractTransactionResponse } from "ethers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" import type { GovernableImpl, GovernableImpl__factory } from "../typechain" const { createSnapshot, restoreSnapshot } = helpers.snapshot @@ -15,7 +15,6 @@ describe("Governable", () => { let thirdParty: SignerWithAddress before(async () => { - // eslint-disable-next-line @typescript-eslint/no-extra-semi ;({ deployer, governance } = await helpers.signers.getNamedSigners()) ;[thirdParty] = await helpers.signers.getUnnamedSigners() @@ -24,11 +23,11 @@ describe("Governable", () => { governable = await GovernableFactory.deploy() }) + // Initializer wiring: governance is unset until transferGovernance runs; the behavioural + // arms live in the groups below. describe("constructor", () => { it("should set governance to default zero address", async () => { - expect(await governable.governance()).to.be.equal( - ethers.constants.AddressZero - ) + expect(await governable.governance()).to.be.equal(ethers.ZeroAddress) }) }) @@ -39,7 +38,7 @@ describe("Governable", () => { await expect( governable .connect(deployer) - .transferGovernance(ethers.Wallet.createRandom().address) + .transferGovernance(ethers.Wallet.createRandom().address), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -49,7 +48,7 @@ describe("Governable", () => { await expect( governable .connect(governance) - .transferGovernance(ethers.Wallet.createRandom().address) + .transferGovernance(ethers.Wallet.createRandom().address), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -59,7 +58,7 @@ describe("Governable", () => { await expect( governable .connect(thirdParty) - .transferGovernance(ethers.Wallet.createRandom().address) + .transferGovernance(ethers.Wallet.createRandom().address), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -75,14 +74,14 @@ describe("Governable", () => { await expect( governable .connect(deployer) - .transferGovernance(ethers.Wallet.createRandom().address) + .transferGovernance(ethers.Wallet.createRandom().address), ).to.be.revertedWith("Caller is not the governance") }) }) describe("when called by the governance", () => { const newGovernance: string = ethers.Wallet.createRandom().address - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -112,7 +111,7 @@ describe("Governable", () => { await expect( governable .connect(thirdParty) - .transferGovernance(ethers.Wallet.createRandom().address) + .transferGovernance(ethers.Wallet.createRandom().address), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -122,7 +121,7 @@ describe("Governable", () => { await expect( governable .connect(governance) - .transferGovernance(ethers.constants.AddressZero) + .transferGovernance(ethers.ZeroAddress), ).to.be.revertedWith("New governance is the zero address") }) }) @@ -148,9 +147,9 @@ describe("Governable", () => { it("should not be exposed directly", async () => { expect( - governable.functions, - "_transferGovernance function is exposed on the contract" - ).to.not.haveOwnProperty("_transferGovernance") + governable.interface.hasFunction("_transferGovernance"), + "_transferGovernance function is exposed on the contract", + ).to.equal(false) }) }) }) diff --git a/solidity/random-beacon/test/Groups.Expiration.test.ts b/solidity/random-beacon/test/Groups.Expiration.test.ts index b0da9e20a3..cecd295753 100644 --- a/solidity/random-beacon/test/Groups.Expiration.test.ts +++ b/solidity/random-beacon/test/Groups.Expiration.test.ts @@ -1,6 +1,8 @@ -import { ethers, waffle, helpers } from "hardhat" +import { ethers, helpers } from "hardhat" +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" import { expect } from "chai" +import requireResult from "./helpers/chain" import { noMisbehaved, hashDKGMembers } from "./utils/dkg" import type { BigNumberish } from "ethers" @@ -22,7 +24,7 @@ describe("Groups", () => { let groups: GroupsStub beforeEach("load test fixture", async () => { - groups = await waffle.loadFixture(fixture) + groups = await loadFixture(fixture) }) describe("expireOldGroups", async () => { @@ -138,25 +140,29 @@ describe("Groups", () => { it("should revert group selection", async () => { await addGroups(1, 5) - const currentBlock = await ethers.provider.getBlock("latest") + const currentBlock = requireResult( + await ethers.provider.getBlock("latest"), + ) await mineBlocksTo(currentBlock.number + groupLifetime) await expect(groups.selectGroup(0)).to.be.revertedWith( - "No active groups" + "No active groups", ) }) it("should allow to add and select new group", async () => { await addGroups(1, 5) - const currentBlock = await ethers.provider.getBlock("latest") + const currentBlock = requireResult( + await ethers.provider.getBlock("latest"), + ) await mineBlocksTo(currentBlock.number + groupLifetime) await groups.addGroup( - ethers.utils.hexlify(6), - hashDKGMembers(members, noMisbehaved) + ethers.toBeHex(6), + hashDKGMembers(members, noMisbehaved), ) - const selected = await groups.callStatic.selectGroup(0) + const selected = await groups.selectGroup.staticCall(0) await groups.selectGroup(0) const numberOfGroups = await groups.numberOfActiveGroups() @@ -180,7 +186,9 @@ describe("Groups", () => { await addTerminatedGroups(3, 2) // terminating [0x4, 0x5] // move blocks so terminated blocks qualify for expiration - const currentBlock = await ethers.provider.getBlock("latest") + const currentBlock = requireResult( + await ethers.provider.getBlock("latest"), + ) await mineBlocksTo(currentBlock.number + groupLifetime) // [0x1, 0x2, 0x3, 0x4, 0x5] @@ -188,7 +196,7 @@ describe("Groups", () => { await addGroups(6, 5) // First active index group that qualifies for selection - const selectedGroupId = await groups.callStatic.selectGroup(5) + const selectedGroupId = await groups.selectGroup.staticCall(5) expect(selectedGroupId).to.be.equal(5) }) @@ -202,7 +210,7 @@ describe("Groups", () => { await addGroups(4, 7) // [0x4,0x5,0x6,0x7,0x8,0x9,0xa] // First active index group that qualifies for selection - const selectedGroupId = await groups.callStatic.selectGroup(1) + const selectedGroupId = await groups.selectGroup.staticCall(1) // 1 expired + 2 terminated + selected index (1) expect(selectedGroupId).to.be.equal(4) }) @@ -212,7 +220,9 @@ describe("Groups", () => { await groups.terminateGroup(1) // [0x2] // move blocks so terminated blocks qualify for expiration - const currentBlock = await ethers.provider.getBlock("latest") + const currentBlock = requireResult( + await ethers.provider.getBlock("latest"), + ) await mineBlocksTo(currentBlock.number + groupLifetime) let activeTerminatedGroups = await groups.activeTerminatedGroups() @@ -238,7 +248,7 @@ describe("Groups", () => { expect(numberOfGroups).to.be.equal(5) // Second active index group that qualifies for selection - const selectedIndex = await groups.callStatic.selectGroup(2) + const selectedIndex = await groups.selectGroup.staticCall(2) // expired ids: [0, 1, 2] // terminated ids: [4, 6] @@ -254,7 +264,7 @@ describe("Groups", () => { await groups.terminateGroup(9) // terminating [0xa] await expect(groups.selectGroup(2)).to.be.revertedWith( - "No active groups" + "No active groups", ) }) @@ -268,7 +278,9 @@ describe("Groups", () => { await groups.terminateGroup(30) // move blocks so terminated blocks qualify for expiration - const currentBlock = await ethers.provider.getBlock("latest") + const currentBlock = requireResult( + await ethers.provider.getBlock("latest"), + ) await mineBlocksTo(currentBlock.number + groupLifetime) await groups.expireOldGroups() @@ -290,8 +302,8 @@ describe("Groups", () => { async function addGroups(firstGroup: number, numberOfGroups: number) { for (let i = firstGroup; i < firstGroup + numberOfGroups; i++) { await groups.addGroup( - ethers.utils.hexlify(i), - hashDKGMembers(members, noMisbehaved) + ethers.toBeHex(i), + hashDKGMembers(members, noMisbehaved), ) } } @@ -299,12 +311,12 @@ describe("Groups", () => { async function expireGroup(groupId: BigNumberish) { const group = await groups.getGroupById(groupId) const registrationBlock = group.registrationBlockNumber - const currentBlock = await ethers.provider.getBlock("latest") + const currentBlock = requireResult(await ethers.provider.getBlock("latest")) - if (currentBlock.number - registrationBlock.toNumber() <= groupLifetime) { + if (currentBlock.number - Number(registrationBlock) <= groupLifetime) { const minedBlocksToExpireGroup = currentBlock.number + - (groupLifetime - (currentBlock.number - registrationBlock.toNumber())) + + (groupLifetime - (currentBlock.number - Number(registrationBlock))) + 1 await mineBlocksTo(minedBlocksToExpireGroup) } @@ -312,7 +324,7 @@ describe("Groups", () => { async function addTerminatedGroups( firstGroupIdToTerminate: number, - numberOfTerminatedGroups: number + numberOfTerminatedGroups: number, ) { for ( let i = firstGroupIdToTerminate; @@ -326,7 +338,7 @@ describe("Groups", () => { async function runExpirationTest( numberOfGroups: number, expiredCount: number, - beaconValue: BigNumberish + beaconValue: BigNumberish, ) { await addGroups(1, numberOfGroups) if (expiredCount > 0) { @@ -334,6 +346,6 @@ describe("Groups", () => { // count since we index from 0. await expireGroup(expiredCount - 1) } - return groups.callStatic.selectGroup(beaconValue) + return groups.selectGroup.staticCall(beaconValue) } }) diff --git a/solidity/random-beacon/test/Groups.Termination.test.ts b/solidity/random-beacon/test/Groups.Termination.test.ts index 8cbc486821..cfe60db9c0 100644 --- a/solidity/random-beacon/test/Groups.Termination.test.ts +++ b/solidity/random-beacon/test/Groups.Termination.test.ts @@ -1,6 +1,8 @@ -import { ethers, waffle, helpers } from "hardhat" +import { ethers, helpers } from "hardhat" +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" import { expect } from "chai" +import requireResult from "./helpers/chain" import { noMisbehaved, hashDKGMembers } from "./utils/dkg" import type { BigNumberish } from "ethers" @@ -22,7 +24,7 @@ describe("Groups", () => { let groups: GroupsStub beforeEach("load test fixture", async () => { - groups = await waffle.loadFixture(fixture) + groups = await loadFixture(fixture) }) describe("terminateGroup", async () => { @@ -77,7 +79,7 @@ describe("Groups", () => { const selectedIndex = await runTerminationTest(8, 0, [7, 0, 4, 2], 3) expect(6).to.be.equal(selectedIndex) }) - } + }, ) context("when not selecting terminated groups", async () => { @@ -218,23 +220,23 @@ describe("Groups", () => { const selectedIndex = await runTerminationTest(10, 3, [3, 4, 6, 9], 5) expect(8).to.be.equal(selectedIndex) }) - } + }, ) context("when there are no active groups", async () => { it("T", async () => { await expect(runTerminationTest(1, 0, [0], 0)).to.be.revertedWith( - "No active groups" + "No active groups", ) }) it("TT", async () => { await expect(runTerminationTest(2, 0, [0, 1], 0)).to.be.revertedWith( - "No active groups" + "No active groups", ) }) it("ET", async () => { await expect(runTerminationTest(2, 1, [1], 0)).to.be.revertedWith( - "No active groups" + "No active groups", ) }) }) @@ -242,8 +244,8 @@ describe("Groups", () => { async function addGroups(start: number, numberOfGroups: number) { for (let i = start; i <= numberOfGroups; i++) { await groups.addGroup( - ethers.utils.hexlify(i), - hashDKGMembers(members, noMisbehaved) + ethers.toBeHex(i), + hashDKGMembers(members, noMisbehaved), ) } } @@ -252,11 +254,13 @@ describe("Groups", () => { groupsCount: number, expiredCount: number, terminatedGroups: number[], - beaconValue: BigNumberish + beaconValue: BigNumberish, ) { await addGroups(1, expiredCount) - const currentBlock = await ethers.provider.getBlock("latest") + const currentBlock = requireResult( + await ethers.provider.getBlock("latest"), + ) await mineBlocksTo(currentBlock.number + groupLifetime) await addGroups(expiredCount + 1, groupsCount) @@ -265,7 +269,7 @@ describe("Groups", () => { await groups.terminateGroup(terminatedGroups[i]) } - return groups.callStatic.selectGroup(beaconValue) + return groups.selectGroup.staticCall(beaconValue) } }) }) diff --git a/solidity/random-beacon/test/Groups.test.ts b/solidity/random-beacon/test/Groups.test.ts index 07b830ef6b..6eca3444f4 100644 --- a/solidity/random-beacon/test/Groups.test.ts +++ b/solidity/random-beacon/test/Groups.test.ts @@ -1,16 +1,18 @@ -import { ethers, waffle } from "hardhat" +import { ethers } from "hardhat" +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" import { expect } from "chai" +import requireResult from "./helpers/chain" import blsData from "./data/bls" import { constants } from "./fixtures" import { noMisbehaved, hashDKGMembers } from "./utils/dkg" import { hashUint32Array } from "./utils/groups" import type { GroupsStub } from "../typechain" -import type { ContractTransaction } from "ethers" -import type { Groups } from "../typechain/GroupsStub" +import type { ContractTransactionResponse } from "ethers" +import type { Groups } from "../typechain/contracts/test/GroupsStub" -const { keccak256 } = ethers.utils +const { keccak256 } = ethers const fixture = async () => { const GroupsStub = await ethers.getContractFactory("GroupsStub") @@ -20,7 +22,7 @@ const fixture = async () => { } describe("Groups", () => { - const groupPublicKey: string = ethers.utils.hexValue(blsData.groupPubKey) + const groupPublicKey: string = ethers.toQuantity(blsData.groupPubKey) const members: number[] = [] let groups: GroupsStub @@ -30,23 +32,23 @@ describe("Groups", () => { }) beforeEach("load test fixture", async () => { - groups = await waffle.loadFixture(fixture) + groups = await loadFixture(fixture) }) describe("validatePublicKey", async () => { beforeEach(async () => { await groups.addGroup( groupPublicKey, - hashDKGMembers(members, noMisbehaved) + hashDKGMembers(members, noMisbehaved), ) }) context("when group is already registered", async () => { it("should revert with 'Group with this public key was already registered' error", async () => { await expect( - groups.validatePublicKey(groupPublicKey) + groups.validatePublicKey(groupPublicKey), ).to.be.revertedWith( - "Group with this public key was already registered" + "Group with this public key was already registered", ) }) }) @@ -54,13 +56,13 @@ describe("Groups", () => { describe("addGroup", async () => { context("when no groups are registered", async () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse context("with no misbehaved members", async () => { beforeEach(async () => { tx = await groups.addGroup( groupPublicKey, - hashDKGMembers(members, noMisbehaved) + hashDKGMembers(members, noMisbehaved), ) }) @@ -82,7 +84,7 @@ describe("Groups", () => { expect(storedGroup.groupPubKey).to.be.equal(groupPublicKey) expect(storedGroup.registrationBlockNumber).to.be.equal( - tx.blockNumber + requireResult(await tx.wait()).blockNumber, ) expect(storedGroup.membersHash).to.be.equal(hashUint32Array(members)) }) @@ -95,7 +97,7 @@ describe("Groups", () => { await groups.addGroup( groupPublicKey, - hashDKGMembers(members, misbehavedIndices) + hashDKGMembers(members, misbehavedIndices), ) const expectedMembers = [...members] @@ -103,7 +105,7 @@ describe("Groups", () => { const expectedMembersHash = hashUint32Array(expectedMembers) expect( - (await groups.getGroup(groupPublicKey)).membersHash + (await groups.getGroup(groupPublicKey)).membersHash, ).to.be.equal(expectedMembersHash) }) }) @@ -113,14 +115,14 @@ describe("Groups", () => { const misbehavedIndices: number[] = [constants.groupSize] await groups.addGroup( groupPublicKey, - hashDKGMembers(members, misbehavedIndices) + hashDKGMembers(members, misbehavedIndices), ) const expectedMembers = [...members] expectedMembers.pop() const expectedMembersHash = hashUint32Array(expectedMembers) expect( - (await groups.getGroup(groupPublicKey)).membersHash + (await groups.getGroup(groupPublicKey)).membersHash, ).to.be.equal(expectedMembersHash) }) }) @@ -130,7 +132,7 @@ describe("Groups", () => { const misbehavedIndices: number[] = [24] await groups.addGroup( groupPublicKey, - hashDKGMembers(members, misbehavedIndices) + hashDKGMembers(members, misbehavedIndices), ) const expectedMembers = [...members] @@ -138,7 +140,7 @@ describe("Groups", () => { const expectedMembersHash = hashUint32Array(expectedMembers) expect( - (await groups.getGroup(groupPublicKey)).membersHash + (await groups.getGroup(groupPublicKey)).membersHash, ).to.be.equal(expectedMembersHash) }) }) @@ -148,7 +150,7 @@ describe("Groups", () => { const misbehavedIndices: number[] = [1, 16, 35, constants.groupSize] await groups.addGroup( groupPublicKey, - hashDKGMembers(members, misbehavedIndices) + hashDKGMembers(members, misbehavedIndices), ) const expectedMembers = [...members] expectedMembers.splice(0, 1) // index -1 @@ -159,7 +161,7 @@ describe("Groups", () => { const expectedMembersHash = hashUint32Array(expectedMembers) expect( - (await groups.getGroup(groupPublicKey)).membersHash + (await groups.getGroup(groupPublicKey)).membersHash, ).to.be.equal(expectedMembersHash) }) }) @@ -179,7 +181,7 @@ describe("Groups", () => { await groups.addGroup( existingGroupPublicKey, - hashDKGMembers(existingGroupMembers, noMisbehaved) + hashDKGMembers(existingGroupMembers, noMisbehaved), ) existingGroup = await groups.getGroup(existingGroupPublicKey) @@ -188,12 +190,12 @@ describe("Groups", () => { context("with unique group public key", async () => { const newGroupPublicKey = groupPublicKey - let tx: ContractTransaction + let tx: ContractTransactionResponse beforeEach(async () => { tx = await groups.addGroup( newGroupPublicKey, - hashDKGMembers(newGroupMembers, noMisbehaved) + hashDKGMembers(newGroupMembers, noMisbehaved), ) }) @@ -215,10 +217,10 @@ describe("Groups", () => { expect(storedGroup.groupPubKey).to.be.equal(newGroupPublicKey) expect(storedGroup.registrationBlockNumber).to.be.equal( - tx.blockNumber + requireResult(await tx.wait()).blockNumber, ) expect(storedGroup.membersHash).to.be.equal( - hashUint32Array(newGroupMembers) + hashUint32Array(newGroupMembers), ) }) @@ -226,18 +228,18 @@ describe("Groups", () => { const groupsRegistry = await groups.getGroupsRegistry() expect(groupsRegistry[0]).to.deep.equal( - keccak256(existingGroupPublicKey) + keccak256(existingGroupPublicKey), ) const storedGroup = await groups.getGroup(existingGroupPublicKey) expect(storedGroup.groupPubKey).to.be.equal(existingGroupPublicKey) expect(storedGroup.registrationBlockNumber).to.be.equal( - existingGroup.registrationBlockNumber + existingGroup.registrationBlockNumber, ) expect(storedGroup.membersHash).to.be.equal( - hashUint32Array(existingGroupMembers) + hashUint32Array(existingGroupMembers), ) }) }) diff --git a/solidity/random-beacon/test/ModUtils.test.ts b/solidity/random-beacon/test/ModUtils.test.ts index 20a6d68eba..7b2c5df855 100644 --- a/solidity/random-beacon/test/ModUtils.test.ts +++ b/solidity/random-beacon/test/ModUtils.test.ts @@ -1,4 +1,5 @@ -import { ethers, waffle } from "hardhat" +import { ethers } from "hardhat" +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" import type { TestModUtils } from "../typechain" @@ -8,13 +9,13 @@ describe("ModUtils", () => { const fixture = async () => { const TestModUtils = await ethers.getContractFactory("TestModUtils") testModUtils = await TestModUtils.deploy() - await testModUtils.deployed() + await testModUtils.waitForDeployment() return testModUtils } beforeEach("load test fixture", async () => { - testModUtils = await waffle.loadFixture(fixture) + testModUtils = await loadFixture(fixture) }) it("runModExponentTest()", async () => { diff --git a/solidity/random-beacon/test/RandomBeacon.Authorization.test.ts b/solidity/random-beacon/test/RandomBeacon.Authorization.test.ts index 6520f5bb01..6a38631f92 100644 --- a/solidity/random-beacon/test/RandomBeacon.Authorization.test.ts +++ b/solidity/random-beacon/test/RandomBeacon.Authorization.test.ts @@ -1,14 +1,18 @@ /* eslint-disable @typescript-eslint/no-unused-expressions */ import { ethers, helpers } from "hardhat" -import { createMock } from "./helpers/mock" import { expect } from "chai" +import { createMock } from "./helpers/mock" import { constants, params, randomBeaconDeployment } from "./fixtures" import { legacyTokenStakingAt } from "./utils/operators" +import { + shouldOverwritePreviousRequest, + shouldRequireUpdatingPoolBeforeApproving, +} from "./behaviors/authorization" import type { Mock } from "./helpers/mock" -import type { BigNumber, BigNumberish, ContractTransaction } from "ethers" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import type { BigNumberish, ContractTransactionResponse } from "ethers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" import type { RandomBeacon, SortitionPool, @@ -23,8 +27,8 @@ const { mineBlocks } = helpers.time const { createSnapshot, restoreSnapshot } = helpers.snapshot -const ZERO_ADDRESS = ethers.constants.AddressZero -const MAX_UINT64 = ethers.BigNumber.from("18446744073709551615") // 2^64 - 1 +const ZERO_ADDRESS = ethers.ZeroAddress +const MAX_UINT64 = BigInt("18446744073709551615") // 2^64 - 1 describe("RandomBeacon - Authorization", () => { let t: T @@ -45,7 +49,7 @@ describe("RandomBeacon - Authorization", () => { let slasher: Mock const stakedAmount = to1e18(1_000_000) // 1MM T - let minimumAuthorization: BigNumber + let minimumAuthorization: bigint before("load test fixture", async () => { const contracts = await randomBeaconDeployment() @@ -61,12 +65,12 @@ describe("RandomBeacon - Authorization", () => { await helpers.signers.getUnnamedSigners() await t.connect(deployer).mint(owner.address, stakedAmount) - await t.connect(owner).approve(staking.address, stakedAmount) + await t.connect(owner).approve(await staking.getAddress(), stakedAmount) await legacyTokenStakingAt(staking, owner).stake( stakingProvider.address, beneficiary.address, authorizer.address, - stakedAmount + stakedAmount, ) minimumAuthorization = await randomBeacon.minimumAuthorization() @@ -75,12 +79,12 @@ describe("RandomBeacon - Authorization", () => { // staking provider. slasher = await createMock("IApplication") await legacyTokenStakingAt(staking, deployer).approveApplication( - slasher.address + slasher.address, ) await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, slasher.address, - stakedAmount + stakedAmount, ) // Fund slasher so that it can call T TokenStaking functions @@ -88,7 +92,7 @@ describe("RandomBeacon - Authorization", () => { await ethers.getSigners() )[0].sendTransaction({ to: slasher.address, - value: ethers.utils.parseEther("100"), + value: ethers.parseEther("100"), }) }) @@ -96,7 +100,7 @@ describe("RandomBeacon - Authorization", () => { context("when called with zero-address operator", () => { it("should revert", async () => { await expect( - randomBeacon.connect(stakingProvider).registerOperator(ZERO_ADDRESS) + randomBeacon.connect(stakingProvider).registerOperator(ZERO_ADDRESS), ).to.be.revertedWith("Operator can not be zero address") }) }) @@ -123,7 +127,7 @@ describe("RandomBeacon - Authorization", () => { await expect( randomBeacon .connect(stakingProvider) - .registerOperator(operator.address) + .registerOperator(operator.address), ).to.be.revertedWith("Operator already set for the staking provider") // should revert even if it's another operator than the one previously @@ -131,10 +135,10 @@ describe("RandomBeacon - Authorization", () => { await expect( randomBeacon .connect(stakingProvider) - .registerOperator(thirdParty.address) + .registerOperator(thirdParty.address), ).to.be.revertedWith("Operator already set for the staking provider") }) - } + }, ) // Some other staking provider is using the given operator address. @@ -155,7 +159,7 @@ describe("RandomBeacon - Authorization", () => { await expect( randomBeacon .connect(stakingProvider) - .registerOperator(operator.address) + .registerOperator(operator.address), ).to.be.revertedWith("Operator address already in use") }) }) @@ -164,7 +168,7 @@ describe("RandomBeacon - Authorization", () => { // the staking provider, and the staking provider is registering operator // for ECDSA application. context("when staking provider is registering new operator", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -179,13 +183,13 @@ describe("RandomBeacon - Authorization", () => { it("should set staking provider -> operator mapping", async () => { expect( - await randomBeacon.stakingProviderToOperator(stakingProvider.address) + await randomBeacon.stakingProviderToOperator(stakingProvider.address), ).to.equal(operator.address) }) it("should set operator -> staking provider mapping", async () => { expect( - await randomBeacon.operatorToStakingProvider(operator.address) + await randomBeacon.operatorToStakingProvider(operator.address), ).to.equal(stakingProvider.address) }) @@ -217,15 +221,19 @@ describe("RandomBeacon - Authorization", () => { await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - stakedAmount + await randomBeacon.getAddress(), + stakedAmount, ) const deauthorizingBy = to1e18(1) await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, deauthorizingBy) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + deauthorizingBy, + ) }) after(async () => { @@ -236,9 +244,9 @@ describe("RandomBeacon - Authorization", () => { await expect( randomBeacon .connect(stakingProvider) - .registerOperator(operator.address) + .registerOperator(operator.address), ).to.be.revertedWith( - "There is a pending authorization decrease request" + "There is a pending authorization decrease request", ) }) }) @@ -249,22 +257,26 @@ describe("RandomBeacon - Authorization", () => { // approving that authorization decrease request, staking provider can // register an operator. context("when authorization decrease request was approved", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - stakedAmount + await randomBeacon.getAddress(), + stakedAmount, ) const deauthorizingBy = to1e18(1) await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, deauthorizingBy) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + deauthorizingBy, + ) await randomBeacon.approveAuthorizationDecrease(stakingProvider.address) @@ -279,13 +291,13 @@ describe("RandomBeacon - Authorization", () => { it("should set staking provider -> operator mapping", async () => { expect( - await randomBeacon.stakingProviderToOperator(stakingProvider.address) + await randomBeacon.stakingProviderToOperator(stakingProvider.address), ).to.equal(operator.address) }) it("should set operator -> staking provider mapping", async () => { expect( - await randomBeacon.operatorToStakingProvider(operator.address) + await randomBeacon.operatorToStakingProvider(operator.address), ).to.equal(stakingProvider.address) }) @@ -303,7 +315,7 @@ describe("RandomBeacon - Authorization", () => { await expect( randomBeacon .connect(thirdParty) - .authorizationIncreased(stakingProvider.address, 0, stakedAmount) + .authorizationIncreased(stakingProvider.address, 0, stakedAmount), ).to.be.revertedWith("Caller is not the staking contract") }) }) @@ -313,9 +325,9 @@ describe("RandomBeacon - Authorization", () => { await expect( legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - minimumAuthorization.sub(1) - ) + await randomBeacon.getAddress(), + minimumAuthorization - 1n, + ), ).to.be.revertedWith("Authorization below the minimum") }) }) @@ -329,17 +341,17 @@ describe("RandomBeacon - Authorization", () => { // Minimum possible authorization - the minimum authorized amount for // ECDSA as set in `minimumAuthorization` parameter. context("when increasing to the minimum possible value", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() tx = await legacyTokenStakingAt( staking, - authorizer + authorizer, ).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - minimumAuthorization + await randomBeacon.getAddress(), + minimumAuthorization, ) }) @@ -354,7 +366,7 @@ describe("RandomBeacon - Authorization", () => { stakingProvider.address, ZERO_ADDRESS, 0, - minimumAuthorization + minimumAuthorization, ) }) }) @@ -362,17 +374,17 @@ describe("RandomBeacon - Authorization", () => { // Maximum possible authorization - the entire stake delegated to the // staking provider. context("when increasing to the maximum possible value", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() tx = await legacyTokenStakingAt( staking, - authorizer + authorizer, ).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - stakedAmount + await randomBeacon.getAddress(), + stakedAmount, ) }) @@ -409,18 +421,18 @@ describe("RandomBeacon - Authorization", () => { // Minimum possible authorization - the minimum authorized amount for // ECDSA as set in `minimumAuthorization` parameter. context("when increasing to the minimum possible value", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() tx = await legacyTokenStakingAt( staking, - authorizer + authorizer, ).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - minimumAuthorization + await randomBeacon.getAddress(), + minimumAuthorization, ) }) @@ -435,7 +447,7 @@ describe("RandomBeacon - Authorization", () => { stakingProvider.address, operator.address, 0, - minimumAuthorization + minimumAuthorization, ) }) }) @@ -443,18 +455,18 @@ describe("RandomBeacon - Authorization", () => { // Maximum possible authorization - the entire stake delegated to the // staking provider. context("when increasing to the maximum possible value", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() tx = await legacyTokenStakingAt( staking, - authorizer + authorizer, ).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - stakedAmount + await randomBeacon.getAddress(), + stakedAmount, ) }) @@ -469,7 +481,7 @@ describe("RandomBeacon - Authorization", () => { stakingProvider.address, operator.address, 0, - stakedAmount + stakedAmount, ) }) }) @@ -482,7 +494,7 @@ describe("RandomBeacon - Authorization", () => { await expect( randomBeacon .connect(thirdParty) - .authorizationDecreaseRequested(stakingProvider.address, 100, 99) + .authorizationDecreaseRequested(stakingProvider.address, 100, 99), ).to.be.revertedWith("Caller is not the staking contract") }) }) @@ -497,8 +509,8 @@ describe("RandomBeacon - Authorization", () => { await createSnapshot() await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - stakedAmount + await randomBeacon.getAddress(), + stakedAmount, ) }) @@ -510,15 +522,19 @@ describe("RandomBeacon - Authorization", () => { // to 0 or to some value above the minimum. context("when decreasing to a non-zero value below the minimum", () => { it("should revert", async () => { - const deauthorizingTo = minimumAuthorization.sub(1) - const deauthorizingBy = stakedAmount.sub(deauthorizingTo) + const deauthorizingTo = minimumAuthorization - 1n + const deauthorizingBy = stakedAmount - deauthorizingTo await expect( legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, deauthorizingBy) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + deauthorizingBy, + ), ).to.be.revertedWith( - "Authorization amount should be 0 or above the minimum" + "Authorization amount should be 0 or above the minimum", ) }) }) @@ -526,17 +542,21 @@ describe("RandomBeacon - Authorization", () => { // Decreasing to zero when operator was not set up yet - authorization // decrease request is valid and can be approved context("when decreasing to zero", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse const decreasingTo = 0 - let decreasingBy: BigNumber + let decreasingBy: bigint before(async () => { await createSnapshot() - decreasingBy = stakedAmount.sub(decreasingTo) + decreasingBy = stakedAmount - BigInt(decreasingTo) tx = await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, decreasingBy) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + decreasingBy, + ) }) after(async () => { @@ -546,8 +566,8 @@ describe("RandomBeacon - Authorization", () => { it("should require no time delay before approving", async () => { expect( await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(0) }) @@ -560,32 +580,36 @@ describe("RandomBeacon - Authorization", () => { ZERO_ADDRESS, stakedAmount, decreasingTo, - now + now, ) }) it("should capture deauthorizing amount", async () => { expect( await randomBeacon.pendingAuthorizationDecrease( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(decreasingBy) }) }) context("when decreasing to the minimum", () => { - let tx: ContractTransaction - let decreasingTo: BigNumber - let decreasingBy: BigNumber + let tx: ContractTransactionResponse + let decreasingTo: bigint + let decreasingBy: bigint before(async () => { await createSnapshot() decreasingTo = minimumAuthorization - decreasingBy = stakedAmount.sub(decreasingTo) + decreasingBy = stakedAmount - decreasingTo tx = await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, decreasingBy) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + decreasingBy, + ) }) after(async () => { @@ -595,8 +619,8 @@ describe("RandomBeacon - Authorization", () => { it("should require no time delay before approving", async () => { expect( await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(0) }) @@ -609,32 +633,36 @@ describe("RandomBeacon - Authorization", () => { ZERO_ADDRESS, stakedAmount, decreasingTo, - now + now, ) }) it("should capture deauthorizing amount", async () => { expect( await randomBeacon.pendingAuthorizationDecrease( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(decreasingBy) }) }) context("when decreasing to a value above the minimum", () => { - let tx: ContractTransaction - let decreasingTo: BigNumber - let decreasingBy: BigNumber + let tx: ContractTransactionResponse + let decreasingTo: bigint + let decreasingBy: bigint before(async () => { await createSnapshot() - decreasingTo = minimumAuthorization.add(1) - decreasingBy = stakedAmount.sub(decreasingTo) + decreasingTo = minimumAuthorization + 1n + decreasingBy = stakedAmount - decreasingTo tx = await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, decreasingBy) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + decreasingBy, + ) }) after(async () => { @@ -644,8 +672,8 @@ describe("RandomBeacon - Authorization", () => { it("should require no time delay before approving", async () => { expect( await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(0) }) @@ -658,15 +686,15 @@ describe("RandomBeacon - Authorization", () => { ZERO_ADDRESS, stakedAmount, decreasingTo, - now + now, ) }) it("should capture deauthorizing amount", async () => { expect( await randomBeacon.pendingAuthorizationDecrease( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(decreasingBy) }) }) @@ -680,7 +708,11 @@ describe("RandomBeacon - Authorization", () => { await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, deauthorizingFirst) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + deauthorizingFirst, + ) }) after(async () => { @@ -696,7 +728,7 @@ describe("RandomBeacon - Authorization", () => { authorizationDecreaseChangePeriod, } = await randomBeacon.authorizationParameters() expect(authorizationDecreaseDelay).to.equal( - authorizationDecreaseChangePeriod + authorizationDecreaseChangePeriod, ) }) @@ -709,8 +741,8 @@ describe("RandomBeacon - Authorization", () => { "requestAuthorizationDecrease(address,address,uint96)" ]( stakingProvider.address, - randomBeacon.address, - deauthorizingSecond + await randomBeacon.getAddress(), + deauthorizingSecond, ) }) @@ -718,28 +750,26 @@ describe("RandomBeacon - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await randomBeacon.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + randomBeacon, + stakingProvider, + deauthorizingSecond, + })) }) context("when delay did not pass", () => { before(async () => { await createSnapshot() await helpers.time.increaseTime( - params.authorizationDecreaseDelay - 60 // -1min + params.authorizationDecreaseDelay - 60, // -1min ) await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" ]( stakingProvider.address, - randomBeacon.address, - deauthorizingSecond + await randomBeacon.getAddress(), + deauthorizingSecond, ) }) @@ -747,13 +777,11 @@ describe("RandomBeacon - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await randomBeacon.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + randomBeacon, + stakingProvider, + deauthorizingSecond, + })) }) }) @@ -773,8 +801,8 @@ describe("RandomBeacon - Authorization", () => { "requestAuthorizationDecrease(address,address,uint96)" ]( stakingProvider.address, - randomBeacon.address, - deauthorizingSecond + await randomBeacon.getAddress(), + deauthorizingSecond, ) }) @@ -782,13 +810,11 @@ describe("RandomBeacon - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await randomBeacon.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + randomBeacon, + stakingProvider, + deauthorizingSecond, + })) }) context("when change period is not equal delay and is non-zero", () => { @@ -819,8 +845,8 @@ describe("RandomBeacon - Authorization", () => { "requestAuthorizationDecrease(address,address,uint96)" ]( stakingProvider.address, - randomBeacon.address, - deauthorizingSecond + await randomBeacon.getAddress(), + deauthorizingSecond, ) }) @@ -828,28 +854,26 @@ describe("RandomBeacon - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await randomBeacon.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + randomBeacon, + stakingProvider, + deauthorizingSecond, + })) }) context("when change period activated", () => { before(async () => { await createSnapshot() await helpers.time.increaseTime( - params.authorizationDecreaseDelay - newChangePeriod + 60 + params.authorizationDecreaseDelay - newChangePeriod + 60, ) // +1min await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" ]( stakingProvider.address, - randomBeacon.address, - deauthorizingSecond + await randomBeacon.getAddress(), + deauthorizingSecond, ) }) @@ -857,28 +881,26 @@ describe("RandomBeacon - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await randomBeacon.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + randomBeacon, + stakingProvider, + deauthorizingSecond, + })) }) context("when change period did not activate", () => { before(async () => { await createSnapshot() await helpers.time.increaseTime( - params.authorizationDecreaseDelay - newChangePeriod - 60 // -1min + params.authorizationDecreaseDelay - newChangePeriod - 60, // -1min ) await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" ]( stakingProvider.address, - randomBeacon.address, - deauthorizingSecond + await randomBeacon.getAddress(), + deauthorizingSecond, ) }) @@ -886,13 +908,11 @@ describe("RandomBeacon - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await randomBeacon.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + randomBeacon, + stakingProvider, + deauthorizingSecond, + })) }) }) }) @@ -905,8 +925,8 @@ describe("RandomBeacon - Authorization", () => { await createSnapshot() await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - stakedAmount + await randomBeacon.getAddress(), + stakedAmount, ) await randomBeacon .connect(stakingProvider) @@ -919,44 +939,49 @@ describe("RandomBeacon - Authorization", () => { context("when decreasing to a non-zero value below the minimum", () => { it("should revert", async () => { - const deauthorizingTo = minimumAuthorization.sub(1) - const deauthorizingBy = stakedAmount.sub(deauthorizingTo) + const deauthorizingTo = minimumAuthorization - 1n + const deauthorizingBy = stakedAmount - deauthorizingTo await expect( legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, deauthorizingBy) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + deauthorizingBy, + ), ).to.be.revertedWith( - "Authorization amount should be 0 or above the minimum" + "Authorization amount should be 0 or above the minimum", ) }) }) context("when decreasing to zero", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse const decreasingTo = 0 - let decreasingBy: BigNumber + let decreasingBy: bigint before(async () => { await createSnapshot() - decreasingBy = stakedAmount.sub(decreasingTo) + decreasingBy = stakedAmount - BigInt(decreasingTo) tx = await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, decreasingBy) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + decreasingBy, + ) }) after(async () => { await restoreSnapshot() }) - it("should require updating the pool before approving", async () => { - expect( - await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(MAX_UINT64) - }) + shouldRequireUpdatingPoolBeforeApproving(() => ({ + randomBeacon, + stakingProvider, + })) it("should emit AuthorizationDecreaseRequested event", async () => { await expect(tx) @@ -966,45 +991,46 @@ describe("RandomBeacon - Authorization", () => { operator.address, stakedAmount, decreasingTo, - MAX_UINT64 + MAX_UINT64, ) }) it("should capture deauthorizing amount", async () => { expect( await randomBeacon.pendingAuthorizationDecrease( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(decreasingBy) }) }) context("when decreasing to the minimum", () => { - let tx: ContractTransaction - let decreasingTo: BigNumber - let decreasingBy: BigNumber + let tx: ContractTransactionResponse + let decreasingTo: bigint + let decreasingBy: bigint before(async () => { await createSnapshot() decreasingTo = minimumAuthorization - decreasingBy = stakedAmount.sub(decreasingTo) + decreasingBy = stakedAmount - decreasingTo tx = await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, decreasingBy) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + decreasingBy, + ) }) after(async () => { await restoreSnapshot() }) - it("should require updating the pool before approving", async () => { - expect( - await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(MAX_UINT64) - }) + shouldRequireUpdatingPoolBeforeApproving(() => ({ + randomBeacon, + stakingProvider, + })) it("should emit AuthorizationDecreaseRequested event", async () => { await expect(tx) @@ -1014,45 +1040,46 @@ describe("RandomBeacon - Authorization", () => { operator.address, stakedAmount, decreasingTo, - MAX_UINT64 + MAX_UINT64, ) }) it("should capture deauthorizing amount", async () => { expect( await randomBeacon.pendingAuthorizationDecrease( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(decreasingBy) }) }) context("when decreasing to a value above the minimum", () => { - let tx: ContractTransaction - let decreasingTo: BigNumber - let decreasingBy: BigNumber + let tx: ContractTransactionResponse + let decreasingTo: bigint + let decreasingBy: bigint before(async () => { await createSnapshot() - decreasingTo = minimumAuthorization.add(1) - decreasingBy = stakedAmount.sub(decreasingTo) + decreasingTo = minimumAuthorization + 1n + decreasingBy = stakedAmount - decreasingTo tx = await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, decreasingBy) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + decreasingBy, + ) }) after(async () => { await restoreSnapshot() }) - it("should require updating the pool before approving", async () => { - expect( - await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(MAX_UINT64) - }) + shouldRequireUpdatingPoolBeforeApproving(() => ({ + randomBeacon, + stakingProvider, + })) it("should emit AuthorizationDecreaseRequested event", async () => { await expect(tx) @@ -1062,15 +1089,15 @@ describe("RandomBeacon - Authorization", () => { operator.address, stakedAmount, decreasingTo, - MAX_UINT64 + MAX_UINT64, ) }) it("should capture deauthorizing amount", async () => { expect( await randomBeacon.pendingAuthorizationDecrease( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(decreasingBy) }) }) @@ -1086,7 +1113,11 @@ describe("RandomBeacon - Authorization", () => { await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, deauthorizingFirst) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + deauthorizingFirst, + ) }) after(async () => { @@ -1102,7 +1133,7 @@ describe("RandomBeacon - Authorization", () => { authorizationDecreaseChangePeriod, } = await randomBeacon.authorizationParameters() expect(authorizationDecreaseDelay).to.equal( - authorizationDecreaseChangePeriod + authorizationDecreaseChangePeriod, ) }) @@ -1114,8 +1145,8 @@ describe("RandomBeacon - Authorization", () => { "requestAuthorizationDecrease(address,address,uint96)" ]( stakingProvider.address, - randomBeacon.address, - deauthorizingSecond + await randomBeacon.getAddress(), + deauthorizingSecond, ) }) @@ -1123,21 +1154,16 @@ describe("RandomBeacon - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await randomBeacon.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + randomBeacon, + stakingProvider, + deauthorizingSecond, + })) - it("should require updating the pool before approving", async () => { - expect( - await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(MAX_UINT64) - }) + shouldRequireUpdatingPoolBeforeApproving(() => ({ + randomBeacon, + stakingProvider, + })) }) context("when called after sortition pool was updated", () => { @@ -1154,7 +1180,7 @@ describe("RandomBeacon - Authorization", () => { before(async () => { await createSnapshot() await helpers.time.increaseTime( - params.authorizationDecreaseDelay + params.authorizationDecreaseDelay, ) }) @@ -1169,8 +1195,8 @@ describe("RandomBeacon - Authorization", () => { "requestAuthorizationDecrease(address,address,uint96)" ]( stakingProvider.address, - randomBeacon.address, - deauthorizingSecond + await randomBeacon.getAddress(), + deauthorizingSecond, ) }) @@ -1178,21 +1204,16 @@ describe("RandomBeacon - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await randomBeacon.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + randomBeacon, + stakingProvider, + deauthorizingSecond, + })) - it("should require updating the pool before approving", async () => { - expect( - await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(MAX_UINT64) - }) + shouldRequireUpdatingPoolBeforeApproving(() => ({ + randomBeacon, + stakingProvider, + })) }) context("when delay did not pass", () => { @@ -1200,15 +1221,15 @@ describe("RandomBeacon - Authorization", () => { await createSnapshot() await helpers.time.increaseTime( - params.authorizationDecreaseDelay - 60 // -1min + params.authorizationDecreaseDelay - 60, // -1min ) await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" ]( stakingProvider.address, - randomBeacon.address, - deauthorizingSecond + await randomBeacon.getAddress(), + deauthorizingSecond, ) }) @@ -1216,21 +1237,16 @@ describe("RandomBeacon - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await randomBeacon.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + randomBeacon, + stakingProvider, + deauthorizingSecond, + })) - it("should require updating the pool before approving", async () => { - expect( - await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(MAX_UINT64) - }) + shouldRequireUpdatingPoolBeforeApproving(() => ({ + randomBeacon, + stakingProvider, + })) }) }) }) @@ -1260,8 +1276,8 @@ describe("RandomBeacon - Authorization", () => { "requestAuthorizationDecrease(address,address,uint96)" ]( stakingProvider.address, - randomBeacon.address, - deauthorizingSecond + await randomBeacon.getAddress(), + deauthorizingSecond, ) }) @@ -1269,21 +1285,16 @@ describe("RandomBeacon - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await randomBeacon.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + randomBeacon, + stakingProvider, + deauthorizingSecond, + })) - it("should require updating the pool before approving", async () => { - expect( - await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(MAX_UINT64) - }) + shouldRequireUpdatingPoolBeforeApproving(() => ({ + randomBeacon, + stakingProvider, + })) }) context("when called after sortition pool was updated", () => { @@ -1304,11 +1315,11 @@ describe("RandomBeacon - Authorization", () => { "requestAuthorizationDecrease(address,address,uint96)" ]( stakingProvider.address, - randomBeacon.address, - deauthorizingSecond - ) + await randomBeacon.getAddress(), + deauthorizingSecond, + ), ).to.be.revertedWith( - "Not enough time passed since the original request" + "Not enough time passed since the original request", ) }) }) @@ -1317,15 +1328,15 @@ describe("RandomBeacon - Authorization", () => { before(async () => { await createSnapshot() await helpers.time.increaseTime( - params.authorizationDecreaseDelay + params.authorizationDecreaseDelay, ) await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" ]( stakingProvider.address, - randomBeacon.address, - deauthorizingSecond + await randomBeacon.getAddress(), + deauthorizingSecond, ) }) @@ -1333,21 +1344,16 @@ describe("RandomBeacon - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await randomBeacon.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + randomBeacon, + stakingProvider, + deauthorizingSecond, + })) - it("should require updating the pool before approving", async () => { - expect( - await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(MAX_UINT64) - }) + shouldRequireUpdatingPoolBeforeApproving(() => ({ + randomBeacon, + stakingProvider, + })) }) }) }) @@ -1379,8 +1385,8 @@ describe("RandomBeacon - Authorization", () => { "requestAuthorizationDecrease(address,address,uint96)" ]( stakingProvider.address, - randomBeacon.address, - deauthorizingSecond + await randomBeacon.getAddress(), + deauthorizingSecond, ) }) @@ -1388,21 +1394,16 @@ describe("RandomBeacon - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await randomBeacon.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + randomBeacon, + stakingProvider, + deauthorizingSecond, + })) - it("should require updating the pool before approving", async () => { - expect( - await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(MAX_UINT64) - }) + shouldRequireUpdatingPoolBeforeApproving(() => ({ + randomBeacon, + stakingProvider, + })) }) context("when called after sortition pool was updated", () => { @@ -1420,7 +1421,7 @@ describe("RandomBeacon - Authorization", () => { before(async () => { await createSnapshot() await helpers.time.increaseTime( - params.authorizationDecreaseDelay - newChangePeriod - 60 // -1min + params.authorizationDecreaseDelay - newChangePeriod - 60, // -1min ) }) @@ -1434,11 +1435,11 @@ describe("RandomBeacon - Authorization", () => { "requestAuthorizationDecrease(address,address,uint96)" ]( stakingProvider.address, - randomBeacon.address, - deauthorizingSecond - ) + await randomBeacon.getAddress(), + deauthorizingSecond, + ), ).to.be.revertedWith( - "Not enough time passed since the original request" + "Not enough time passed since the original request", ) }) }) @@ -1447,15 +1448,15 @@ describe("RandomBeacon - Authorization", () => { before(async () => { await createSnapshot() await helpers.time.increaseTime( - params.authorizationDecreaseDelay - newChangePeriod + 60 // +1min + params.authorizationDecreaseDelay - newChangePeriod + 60, // +1min ) await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" ]( stakingProvider.address, - randomBeacon.address, - deauthorizingSecond + await randomBeacon.getAddress(), + deauthorizingSecond, ) }) @@ -1463,36 +1464,31 @@ describe("RandomBeacon - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await randomBeacon.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + randomBeacon, + stakingProvider, + deauthorizingSecond, + })) - it("should require updating the pool before approving", async () => { - expect( - await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(MAX_UINT64) - }) + shouldRequireUpdatingPoolBeforeApproving(() => ({ + randomBeacon, + stakingProvider, + })) }) context("when delay passed", () => { before(async () => { await createSnapshot() await helpers.time.increaseTime( - params.authorizationDecreaseDelay + params.authorizationDecreaseDelay, ) await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" ]( stakingProvider.address, - randomBeacon.address, - deauthorizingSecond + await randomBeacon.getAddress(), + deauthorizingSecond, ) }) @@ -1500,21 +1496,16 @@ describe("RandomBeacon - Authorization", () => { await restoreSnapshot() }) - it("should overwrite the previous request", async () => { - expect( - await randomBeacon.pendingAuthorizationDecrease( - stakingProvider.address - ) - ).to.be.equal(deauthorizingSecond) - }) + shouldOverwritePreviousRequest(() => ({ + randomBeacon, + stakingProvider, + deauthorizingSecond, + })) - it("should require updating the pool before approving", async () => { - expect( - await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) - ).to.equal(MAX_UINT64) - }) + shouldRequireUpdatingPoolBeforeApproving(() => ({ + randomBeacon, + stakingProvider, + })) }) }) }) @@ -1527,8 +1518,8 @@ describe("RandomBeacon - Authorization", () => { await createSnapshot() await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - stakedAmount + await randomBeacon.getAddress(), + stakedAmount, ) }) @@ -1539,7 +1530,7 @@ describe("RandomBeacon - Authorization", () => { context("when decrease was not requested", () => { it("should revert", async () => { await expect( - randomBeacon.approveAuthorizationDecrease(stakingProvider.address) + randomBeacon.approveAuthorizationDecrease(stakingProvider.address), ).to.be.revertedWith("Authorization decrease not requested") }) }) @@ -1553,7 +1544,11 @@ describe("RandomBeacon - Authorization", () => { await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, deauthorizingBy) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + deauthorizingBy, + ) }) after(async () => { @@ -1562,7 +1557,7 @@ describe("RandomBeacon - Authorization", () => { it("should let to approve immediately", async () => { const tx = await randomBeacon.approveAuthorizationDecrease( - stakingProvider.address + stakingProvider.address, ) // ok, did not revert await expect(tx) @@ -1583,7 +1578,11 @@ describe("RandomBeacon - Authorization", () => { const deauthorizingBy = stakedAmount await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, deauthorizingBy) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + deauthorizingBy, + ) }) after(async () => { @@ -1604,7 +1603,7 @@ describe("RandomBeacon - Authorization", () => { it("should revert", async () => { await expect( - randomBeacon.approveAuthorizationDecrease(stakingProvider.address) + randomBeacon.approveAuthorizationDecrease(stakingProvider.address), ).to.be.revertedWith("Authorization decrease request not activated") }) }) @@ -1615,7 +1614,7 @@ describe("RandomBeacon - Authorization", () => { await randomBeacon.updateOperatorStatus(operator.address) await helpers.time.increaseTime( - params.authorizationDecreaseDelay - 60 // -1min + params.authorizationDecreaseDelay - 60, // -1min ) }) @@ -1625,13 +1624,13 @@ describe("RandomBeacon - Authorization", () => { it("should revert", async () => { await expect( - randomBeacon.approveAuthorizationDecrease(stakingProvider.address) + randomBeacon.approveAuthorizationDecrease(stakingProvider.address), ).to.be.revertedWith("Authorization decrease delay not passed") }) }) context("when the pool was updated and the delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1640,7 +1639,7 @@ describe("RandomBeacon - Authorization", () => { await helpers.time.increaseTime(params.authorizationDecreaseDelay) tx = await randomBeacon.approveAuthorizationDecrease( - stakingProvider.address + stakingProvider.address, ) }) @@ -1650,7 +1649,7 @@ describe("RandomBeacon - Authorization", () => { it("should reduce authorized stake amount", async () => { expect(await sortitionPool.getPoolWeight(operator.address)).to.equal( - 0 + 0, ) }) @@ -1663,8 +1662,8 @@ describe("RandomBeacon - Authorization", () => { it("should clear pending authorization decrease", async () => { expect( await randomBeacon.pendingAuthorizationDecrease( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(0) }) }) @@ -1677,21 +1676,21 @@ describe("RandomBeacon - Authorization", () => { await expect( randomBeacon .connect(thirdParty) - .involuntaryAuthorizationDecrease(stakingProvider.address, 100, 99) + .involuntaryAuthorizationDecrease(stakingProvider.address, 100, 99), ).to.be.revertedWith("Caller is not the staking contract") }) }) context("when the operator is unknown", () => { const slashedAmount = to1e18(100) - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - stakedAmount + await randomBeacon.getAddress(), + stakedAmount, ) // lock the pool for DKG @@ -1714,7 +1713,7 @@ describe("RandomBeacon - Authorization", () => { it("should ignore the update", async () => { await expect(tx).to.not.emit( randomBeacon, - "InvoluntaryAuthorizationDecreaseFailed" + "InvoluntaryAuthorizationDecreaseFailed", ) }) }) @@ -1724,8 +1723,8 @@ describe("RandomBeacon - Authorization", () => { await createSnapshot() await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - stakedAmount + await randomBeacon.getAddress(), + stakedAmount, ) await randomBeacon @@ -1739,7 +1738,7 @@ describe("RandomBeacon - Authorization", () => { context("when the operator is not in the sortition pool", () => { const slashedAmount = to1e18(100) - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1755,7 +1754,7 @@ describe("RandomBeacon - Authorization", () => { .connect(slasher.wallet) .slash(slashedAmount, [stakingProvider.address]) tx = await legacyTokenStakingAt(staking, thirdParty).processSlashing( - 1 + 1, ) }) @@ -1766,7 +1765,7 @@ describe("RandomBeacon - Authorization", () => { it("should ignore the update", async () => { await expect(tx).to.not.emit( randomBeacon, - "InvoluntaryAuthorizationDecreaseFailed" + "InvoluntaryAuthorizationDecreaseFailed", ) }) }) @@ -1783,7 +1782,7 @@ describe("RandomBeacon - Authorization", () => { context("when the sortition pool is locked", () => { const slashedAmount = to1e18(100) - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1797,7 +1796,7 @@ describe("RandomBeacon - Authorization", () => { .slash(slashedAmount, [stakingProvider.address]) tx = await legacyTokenStakingAt( staking, - thirdParty + thirdParty, ).processSlashing(1) }) @@ -1817,7 +1816,7 @@ describe("RandomBeacon - Authorization", () => { stakingProvider.address, operator.address, stakedAmount, - stakedAmount.sub(slashedAmount) + stakedAmount - slashedAmount, ) }) }) @@ -1825,7 +1824,7 @@ describe("RandomBeacon - Authorization", () => { context("when the sortition pool is not locked", () => { context("when the authorization drops to above the minimum", () => { const slashedAmount = to1e18(100) - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1836,7 +1835,7 @@ describe("RandomBeacon - Authorization", () => { .slash(slashedAmount, [stakingProvider.address]) tx = await legacyTokenStakingAt( staking, - thirdParty + thirdParty, ).processSlashing(1) }) @@ -1852,7 +1851,7 @@ describe("RandomBeacon - Authorization", () => { it("should not emit InvoluntaryAuthorizationDecreaseFailed event", async () => { await expect(tx).to.not.emit( randomBeacon, - "InvoluntaryAuthorizationDecreaseFailed" + "InvoluntaryAuthorizationDecreaseFailed", ) }) }) @@ -1861,8 +1860,8 @@ describe("RandomBeacon - Authorization", () => { "when the authorized amount drops to below the minimum", () => { before(async () => { - const slashingTo = minimumAuthorization.sub(1) - const slashingBy = stakedAmount.sub(slashingTo) + const slashingTo = minimumAuthorization - 1n + const slashingBy = stakedAmount - slashingTo await createSnapshot() @@ -1872,7 +1871,7 @@ describe("RandomBeacon - Authorization", () => { .slash(slashingBy, [stakingProvider.address]) await legacyTokenStakingAt(staking, thirdParty).processSlashing( - 1 + 1, ) }) @@ -1884,7 +1883,7 @@ describe("RandomBeacon - Authorization", () => { expect(await randomBeacon.isOperatorInPool(operator.address)).to .be.false }) - } + }, ) }) }) @@ -1895,7 +1894,7 @@ describe("RandomBeacon - Authorization", () => { context("when the operator is unknown", () => { it("should revert", async () => { await expect( - randomBeacon.connect(thirdParty).joinSortitionPool() + randomBeacon.connect(thirdParty).joinSortitionPool(), ).to.be.revertedWith("Unknown operator") }) }) @@ -1915,7 +1914,7 @@ describe("RandomBeacon - Authorization", () => { it("should revert", async () => { await expect( - randomBeacon.connect(operator).joinSortitionPool() + randomBeacon.connect(operator).joinSortitionPool(), ).to.be.revertedWith("Authorization below the minimum") }) }) @@ -1934,12 +1933,12 @@ describe("RandomBeacon - Authorization", () => { const authorizedAmount = minimumAuthorization await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - authorizedAmount + await randomBeacon.getAddress(), + authorizedAmount, ) - const slashingTo = minimumAuthorization.sub(1) - const slashedAmount = authorizedAmount.sub(slashingTo) + const slashingTo = minimumAuthorization - 1n + const slashedAmount = authorizedAmount - slashingTo await staking .connect(slasher.wallet) @@ -1953,14 +1952,14 @@ describe("RandomBeacon - Authorization", () => { it("should revert", async () => { await expect( - randomBeacon.connect(operator).joinSortitionPool() + randomBeacon.connect(operator).joinSortitionPool(), ).to.be.revertedWith("Authorization below the minimum") }) - } + }, ) context("when the operator has the minimum stake authorized", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1971,8 +1970,8 @@ describe("RandomBeacon - Authorization", () => { await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - minimumAuthorization + await randomBeacon.getAddress(), + minimumAuthorization, ) tx = await randomBeacon.connect(operator).joinSortitionPool() @@ -1988,7 +1987,7 @@ describe("RandomBeacon - Authorization", () => { it("should use a correct stake weight", async () => { expect(await sortitionPool.getPoolWeight(operator.address)).to.equal( - minimumAuthorization.div(constants.poolWeightDivisor) + minimumAuthorization / constants.poolWeightDivisor, ) }) @@ -2002,7 +2001,7 @@ describe("RandomBeacon - Authorization", () => { context( "when the operator has more than the minimum stake authorized", () => { - let authorizedStake: BigNumber + let authorizedStake: bigint before(async () => { await createSnapshot() @@ -2011,12 +2010,12 @@ describe("RandomBeacon - Authorization", () => { .connect(stakingProvider) .registerOperator(operator.address) - authorizedStake = minimumAuthorization.mul(2) + authorizedStake = minimumAuthorization * 2n await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - authorizedStake + await randomBeacon.getAddress(), + authorizedStake, ) await randomBeacon.connect(operator).joinSortitionPool() @@ -2033,14 +2032,14 @@ describe("RandomBeacon - Authorization", () => { it("should use a correct stake weight", async () => { expect(await sortitionPool.getPoolWeight(operator.address)).to.equal( - authorizedStake.div(constants.poolWeightDivisor) + authorizedStake / constants.poolWeightDivisor, ) }) - } + }, ) context("when operator is in the process of deauthorizing", () => { - let deauthorizingTo: BigNumber + let deauthorizingTo: bigint before(async () => { await createSnapshot() @@ -2053,16 +2052,20 @@ describe("RandomBeacon - Authorization", () => { await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - authorizedStake + await randomBeacon.getAddress(), + authorizedStake, ) - deauthorizingTo = minimumAuthorization.add(to1e18(1337)) - const deauthorizingBy = authorizedStake.sub(deauthorizingTo) + deauthorizingTo = minimumAuthorization + to1e18(1337) + const deauthorizingBy = authorizedStake - deauthorizingTo await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, deauthorizingBy) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + deauthorizingBy, + ) await randomBeacon.connect(operator).joinSortitionPool() }) @@ -2077,15 +2080,15 @@ describe("RandomBeacon - Authorization", () => { it("should use a correct stake weight", async () => { expect(await sortitionPool.getPoolWeight(operator.address)).to.equal( - deauthorizingTo.div(constants.poolWeightDivisor) + deauthorizingTo / constants.poolWeightDivisor, ) }) it("should activate authorization decrease delay", async () => { expect( await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(params.authorizationDecreaseDelay) }) }) @@ -2093,7 +2096,7 @@ describe("RandomBeacon - Authorization", () => { context( "when operator is in the process of deauthorizing but also increased authorization in the meantime", () => { - let expectedAuthorizedStake: BigNumber + let expectedAuthorizedStake: bigint before(async () => { await createSnapshot() @@ -2102,29 +2105,33 @@ describe("RandomBeacon - Authorization", () => { .connect(stakingProvider) .registerOperator(operator.address) - const authorizedStake = minimumAuthorization.add(to1e18(100)) + const authorizedStake = minimumAuthorization + to1e18(100) await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - authorizedStake + await randomBeacon.getAddress(), + authorizedStake, ) - const deauthorizingTo = minimumAuthorization.add(to1e18(50)) - const deauthorizingBy = authorizedStake.sub(deauthorizingTo) + const deauthorizingTo = minimumAuthorization + to1e18(50) + const deauthorizingBy = authorizedStake - deauthorizingTo await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, deauthorizingBy) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + deauthorizingBy, + ) const increasingBy = to1e18(5000) await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - increasingBy + await randomBeacon.getAddress(), + increasingBy, ) - expectedAuthorizedStake = deauthorizingTo.add(increasingBy) + expectedAuthorizedStake = deauthorizingTo + increasingBy await randomBeacon.connect(operator).joinSortitionPool() }) @@ -2140,18 +2147,18 @@ describe("RandomBeacon - Authorization", () => { it("should use a correct stake weight", async () => { expect(await sortitionPool.getPoolWeight(operator.address)).to.equal( - expectedAuthorizedStake.div(constants.poolWeightDivisor) + expectedAuthorizedStake / constants.poolWeightDivisor, ) }) it("should activate authorization decrease delay", async () => { expect( await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(params.authorizationDecreaseDelay) }) - } + }, ) }) @@ -2159,7 +2166,7 @@ describe("RandomBeacon - Authorization", () => { context("when the operator is unknown", () => { it("should revert", async () => { await expect( - randomBeacon.updateOperatorStatus(thirdParty.address) + randomBeacon.updateOperatorStatus(thirdParty.address), ).to.be.revertedWith("Unknown operator") }) }) @@ -2178,15 +2185,15 @@ describe("RandomBeacon - Authorization", () => { }) context("when the authorization increased", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - minimumAuthorization + await randomBeacon.getAddress(), + minimumAuthorization, ) tx = await randomBeacon @@ -2211,21 +2218,25 @@ describe("RandomBeacon - Authorization", () => { }) context("when there was an authorization decrease request", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - stakedAmount + await randomBeacon.getAddress(), + stakedAmount, ) const deauthorizingBy = to1e18(100) await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, deauthorizingBy) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + deauthorizingBy, + ) tx = await randomBeacon .connect(thirdParty) @@ -2244,8 +2255,8 @@ describe("RandomBeacon - Authorization", () => { it("should activate authorization decrease delay", async () => { expect( await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(params.authorizationDecreaseDelay) }) @@ -2267,8 +2278,8 @@ describe("RandomBeacon - Authorization", () => { await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - minimumAuthorization.mul(2) + await randomBeacon.getAddress(), + minimumAuthorization * 2n, ) await randomBeacon.connect(operator).joinSortitionPool() @@ -2279,8 +2290,8 @@ describe("RandomBeacon - Authorization", () => { }) context("when the authorization increased", () => { - let tx: ContractTransaction - let expectedWeight: BigNumber + let tx: ContractTransactionResponse + let expectedWeight: bigint before(async () => { await createSnapshot() @@ -2288,17 +2299,15 @@ describe("RandomBeacon - Authorization", () => { const topUp = to1e18(1337) await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - topUp + await randomBeacon.getAddress(), + topUp, ) // initial authorization was 2 x minimum // it was increased by 1337 tokens // so the final authorization should be 2 x minimum + 1337 - expectedWeight = minimumAuthorization - .mul(2) - .add(topUp) - .div(constants.poolWeightDivisor) + expectedWeight = + (minimumAuthorization * 2n + topUp) / constants.poolWeightDivisor tx = await randomBeacon .connect(thirdParty) @@ -2311,7 +2320,7 @@ describe("RandomBeacon - Authorization", () => { it("should update the pool", async () => { expect(await sortitionPool.getPoolWeight(operator.address)).to.equal( - expectedWeight + expectedWeight, ) }) @@ -2325,23 +2334,25 @@ describe("RandomBeacon - Authorization", () => { context( "when there was an authorization decrease request to non-zero", () => { - let tx: ContractTransaction - let expectedWeight: BigNumber + let tx: ContractTransactionResponse + let expectedWeight: bigint before(async () => { await createSnapshot() // initial authorization was 2 x minimum // we want to decrease to minimum + 1337 - const deauthorizingTo = minimumAuthorization.add(to1e18(1337)) - const deauthorizingBy = minimumAuthorization - .mul(2) - .sub(deauthorizingTo) - expectedWeight = deauthorizingTo.div(constants.poolWeightDivisor) + const deauthorizingTo = minimumAuthorization + to1e18(1337) + const deauthorizingBy = minimumAuthorization * 2n - deauthorizingTo + expectedWeight = deauthorizingTo / constants.poolWeightDivisor await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, deauthorizingBy) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + deauthorizingBy, + ) tx = await randomBeacon .connect(thirdParty) @@ -2354,15 +2365,15 @@ describe("RandomBeacon - Authorization", () => { it("should update the pool", async () => { expect( - await sortitionPool.getPoolWeight(operator.address) + await sortitionPool.getPoolWeight(operator.address), ).to.equal(expectedWeight) }) it("should activate authorization decrease delay", async () => { expect( await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(params.authorizationDecreaseDelay) }) @@ -2371,24 +2382,28 @@ describe("RandomBeacon - Authorization", () => { .to.emit(randomBeacon, "OperatorStatusUpdated") .withArgs(stakingProvider.address, operator.address) }) - } + }, ) context( "when there was an authorization decrease request to zero", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() // initial authorization was 2 x minimum // we want to decrease to zero - const deauthorizingBy = minimumAuthorization.mul(2) + const deauthorizingBy = minimumAuthorization * 2n await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, deauthorizingBy) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + deauthorizingBy, + ) tx = await randomBeacon .connect(thirdParty) @@ -2407,8 +2422,8 @@ describe("RandomBeacon - Authorization", () => { it("should activate authorization decrease delay", async () => { expect( await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(params.authorizationDecreaseDelay) }) @@ -2417,14 +2432,14 @@ describe("RandomBeacon - Authorization", () => { .to.emit(randomBeacon, "OperatorStatusUpdated") .withArgs(stakingProvider.address, operator.address) }) - } + }, ) context( "when operator is in the process of deauthorizing but also increased authorization in the meantime", () => { - let tx: ContractTransaction - let expectedWeight: BigNumber + let tx: ContractTransactionResponse + let expectedWeight: bigint before(async () => { await createSnapshot() @@ -2432,25 +2447,27 @@ describe("RandomBeacon - Authorization", () => { // initial authorization was 2 x minimum // we want to decrease to minimum + 1337 // and then decrease by 7331 - const deauthorizingTo = minimumAuthorization.add(to1e18(1337)) - const deauthorizingBy = minimumAuthorization - .mul(2) - .sub(deauthorizingTo) + const deauthorizingTo = minimumAuthorization + to1e18(1337) + const deauthorizingBy = minimumAuthorization * 2n - deauthorizingTo const increasingBy = to1e18(7331) - const increasingTo = deauthorizingTo.add(increasingBy) - expectedWeight = increasingTo.div(constants.poolWeightDivisor) + const increasingTo = deauthorizingTo + increasingBy + expectedWeight = increasingTo / constants.poolWeightDivisor await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, deauthorizingBy) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + deauthorizingBy, + ) await legacyTokenStakingAt( staking, - authorizer + authorizer, ).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - increasingBy + await randomBeacon.getAddress(), + increasingBy, ) tx = await randomBeacon @@ -2464,15 +2481,15 @@ describe("RandomBeacon - Authorization", () => { it("should update the pool", async () => { expect( - await sortitionPool.getPoolWeight(operator.address) + await sortitionPool.getPoolWeight(operator.address), ).to.equal(expectedWeight) }) it("should activate authorization decrease delay", async () => { expect( await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(params.authorizationDecreaseDelay) }) @@ -2481,7 +2498,7 @@ describe("RandomBeacon - Authorization", () => { .to.emit(randomBeacon, "OperatorStatusUpdated") .withArgs(stakingProvider.address, operator.address) }) - } + }, ) }) }) @@ -2490,13 +2507,13 @@ describe("RandomBeacon - Authorization", () => { context("when staking provider has no stake authorized", () => { it("should return zero", async () => { expect( - await randomBeacon.eligibleStake(stakingProvider.address) + await randomBeacon.eligibleStake(stakingProvider.address), ).to.equal(0) }) }) context("when staking provider has stake authorized", () => { - let authorizedAmount: BigNumber + let authorizedAmount: bigint before(async () => { await createSnapshot() @@ -2504,8 +2521,8 @@ describe("RandomBeacon - Authorization", () => { authorizedAmount = minimumAuthorization await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - authorizedAmount + await randomBeacon.getAddress(), + authorizedAmount, ) }) @@ -2515,7 +2532,7 @@ describe("RandomBeacon - Authorization", () => { it("should return authorized amount", async () => { expect( - await randomBeacon.eligibleStake(stakingProvider.address) + await randomBeacon.eligibleStake(stakingProvider.address), ).to.equal(authorizedAmount) }) }) @@ -2523,24 +2540,28 @@ describe("RandomBeacon - Authorization", () => { context( "when staking provider has some part of the stake deauthorizing", () => { - let authorizedAmount: BigNumber - let deauthorizingAmount: BigNumber + let authorizedAmount: bigint + let deauthorizingAmount: bigint before(async () => { await createSnapshot() - authorizedAmount = minimumAuthorization.add(to1e18(2000)) + authorizedAmount = minimumAuthorization + to1e18(2000) await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - authorizedAmount + await randomBeacon.getAddress(), + authorizedAmount, ) deauthorizingAmount = to1e18(1337) await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, deauthorizingAmount) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + deauthorizingAmount, + ) }) after(async () => { @@ -2549,10 +2570,10 @@ describe("RandomBeacon - Authorization", () => { it("should return authorized amount minus deauthorizing amount", async () => { expect( - await randomBeacon.eligibleStake(stakingProvider.address) - ).to.equal(authorizedAmount.sub(deauthorizingAmount)) + await randomBeacon.eligibleStake(stakingProvider.address), + ).to.equal(authorizedAmount - deauthorizingAmount) }) - } + }, ) context("when staking provider has all of the stake deauthorizing", () => { @@ -2562,13 +2583,17 @@ describe("RandomBeacon - Authorization", () => { const authorizedAmount = minimumAuthorization await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - authorizedAmount + await randomBeacon.getAddress(), + authorizedAmount, ) await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, authorizedAmount) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + authorizedAmount, + ) }) after(async () => { @@ -2577,7 +2602,7 @@ describe("RandomBeacon - Authorization", () => { it("should return zero", async () => { expect( - await randomBeacon.eligibleStake(stakingProvider.address) + await randomBeacon.eligibleStake(stakingProvider.address), ).to.equal(0) }) }) @@ -2586,16 +2611,20 @@ describe("RandomBeacon - Authorization", () => { before(async () => { await createSnapshot() - const authorizedAmount = minimumAuthorization.add(1200) + const authorizedAmount = minimumAuthorization + 1200n await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - authorizedAmount + await randomBeacon.getAddress(), + authorizedAmount, ) await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, authorizedAmount) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + authorizedAmount, + ) await randomBeacon.approveAuthorizationDecrease(stakingProvider.address) }) @@ -2606,7 +2635,7 @@ describe("RandomBeacon - Authorization", () => { it("should return zero", async () => { expect( - await randomBeacon.eligibleStake(stakingProvider.address) + await randomBeacon.eligibleStake(stakingProvider.address), ).to.equal(0) }) }) @@ -2621,12 +2650,12 @@ describe("RandomBeacon - Authorization", () => { const authorizedAmount = minimumAuthorization await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - authorizedAmount + await randomBeacon.getAddress(), + authorizedAmount, ) - const slashingTo = minimumAuthorization.sub(1) - const slashedAmount = authorizedAmount.sub(slashingTo) + const slashingTo = minimumAuthorization - 1n + const slashedAmount = authorizedAmount - slashingTo await staking .connect(slasher.wallet) @@ -2640,10 +2669,10 @@ describe("RandomBeacon - Authorization", () => { it("should return zero", async () => { expect( - await randomBeacon.eligibleStake(stakingProvider.address) + await randomBeacon.eligibleStake(stakingProvider.address), ).to.equal(0) }) - } + }, ) }) @@ -2651,11 +2680,11 @@ describe("RandomBeacon - Authorization", () => { before(async () => { await createSnapshot() - const authorizedAmount = minimumAuthorization.add(1200) + const authorizedAmount = minimumAuthorization + 1200n await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - authorizedAmount + await randomBeacon.getAddress(), + authorizedAmount, ) await randomBeacon @@ -2665,7 +2694,11 @@ describe("RandomBeacon - Authorization", () => { await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, authorizedAmount) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + authorizedAmount, + ) }) after(async () => { @@ -2679,8 +2712,8 @@ describe("RandomBeacon - Authorization", () => { it("should not activate before sortition pool is updated", async () => { expect( await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(MAX_UINT64) }) @@ -2688,8 +2721,8 @@ describe("RandomBeacon - Authorization", () => { await randomBeacon.updateOperatorStatus(operator.address) expect( await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(params.authorizationDecreaseDelay) }) @@ -2698,11 +2731,11 @@ describe("RandomBeacon - Authorization", () => { await helpers.time.increaseTime(params.authorizationDecreaseDelay / 2) expect( await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.be.closeTo( - ethers.BigNumber.from(params.authorizationDecreaseDelay / 2), - 5 // +- 5sec + BigInt(params.authorizationDecreaseDelay / 2), + 5, // +- 5sec ) }) @@ -2711,16 +2744,16 @@ describe("RandomBeacon - Authorization", () => { await helpers.time.increaseTime(params.authorizationDecreaseDelay) expect( await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(0) // ...and should remain zero await helpers.time.increaseTime(3600) // +1h expect( await randomBeacon.remainingAuthorizationDecreaseDelay( - stakingProvider.address - ) + stakingProvider.address, + ), ).to.equal(0) }) }) @@ -2730,7 +2763,7 @@ describe("RandomBeacon - Authorization", () => { it("should revert", async () => { it("should revert", async () => { await expect( - randomBeacon.isOperatorUpToDate(thirdParty.address) + randomBeacon.isOperatorUpToDate(thirdParty.address), ).to.be.revertedWith("Unknown operator") }) }) @@ -2762,8 +2795,8 @@ describe("RandomBeacon - Authorization", () => { await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - minimumAuthorization + await randomBeacon.getAddress(), + minimumAuthorization, ) }) @@ -2788,8 +2821,8 @@ describe("RandomBeacon - Authorization", () => { await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - minimumAuthorization.mul(2) + await randomBeacon.getAddress(), + minimumAuthorization * 2n, ) await randomBeacon.connect(operator).joinSortitionPool() @@ -2812,8 +2845,8 @@ describe("RandomBeacon - Authorization", () => { await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - to1e18(1337) + await randomBeacon.getAddress(), + to1e18(1337), ) }) @@ -2844,7 +2877,11 @@ describe("RandomBeacon - Authorization", () => { const deauthorizingBy = to1e18(1) await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, deauthorizingBy) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + deauthorizingBy, + ) }) after(async () => { @@ -2876,13 +2913,13 @@ describe("RandomBeacon - Authorization", () => { // will affect authorized stake amount for RandomBeacon. const authorized = await staking.authorizedStake( stakingProvider.address, - randomBeacon.address + await randomBeacon.getAddress(), ) - const increaseBy = stakedAmount.sub(authorized) + const increaseBy = stakedAmount - authorized await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - increaseBy + await randomBeacon.getAddress(), + increaseBy, ) await randomBeacon.updateOperatorStatus(operator.address) @@ -2897,7 +2934,7 @@ describe("RandomBeacon - Authorization", () => { // unlock the pool by stopping DKG await mineBlocks( - constants.offchainDkgTime + params.dkgResultSubmissionTimeout + constants.offchainDkgTime + params.dkgResultSubmissionTimeout, ) await randomBeacon.notifyDkgTimeout() }) @@ -2927,7 +2964,7 @@ describe("RandomBeacon - Authorization", () => { // Testing final states for scenarios when functions are invoked one after // another. Operator is known and registered in the sortition pool. context("mixed interactions", () => { - let initialIncrease: BigNumber + let initialIncrease: bigint before(async () => { await createSnapshot() @@ -2938,11 +2975,11 @@ describe("RandomBeacon - Authorization", () => { // Authorized almost the entire staked amount but leave some margin for // authorization increase. - initialIncrease = stakedAmount.sub(to1e18(20000)) + initialIncrease = stakedAmount - to1e18(20000) await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - initialIncrease + await randomBeacon.getAddress(), + initialIncrease, ) await randomBeacon.connect(operator).joinSortitionPool() }) @@ -2961,8 +2998,8 @@ describe("RandomBeacon - Authorization", () => { secondIncrease = to1e18(11111) await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - secondIncrease + await randomBeacon.getAddress(), + secondIncrease, ) await randomBeacon @@ -2976,8 +3013,8 @@ describe("RandomBeacon - Authorization", () => { it("should have correct eligible stake", async () => { expect( - await randomBeacon.eligibleStake(stakingProvider.address) - ).to.equal(initialIncrease.add(secondIncrease)) + await randomBeacon.eligibleStake(stakingProvider.address), + ).to.equal(initialIncrease + BigInt(secondIncrease)) }) it("should have operator status updated", async () => { @@ -2998,7 +3035,11 @@ describe("RandomBeacon - Authorization", () => { firstDecrease = to1e18(111) await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, firstDecrease) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + firstDecrease, + ) await randomBeacon .connect(operator) .updateOperatorStatus(operator.address) @@ -3006,8 +3047,8 @@ describe("RandomBeacon - Authorization", () => { secondIncrease = to1e18(11111) await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - secondIncrease + await randomBeacon.getAddress(), + secondIncrease, ) await randomBeacon .connect(operator) @@ -3020,8 +3061,10 @@ describe("RandomBeacon - Authorization", () => { it("should have correct eligible stake", async () => { expect( - await randomBeacon.eligibleStake(stakingProvider.address) - ).to.equal(initialIncrease.sub(firstDecrease).add(secondIncrease)) + await randomBeacon.eligibleStake(stakingProvider.address), + ).to.equal( + initialIncrease - BigInt(firstDecrease) + BigInt(secondIncrease), + ) }) it("should have operator status updated", async () => { @@ -3033,8 +3076,8 @@ describe("RandomBeacon - Authorization", () => { // Invoke `increaseAuthorization` after `approveAuthorizationDecrease`. // The decrease is approved when `increaseAuthorization` is called. describe("non-zero approveAuthorizationDecrease -> authorizationIncreased", () => { - let firstDecrease: BigNumber - let secondIncrease: BigNumber + let firstDecrease: bigint + let secondIncrease: bigint before(async () => { await createSnapshot() @@ -3042,7 +3085,11 @@ describe("RandomBeacon - Authorization", () => { firstDecrease = to1e18(222) await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, firstDecrease) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + firstDecrease, + ) await randomBeacon .connect(operator) .updateOperatorStatus(operator.address) @@ -3053,8 +3100,8 @@ describe("RandomBeacon - Authorization", () => { secondIncrease = to1e18(7311) await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - secondIncrease + await randomBeacon.getAddress(), + secondIncrease, ) await randomBeacon .connect(operator) @@ -3067,8 +3114,8 @@ describe("RandomBeacon - Authorization", () => { it("should have correct eligible stake", async () => { expect( - await randomBeacon.eligibleStake(stakingProvider.address) - ).to.equal(initialIncrease.sub(firstDecrease).add(secondIncrease)) + await randomBeacon.eligibleStake(stakingProvider.address), + ).to.equal(initialIncrease - firstDecrease + secondIncrease) }) it("should have operator status updated", async () => { @@ -3086,7 +3133,11 @@ describe("RandomBeacon - Authorization", () => { await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, initialIncrease) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + initialIncrease, + ) await randomBeacon .connect(operator) .updateOperatorStatus(operator.address) @@ -3094,11 +3145,11 @@ describe("RandomBeacon - Authorization", () => { await helpers.time.increaseTime(params.authorizationDecreaseDelay) await randomBeacon.approveAuthorizationDecrease(stakingProvider.address) - secondIncrease = minimumAuthorization.add(to1e18(21)) + secondIncrease = minimumAuthorization + to1e18(21) await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - secondIncrease + await randomBeacon.getAddress(), + secondIncrease, ) await randomBeacon.connect(operator).joinSortitionPool() }) @@ -3109,7 +3160,7 @@ describe("RandomBeacon - Authorization", () => { it("should have correct eligible stake", async () => { expect( - await randomBeacon.eligibleStake(stakingProvider.address) + await randomBeacon.eligibleStake(stakingProvider.address), ).to.equal(secondIncrease) }) @@ -3122,14 +3173,14 @@ describe("RandomBeacon - Authorization", () => { // Invoke `increaseAuthorization` after `involuntaryAuthorizationDecrease` // when the authorization amount dropped below the minimum authorization. describe("below-minimum involuntaryAuthorizationDecrease -> authorizationIncreased", () => { - let slashingTo: BigNumber - let secondIncrease: BigNumber + let slashingTo: bigint + let secondIncrease: bigint before(async () => { await createSnapshot() - slashingTo = minimumAuthorization.sub(1) - const slashedAmount = initialIncrease.sub(slashingTo) + slashingTo = minimumAuthorization - 1n + const slashedAmount = initialIncrease - slashingTo await staking .connect(slasher.wallet) @@ -3140,7 +3191,9 @@ describe("RandomBeacon - Authorization", () => { // they increase the authorization again. secondIncrease = to1e18(10000) await t.connect(deployer).mint(owner.address, secondIncrease) - await t.connect(owner).approve(staking.address, secondIncrease) + await t + .connect(owner) + .approve(await staking.getAddress(), secondIncrease) await staking .connect(owner) .topUp(stakingProvider.address, secondIncrease) @@ -3148,8 +3201,8 @@ describe("RandomBeacon - Authorization", () => { // And finally increase! await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - secondIncrease + await randomBeacon.getAddress(), + secondIncrease, ) await randomBeacon.connect(operator).joinSortitionPool() }) @@ -3160,8 +3213,8 @@ describe("RandomBeacon - Authorization", () => { it("should have correct eligible stake", async () => { expect( - await randomBeacon.eligibleStake(stakingProvider.address) - ).to.equal(slashingTo.add(secondIncrease)) + await randomBeacon.eligibleStake(stakingProvider.address), + ).to.equal(slashingTo + secondIncrease) }) it("should have operator status updated", async () => { @@ -3171,8 +3224,8 @@ describe("RandomBeacon - Authorization", () => { }) describe("authorizationDecreaseRequested -> involuntaryAuthorizationDecrease", () => { - let decreasedAmount: BigNumber - let slashingTo: BigNumber + let decreasedAmount: bigint + let slashingTo: bigint before(async () => { await createSnapshot() @@ -3180,13 +3233,17 @@ describe("RandomBeacon - Authorization", () => { decreasedAmount = to1e18(20000) await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, decreasedAmount) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + decreasedAmount, + ) await randomBeacon .connect(operator) .updateOperatorStatus(operator.address) - slashingTo = initialIncrease.sub(to1e18(100)) - const slashedAmount = initialIncrease.sub(slashingTo) + slashingTo = initialIncrease - to1e18(100) + const slashedAmount = initialIncrease - slashingTo await staking .connect(slasher.wallet) @@ -3200,8 +3257,8 @@ describe("RandomBeacon - Authorization", () => { it("should have correct eligible stake", async () => { expect( - await randomBeacon.eligibleStake(stakingProvider.address) - ).to.equal(slashingTo.sub(decreasedAmount)) + await randomBeacon.eligibleStake(stakingProvider.address), + ).to.equal(slashingTo - decreasedAmount) }) it("should have operator status updated", async () => { @@ -3211,8 +3268,8 @@ describe("RandomBeacon - Authorization", () => { }) describe("authorizationDecreaseRequested -> involuntaryAuthorizationDecrease -> approveAuthorizationDecrease", () => { - let decreasedAmount: BigNumber - let slashingTo: BigNumber + let decreasedAmount: bigint + let slashingTo: bigint before(async () => { await createSnapshot() @@ -3220,13 +3277,17 @@ describe("RandomBeacon - Authorization", () => { decreasedAmount = to1e18(20000) await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, decreasedAmount) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + decreasedAmount, + ) await randomBeacon .connect(operator) .updateOperatorStatus(operator.address) - slashingTo = initialIncrease.sub(to1e18(100)) - const slashedAmount = initialIncrease.sub(slashingTo) + slashingTo = initialIncrease - to1e18(100) + const slashedAmount = initialIncrease - slashingTo await staking .connect(slasher.wallet) @@ -3243,8 +3304,8 @@ describe("RandomBeacon - Authorization", () => { it("should have correct eligible stake", async () => { expect( - await randomBeacon.eligibleStake(stakingProvider.address) - ).to.equal(slashingTo.sub(decreasedAmount)) + await randomBeacon.eligibleStake(stakingProvider.address), + ).to.equal(slashingTo - decreasedAmount) }) it("should have operator status updated", async () => { @@ -3263,7 +3324,11 @@ describe("RandomBeacon - Authorization", () => { decreasedAmount = to1e18(1000) await legacyTokenStakingAt(staking, authorizer)[ "requestAuthorizationDecrease(address,address,uint96)" - ](stakingProvider.address, randomBeacon.address, decreasedAmount) + ]( + stakingProvider.address, + await randomBeacon.getAddress(), + decreasedAmount, + ) await randomBeacon .connect(operator) .updateOperatorStatus(operator.address) @@ -3271,10 +3336,8 @@ describe("RandomBeacon - Authorization", () => { await helpers.time.increaseTime(params.authorizationDecreaseDelay) await randomBeacon.approveAuthorizationDecrease(stakingProvider.address) - slashingTo = initialIncrease.sub(to1e18(2500)) - const slashedAmount = initialIncrease - .sub(decreasedAmount) - .sub(slashingTo) + slashingTo = initialIncrease - to1e18(2500) + const slashedAmount = initialIncrease - decreasedAmount - slashingTo await staking .connect(slasher.wallet) @@ -3288,7 +3351,7 @@ describe("RandomBeacon - Authorization", () => { it("should have correct eligible stake", async () => { expect( - await randomBeacon.eligibleStake(stakingProvider.address) + await randomBeacon.eligibleStake(stakingProvider.address), ).to.equal(slashingTo) }) diff --git a/solidity/random-beacon/test/RandomBeacon.Callback.test.ts b/solidity/random-beacon/test/RandomBeacon.Callback.test.ts index 2c905527d0..e07d240789 100644 --- a/solidity/random-beacon/test/RandomBeacon.Callback.test.ts +++ b/solidity/random-beacon/test/RandomBeacon.Callback.test.ts @@ -1,24 +1,24 @@ -/* eslint-disable @typescript-eslint/no-extra-semi */ - -import { ethers, waffle, helpers } from "hardhat" +import { ethers, helpers } from "hardhat" +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" import { expect } from "chai" +import requireResult from "./helpers/chain" import blsData from "./data/bls" import { constants, params, randomBeaconDeployment } from "./fixtures" import { createGroup } from "./utils/groups" import { registerOperators } from "./utils/operators" -import type { RandomBeaconGovernance } from "../typechain/RandomBeaconGovernance" import type { DeployedContracts } from "./fixtures" import type { RandomBeaconStub, T, CallbackContractStub, RandomBeacon, + RandomBeaconGovernance, } from "../typechain" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" -const ZERO_ADDRESS = ethers.constants.AddressZero +const ZERO_ADDRESS = ethers.ZeroAddress const { createSnapshot, restoreSnapshot } = helpers.snapshot const fixture = async () => { @@ -42,7 +42,7 @@ const fixture = async () => { contracts.randomBeacon as RandomBeacon, contracts.t as T, constants.groupSize, - 2 + 2, ) await createGroup(contracts.randomBeacon as RandomBeacon, signers) @@ -65,7 +65,7 @@ describe("RandomBeacon - Callback", () => { ;[requester, submitter] = await helpers.signers.getUnnamedSigners() ;({ governance } = await helpers.signers.getNamedSigners()) - const { contracts } = await waffle.loadFixture(fixture) + const { contracts } = await loadFixture(fixture) randomBeacon = contracts.randomBeacon as RandomBeaconStub randomBeaconGovernance = @@ -94,10 +94,10 @@ describe("RandomBeacon - Callback", () => { await randomBeacon .connect(requester) - .requestRelayEntry(callbackContract.address) + .requestRelayEntry(await callbackContract.getAddress()) await expect(await randomBeacon.getCallbackContract()).to.equal( - callbackContract.address + await callbackContract.getAddress(), ) await restoreSnapshot() @@ -108,7 +108,7 @@ describe("RandomBeacon - Callback", () => { await randomBeacon .connect(requester) - .requestRelayEntry(callbackContract.address) + .requestRelayEntry(await callbackContract.getAddress()) await randomBeacon .connect(submitter) @@ -117,7 +117,7 @@ describe("RandomBeacon - Callback", () => { await randomBeacon.connect(requester).requestRelayEntry(ZERO_ADDRESS) await expect(await randomBeacon.getCallbackContract()).to.equal( - ZERO_ADDRESS + ZERO_ADDRESS, ) await restoreSnapshot() @@ -128,7 +128,7 @@ describe("RandomBeacon - Callback", () => { await randomBeacon .connect(requester) - .requestRelayEntry(callbackContract.address) + .requestRelayEntry(await callbackContract.getAddress()) await randomBeacon .connect(submitter) @@ -136,10 +136,10 @@ describe("RandomBeacon - Callback", () => { await randomBeacon .connect(requester) - .requestRelayEntry(callbackContract1.address) + .requestRelayEntry(await callbackContract1.getAddress()) await expect(await randomBeacon.getCallbackContract()).to.equal( - callbackContract1.address + await callbackContract1.getAddress(), ) await restoreSnapshot() @@ -163,7 +163,7 @@ describe("RandomBeacon - Callback", () => { await randomBeacon .connect(requester) - .requestRelayEntry(callbackContract.address) + .requestRelayEntry(await callbackContract.getAddress()) await randomBeacon .connect(submitter) @@ -173,7 +173,9 @@ describe("RandomBeacon - Callback", () => { await expect(lastEntry).to.equal(blsData.groupSignatureUint256) const blockNumber = await callbackContract.blockNumber() - const latestBlock = await ethers.provider.getBlock("latest") + const latestBlock = requireResult( + await ethers.provider.getBlock("latest"), + ) await expect(blockNumber).to.equal(latestBlock.number) @@ -195,7 +197,7 @@ describe("RandomBeacon - Callback", () => { await randomBeacon .connect(requester) - .requestRelayEntry(callbackContract.address) + .requestRelayEntry(await callbackContract.getAddress()) const tx = await randomBeacon .connect(submitter) @@ -203,7 +205,10 @@ describe("RandomBeacon - Callback", () => { await expect(tx) .to.emit(randomBeacon, "CallbackFailed") - .withArgs(blsData.groupSignatureUint256, tx.blockNumber) + .withArgs( + blsData.groupSignatureUint256, + requireResult(await tx.wait()).blockNumber, + ) await restoreSnapshot() }) @@ -213,7 +218,7 @@ describe("RandomBeacon - Callback", () => { await randomBeacon .connect(requester) - .requestRelayEntry(callbackContract.address) + .requestRelayEntry(await callbackContract.getAddress()) await callbackContract.setFailureFlag(true) @@ -223,7 +228,10 @@ describe("RandomBeacon - Callback", () => { await expect(tx) .to.emit(randomBeacon, "CallbackFailed") - .withArgs(blsData.groupSignatureUint256, tx.blockNumber) + .withArgs( + blsData.groupSignatureUint256, + requireResult(await tx.wait()).blockNumber, + ) await restoreSnapshot() }) diff --git a/solidity/random-beacon/test/RandomBeacon.Constructor.test.ts b/solidity/random-beacon/test/RandomBeacon.Constructor.test.ts index 7b2520f268..00d0ba805d 100644 --- a/solidity/random-beacon/test/RandomBeacon.Constructor.test.ts +++ b/solidity/random-beacon/test/RandomBeacon.Constructor.test.ts @@ -3,7 +3,7 @@ import { expect } from "chai" import type { RandomBeacon__factory, SortitionPool } from "../typechain" -const ZERO_ADDRESS = ethers.constants.AddressZero +const ZERO_ADDRESS = ethers.ZeroAddress const { to1e18 } = helpers.number @@ -17,7 +17,6 @@ describe("RandomBeacon - Constructor", () => { let RandomBeacon: RandomBeacon__factory before(async () => { - // eslint-disable-next-line @typescript-eslint/no-extra-semi ;[tToken, staking, dkgValidator, reimbursementPool] = await getUnnamedAccounts() @@ -27,31 +26,31 @@ describe("RandomBeacon - Constructor", () => { const SortitionPool = await ethers.getContractFactory("SortitionPool") sortitionPool = (await SortitionPool.deploy( tToken, - to1e18(1) + to1e18(1), )) as SortitionPool const BLS = await ethers.getContractFactory("BLS") const bls = await BLS.deploy() - await bls.deployed() + await bls.waitForDeployment() const Authorization = await ethers.getContractFactory("BeaconAuthorization") const authorization = await Authorization.deploy() - await authorization.deployed() + await authorization.waitForDeployment() const BeaconDkg = await ethers.getContractFactory("BeaconDkg") const dkg = await BeaconDkg.deploy() - await dkg.deployed() + await dkg.waitForDeployment() const BeaconInactivity = await ethers.getContractFactory("BeaconInactivity") const inactivity = await BeaconInactivity.deploy() - await inactivity.deployed() + await inactivity.waitForDeployment() RandomBeacon = await ethers.getContractFactory("RandomBeacon", { libraries: { - BLS: bls.address, - BeaconAuthorization: authorization.address, - BeaconDkg: dkg.address, - BeaconInactivity: inactivity.address, + BLS: await bls.getAddress(), + BeaconAuthorization: await authorization.getAddress(), + BeaconDkg: await dkg.getAddress(), + BeaconInactivity: await inactivity.getAddress(), }, }) }) @@ -61,12 +60,12 @@ describe("RandomBeacon - Constructor", () => { it("should work", async () => { await expect( RandomBeacon.deploy( - sortitionPool.address, + await sortitionPool.getAddress(), tToken, staking, dkgValidator, - reimbursementPool - ) + reimbursementPool, + ), ).not.to.be.reverted }) }) @@ -79,8 +78,8 @@ describe("RandomBeacon - Constructor", () => { tToken, staking, dkgValidator, - reimbursementPool - ) + reimbursementPool, + ), ).to.be.revertedWith("Zero-address reference") }) }) @@ -89,12 +88,12 @@ describe("RandomBeacon - Constructor", () => { it("should revert", async () => { await expect( RandomBeacon.deploy( - sortitionPool.address, + await sortitionPool.getAddress(), ZERO_ADDRESS, staking, dkgValidator, - reimbursementPool - ) + reimbursementPool, + ), ).to.be.revertedWith("Zero-address reference") }) }) @@ -103,12 +102,12 @@ describe("RandomBeacon - Constructor", () => { it("should revert", async () => { await expect( RandomBeacon.deploy( - sortitionPool.address, + await sortitionPool.getAddress(), tToken, ZERO_ADDRESS, dkgValidator, - reimbursementPool - ) + reimbursementPool, + ), ).to.be.revertedWith("Zero-address reference") }) }) @@ -117,12 +116,12 @@ describe("RandomBeacon - Constructor", () => { it("should revert", async () => { await expect( RandomBeacon.deploy( - sortitionPool.address, + await sortitionPool.getAddress(), tToken, staking, ZERO_ADDRESS, - reimbursementPool - ) + reimbursementPool, + ), ).to.be.revertedWith("Zero-address reference") }) }) @@ -131,12 +130,12 @@ describe("RandomBeacon - Constructor", () => { it("should revert", async () => { await expect( RandomBeacon.deploy( - sortitionPool.address, + await sortitionPool.getAddress(), tToken, staking, dkgValidator, - ZERO_ADDRESS - ) + ZERO_ADDRESS, + ), ).to.be.revertedWith("Zero-address reference") }) }) diff --git a/solidity/random-beacon/test/RandomBeacon.GroupCreation.test.ts b/solidity/random-beacon/test/RandomBeacon.GroupCreation.test.ts index 839f720b95..2799bf9da2 100644 --- a/solidity/random-beacon/test/RandomBeacon.GroupCreation.test.ts +++ b/solidity/random-beacon/test/RandomBeacon.GroupCreation.test.ts @@ -1,8 +1,11 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions, @typescript-eslint/no-extra-semi */ +import { toBeHex } from "ethers" +/* eslint-disable @typescript-eslint/no-unused-expressions */ -import { ethers, waffle, helpers } from "hardhat" +import { ethers, helpers } from "hardhat" +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" import { expect } from "chai" +import requireResult from "./helpers/chain" import blsData from "./data/bls" import { constants, dkgState, params, randomBeaconDeployment } from "./fixtures" import { @@ -19,16 +22,16 @@ import { registerOperators } from "./utils/operators" import { selectGroup, createGroup, hashUint32Array } from "./utils/groups" import { fakeTokenStaking } from "./mocks/staking" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" -import type { BigNumber, BytesLike, ContractTransaction } from "ethers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" +import type { BytesLike, ContractTransactionResponse } from "ethers" import type { Operator } from "./utils/operators" -import type { BeaconDkg as DKG } from "../typechain/RandomBeaconStub" +import type { BeaconDkg as DKG } from "../typechain/contracts/test/RandomBeaconStub" import type { Mock } from "./helpers/mock" import type { RandomBeacon, SortitionPool, T, TokenStaking } from "../typechain" const { mineBlocks, mineBlocksTo } = helpers.time -const { keccak256 } = ethers.utils -const { provider } = waffle +const { keccak256 } = ethers +const { provider } = ethers const { createSnapshot, restoreSnapshot } = helpers.snapshot // FIXME: As a workaround for a bug https://github.com/dethcrypto/TypeChain/issues/601 @@ -37,8 +40,8 @@ type RandomBeaconTest = RandomBeacon & { getDkgData: () => Promise roughlyAddGroup: ( groupPubKey: BytesLike, - groupMembersHash: BytesLike - ) => Promise + groupMembersHash: BytesLike, + ) => Promise } const fixture = async () => { @@ -50,7 +53,7 @@ const fixture = async () => { contracts.randomBeacon as RandomBeacon, contracts.t as T, constants.groupSize, - 1 + 1, ) const randomBeacon = contracts.randomBeacon as RandomBeaconTest @@ -72,7 +75,7 @@ const fixture = async () => { describe("RandomBeacon - Group Creation", () => { const dkgTimeout: number = constants.offchainDkgTime + params.dkgResultSubmissionTimeout - const groupPublicKey: string = ethers.utils.hexValue(blsData.groupPubKey) + const groupPublicKey: string = ethers.toQuantity(blsData.groupPubKey) let thirdParty: SignerWithAddress let signers: Operator[] @@ -91,14 +94,14 @@ describe("RandomBeacon - Group Creation", () => { staking, t, signers, - } = await waffle.loadFixture(fixture)) + } = await loadFixture(fixture)) randomBeacon = randomBeaconStub }) describe("genesis", async () => { context("when called by a third party", async () => { - let tx: Promise + let tx: Promise before("run genesis", async () => { await createSnapshot() @@ -116,8 +119,8 @@ describe("RandomBeacon - Group Creation", () => { }) context("with initial contract state", async () => { - let tx: ContractTransaction - let expectedSeed: BigNumber + let tx: ContractTransactionResponse + let expectedSeed: bigint before("run genesis", async () => { await createSnapshot() @@ -146,13 +149,13 @@ describe("RandomBeacon - Group Creation", () => { context("with no registered groups", async () => { context("with genesis in progress", async () => { let startBlock: number - let genesisSeed: BigNumber + let genesisSeed: bigint before("run genesis", async () => { await createSnapshot() const [genesisTx, seed] = await genesis(randomBeacon) - startBlock = genesisTx.blockNumber + startBlock = requireResult(await genesisTx.wait()).blockNumber genesisSeed = seed }) @@ -163,7 +166,7 @@ describe("RandomBeacon - Group Creation", () => { context("with dkg result not submitted", async () => { it("should revert with 'Current state is not IDLE' error", async () => { await expect(randomBeacon.genesis()).to.be.revertedWith( - "Current state is not IDLE" + "Current state is not IDLE", ) }) }) @@ -181,7 +184,7 @@ describe("RandomBeacon - Group Creation", () => { groupPublicKey, genesisSeed, startBlock, - noMisbehaved + noMisbehaved, )) }) @@ -192,7 +195,7 @@ describe("RandomBeacon - Group Creation", () => { context("with dkg result not approved", async () => { it("should revert with 'Current state is not IDLE' error", async () => { await expect(randomBeacon.genesis()).to.be.revertedWith( - "Current state is not IDLE" + "Current state is not IDLE", ) }) }) @@ -212,7 +215,7 @@ describe("RandomBeacon - Group Creation", () => { it("should succeed", async () => { await expect(randomBeacon.genesis()).to.be.revertedWith( - "Not awaiting genesis" + "Not awaiting genesis", ) }) }) @@ -230,7 +233,7 @@ describe("RandomBeacon - Group Creation", () => { // Mix operators to make the result malicious mixSigners(await selectGroup(sortitionPool, genesisSeed)), startBlock, - noMisbehaved + noMisbehaved, ) await randomBeacon.challengeDkgResult(dkgResult) @@ -242,7 +245,7 @@ describe("RandomBeacon - Group Creation", () => { it("should revert", async () => { await expect(randomBeacon.genesis()).to.be.revertedWith( - "Current state is not IDLE" + "Current state is not IDLE", ) }) }) @@ -281,7 +284,7 @@ describe("RandomBeacon - Group Creation", () => { it("should revert with 'current state is not IDLE' error", async () => { await expect(randomBeacon.genesis()).to.be.revertedWith( - "Not awaiting genesis" + "Not awaiting genesis", ) }) }) @@ -291,20 +294,20 @@ describe("RandomBeacon - Group Creation", () => { context("with initial contract state", async () => { it("should return IDLE state", async () => { expect(await randomBeacon.getGroupCreationState()).to.be.equal( - dkgState.IDLE + dkgState.IDLE, ) }) }) context("when genesis dkg started", async () => { let startBlock: number - let genesisSeed: BigNumber + let genesisSeed: bigint before("run genesis", async () => { await createSnapshot() const [genesisTx, seed] = await genesis(randomBeacon) - startBlock = genesisTx.blockNumber + startBlock = requireResult(await genesisTx.wait()).blockNumber genesisSeed = seed }) @@ -315,7 +318,7 @@ describe("RandomBeacon - Group Creation", () => { context("at the start of off-chain dkg period", async () => { it("should return KEY_GENERATION state", async () => { expect(await randomBeacon.getGroupCreationState()).to.be.equal( - dkgState.KEY_GENERATION + dkgState.KEY_GENERATION, ) }) }) @@ -333,7 +336,7 @@ describe("RandomBeacon - Group Creation", () => { it("should return KEY_GENERATION state", async () => { expect(await randomBeacon.getGroupCreationState()).to.be.equal( - dkgState.KEY_GENERATION + dkgState.KEY_GENERATION, ) }) }) @@ -352,7 +355,7 @@ describe("RandomBeacon - Group Creation", () => { context("when dkg result was not submitted", async () => { it("should return AWAITING_RESULT state", async () => { expect(await randomBeacon.getGroupCreationState()).to.be.equal( - dkgState.AWAITING_RESULT + dkgState.AWAITING_RESULT, ) }) @@ -369,7 +372,7 @@ describe("RandomBeacon - Group Creation", () => { it("should return AWAITING_RESULT state", async () => { expect(await randomBeacon.getGroupCreationState()).to.be.equal( - dkgState.AWAITING_RESULT + dkgState.AWAITING_RESULT, ) }) }) @@ -386,7 +389,7 @@ describe("RandomBeacon - Group Creation", () => { groupPublicKey, genesisSeed, startBlock, - noMisbehaved + noMisbehaved, )) }) @@ -397,7 +400,7 @@ describe("RandomBeacon - Group Creation", () => { context("when dkg result was not approved", async () => { it("should return CHALLENGE state", async () => { expect(await randomBeacon.getGroupCreationState()).to.be.equal( - dkgState.CHALLENGE + dkgState.CHALLENGE, ) }) }) @@ -417,7 +420,7 @@ describe("RandomBeacon - Group Creation", () => { it("should return IDLE state", async () => { expect(await randomBeacon.getGroupCreationState()).to.be.equal( - dkgState.IDLE + dkgState.IDLE, ) }) }) @@ -434,7 +437,7 @@ describe("RandomBeacon - Group Creation", () => { // Mix signers to make the result malicious mixSigners(await selectGroup(sortitionPool, genesisSeed)), startBlock, - noMisbehaved + noMisbehaved, )) }) @@ -455,7 +458,7 @@ describe("RandomBeacon - Group Creation", () => { it("should return AWAITING_RESULT state", async () => { expect(await randomBeacon.getGroupCreationState()).to.be.equal( - dkgState.AWAITING_RESULT + dkgState.AWAITING_RESULT, ) }) }) @@ -473,13 +476,13 @@ describe("RandomBeacon - Group Creation", () => { context("when genesis dkg started", async () => { let startBlock: number - let genesisSeed: BigNumber + let genesisSeed: bigint before("run genesis", async () => { await createSnapshot() const [genesisTx, seed] = await genesis(randomBeacon) - startBlock = genesisTx.blockNumber + startBlock = requireResult(await genesisTx.wait()).blockNumber genesisSeed = seed }) @@ -550,7 +553,7 @@ describe("RandomBeacon - Group Creation", () => { before(async () => { await createSnapshot() - let tx: ContractTransaction + let tx: ContractTransactionResponse ;({ transaction: tx, dkgResult, @@ -560,10 +563,10 @@ describe("RandomBeacon - Group Creation", () => { groupPublicKey, genesisSeed, startBlock, - noMisbehaved + noMisbehaved, )) - resultSubmissionBlock = tx.blockNumber + resultSubmissionBlock = requireResult(await tx.wait()).blockNumber }) after(async () => { @@ -608,7 +611,7 @@ describe("RandomBeacon - Group Creation", () => { await createSnapshot() await mineBlocksTo( - resultSubmissionBlock + params.dkgResultChallengePeriodLength + resultSubmissionBlock + params.dkgResultChallengePeriodLength, ) }) @@ -628,7 +631,7 @@ describe("RandomBeacon - Group Creation", () => { await mineBlocksTo( resultSubmissionBlock + params.dkgResultChallengePeriodLength + - 1 + 1, ) }) @@ -647,7 +650,7 @@ describe("RandomBeacon - Group Creation", () => { await createSnapshot() await mineBlocksTo( - resultSubmissionBlock + params.dkgResultChallengePeriodLength + resultSubmissionBlock + params.dkgResultChallengePeriodLength, ) await randomBeacon.connect(submitter).approveDkgResult(dkgResult) @@ -674,7 +677,7 @@ describe("RandomBeacon - Group Creation", () => { // Mix signers to make the result malicious. mixSigners(await selectGroup(sortitionPool, genesisSeed)), startBlock, - noMisbehaved + noMisbehaved, )) }) @@ -689,7 +692,7 @@ describe("RandomBeacon - Group Creation", () => { await createSnapshot() const tx = await randomBeacon.challengeDkgResult(dkgResult) - challengeBlockNumber = tx.blockNumber + challengeBlockNumber = requireResult(await tx.wait()).blockNumber }) after(async () => { @@ -701,7 +704,7 @@ describe("RandomBeacon - Group Creation", () => { await createSnapshot() await mineBlocksTo( - challengeBlockNumber + params.dkgResultSubmissionTimeout + challengeBlockNumber + params.dkgResultSubmissionTimeout, ) }) @@ -719,7 +722,7 @@ describe("RandomBeacon - Group Creation", () => { await createSnapshot() await mineBlocksTo( - challengeBlockNumber + params.dkgResultSubmissionTimeout + 1 + challengeBlockNumber + params.dkgResultSubmissionTimeout + 1, ) }) @@ -746,22 +749,22 @@ describe("RandomBeacon - Group Creation", () => { groupPublicKey, signers, 1, - noMisbehaved - ) + noMisbehaved, + ), ).to.be.revertedWith("Current state is not AWAITING_RESULT") }) }) context("with group creation in progress", async () => { let startBlock: number - let genesisSeed: BigNumber + let genesisSeed: bigint before("run genesis", async () => { await createSnapshot() const [genesisTx, seed] = await genesis(randomBeacon) - startBlock = genesisTx.blockNumber + startBlock = requireResult(await genesisTx.wait()).blockNumber genesisSeed = seed }) @@ -788,8 +791,8 @@ describe("RandomBeacon - Group Creation", () => { groupPublicKey, genesisSeed, startBlock, - noMisbehaved - ) + noMisbehaved, + ), ).to.be.revertedWith("Current state is not AWAITING_RESULT") }) }) @@ -806,7 +809,7 @@ describe("RandomBeacon - Group Creation", () => { }) context("with enough signatures on the result", async () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse let dkgResult: DKG.ResultStruct let dkgResultHash: string @@ -824,7 +827,7 @@ describe("RandomBeacon - Group Creation", () => { noMisbehaved, 1, undefined, - constants.groupThreshold + constants.groupThreshold, )) }) @@ -856,7 +859,7 @@ describe("RandomBeacon - Group Creation", () => { }) context("with not enough signatures on the result", async () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse let dkgResult: DKG.ResultStruct let dkgResultHash: string @@ -874,7 +877,7 @@ describe("RandomBeacon - Group Creation", () => { noMisbehaved, 1, undefined, - constants.groupThreshold - 1 + constants.groupThreshold - 1, )) }) @@ -940,7 +943,7 @@ describe("RandomBeacon - Group Creation", () => { await mineBlocksTo( submissionStartBlockNumber + params.dkgResultSubmissionTimeout - - 1 + 1, ) }) @@ -966,7 +969,8 @@ describe("RandomBeacon - Group Creation", () => { await createSnapshot() await mineBlocksTo( - submissionStartBlockNumber + params.dkgResultSubmissionTimeout + submissionStartBlockNumber + + params.dkgResultSubmissionTimeout, ) }) @@ -996,7 +1000,7 @@ describe("RandomBeacon - Group Creation", () => { before(async () => { await createSnapshot() - let tx: ContractTransaction + let tx: ContractTransactionResponse ;({ transaction: tx, dkgResult, @@ -1006,10 +1010,10 @@ describe("RandomBeacon - Group Creation", () => { groupPublicKey, genesisSeed, startBlock, - noMisbehaved + noMisbehaved, )) - resultSubmissionBlock = tx.blockNumber + resultSubmissionBlock = requireResult(await tx.wait()).blockNumber }) after(async () => { @@ -1023,8 +1027,8 @@ describe("RandomBeacon - Group Creation", () => { groupPublicKey, genesisSeed, startBlock, - noMisbehaved - ) + noMisbehaved, + ), ).to.be.revertedWith("Current state is not AWAITING_RESULT") }) @@ -1033,7 +1037,7 @@ describe("RandomBeacon - Group Creation", () => { await createSnapshot() await mineBlocksTo( - resultSubmissionBlock + params.dkgResultChallengePeriodLength + resultSubmissionBlock + params.dkgResultChallengePeriodLength, ) await randomBeacon @@ -1052,8 +1056,8 @@ describe("RandomBeacon - Group Creation", () => { groupPublicKey, genesisSeed, startBlock, - noMisbehaved - ) + noMisbehaved, + ), ).to.be.revertedWith("Sortition pool unlocked") }) }) @@ -1071,11 +1075,11 @@ describe("RandomBeacon - Group Creation", () => { // Mix signers to make the result malicious. mixSigners(await selectGroup(sortitionPool, genesisSeed)), startBlock, - noMisbehaved + noMisbehaved, ) const tx = await randomBeacon.challengeDkgResult(dkgResult) - challengeBlockNumber = tx.blockNumber + challengeBlockNumber = requireResult(await tx.wait()).blockNumber }) after(async () => { @@ -1083,7 +1087,7 @@ describe("RandomBeacon - Group Creation", () => { }) describe("group registration", async () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1092,7 +1096,7 @@ describe("RandomBeacon - Group Creation", () => { groupPublicKey, genesisSeed, startBlock, - noMisbehaved + noMisbehaved, )) }) @@ -1145,7 +1149,7 @@ describe("RandomBeacon - Group Creation", () => { await mineBlocksTo( submissionStartBlockNumber + params.dkgResultSubmissionTimeout - - 1 + 1, ) }) @@ -1172,7 +1176,7 @@ describe("RandomBeacon - Group Creation", () => { await mineBlocksTo( submissionStartBlockNumber + - params.dkgResultSubmissionTimeout + params.dkgResultSubmissionTimeout, ) }) @@ -1195,7 +1199,7 @@ describe("RandomBeacon - Group Creation", () => { }) context("with misbehaved members", async () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse let dkgResult: DKG.ResultStruct let dkgResultHash: string @@ -1215,7 +1219,7 @@ describe("RandomBeacon - Group Creation", () => { groupPublicKey, genesisSeed, startBlock, - misbehavedIndices + misbehavedIndices, )) }) @@ -1230,7 +1234,7 @@ describe("RandomBeacon - Group Creation", () => { result: dkgResult, }) }) - } + }, ) }) }) @@ -1244,7 +1248,7 @@ describe("RandomBeacon - Group Creation", () => { invalidPublicKey, noMisbehaved, startBlock, - constants.groupThreshold + constants.groupThreshold, ) const submitterIndex = 1 @@ -1264,7 +1268,7 @@ describe("RandomBeacon - Group Creation", () => { } await expect( - randomBeacon.connect(submitter).submitDkgResult(dkgResult) + randomBeacon.connect(submitter).submitDkgResult(dkgResult), ).to.be.revertedWith("Invalid length of the public key") }) }) @@ -1275,7 +1279,7 @@ describe("RandomBeacon - Group Creation", () => { await randomBeacon.roughlyAddGroup( groupPublicKey, // group members do not matter for this test - "0x0000000000000000000000000000000000000000000000000000000000000000" + "0x0000000000000000000000000000000000000000000000000000000000000000", ) }) @@ -1290,7 +1294,7 @@ describe("RandomBeacon - Group Creation", () => { groupPublicKey, noMisbehaved, startBlock, - constants.groupThreshold + constants.groupThreshold, ) const submitterIndex = 1 @@ -1310,9 +1314,9 @@ describe("RandomBeacon - Group Creation", () => { } await expect( - randomBeacon.connect(submitter).submitDkgResult(dkgResult) + randomBeacon.connect(submitter).submitDkgResult(dkgResult), ).to.be.revertedWith( - "Group with this public key was already registered" + "Group with this public key was already registered", ) }) }) @@ -1338,8 +1342,8 @@ describe("RandomBeacon - Group Creation", () => { groupPublicKey, genesisSeed, startBlock, - noMisbehaved - ) + noMisbehaved, + ), ).to.be.revertedWith("DKG timeout already passed") }) }) @@ -1347,7 +1351,7 @@ describe("RandomBeacon - Group Creation", () => { // Submission Test Helpers async function assertSubmissionSucceeds( - submitterIndex: number + submitterIndex: number, ): Promise { const { transaction: tx, @@ -1359,7 +1363,7 @@ describe("RandomBeacon - Group Creation", () => { genesisSeed, startBlock, noMisbehaved, - submitterIndex + submitterIndex, ) await expectDkgResultSubmittedEvent(tx, { @@ -1371,7 +1375,7 @@ describe("RandomBeacon - Group Creation", () => { async function assertSubmissionReverts( submitterIndex: number, - message = "DKG timeout already passed" + message = "DKG timeout already passed", ): Promise { await expect( signAndSubmitCorrectDkgResult( @@ -1380,8 +1384,8 @@ describe("RandomBeacon - Group Creation", () => { genesisSeed, startBlock, noMisbehaved, - submitterIndex - ) + submitterIndex, + ), ).to.be.revertedWith(message) } }) @@ -1402,21 +1406,21 @@ describe("RandomBeacon - Group Creation", () => { context("with initial contract state", async () => { it("should revert with 'Current state is not CHALLENGE' error", async () => { await expect( - randomBeacon.approveDkgResult(stubDkgResult) + randomBeacon.approveDkgResult(stubDkgResult), ).to.be.revertedWith("Current state is not CHALLENGE") }) }) context("with group creation in progress", async () => { let startBlock: number - let genesisSeed: BigNumber + let genesisSeed: bigint before("run genesis", async () => { await createSnapshot() const [genesisTx, seed] = await genesis(randomBeacon) - startBlock = genesisTx.blockNumber + startBlock = requireResult(await genesisTx.wait()).blockNumber genesisSeed = seed }) @@ -1426,7 +1430,7 @@ describe("RandomBeacon - Group Creation", () => { it("should revert with 'Current state is not CHALLENGE' error", async () => { await expect( - randomBeacon.approveDkgResult(stubDkgResult) + randomBeacon.approveDkgResult(stubDkgResult), ).to.be.revertedWith("Current state is not CHALLENGE") }) @@ -1444,7 +1448,7 @@ describe("RandomBeacon - Group Creation", () => { context("with dkg result not submitted", async () => { it("should revert with 'Current state is not CHALLENGE' error", async () => { await expect( - randomBeacon.approveDkgResult(stubDkgResult) + randomBeacon.approveDkgResult(stubDkgResult), ).to.be.revertedWith("Current state is not CHALLENGE") }) }) @@ -1454,14 +1458,14 @@ describe("RandomBeacon - Group Creation", () => { let dkgResultHash: string let dkgResult: DKG.ResultStruct let submitter: SignerWithAddress - let submitterInitialBalance: BigNumber + let submitterInitialBalance: bigint const submitterIndex = 1 before(async () => { await createSnapshot() - let tx: ContractTransaction + let tx: ContractTransactionResponse ;({ transaction: tx, dkgResult, @@ -1474,10 +1478,10 @@ describe("RandomBeacon - Group Creation", () => { genesisSeed, startBlock, noMisbehaved, - submitterIndex + submitterIndex, )) - resultSubmissionBlock = tx.blockNumber + resultSubmissionBlock = requireResult(await tx.wait()).blockNumber }) after(async () => { @@ -1491,7 +1495,7 @@ describe("RandomBeacon - Group Creation", () => { await mineBlocksTo( resultSubmissionBlock + params.dkgResultChallengePeriodLength - - 1 + 1, ) }) @@ -1501,7 +1505,7 @@ describe("RandomBeacon - Group Creation", () => { it("should revert with 'Challenge period has not passed yet' error", async () => { await expect( - randomBeacon.connect(submitter).approveDkgResult(dkgResult) + randomBeacon.connect(submitter).approveDkgResult(dkgResult), ).to.be.revertedWith("Challenge period has not passed yet") }) }) @@ -1511,7 +1515,7 @@ describe("RandomBeacon - Group Creation", () => { await createSnapshot() await mineBlocksTo( - resultSubmissionBlock + params.dkgResultChallengePeriodLength + resultSubmissionBlock + params.dkgResultChallengePeriodLength, ) }) @@ -1520,7 +1524,7 @@ describe("RandomBeacon - Group Creation", () => { }) context("when called by a DKG result submitter", async () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1549,19 +1553,18 @@ describe("RandomBeacon - Group Creation", () => { expect(groupsRegistry).to.be.lengthOf(1) expect(groupsRegistry[0]).to.deep.equal( - keccak256(groupPublicKey) + keccak256(groupPublicKey), ) - const storedGroup = await randomBeacon["getGroup(bytes)"]( - groupPublicKey - ) + const storedGroup = + await randomBeacon["getGroup(bytes)"](groupPublicKey) expect(storedGroup.groupPubKey).to.be.equal(groupPublicKey) expect(storedGroup.registrationBlockNumber).to.be.equal( - tx.blockNumber + requireResult(await tx.wait()).blockNumber, ) expect(storedGroup.membersHash).to.be.equal( - hashUint32Array(dkgResult.members) + hashUint32Array(dkgResult.members), ) }) @@ -1577,11 +1580,11 @@ describe("RandomBeacon - Group Creation", () => { it("should refund ETH", async () => { const postBalance = await provider.getBalance(submitter.address) - const diff = postBalance.sub(submitterInitialBalance) + const diff = postBalance - submitterInitialBalance expect(diff).to.be.gt(0) expect(diff).to.be.lt( - ethers.utils.parseUnits("2000000", "gwei") // 0,002 ETH + ethers.parseUnits("2000000", "gwei"), // 0,002 ETH ) }) }) @@ -1592,7 +1595,7 @@ describe("RandomBeacon - Group Creation", () => { await createSnapshot() await mineBlocks( - params.dkgSubmitterPrecedencePeriodLength - 1 + params.dkgSubmitterPrecedencePeriodLength - 1, ) }) @@ -1602,23 +1605,25 @@ describe("RandomBeacon - Group Creation", () => { it("should revert", async () => { await expect( - randomBeacon.connect(thirdParty).approveDkgResult(dkgResult) + randomBeacon + .connect(thirdParty) + .approveDkgResult(dkgResult), ).to.be.revertedWith( - "Only the DKG result submitter can approve the result at this moment" + "Only the DKG result submitter can approve the result at this moment", ) }) }) context("when the third party is eligible", async () => { - let tx: Promise - let initApproverBalance: BigNumber + let tx: Promise + let initApproverBalance: bigint before(async () => { await createSnapshot() await mineBlocks(params.dkgSubmitterPrecedencePeriodLength) initApproverBalance = await provider.getBalance( - thirdParty.address + thirdParty.address, ) tx = randomBeacon .connect(thirdParty) @@ -1635,9 +1640,9 @@ describe("RandomBeacon - Group Creation", () => { it("should refund ETH", async () => { const postBalance = await provider.getBalance( - thirdParty.address + thirdParty.address, ) - const diff = postBalance.sub(initApproverBalance) + const diff = postBalance - initApproverBalance expect(diff).to.be.gt(0) // The third party did not submit the result so we are not @@ -1659,7 +1664,7 @@ describe("RandomBeacon - Group Creation", () => { // Submit a second result by another submitter const anotherSubmitterIndex = 6 let anotherSubmitter: SignerWithAddress - let anotherSubmitterInitialBalance: BigNumber + let anotherSubmitterInitialBalance: bigint before(async () => { await createSnapshot() @@ -1672,12 +1677,12 @@ describe("RandomBeacon - Group Creation", () => { mixSigners(await selectGroup(sortitionPool, genesisSeed)), startBlock, noMisbehaved, - maliciousSubmitter + maliciousSubmitter, ) await randomBeacon.challengeDkgResult(maliciousDkgResult) - let tx: ContractTransaction + let tx: ContractTransactionResponse ;({ transaction: tx, dkgResult, @@ -1690,10 +1695,10 @@ describe("RandomBeacon - Group Creation", () => { genesisSeed, startBlock, noMisbehaved, - anotherSubmitterIndex + anotherSubmitterIndex, )) - resultSubmissionBlock = tx.blockNumber + resultSubmissionBlock = requireResult(await tx.wait()).blockNumber }) after(async () => { @@ -1707,7 +1712,7 @@ describe("RandomBeacon - Group Creation", () => { await mineBlocksTo( resultSubmissionBlock + params.dkgResultChallengePeriodLength - - 1 + 1, ) }) @@ -1719,19 +1724,19 @@ describe("RandomBeacon - Group Creation", () => { await expect( randomBeacon .connect(anotherSubmitter) - .approveDkgResult(dkgResult) + .approveDkgResult(dkgResult), ).to.be.revertedWith("Challenge period has not passed yet") }) }) context("with challenge period passed", async () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() await mineBlocksTo( - resultSubmissionBlock + params.dkgResultChallengePeriodLength + resultSubmissionBlock + params.dkgResultChallengePeriodLength, ) tx = await randomBeacon @@ -1755,16 +1760,15 @@ describe("RandomBeacon - Group Creation", () => { expect(groupsRegistry).to.be.lengthOf(1) expect(groupsRegistry[0]).to.deep.equal(keccak256(groupPublicKey)) - const storedGroup = await randomBeacon["getGroup(bytes)"]( - groupPublicKey - ) + const storedGroup = + await randomBeacon["getGroup(bytes)"](groupPublicKey) expect(storedGroup.groupPubKey).to.be.equal(groupPublicKey) expect(storedGroup.registrationBlockNumber).to.be.equal( - tx.blockNumber + requireResult(await tx.wait()).blockNumber, ) expect(storedGroup.membersHash).to.be.equal( - hashUint32Array(dkgResult.members) + hashUint32Array(dkgResult.members), ) }) @@ -1780,13 +1784,13 @@ describe("RandomBeacon - Group Creation", () => { it("should refund ETH", async () => { const postBalance = await provider.getBalance( - anotherSubmitter.address + anotherSubmitter.address, ) - const diff = postBalance.sub(anotherSubmitterInitialBalance) + const diff = postBalance - anotherSubmitterInitialBalance expect(diff).to.be.gt(0) expect(diff).to.be.lt( - ethers.utils.parseUnits("2400000", "gwei") // 0,0024 ETH + ethers.parseUnits("2400000", "gwei"), // 0,0024 ETH ) }) }) @@ -1794,7 +1798,7 @@ describe("RandomBeacon - Group Creation", () => { }) context("with max periods duration", async () => { - let tx: Promise + let tx: Promise before(async () => { await createSnapshot() @@ -1806,7 +1810,7 @@ describe("RandomBeacon - Group Creation", () => { groupPublicKey, genesisSeed, startBlock, - noMisbehaved + noMisbehaved, ) await mineBlocks(params.dkgResultChallengePeriodLength) @@ -1832,10 +1836,10 @@ describe("RandomBeacon - Group Creation", () => { context("with misbehaved operators", async () => { const misbehavedIndices: number[] = [2, 9, 11, 30, 60, 64] let misbehavedIds: number[] - let tx: ContractTransaction + let tx: ContractTransactionResponse let dkgResult: DKG.ResultStruct let submitter: SignerWithAddress - let submitterInitialBalance: BigNumber + let submitterInitialBalance: bigint before(async () => { await createSnapshot() @@ -1849,7 +1853,7 @@ describe("RandomBeacon - Group Creation", () => { groupPublicKey, genesisSeed, startBlock, - misbehavedIndices + misbehavedIndices, )) misbehavedIds = misbehavedIndices.map((i) => members[i - 1]) @@ -1863,9 +1867,8 @@ describe("RandomBeacon - Group Creation", () => { }) it("should correctly set a group members hash", async () => { - const storedGroup = await randomBeacon["getGroup(bytes)"]( - groupPublicKey - ) + const storedGroup = + await randomBeacon["getGroup(bytes)"](groupPublicKey) // misbehavedIndices: [2, 9, 11, 30, 60, 64] const expectedMembers = [...dkgResult.members] @@ -1876,7 +1879,7 @@ describe("RandomBeacon - Group Creation", () => { expectedMembers.splice(55, 1) // index -5 expectedMembers.splice(58, 1) // index -6 expect(storedGroup.membersHash).to.be.equal( - hashUint32Array(expectedMembers) + hashUint32Array(expectedMembers), ) }) @@ -1895,11 +1898,11 @@ describe("RandomBeacon - Group Creation", () => { it("should refund ETH", async () => { const postBalance = await provider.getBalance(submitter.address) - const diff = postBalance.sub(submitterInitialBalance) + const diff = postBalance - submitterInitialBalance expect(diff).to.be.gt(0) expect(diff).to.be.lt( - ethers.utils.parseUnits("1000000", "gwei") // 0,001 ETH + ethers.parseUnits("1000000", "gwei"), // 0,001 ETH ) }) }) @@ -1913,8 +1916,8 @@ describe("RandomBeacon - Group Creation", () => { let dkgResult: DKG.ResultStruct let submitter: SignerWithAddress - let submitterInitialBalance: BigNumber - let tx: Promise + let submitterInitialBalance: bigint + let tx: Promise before(async () => { await createSnapshot() @@ -1925,7 +1928,7 @@ describe("RandomBeacon - Group Creation", () => { groupPublicKey, genesisSeed, startBlock, - misbehavedIndices + misbehavedIndices, )) await mineBlocks(params.dkgResultChallengePeriodLength) @@ -1943,14 +1946,14 @@ describe("RandomBeacon - Group Creation", () => { it("should refund ETH", async () => { const postBalance = await provider.getBalance(submitter.address) - const diff = postBalance.sub(submitterInitialBalance) + const diff = postBalance - submitterInitialBalance expect(diff).to.be.gt(0) expect(diff).to.be.lt( - ethers.utils.parseUnits("1000000", "gwei") // 0,001 ETH + ethers.parseUnits("1000000", "gwei"), // 0,001 ETH ) }) - } + }, ) context("when misbehaved members contains duplicates", async () => { @@ -1958,8 +1961,8 @@ describe("RandomBeacon - Group Creation", () => { let dkgResult: DKG.ResultStruct let submitter: SignerWithAddress - let tx: Promise - let submitterInitialBalance: BigNumber + let tx: Promise + let submitterInitialBalance: bigint before(async () => { await createSnapshot() @@ -1970,7 +1973,7 @@ describe("RandomBeacon - Group Creation", () => { groupPublicKey, genesisSeed, startBlock, - misbehavedIndices + misbehavedIndices, )) await mineBlocks(params.dkgResultChallengePeriodLength) @@ -1988,11 +1991,11 @@ describe("RandomBeacon - Group Creation", () => { it("should refund ETH", async () => { const postBalance = await provider.getBalance(submitter.address) - const diff = postBalance.sub(submitterInitialBalance) + const diff = postBalance - submitterInitialBalance expect(diff).to.be.gt(0) expect(diff).to.be.lt( - ethers.utils.parseUnits("2000000", "gwei") // 0,002 ETH + ethers.parseUnits("2000000", "gwei"), // 0,002 ETH ) }) }) @@ -2003,7 +2006,7 @@ describe("RandomBeacon - Group Creation", () => { context("with initial contract state", async () => { it("should revert with 'DKG has not timed out' error", async () => { await expect(randomBeacon.notifyDkgTimeout()).to.be.revertedWith( - "DKG has not timed out" + "DKG has not timed out", ) }) }) @@ -2016,7 +2019,7 @@ describe("RandomBeacon - Group Creation", () => { const [genesisTx] = await genesis(randomBeacon) - startBlock = genesisTx.blockNumber + startBlock = requireResult(await genesisTx.wait()).blockNumber }) after(async () => { @@ -2037,7 +2040,7 @@ describe("RandomBeacon - Group Creation", () => { it("should revert with 'DKG has not timed out' error", async () => { await expect(randomBeacon.notifyDkgTimeout()).to.be.revertedWith( - "DKG has not timed out" + "DKG has not timed out", ) }) }) @@ -2055,7 +2058,7 @@ describe("RandomBeacon - Group Creation", () => { it("should revert with 'DKG has not timed out' error", async () => { await expect(randomBeacon.notifyDkgTimeout()).to.be.revertedWith( - "DKG has not timed out" + "DKG has not timed out", ) }) }) @@ -2073,7 +2076,7 @@ describe("RandomBeacon - Group Creation", () => { it("should revert with 'DKG has not timed out' error", async () => { await expect(randomBeacon.notifyDkgTimeout()).to.be.revertedWith( - "DKG has not timed out" + "DKG has not timed out", ) }) }) @@ -2091,14 +2094,14 @@ describe("RandomBeacon - Group Creation", () => { }) context("called by a third party", async () => { - let tx: ContractTransaction - let initialThirdPartyBalance: BigNumber + let tx: ContractTransactionResponse + let initialThirdPartyBalance: bigint before(async () => { await createSnapshot() initialThirdPartyBalance = await provider.getBalance( - await thirdParty.getAddress() + await thirdParty.getAddress(), ) tx = await randomBeacon.connect(thirdParty).notifyDkgTimeout() }) @@ -2121,10 +2124,10 @@ describe("RandomBeacon - Group Creation", () => { it("should refund ETH", async () => { const postBalance = await provider.getBalance(thirdParty.address) - const diff = postBalance.sub(initialThirdPartyBalance) + const diff = postBalance - initialThirdPartyBalance expect(diff).to.be.gt(0) expect(diff).to.be.lt( - ethers.utils.parseUnits("2000000", "gwei") // 0,002 ETH + ethers.parseUnits("2000000", "gwei"), // 0,002 ETH ) }) }) @@ -2147,21 +2150,21 @@ describe("RandomBeacon - Group Creation", () => { context("with initial contract state", async () => { it("should revert with 'Current state is not CHALLENGE' error", async () => { await expect( - randomBeacon.challengeDkgResult(stubDkgResult) + randomBeacon.challengeDkgResult(stubDkgResult), ).to.be.revertedWith("Current state is not CHALLENGE") }) }) context("with group creation in progress", async () => { let startBlock: number - let genesisSeed: BigNumber + let genesisSeed: bigint before("run genesis", async () => { await createSnapshot() const [genesisTx, seed] = await genesis(randomBeacon) - startBlock = genesisTx.blockNumber + startBlock = requireResult(await genesisTx.wait()).blockNumber genesisSeed = seed }) @@ -2171,7 +2174,7 @@ describe("RandomBeacon - Group Creation", () => { it("should revert with 'Current state is not CHALLENGE' error", async () => { await expect( - randomBeacon.challengeDkgResult(stubDkgResult) + randomBeacon.challengeDkgResult(stubDkgResult), ).to.be.revertedWith("Current state is not CHALLENGE") }) @@ -2189,7 +2192,7 @@ describe("RandomBeacon - Group Creation", () => { context("with dkg result not submitted", async () => { it("should revert with 'Current state is not CHALLENGE' error", async () => { await expect( - randomBeacon.challengeDkgResult(stubDkgResult) + randomBeacon.challengeDkgResult(stubDkgResult), ).to.be.revertedWith("Current state is not CHALLENGE") }) }) @@ -2217,7 +2220,7 @@ describe("RandomBeacon - Group Creation", () => { const invalidMisbehavedIndices = [3, 8, 15, 41] const invalidMembersHash = hashDKGMembers( membersIds, - invalidMisbehavedIndices + invalidMisbehavedIndices, ) ;({ dkgResult, dkgResultHash } = @@ -2228,7 +2231,7 @@ describe("RandomBeacon - Group Creation", () => { startBlock, actualMisbehavedIndices, undefined, - invalidMembersHash + invalidMembersHash, )) const tx = await randomBeacon @@ -2240,7 +2243,7 @@ describe("RandomBeacon - Group Creation", () => { .withArgs( dkgResultHash, await thirdParty.getAddress(), - "Invalid members hash" + "Invalid members hash", ) }) }) @@ -2250,7 +2253,7 @@ describe("RandomBeacon - Group Creation", () => { const invalidMisbehavedIndices = [3] const invalidMembersHash = hashDKGMembers( membersIds, - invalidMisbehavedIndices + invalidMisbehavedIndices, ) ;({ dkgResult, dkgResultHash } = @@ -2261,7 +2264,7 @@ describe("RandomBeacon - Group Creation", () => { startBlock, noMisbehaved, undefined, - invalidMembersHash + invalidMembersHash, )) const tx = await randomBeacon @@ -2273,7 +2276,7 @@ describe("RandomBeacon - Group Creation", () => { .withArgs( dkgResultHash, await thirdParty.getAddress(), - "Invalid members hash" + "Invalid members hash", ) }) }) @@ -2288,7 +2291,7 @@ describe("RandomBeacon - Group Creation", () => { before(async () => { await createSnapshot() - let tx: ContractTransaction + let tx: ContractTransactionResponse ;({ transaction: tx, dkgResult, @@ -2300,10 +2303,10 @@ describe("RandomBeacon - Group Creation", () => { // Mix signers to make the result malicious. mixSigners(await selectGroup(sortitionPool, genesisSeed)), startBlock, - noMisbehaved + noMisbehaved, )) - resultSubmissionBlock = tx.blockNumber + resultSubmissionBlock = requireResult(await tx.wait()).blockNumber }) after(async () => { @@ -2312,8 +2315,8 @@ describe("RandomBeacon - Group Creation", () => { context("at the beginning of challenge period", async () => { context("called by a third party", async () => { - let challengeTx: ContractTransaction - let slashingTx: ContractTransaction + let challengeTx: ContractTransactionResponse + let slashingTx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2335,7 +2338,7 @@ describe("RandomBeacon - Group Creation", () => { .withArgs( dkgResultHash, await thirdParty.getAddress(), - "Invalid group members" + "Invalid group members", ) }) @@ -2349,14 +2352,14 @@ describe("RandomBeacon - Group Creation", () => { .withArgs( dkgResultHash, params.maliciousDkgResultSlashingAmount, - submitter.address + submitter.address, ) }) it("should not emit DkgMaliciousResultSlashingFailed event", async () => { await expect(challengeTx).to.not.emit( randomBeacon, - "DkgMaliciousResultSlashingFailed" + "DkgMaliciousResultSlashingFailed", ) }) @@ -2365,18 +2368,18 @@ describe("RandomBeacon - Group Creation", () => { .to.emit(staking, "NotifierRewarded") .withArgs( thirdParty.address, - constants.tokenStakingNotificationReward - .mul( - params.dkgMaliciousResultNotificationRewardMultiplier - ) - .div(100) + (constants.tokenStakingNotificationReward * + BigInt( + params.dkgMaliciousResultNotificationRewardMultiplier, + )) / + 100n, ) }) it("should slash malicious result submitter", async () => { const stakingProvider = await randomBeacon.operatorToStakingProvider( - submitter.address + submitter.address, ) await expect(slashingTx) @@ -2384,7 +2387,7 @@ describe("RandomBeacon - Group Creation", () => { .withArgs( stakingProvider, params.maliciousDkgResultSlashingAmount, - false + false, ) }) }) @@ -2397,7 +2400,7 @@ describe("RandomBeacon - Group Creation", () => { await mineBlocksTo( resultSubmissionBlock + params.dkgResultChallengePeriodLength - - 1 + 1, ) }) @@ -2406,8 +2409,8 @@ describe("RandomBeacon - Group Creation", () => { }) context("called by a third party", async () => { - let challengeTx: ContractTransaction - let slashingTx: ContractTransaction + let challengeTx: ContractTransactionResponse + let slashingTx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2429,7 +2432,7 @@ describe("RandomBeacon - Group Creation", () => { .withArgs( dkgResultHash, await thirdParty.getAddress(), - "Invalid group members" + "Invalid group members", ) }) @@ -2443,14 +2446,14 @@ describe("RandomBeacon - Group Creation", () => { .withArgs( dkgResultHash, params.maliciousDkgResultSlashingAmount, - submitter.address + submitter.address, ) }) it("should not emit DkgMaliciousResultSlashingFailed event", async () => { await expect(challengeTx).to.not.emit( randomBeacon, - "DkgMaliciousResultSlashingFailed" + "DkgMaliciousResultSlashingFailed", ) }) @@ -2459,18 +2462,18 @@ describe("RandomBeacon - Group Creation", () => { .to.emit(staking, "NotifierRewarded") .withArgs( thirdParty.address, - constants.tokenStakingNotificationReward - .mul( - params.dkgMaliciousResultNotificationRewardMultiplier - ) - .div(100) + (constants.tokenStakingNotificationReward * + BigInt( + params.dkgMaliciousResultNotificationRewardMultiplier, + )) / + 100n, ) }) it("should slash malicious result submitter", async () => { const stakingProvider = await randomBeacon.operatorToStakingProvider( - submitter.address + submitter.address, ) await expect(slashingTx) @@ -2478,7 +2481,7 @@ describe("RandomBeacon - Group Creation", () => { .withArgs( stakingProvider, params.maliciousDkgResultSlashingAmount, - false + false, ) }) }) @@ -2489,7 +2492,7 @@ describe("RandomBeacon - Group Creation", () => { await createSnapshot() await mineBlocksTo( - resultSubmissionBlock + params.dkgResultChallengePeriodLength + resultSubmissionBlock + params.dkgResultChallengePeriodLength, ) }) @@ -2499,14 +2502,14 @@ describe("RandomBeacon - Group Creation", () => { it("should revert with 'Challenge period has already passed' error", async () => { await expect( - randomBeacon.challengeDkgResult(dkgResult) + randomBeacon.challengeDkgResult(dkgResult), ).to.be.revertedWith("Challenge period has already passed") }) }) context("with token staking seize call failure", async () => { let tokenStakingFake: Mock - let tx: Promise + let tx: Promise before(async () => { await createSnapshot() @@ -2533,7 +2536,7 @@ describe("RandomBeacon - Group Creation", () => { .withArgs( dkgResultHash, params.maliciousDkgResultSlashingAmount, - submitter.address + submitter.address, ) }) }) @@ -2544,17 +2547,17 @@ describe("RandomBeacon - Group Creation", () => { it("should revert with 'Result under challenge is different than the submitted one'", async () => { const modifiedDkgResult: DKG.ResultStruct = { ...dkgResult } const modifiedMembersHash = hashUint32Array( - modifiedDkgResult.members.splice(42, 1) + modifiedDkgResult.members.splice(42, 1), ) modifiedDkgResult.membersHash = modifiedMembersHash await expect( - randomBeacon.challengeDkgResult(modifiedDkgResult) + randomBeacon.challengeDkgResult(modifiedDkgResult), ).to.be.revertedWith( - "Result under challenge is different than the submitted one" + "Result under challenge is different than the submitted one", ) }) - } + }, ) }) @@ -2564,8 +2567,8 @@ describe("RandomBeacon - Group Creation", () => { let dkgResultHash: string let dkgResult: DKG.ResultStruct let submitter: SignerWithAddress - let challengeTx: ContractTransaction - let slashingTx: ContractTransaction + let challengeTx: ContractTransactionResponse + let slashingTx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2575,7 +2578,7 @@ describe("RandomBeacon - Group Creation", () => { groupPublicKey, await selectGroup(sortitionPool, genesisSeed), startBlock, - noMisbehaved + noMisbehaved, )) challengeTx = await randomBeacon @@ -2595,7 +2598,7 @@ describe("RandomBeacon - Group Creation", () => { .withArgs( dkgResultHash, await thirdParty.getAddress(), - "validation reverted" + "validation reverted", ) }) @@ -2609,14 +2612,14 @@ describe("RandomBeacon - Group Creation", () => { .withArgs( dkgResultHash, params.maliciousDkgResultSlashingAmount, - submitter.address + submitter.address, ) }) it("should not emit DkgMaliciousResultSlashingFailed event", async () => { await expect(challengeTx).to.not.emit( randomBeacon, - "DkgMaliciousResultSlashingFailed" + "DkgMaliciousResultSlashingFailed", ) }) @@ -2625,9 +2628,11 @@ describe("RandomBeacon - Group Creation", () => { .to.emit(staking, "NotifierRewarded") .withArgs( thirdParty.address, - constants.tokenStakingNotificationReward - .mul(params.dkgMaliciousResultNotificationRewardMultiplier) - .div(100) + (constants.tokenStakingNotificationReward * + BigInt( + params.dkgMaliciousResultNotificationRewardMultiplier, + )) / + 100n, ) }) @@ -2640,10 +2645,10 @@ describe("RandomBeacon - Group Creation", () => { .withArgs( stakingProvider, params.maliciousDkgResultSlashingAmount, - false + false, ) }) - } + }, ) context("with correct dkg result submitted", async () => { @@ -2656,7 +2661,7 @@ describe("RandomBeacon - Group Creation", () => { groupPublicKey, genesisSeed, startBlock, - noMisbehaved + noMisbehaved, )) }) @@ -2666,7 +2671,7 @@ describe("RandomBeacon - Group Creation", () => { it("should revert with 'unjustified challenge' error", async () => { await expect( - randomBeacon.challengeDkgResult(dkgResult) + randomBeacon.challengeDkgResult(dkgResult), ).to.be.revertedWith("unjustified challenge") }) }) @@ -2682,7 +2687,7 @@ describe("RandomBeacon - Group Creation", () => { let dkgResult: DKG.ResultStruct const [genesisTx] = await genesis(randomBeacon) - const startBlock = genesisTx.blockNumber + const startBlock = requireResult(await genesisTx.wait()).blockNumber await mineBlocks(constants.offchainDkgTime) @@ -2692,14 +2697,12 @@ describe("RandomBeacon - Group Creation", () => { groupPublicKey, signers, startBlock, - noMisbehaved + noMisbehaved, )) await expect( - ( - await randomBeacon.getDkgData() - ).resultSubmissionStartBlockOffset, - "invalid resultSubmissionStartBlockOffset for result 1 after submission" + (await randomBeacon.getDkgData()).resultSubmissionStartBlockOffset, + "invalid resultSubmissionStartBlockOffset for result 1 after submission", ).to.equal(0) // Challenge result 1 at the beginning of the challenge period @@ -2709,10 +2712,8 @@ describe("RandomBeacon - Group Creation", () => { let expectedSubmissionOffset = 2 await expect( - ( - await randomBeacon.getDkgData() - ).resultSubmissionStartBlockOffset, - "invalid resultSubmissionStartBlockOffset for result 1 after challenge" + (await randomBeacon.getDkgData()).resultSubmissionStartBlockOffset, + "invalid resultSubmissionStartBlockOffset for result 1 after challenge", ).to.equal(expectedSubmissionOffset) // Submit result 2 in the middle of the submission period @@ -2723,14 +2724,12 @@ describe("RandomBeacon - Group Creation", () => { groupPublicKey, signers, startBlock, - noMisbehaved + noMisbehaved, )) await expect( - ( - await randomBeacon.getDkgData() - ).resultSubmissionStartBlockOffset, - "invalid resultSubmissionStartBlockOffset for result 2 after submission" + (await randomBeacon.getDkgData()).resultSubmissionStartBlockOffset, + "invalid resultSubmissionStartBlockOffset for result 2 after submission", ).to.equal(expectedSubmissionOffset) // same as before expectedSubmissionOffset += blocksToMine @@ -2742,10 +2741,8 @@ describe("RandomBeacon - Group Creation", () => { expectedSubmissionOffset += 2 // 1 block for dkg result submission tx + 1 block for challenge tx await expect( - ( - await randomBeacon.getDkgData() - ).resultSubmissionStartBlockOffset, - "invalid resultSubmissionStartBlockOffset for result 2 after challenge" + (await randomBeacon.getDkgData()).resultSubmissionStartBlockOffset, + "invalid resultSubmissionStartBlockOffset for result 2 after challenge", ).to.equal(expectedSubmissionOffset) // Submit result 3 at the end of the submission period @@ -2756,14 +2753,12 @@ describe("RandomBeacon - Group Creation", () => { groupPublicKey, signers, startBlock, - noMisbehaved + noMisbehaved, )) await expect( - ( - await randomBeacon.getDkgData() - ).resultSubmissionStartBlockOffset, - "invalid resultSubmissionStartBlockOffset for result 3 after submission" + (await randomBeacon.getDkgData()).resultSubmissionStartBlockOffset, + "invalid resultSubmissionStartBlockOffset for result 3 after submission", ).to.equal(expectedSubmissionOffset) // same as before expectedSubmissionOffset += blocksToMine @@ -2774,17 +2769,15 @@ describe("RandomBeacon - Group Creation", () => { expectedSubmissionOffset += blocksToMine await expect( - randomBeacon.callStatic.notifyDkgTimeout() + randomBeacon.notifyDkgTimeout.staticCall(), ).to.be.revertedWith("DKG has not timed out") await randomBeacon.challengeDkgResult(dkgResult) expectedSubmissionOffset += 2 // 1 block for dkg result submission tx + 1 block for challenge tx await expect( - ( - await randomBeacon.getDkgData() - ).resultSubmissionStartBlockOffset, - "invalid resultSubmissionStartBlockOffset for result 3 after challenge" + (await randomBeacon.getDkgData()).resultSubmissionStartBlockOffset, + "invalid resultSubmissionStartBlockOffset for result 3 after challenge", ).to.equal(expectedSubmissionOffset) // Submit result 4 after the submission period @@ -2796,8 +2789,8 @@ describe("RandomBeacon - Group Creation", () => { groupPublicKey, signers, startBlock, - noMisbehaved - ) + noMisbehaved, + ), ).to.be.revertedWith("DKG timeout already passed") await randomBeacon.notifyDkgTimeout() @@ -2818,13 +2811,13 @@ describe("RandomBeacon - Group Creation", () => { it("should revert", async () => { await expect(randomBeacon.selectGroup()).to.be.revertedWith( - "Sortition pool unlocked" + "Sortition pool unlocked", ) }) }) context("when dkg was triggered", async () => { - let genesisSeed: BigNumber + let genesisSeed: bigint before(async () => { await createSnapshot() @@ -2845,7 +2838,7 @@ describe("RandomBeacon - Group Creation", () => { it("should be the same group as if called the sortition pool directly", async () => { const exectedGroup = await sortitionPool.selectGroup( constants.groupSize, - ethers.utils.hexZeroPad(genesisSeed.toHexString(), 32) + ethers.zeroPadValue(toBeHex(genesisSeed), 32), ) const actualGroup = await randomBeacon.selectGroup() expect(exectedGroup).to.be.deep.equal(actualGroup) @@ -2861,32 +2854,32 @@ async function assertDkgResultCleanData(randomBeacon: { expect( dkgData.parameters.resultChallengePeriodLength, - "unexpected resultChallengePeriodLength" + "unexpected resultChallengePeriodLength", ).to.eq(params.dkgResultChallengePeriodLength) expect( dkgData.parameters.resultSubmissionTimeout, - "unexpected resultSubmissionTimeout" + "unexpected resultSubmissionTimeout", ).to.eq(params.dkgResultSubmissionTimeout) expect( dkgData.parameters.submitterPrecedencePeriodLength, - "unexpected submitterPrecedencePeriodLength" + "unexpected submitterPrecedencePeriodLength", ).to.eq(params.dkgSubmitterPrecedencePeriodLength) expect(dkgData.startBlock, "unexpected startBlock").to.eq(0) expect( dkgData.resultSubmissionStartBlockOffset, - "unexpected resultSubmissionStartBlockOffset" + "unexpected resultSubmissionStartBlockOffset", ).to.eq(0) expect(dkgData.submittedResultHash, "unexpected submittedResultHash").to.eq( - ethers.constants.HashZero + ethers.ZeroHash, ) expect(dkgData.submittedResultBlock, "unexpected submittedResultBlock").to.eq( - 0 + 0, ) } diff --git a/solidity/random-beacon/test/RandomBeacon.Parameters.test.ts b/solidity/random-beacon/test/RandomBeacon.Parameters.test.ts index ae813a6cb3..634281f55f 100644 --- a/solidity/random-beacon/test/RandomBeacon.Parameters.test.ts +++ b/solidity/random-beacon/test/RandomBeacon.Parameters.test.ts @@ -1,12 +1,13 @@ /* eslint-disable @typescript-eslint/no-unused-expressions */ -import { ethers, waffle, helpers } from "hardhat" +import { ethers, helpers } from "hardhat" +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" import { expect } from "chai" import { randomBeaconDeployment, params } from "./fixtures" -import type { ContractTransaction, Signer } from "ethers" +import type { ContractTransactionResponse, Signer } from "ethers" import type { RandomBeaconStub, RandomBeaconGovernance } from "../typechain" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" const { createSnapshot, restoreSnapshot } = helpers.snapshot @@ -18,13 +19,12 @@ describe("RandomBeacon - Parameters", () => { let randomBeaconGovernance: RandomBeaconGovernance before("load test fixture", async () => { - // eslint-disable-next-line @typescript-eslint/no-extra-semi ;[impersonatedGovernance, thirdParty, thirdPartyContract] = await ethers.getSigners() const { governance } = await helpers.signers.getNamedSigners() - const contracts = await waffle.loadFixture(randomBeaconDeployment) + const contracts = await loadFixture(randomBeaconDeployment) randomBeacon = contracts.randomBeacon as RandomBeaconStub randomBeaconGovernance = contracts.randomBeaconGovernance as RandomBeaconGovernance @@ -55,14 +55,14 @@ describe("RandomBeacon - Parameters", () => { .updateRelayEntryParameters( newRelayEntrySoftTimeout, newRelayEntryHardTimeout, - newCallbackGasLimit - ) + newCallbackGasLimit, + ), ).to.be.revertedWith("Caller is not the governance") }) }) context("when the caller is the governance", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -72,7 +72,7 @@ describe("RandomBeacon - Parameters", () => { .updateRelayEntryParameters( newRelayEntrySoftTimeout, newRelayEntryHardTimeout, - newCallbackGasLimit + newCallbackGasLimit, ) }) @@ -103,7 +103,7 @@ describe("RandomBeacon - Parameters", () => { .withArgs( newRelayEntrySoftTimeout, newRelayEntryHardTimeout, - newCallbackGasLimit + newCallbackGasLimit, ) }) }) @@ -122,14 +122,14 @@ describe("RandomBeacon - Parameters", () => { .updateAuthorizationParameters( newMinimumAuthorization, newAuthorizationDecreaseDelay, - newAuthorizationDecreaseChangePeriod - ) + newAuthorizationDecreaseChangePeriod, + ), ).to.be.revertedWith("Caller is not the governance") }) }) context("when the caller is the governance", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -139,7 +139,7 @@ describe("RandomBeacon - Parameters", () => { .updateAuthorizationParameters( newMinimumAuthorization, newAuthorizationDecreaseDelay, - newAuthorizationDecreaseChangePeriod + newAuthorizationDecreaseChangePeriod, ) }) @@ -149,23 +149,7 @@ describe("RandomBeacon - Parameters", () => { it("should update the group creation frequency", async () => { expect(await randomBeacon.minimumAuthorization()).to.be.equal( - newMinimumAuthorization - ) - }) - - it("should update the authorization decrease delay", async () => { - const { authorizationDecreaseDelay } = - await randomBeacon.authorizationParameters() - expect(authorizationDecreaseDelay).to.be.equal( - authorizationDecreaseDelay - ) - }) - - it("should update the authorization decrease change period", async () => { - const { authorizationDecreaseChangePeriod } = - await randomBeacon.authorizationParameters() - expect(authorizationDecreaseChangePeriod).to.be.equal( - authorizationDecreaseChangePeriod + newMinimumAuthorization, ) }) @@ -175,7 +159,7 @@ describe("RandomBeacon - Parameters", () => { .withArgs( newMinimumAuthorization, newAuthorizationDecreaseDelay, - newAuthorizationDecreaseChangePeriod + newAuthorizationDecreaseChangePeriod, ) }) }) @@ -200,14 +184,14 @@ describe("RandomBeacon - Parameters", () => { newDkgResultChallengePeriodLength, newDkgResultChallengeExtraGas, newDkgResultSubmissionTimeout, - newDkgSubmitterPrecedencePeriodLength - ) + newDkgSubmitterPrecedencePeriodLength, + ), ).to.be.revertedWith("Caller is not the governance") }) }) context("when the caller is the governance", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -220,7 +204,7 @@ describe("RandomBeacon - Parameters", () => { newDkgResultChallengePeriodLength, newDkgResultChallengeExtraGas, newDkgResultSubmissionTimeout, - newDkgSubmitterPrecedencePeriodLength + newDkgSubmitterPrecedencePeriodLength, ) }) @@ -228,12 +212,6 @@ describe("RandomBeacon - Parameters", () => { await restoreSnapshot() }) - it("should update the group creation frequency", async () => { - const { groupCreationFrequency } = - await randomBeacon.groupCreationParameters() - expect(groupCreationFrequency).to.be.equal(groupCreationFrequency) - }) - it("should update the group lifetime", async () => { const { groupLifetime } = await randomBeacon.groupCreationParameters() expect(groupLifetime).to.be.equal(newGroupLifetime) @@ -243,7 +221,7 @@ describe("RandomBeacon - Parameters", () => { const { dkgResultChallengePeriodLength } = await randomBeacon.groupCreationParameters() expect(dkgResultChallengePeriodLength).to.be.equal( - newDkgResultChallengePeriodLength + newDkgResultChallengePeriodLength, ) }) @@ -251,7 +229,7 @@ describe("RandomBeacon - Parameters", () => { const { dkgResultChallengeExtraGas } = await randomBeacon.groupCreationParameters() expect(dkgResultChallengeExtraGas).to.be.equal( - newDkgResultChallengeExtraGas + newDkgResultChallengeExtraGas, ) }) @@ -259,7 +237,7 @@ describe("RandomBeacon - Parameters", () => { const { dkgResultSubmissionTimeout } = await randomBeacon.groupCreationParameters() expect(dkgResultSubmissionTimeout).to.be.equal( - newDkgResultSubmissionTimeout + newDkgResultSubmissionTimeout, ) }) @@ -267,7 +245,7 @@ describe("RandomBeacon - Parameters", () => { const { dkgSubmitterPrecedencePeriodLength } = await randomBeacon.groupCreationParameters() expect(dkgSubmitterPrecedencePeriodLength).to.be.equal( - newDkgSubmitterPrecedencePeriodLength + newDkgSubmitterPrecedencePeriodLength, ) }) @@ -280,7 +258,7 @@ describe("RandomBeacon - Parameters", () => { newDkgResultChallengePeriodLength, newDkgResultChallengeExtraGas, newDkgResultSubmissionTimeout, - newDkgSubmitterPrecedencePeriodLength + newDkgSubmitterPrecedencePeriodLength, ) }) @@ -301,13 +279,13 @@ describe("RandomBeacon - Parameters", () => { newDkgResultChallengePeriodLength, newDkgResultChallengeExtraGas, newDkgResultSubmissionTimeout, - invalidDkgSubmitterPrecedencePeriodLength - ) + invalidDkgSubmitterPrecedencePeriodLength, + ), ).to.be.revertedWith( - "Submitter precedence period length should be less than the result submission timeout" + "Submitter precedence period length should be less than the result submission timeout", ) }) - } + }, ) context( @@ -326,13 +304,13 @@ describe("RandomBeacon - Parameters", () => { newDkgResultChallengePeriodLength, newDkgResultChallengeExtraGas, newDkgResultSubmissionTimeout, - invalidDkgSubmitterPrecedencePeriodLength - ) + invalidDkgSubmitterPrecedencePeriodLength, + ), ).to.be.revertedWith( - "Submitter precedence period length should be less than the result submission timeout" + "Submitter precedence period length should be less than the result submission timeout", ) }) - } + }, ) }) }) @@ -353,14 +331,14 @@ describe("RandomBeacon - Parameters", () => { newSortitionPoolRewardsBanDuration, newRelayEntryTimeoutNotificationRewardMultiplier, newUnauthorizedSigningNotificationRewardMultiplier, - newDkgMaliciousResultNotificationRewardMultiplier - ) + newDkgMaliciousResultNotificationRewardMultiplier, + ), ).to.be.revertedWith("Caller is not the governance") }) }) context("when the caller is the governance", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -371,7 +349,7 @@ describe("RandomBeacon - Parameters", () => { newSortitionPoolRewardsBanDuration, newRelayEntryTimeoutNotificationRewardMultiplier, newUnauthorizedSigningNotificationRewardMultiplier, - newDkgMaliciousResultNotificationRewardMultiplier + newDkgMaliciousResultNotificationRewardMultiplier, ) }) @@ -383,7 +361,7 @@ describe("RandomBeacon - Parameters", () => { const { sortitionPoolRewardsBanDuration } = await randomBeacon.rewardParameters() expect(sortitionPoolRewardsBanDuration).to.be.equal( - newSortitionPoolRewardsBanDuration + newSortitionPoolRewardsBanDuration, ) }) @@ -391,7 +369,7 @@ describe("RandomBeacon - Parameters", () => { const { relayEntryTimeoutNotificationRewardMultiplier } = await randomBeacon.rewardParameters() expect(relayEntryTimeoutNotificationRewardMultiplier).to.be.equal( - newRelayEntryTimeoutNotificationRewardMultiplier + newRelayEntryTimeoutNotificationRewardMultiplier, ) }) @@ -399,7 +377,7 @@ describe("RandomBeacon - Parameters", () => { const { unauthorizedSigningNotificationRewardMultiplier } = await randomBeacon.rewardParameters() expect(unauthorizedSigningNotificationRewardMultiplier).to.be.equal( - newUnauthorizedSigningNotificationRewardMultiplier + newUnauthorizedSigningNotificationRewardMultiplier, ) }) @@ -407,7 +385,7 @@ describe("RandomBeacon - Parameters", () => { const { dkgMaliciousResultNotificationRewardMultiplier } = await randomBeacon.rewardParameters() expect(dkgMaliciousResultNotificationRewardMultiplier).to.be.equal( - newDkgMaliciousResultNotificationRewardMultiplier + newDkgMaliciousResultNotificationRewardMultiplier, ) }) @@ -418,7 +396,7 @@ describe("RandomBeacon - Parameters", () => { newSortitionPoolRewardsBanDuration, newRelayEntryTimeoutNotificationRewardMultiplier, newUnauthorizedSigningNotificationRewardMultiplier, - newDkgMaliciousResultNotificationRewardMultiplier + newDkgMaliciousResultNotificationRewardMultiplier, ) }) }) @@ -437,14 +415,14 @@ describe("RandomBeacon - Parameters", () => { .updateSlashingParameters( newRelayEntrySubmissionFailureSlashingAmount, newMaliciousDkgResultSlashingAmount, - newUnauthorizedSigningSlashingAmount - ) + newUnauthorizedSigningSlashingAmount, + ), ).to.be.revertedWith("Caller is not the governance") }) }) context("when the caller is the governance", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -454,7 +432,7 @@ describe("RandomBeacon - Parameters", () => { .updateSlashingParameters( newRelayEntrySubmissionFailureSlashingAmount, newMaliciousDkgResultSlashingAmount, - newUnauthorizedSigningSlashingAmount + newUnauthorizedSigningSlashingAmount, ) }) @@ -466,7 +444,7 @@ describe("RandomBeacon - Parameters", () => { const { relayEntrySubmissionFailureSlashingAmount } = await randomBeacon.slashingParameters() expect(relayEntrySubmissionFailureSlashingAmount).to.be.equal( - newRelayEntrySubmissionFailureSlashingAmount + newRelayEntrySubmissionFailureSlashingAmount, ) }) @@ -474,7 +452,7 @@ describe("RandomBeacon - Parameters", () => { const { maliciousDkgResultSlashingAmount } = await randomBeacon.slashingParameters() expect(maliciousDkgResultSlashingAmount).to.be.equal( - newMaliciousDkgResultSlashingAmount + newMaliciousDkgResultSlashingAmount, ) }) @@ -482,7 +460,7 @@ describe("RandomBeacon - Parameters", () => { const { unauthorizedSigningSlashingAmount } = await randomBeacon.slashingParameters() expect(unauthorizedSigningSlashingAmount).to.be.equal( - newUnauthorizedSigningSlashingAmount + newUnauthorizedSigningSlashingAmount, ) }) @@ -492,7 +470,7 @@ describe("RandomBeacon - Parameters", () => { .withArgs( newRelayEntrySubmissionFailureSlashingAmount, newMaliciousDkgResultSlashingAmount, - newUnauthorizedSigningSlashingAmount + newUnauthorizedSigningSlashingAmount, ) }) }) @@ -501,7 +479,7 @@ describe("RandomBeacon - Parameters", () => { describe("authorizedRequesters", () => { it("should be false by default", async () => { const isAuthorized = await randomBeacon.authorizedRequesters( - thirdPartyContract.address + thirdPartyContract.address, ) await expect(isAuthorized).to.be.false }) @@ -513,14 +491,14 @@ describe("RandomBeacon - Parameters", () => { await expect( randomBeacon .connect(thirdParty) - .setRequesterAuthorization(thirdPartyContract.address, true) + .setRequesterAuthorization(thirdPartyContract.address, true), ).to.be.revertedWith("Caller is not the governance") }) }) context("when the caller is the governance", () => { context("when authorizing a contract", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -536,7 +514,7 @@ describe("RandomBeacon - Parameters", () => { it("should set contract as authorized", async () => { const isAuthorized = await randomBeacon.authorizedRequesters( - thirdPartyContract.address + thirdPartyContract.address, ) expect(isAuthorized).to.be.true }) @@ -549,7 +527,7 @@ describe("RandomBeacon - Parameters", () => { }) context("when deauthorizing the contract", async () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -569,7 +547,7 @@ describe("RandomBeacon - Parameters", () => { it("should set contract as not authorized", async () => { const isAuthorized = await randomBeacon.authorizedRequesters( - thirdPartyContract.address + thirdPartyContract.address, ) expect(isAuthorized).to.be.false }) diff --git a/solidity/random-beacon/test/RandomBeacon.Relay.test.ts b/solidity/random-beacon/test/RandomBeacon.Relay.test.ts index 6ee2929264..0406e72437 100644 --- a/solidity/random-beacon/test/RandomBeacon.Relay.test.ts +++ b/solidity/random-beacon/test/RandomBeacon.Relay.test.ts @@ -1,8 +1,8 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions, no-await-in-loop, @typescript-eslint/no-extra-semi */ +/* eslint-disable @typescript-eslint/no-unused-expressions */ -import { ethers, waffle, helpers } from "hardhat" +import { ethers, helpers } from "hardhat" +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" import { expect } from "chai" -import { BigNumber } from "ethers" import blsData from "./data/bls" import { @@ -17,7 +17,7 @@ import { signOperatorInactivityClaim } from "./utils/inactivity" import { registerOperators } from "./utils/operators" import { fakeTokenStaking } from "./mocks/staking" -import type { Groups } from "../typechain/RandomBeacon" +import type { Groups } from "../typechain/contracts/RandomBeacon" import type { Operator, OperatorID } from "./utils/operators" import type { Mock } from "./helpers/mock" import type { @@ -31,19 +31,19 @@ import type { RandomBeaconGovernance, } from "../typechain" import type { Address } from "hardhat-deploy/types" -import type { ContractTransaction, BigNumberish } from "ethers" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import type { ContractTransactionResponse, BigNumberish } from "ethers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" const { mineBlocks, mineBlocksTo } = helpers.time const { to1e18 } = helpers.number -const ZERO_ADDRESS = ethers.constants.AddressZero +const ZERO_ADDRESS = ethers.ZeroAddress const { createSnapshot, restoreSnapshot } = helpers.snapshot -const { provider } = waffle +const { provider } = ethers // FIXME: As a workaround for a bug https://github.com/dethcrypto/TypeChain/issues/601 // we declare a new type instead of using `RandomBeaconStub & RandomBeacon` intersection. type RandomBeaconTest = RandomBeacon & { - dkgLockState: () => Promise + dkgLockState: () => Promise } async function fixture() { @@ -63,7 +63,7 @@ async function fixture() { deployment.randomBeacon as RandomBeacon, deployment.t as T, constants.groupSize, - 4 + 4, ) return { @@ -107,7 +107,7 @@ describe("RandomBeacon - Relay", () => { bls, operators: members, randomBeaconGovernance, - } = await waffle.loadFixture(fixture)) + } = await loadFixture(fixture)) membersIDs = members.map((member) => member.id) membersAddresses = members.map((member) => member.signer.address) @@ -121,7 +121,7 @@ describe("RandomBeacon - Relay", () => { context("when requester is not authorized", () => { it("should revert", async () => { await expect( - randomBeacon.connect(thirdParty).requestRelayEntry(ZERO_ADDRESS) + randomBeacon.connect(thirdParty).requestRelayEntry(ZERO_ADDRESS), ).to.be.revertedWith("Requester must be authorized") }) }) @@ -139,7 +139,7 @@ describe("RandomBeacon - Relay", () => { }) context("when there is no other relay entry in progress", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -172,11 +172,11 @@ describe("RandomBeacon - Relay", () => { it("should not lock DKG state", async () => { expect(await randomBeacon.getGroupCreationState()).to.be.equal( - dkgState.IDLE + dkgState.IDLE, ) expect(await sortitionPool.isLocked()).to.be.false }) - } + }, ) context( @@ -211,7 +211,7 @@ describe("RandomBeacon - Relay", () => { it("should lock DKG state", async () => { expect(await randomBeacon.getGroupCreationState()).to.be.equal( - dkgState.AWAITING_SEED + dkgState.AWAITING_SEED, ) expect(await sortitionPool.isLocked()).to.be.true }) @@ -219,7 +219,7 @@ describe("RandomBeacon - Relay", () => { it("should emit DkgStateLocked event", async () => { await expect(tx).to.emit(randomBeacon, "DkgStateLocked") }) - } + }, ) }) @@ -238,7 +238,7 @@ describe("RandomBeacon - Relay", () => { it("should revert", async () => { await expect( - randomBeacon.connect(requester).requestRelayEntry(ZERO_ADDRESS) + randomBeacon.connect(requester).requestRelayEntry(ZERO_ADDRESS), ).to.be.revertedWith("Another relay request in progress") }) }) @@ -247,7 +247,7 @@ describe("RandomBeacon - Relay", () => { context("when no groups exist", () => { it("should revert", async () => { await expect( - randomBeacon.connect(requester).requestRelayEntry(ZERO_ADDRESS) + randomBeacon.connect(requester).requestRelayEntry(ZERO_ADDRESS), ).to.be.revertedWith("No active groups") }) }) @@ -279,14 +279,14 @@ describe("RandomBeacon - Relay", () => { context("when relay entry has not timed out", () => { context("when entry is valid", () => { context("when result is submitted before the soft timeout", () => { - let tx: ContractTransaction - let initialSubmitterBalance: BigNumber + let tx: ContractTransactionResponse + let initialSubmitterBalance: bigint before(async () => { await createSnapshot() initialSubmitterBalance = await provider.getBalance( - submitter.address + submitter.address, ) tx = await randomBeacon @@ -319,12 +319,12 @@ describe("RandomBeacon - Relay", () => { it("should refund ETH", async () => { const postNotifierBalance = await provider.getBalance( - submitter.address + submitter.address, ) - const diff = postNotifierBalance.sub(initialSubmitterBalance) + const diff = postNotifierBalance - initialSubmitterBalance expect(diff).to.be.gt(0) expect(diff).to.be.lt( - ethers.utils.parseUnits("2000000", "gwei") // 0,002 ETH + ethers.parseUnits("2000000", "gwei"), // 0,002 ETH ) }) }) @@ -343,13 +343,13 @@ describe("RandomBeacon - Relay", () => { await expect( randomBeacon .connect(submitter) - ["submitRelayEntry(bytes)"](blsData.groupSignature) + ["submitRelayEntry(bytes)"](blsData.groupSignature), ).to.be.revertedWith("Relay entry soft timeout passed") }) }) context("when DKG is awaiting a seed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -379,7 +379,7 @@ describe("RandomBeacon - Relay", () => { await expect( randomBeacon .connect(submitter) - ["submitRelayEntry(bytes)"](blsData.nextGroupSignature) + ["submitRelayEntry(bytes)"](blsData.nextGroupSignature), ).to.be.revertedWith("Invalid entry") }) }) @@ -411,21 +411,21 @@ describe("RandomBeacon - Relay", () => { context("when the input params are valid", () => { context("when result is submitted before the soft timeout", () => { - let tx: ContractTransaction - let initialSubmitterBalance: BigNumber + let tx: ContractTransactionResponse + let initialSubmitterBalance: bigint before(async () => { await createSnapshot() initialSubmitterBalance = await provider.getBalance( - submitter.address + submitter.address, ) tx = await randomBeacon .connect(submitter) ["submitRelayEntry(bytes,uint32[])"]( blsData.groupSignature, - membersIDs + membersIDs, ) }) @@ -456,26 +456,26 @@ describe("RandomBeacon - Relay", () => { it("should refund ETH", async () => { const postNotifierBalance = await provider.getBalance( - submitter.address + submitter.address, ) - const diff = postNotifierBalance.sub(initialSubmitterBalance) + const diff = postNotifierBalance - initialSubmitterBalance expect(diff).to.be.gt(0) expect(diff).to.be.lt( - ethers.utils.parseUnits("1000000", "gwei") // 0,001 ETH + ethers.parseUnits("1000000", "gwei"), // 0,001 ETH ) }) }) context("when result is submitted after the soft timeout", () => { - let initialSubmitterBalance: BigNumber + let initialSubmitterBalance: bigint // `relayEntrySubmissionFailureSlashingAmount = 1000e18`. // 75% of the soft timeout period elapsed so we expect // `750e18` to be slashed. const slashingAmount = to1e18(750) - let submissionTx: ContractTransaction - let slashingTx: ContractTransaction + let submissionTx: ContractTransactionResponse + let slashingTx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -491,17 +491,17 @@ describe("RandomBeacon - Relay", () => { await mineBlocks( params.relayEntrySoftTimeout + 0.75 * params.relayEntryHardTimeout - - 1 + 1, ) initialSubmitterBalance = await provider.getBalance( - submitter.address + submitter.address, ) submissionTx = await randomBeacon .connect(submitter) ["submitRelayEntry(bytes,uint32[])"]( blsData.groupSignature, - membersIDs + membersIDs, ) slashingTx = await staking.processSlashing(membersAddresses.length) @@ -520,7 +520,7 @@ describe("RandomBeacon - Relay", () => { for (let i = 0; i < membersAddresses.length; i++) { const stakingProvider = await randomBeacon.operatorToStakingProvider( - membersAddresses[i] + membersAddresses[i], ) await expect(slashingTx) @@ -547,12 +547,12 @@ describe("RandomBeacon - Relay", () => { it("should refund ETH", async () => { const postNotifierBalance = await provider.getBalance( - submitter.address + submitter.address, ) - const diff = postNotifierBalance.sub(initialSubmitterBalance) + const diff = postNotifierBalance - initialSubmitterBalance expect(diff).to.be.gt(0) expect(diff).to.be.lt( - ethers.utils.parseUnits("1000000", "gwei") // 0,001 ETH + ethers.parseUnits("1000000", "gwei"), // 0,001 ETH ) }) }) @@ -575,8 +575,8 @@ describe("RandomBeacon - Relay", () => { .connect(submitter) ["submitRelayEntry(bytes,uint32[])"]( blsData.nextGroupSignature, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Invalid entry") }) }) @@ -589,8 +589,8 @@ describe("RandomBeacon - Relay", () => { .connect(submitter) ["submitRelayEntry(bytes,uint32[])"]( blsData.nextGroupSignature, - invalidMembersId - ) + invalidMembersId, + ), ).to.be.revertedWith("Invalid group members") }) }) @@ -599,7 +599,7 @@ describe("RandomBeacon - Relay", () => { context("when a relay entry has timed out", () => { it("should revert", async () => { await mineBlocks( - params.relayEntrySoftTimeout + params.relayEntryHardTimeout + params.relayEntrySoftTimeout + params.relayEntryHardTimeout, ) await expect( @@ -607,8 +607,8 @@ describe("RandomBeacon - Relay", () => { .connect(submitter) ["submitRelayEntry(bytes,uint32[])"]( blsData.nextGroupSignature, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Relay request timed out") }) }) @@ -632,7 +632,7 @@ describe("RandomBeacon - Relay", () => { await createSnapshot() await mineBlocks( - params.relayEntrySoftTimeout + params.relayEntryHardTimeout + params.relayEntrySoftTimeout + params.relayEntryHardTimeout, ) }) @@ -643,15 +643,15 @@ describe("RandomBeacon - Relay", () => { context( "when other active groups exist after timeout is reported", () => { - let reportTx: ContractTransaction - let slashingTx: ContractTransaction + let reportTx: ContractTransactionResponse + let slashingTx: ContractTransactionResponse before(async () => { await createSnapshot() await (randomBeacon as unknown as RandomBeaconStub).roughlyAddGroup( "0x01", - hashUint32Array(membersIDs) + hashUint32Array(membersIDs), ) reportTx = await randomBeacon @@ -670,10 +670,12 @@ describe("RandomBeacon - Relay", () => { .to.emit(staking, "NotifierRewarded") .withArgs( notifier.address, - constants.tokenStakingNotificationReward - .mul(params.relayEntryTimeoutNotificationRewardMultiplier) - .div(100) - .mul(membersIDs.length) + ((constants.tokenStakingNotificationReward * + BigInt( + params.relayEntryTimeoutNotificationRewardMultiplier, + )) / + 100n) * + BigInt(membersIDs.length), ) }) @@ -681,7 +683,7 @@ describe("RandomBeacon - Relay", () => { for (let i = 0; i < membersAddresses.length; i++) { const stakingProvider = await randomBeacon.operatorToStakingProvider( - membersAddresses[i] + membersAddresses[i], ) await expect(slashingTx) @@ -689,7 +691,7 @@ describe("RandomBeacon - Relay", () => { .withArgs( stakingProvider, params.relayEntrySubmissionFailureSlashingAmount, - false + false, ) } }) @@ -700,14 +702,14 @@ describe("RandomBeacon - Relay", () => { .withArgs( 1, params.relayEntrySubmissionFailureSlashingAmount, - membersAddresses + membersAddresses, ) }) it("should not emit RelayEntryTimeoutSlashingFailed event", async () => { await expect(reportTx).to.not.emit( randomBeacon, - "RelayEntryTimeoutSlashingFailed" + "RelayEntryTimeoutSlashingFailed", ) }) @@ -731,13 +733,13 @@ describe("RandomBeacon - Relay", () => { expect(await randomBeacon.isRelayRequestInProgress()).to.be.true }) - } + }, ) context( "when a group that was supposed to submit a relay request is terminated and another group expires", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -750,7 +752,7 @@ describe("RandomBeacon - Relay", () => { // made to ensure it is not selected for signing the original request. await (randomBeacon as unknown as RandomBeaconStub).roughlyAddGroup( "0x01", - hashUint32Array(membersIDs) + hashUint32Array(membersIDs), ) // Set a short value of group lifetime to avoid long test execution @@ -767,7 +769,7 @@ describe("RandomBeacon - Relay", () => { const secondGroupLifetime = await groupLifetimeOf(1) // Expire second group - await mineBlocksTo(secondGroupLifetime.toNumber() + 1) + await mineBlocksTo(Number(secondGroupLifetime) + 1) tx = await randomBeacon.reportRelayEntryTimeout(membersIDs) }) @@ -787,12 +789,12 @@ describe("RandomBeacon - Relay", () => { it("should clean up current relay request data", async () => { expect(await randomBeacon.isRelayRequestInProgress()).to.be.false }) - } + }, ) context("when no active groups exist after timeout is reported", () => { - let reportTx: ContractTransaction - let slashingTx: ContractTransaction + let reportTx: ContractTransactionResponse + let slashingTx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -813,10 +815,10 @@ describe("RandomBeacon - Relay", () => { .to.emit(staking, "NotifierRewarded") .withArgs( notifier.address, - constants.tokenStakingNotificationReward - .mul(params.relayEntryTimeoutNotificationRewardMultiplier) - .div(100) - .mul(membersIDs.length) + ((constants.tokenStakingNotificationReward * + BigInt(params.relayEntryTimeoutNotificationRewardMultiplier)) / + 100n) * + BigInt(membersIDs.length), ) }) @@ -830,7 +832,7 @@ describe("RandomBeacon - Relay", () => { .withArgs( stakingProvider, params.relayEntrySubmissionFailureSlashingAmount, - false + false, ) } }) @@ -841,14 +843,14 @@ describe("RandomBeacon - Relay", () => { .withArgs( 1, params.relayEntrySubmissionFailureSlashingAmount, - membersAddresses + membersAddresses, ) }) it("should not emit RelayEntryTimeoutSlashingFailed event", async () => { await expect(reportTx).to.not.emit( randomBeacon, - "RelayEntryTimeoutSlashingFailed" + "RelayEntryTimeoutSlashingFailed", ) }) @@ -865,7 +867,7 @@ describe("RandomBeacon - Relay", () => { it("should clean up current relay request data", async () => { await expect(reportTx).to.not.emit( randomBeacon, - "RelayEntryRequested" + "RelayEntryRequested", ) expect(await randomBeacon.isRelayRequestInProgress()).to.be.false }) @@ -874,7 +876,7 @@ describe("RandomBeacon - Relay", () => { context( "when no active groups exist after timeout is reported and DKG is awaiting seed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -893,7 +895,7 @@ describe("RandomBeacon - Relay", () => { it("should notify DKG seed timed out", async () => { expect(await randomBeacon.getGroupCreationState()).to.be.equal( - dkgState.IDLE + dkgState.IDLE, ) expect(await sortitionPool.isLocked()).to.be.false }) @@ -901,12 +903,12 @@ describe("RandomBeacon - Relay", () => { it("should emit DkgSeedTimedOut event", async () => { await expect(tx).to.emit(randomBeacon, "DkgSeedTimedOut") }) - } + }, ) context("when token staking seize call fails", async () => { let tokenStakingFake: Mock - let tx: Promise + let tx: Promise before(async () => { await createSnapshot() @@ -931,7 +933,7 @@ describe("RandomBeacon - Relay", () => { .withArgs( 1, params.relayEntrySubmissionFailureSlashingAmount, - membersAddresses + membersAddresses, ) }) }) @@ -940,7 +942,7 @@ describe("RandomBeacon - Relay", () => { context("when relay entry did not time out", () => { it("should revert", async () => { await expect( - randomBeacon.reportRelayEntryTimeout(membersIDs) + randomBeacon.reportRelayEntryTimeout(membersIDs), ).to.be.revertedWith("Relay request did not time out") }) }) @@ -949,7 +951,7 @@ describe("RandomBeacon - Relay", () => { it("should revert", async () => { const invalidMembersId = [0, 1, 42] await expect( - randomBeacon.reportRelayEntryTimeout(invalidMembersId) + randomBeacon.reportRelayEntryTimeout(invalidMembersId), ).to.be.revertedWith("Invalid group members") }) }) @@ -969,15 +971,15 @@ describe("RandomBeacon - Relay", () => { context("when a group is active", () => { context("when provided signature is valid", () => { - let reportTx: ContractTransaction - let slashingTx: ContractTransaction + let reportTx: ContractTransactionResponse + let slashingTx: ContractTransactionResponse before(async () => { await createSnapshot() const notifierSignature = await bls.sign( notifier.address, - blsData.secretKey + blsData.secretKey, ) reportTx = await randomBeacon .connect(notifier) @@ -999,10 +1001,12 @@ describe("RandomBeacon - Relay", () => { .to.emit(staking, "NotifierRewarded") .withArgs( notifier.address, - constants.tokenStakingNotificationReward - .mul(params.unauthorizedSigningNotificationRewardMultiplier) - .div(100) - .mul(membersIDs.length) + ((constants.tokenStakingNotificationReward * + BigInt( + params.unauthorizedSigningNotificationRewardMultiplier, + )) / + 100n) * + BigInt(membersIDs.length), ) }) @@ -1016,7 +1020,7 @@ describe("RandomBeacon - Relay", () => { .withArgs( stakingProvider, params.unauthorizedSigningSlashingAmount, - false + false, ) } }) @@ -1027,21 +1031,21 @@ describe("RandomBeacon - Relay", () => { .withArgs( 0, params.unauthorizedSigningSlashingAmount, - membersAddresses + membersAddresses, ) }) it("should not emit UnauthorizedSigningSlashingFailed", async () => { await expect(reportTx).to.not.emit( randomBeacon, - "UnauthorizedSigningSlashingFailed" + "UnauthorizedSigningSlashingFailed", ) }) }) context("when token staking seize call fails", async () => { let tokenStakingFake: Mock - let tx: Promise + let tx: Promise before(async () => { await createSnapshot() @@ -1051,7 +1055,7 @@ describe("RandomBeacon - Relay", () => { const notifierSignature = await bls.sign( notifier.address, - blsData.secretKey + blsData.secretKey, ) tx = randomBeacon .connect(notifier) @@ -1079,7 +1083,7 @@ describe("RandomBeacon - Relay", () => { await createSnapshot() await mineBlocks( - params.relayEntrySoftTimeout + params.relayEntryHardTimeout + params.relayEntrySoftTimeout + params.relayEntryHardTimeout, ) await ( @@ -1094,13 +1098,13 @@ describe("RandomBeacon - Relay", () => { it("should revert", async () => { const notifierSignature = await bls.sign( notifier.address, - blsData.secretKey + blsData.secretKey, ) await expect( randomBeacon .connect(notifier) - .reportUnauthorizedSigning(notifierSignature, 0, membersIDs) + .reportUnauthorizedSigning(notifierSignature, 0, membersIDs), ).to.be.revertedWith("Group cannot be terminated") }) }) @@ -1112,7 +1116,7 @@ describe("RandomBeacon - Relay", () => { await expect( randomBeacon .connect(notifier) - .reportUnauthorizedSigning(notifierSignature, 0, membersIDs) + .reportUnauthorizedSigning(notifierSignature, 0, membersIDs), ).to.be.revertedWith("Invalid signature") }) }) @@ -1124,7 +1128,7 @@ describe("RandomBeacon - Relay", () => { await expect( randomBeacon .connect(notifier) - .reportUnauthorizedSigning(notifierSignature, 0, invalidMembersId) + .reportUnauthorizedSigning(notifierSignature, 0, invalidMembersId), ).to.be.revertedWith("Invalid group members") }) }) @@ -1134,10 +1138,10 @@ describe("RandomBeacon - Relay", () => { before(async () => { await relayStub.setTimeouts( params.relayEntrySoftTimeout, - params.relayEntryHardTimeout + params.relayEntryHardTimeout, ) await relayStub.setRelayEntrySubmissionFailureSlashingAmount( - params.relayEntrySubmissionFailureSlashingAmount + params.relayEntrySubmissionFailureSlashingAmount, ) await relayStub.setCurrentRequestStartBlock() }) @@ -1157,8 +1161,8 @@ describe("RandomBeacon - Relay", () => { // We exceeded the soft timeout by `1` // slashing amount: 1 * 1000e18 / 100 = 10e18 expect( - await relayStub.callStatic.calculateSlashingAmount() - ).to.be.equal(BigNumber.from("10000000000000000000")) + await relayStub.calculateSlashingAmount.staticCall(), + ).to.be.equal(BigInt("10000000000000000000")) }) }) @@ -1167,16 +1171,16 @@ describe("RandomBeacon - Relay", () => { () => { it("should return a correct slashing amount", async () => { await mineBlocks( - params.relayEntrySoftTimeout + params.relayEntryHardTimeout + params.relayEntrySoftTimeout + params.relayEntryHardTimeout, ) // We exceeded the soft timeout by `100` // slashing amount: 100 * 1000e18 / 100 = 1000e18 expect( - await relayStub.callStatic.calculateSlashingAmount() - ).to.be.equal(BigNumber.from("1000000000000000000000")) + await relayStub.calculateSlashingAmount.staticCall(), + ).to.be.equal(BigInt("1000000000000000000000")) }) - } + }, ) context( @@ -1184,17 +1188,17 @@ describe("RandomBeacon - Relay", () => { () => { it("should return a correct slashing factor", async () => { await mineBlocks( - params.relayEntrySoftTimeout + params.relayEntryHardTimeout + 1 + params.relayEntrySoftTimeout + params.relayEntryHardTimeout + 1, ) // We are exceeded the soft timeout by a value bigger than the // hard timeout. In that case the maximum value (100%) of the slashing // amount should be returned. expect( - await relayStub.callStatic.calculateSlashingAmount() - ).to.be.equal(BigNumber.from("1000000000000000000000")) + await relayStub.calculateSlashingAmount.staticCall(), + ).to.be.equal(BigInt("1000000000000000000000")) }) - } + }, ) }) @@ -1208,7 +1212,7 @@ describe("RandomBeacon - Relay", () => { // during a single `notifyOperatorInactivity` call. const subsequentInactiveMembersIndices = Array.from( Array(31), - (_, i) => i + 1 + (_, i) => i + 1, ) const nonSubsequentInactiveMembersIndices = [2, 5, 7, 23, 56] const groupThreshold = 33 @@ -1238,12 +1242,12 @@ describe("RandomBeacon - Relay", () => { signaturesCount: number, modifySignatures: (signatures: string) => string, modifySigningMemberIndices: ( - signingMemberIndices: number[] - ) => number[] + signingMemberIndices: number[], + ) => number[], ) => { - let tx: ContractTransaction - let initialNonce: BigNumber - let initialNotifierBalance: BigNumber + let tx: ContractTransactionResponse + let initialNonce: bigint + let initialNotifierBalance: bigint let claimSender: SignerWithAddress before(async () => { @@ -1252,12 +1256,11 @@ describe("RandomBeacon - Relay", () => { // Assume claim sender is the first signing member. claimSender = members[0].signer - initialNonce = await randomBeacon.inactivityClaimNonce( - groupId - ) + initialNonce = + await randomBeacon.inactivityClaimNonce(groupId) initialNotifierBalance = await provider.getBalance( - claimSender.address + claimSender.address, ) const { signatures, signingMembersIndices } = @@ -1266,7 +1269,7 @@ describe("RandomBeacon - Relay", () => { 0, group.groupPubKey, inactiveMembersIndices, - signaturesCount + signaturesCount, ) tx = await randomBeacon @@ -1277,11 +1280,11 @@ describe("RandomBeacon - Relay", () => { inactiveMembersIndices, signatures: modifySignatures(signatures), signingMembersIndices: modifySigningMemberIndices( - signingMembersIndices + signingMembersIndices, ), }, 0, - membersIDs + membersIDs, ) }) @@ -1291,8 +1294,8 @@ describe("RandomBeacon - Relay", () => { it("should increment inactivity claim nonce for the group", async () => { expect( - await randomBeacon.inactivityClaimNonce(groupId) - ).to.be.equal(initialNonce.add(1)) + await randomBeacon.inactivityClaimNonce(groupId), + ).to.be.equal(initialNonce + 1n) }) it("should emit InactivityClaimed event", async () => { @@ -1300,8 +1303,8 @@ describe("RandomBeacon - Relay", () => { .to.emit(randomBeacon, "InactivityClaimed") .withArgs( groupId, - initialNonce.toNumber(), - claimSender.address + Number(initialNonce), + claimSender.address, ) }) @@ -1320,14 +1323,12 @@ describe("RandomBeacon - Relay", () => { it("should refund ETH", async () => { const postNotifierBalance = await provider.getBalance( - await claimSender.getAddress() - ) - const diff = postNotifierBalance.sub( - initialNotifierBalance + await claimSender.getAddress(), ) + const diff = postNotifierBalance - initialNotifierBalance expect(diff).to.be.gt(0) expect(diff).to.be.lt( - ethers.utils.parseUnits("1000000", "gwei") // 0,001 ETH + ethers.parseUnits("1000000", "gwei"), // 0,001 ETH ) }) } @@ -1339,9 +1340,9 @@ describe("RandomBeacon - Relay", () => { subsequentInactiveMembersIndices, groupThreshold, (signatures) => signatures, - (signingMembersIndices) => signingMembersIndices + (signingMembersIndices) => signingMembersIndices, ) - } + }, ) context( @@ -1351,9 +1352,9 @@ describe("RandomBeacon - Relay", () => { [32], groupThreshold, (signatures) => signatures, - (signingMembersIndices) => signingMembersIndices + (signingMembersIndices) => signingMembersIndices, ) - } + }, ) context( @@ -1363,9 +1364,9 @@ describe("RandomBeacon - Relay", () => { nonSubsequentInactiveMembersIndices, groupThreshold, (signatures) => signatures, - (signingMembersIndices) => signingMembersIndices + (signingMembersIndices) => signingMembersIndices, ) - } + }, ) context( @@ -1382,7 +1383,7 @@ describe("RandomBeacon - Relay", () => { // signature has 65 bytes so 130 characters const getSignature = ( signatures: string, - index: number + index: number, ) => signatures .slice(2) @@ -1400,7 +1401,7 @@ describe("RandomBeacon - Relay", () => { newSigningMembersIndices[i] newSignatures += getSignature( signatures, - newSigningMemberIndex - 1 + newSigningMemberIndex - 1, ) } @@ -1413,9 +1414,9 @@ describe("RandomBeacon - Relay", () => { // arbitrary signatures. 64, modifySignatures, - () => newSigningMembersIndices + () => newSigningMembersIndices, ) - } + }, ) }) @@ -1429,7 +1430,7 @@ describe("RandomBeacon - Relay", () => { 0, group.groupPubKey, subsequentInactiveMembersIndices, - groupThreshold + groupThreshold, ) const claimSender = thirdParty @@ -1446,17 +1447,17 @@ describe("RandomBeacon - Relay", () => { signingMembersIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Sender must be claim signer") }) - } + }, ) }) context("when one of the signatures is incorrect", () => { const assertInvalidSignature = async ( - invalidSignature: string + invalidSignature: string, ) => { // The 32 signers sign correct parameters. Invalid signature // is expected to be provided by signer 33. @@ -1466,7 +1467,7 @@ describe("RandomBeacon - Relay", () => { 0, group.groupPubKey, subsequentInactiveMembersIndices, - groupThreshold - 1 + groupThreshold - 1, ) await expect( @@ -1480,8 +1481,8 @@ describe("RandomBeacon - Relay", () => { signingMembersIndices: [...signingMembersIndices, 33], }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Invalid signature") } @@ -1496,13 +1497,13 @@ describe("RandomBeacon - Relay", () => { 1, group.groupPubKey, subsequentInactiveMembersIndices, - 1 + 1, ) ).signatures await assertInvalidSignature(invalidSignature) }) - } + }, ) context( @@ -1516,13 +1517,13 @@ describe("RandomBeacon - Relay", () => { 0, "0x010203", subsequentInactiveMembersIndices, - 1 + 1, ) ).signatures await assertInvalidSignature(invalidSignature) }) - } + }, ) context( @@ -1536,13 +1537,13 @@ describe("RandomBeacon - Relay", () => { 0, group.groupPubKey, [1, 2, 3, 4, 5, 6, 7, 8], - 1 + 1, ) ).signatures await assertInvalidSignature(invalidSignature) }) - } + }, ) }) }) @@ -1558,7 +1559,7 @@ describe("RandomBeacon - Relay", () => { 0, group.groupPubKey, subsequentInactiveMembersIndices, - groupThreshold + groupThreshold, ) await expect( @@ -1572,11 +1573,11 @@ describe("RandomBeacon - Relay", () => { signingMembersIndices: signingMembersIndices.slice(1), }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Unexpected signatures count") }) - } + }, ) context("when first signing member index is zero", () => { @@ -1587,7 +1588,7 @@ describe("RandomBeacon - Relay", () => { 0, group.groupPubKey, subsequentInactiveMembersIndices, - groupThreshold + groupThreshold, ) signingMembersIndices[0] = 0 @@ -1602,8 +1603,8 @@ describe("RandomBeacon - Relay", () => { signingMembersIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Corrupted members indices") }) }) @@ -1618,7 +1619,7 @@ describe("RandomBeacon - Relay", () => { 0, group.groupPubKey, subsequentInactiveMembersIndices, - groupThreshold + groupThreshold, ) signingMembersIndices[signingMembersIndices.length - 1] = 65 @@ -1633,11 +1634,11 @@ describe("RandomBeacon - Relay", () => { signingMembersIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Corrupted members indices") }) - } + }, ) context( @@ -1650,7 +1651,7 @@ describe("RandomBeacon - Relay", () => { 0, group.groupPubKey, subsequentInactiveMembersIndices, - groupThreshold + groupThreshold, ) // eslint-disable-next-line prefer-destructuring @@ -1666,11 +1667,11 @@ describe("RandomBeacon - Relay", () => { signingMembersIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Corrupted members indices") }) - } + }, ) }) }) @@ -1689,8 +1690,8 @@ describe("RandomBeacon - Relay", () => { signingMembersIndices: emptyMemberIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("No signatures provided") }) }) @@ -1711,11 +1712,11 @@ describe("RandomBeacon - Relay", () => { signingMembersIndices: emptyMemberIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Malformed signatures array") }) - } + }, ) context( @@ -1728,7 +1729,7 @@ describe("RandomBeacon - Relay", () => { 0, group.groupPubKey, subsequentInactiveMembersIndices, - groupThreshold + groupThreshold, ) await expect( @@ -1743,11 +1744,11 @@ describe("RandomBeacon - Relay", () => { signingMembersIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Unexpected signatures count") }) - } + }, ) context( @@ -1761,7 +1762,7 @@ describe("RandomBeacon - Relay", () => { group.groupPubKey, subsequentInactiveMembersIndices, // Provide one signature too few. - groupThreshold - 1 + groupThreshold - 1, ) await expect( @@ -1774,11 +1775,11 @@ describe("RandomBeacon - Relay", () => { signingMembersIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Too few signatures") }) - } + }, ) context("when signatures count is bigger than group size", () => { @@ -1790,7 +1791,7 @@ describe("RandomBeacon - Relay", () => { group.groupPubKey, subsequentInactiveMembersIndices, // All group signs. - members.length + members.length, ) await expect( @@ -1806,8 +1807,8 @@ describe("RandomBeacon - Relay", () => { ], }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Too many signatures") }) }) @@ -1816,7 +1817,7 @@ describe("RandomBeacon - Relay", () => { context("when inactive members indices are incorrect", () => { const assertInactiveMembersIndicesCorrupted = async ( - inactiveMembersIndices: number[] + inactiveMembersIndices: number[], ) => { const { signatures, signingMembersIndices } = await signOperatorInactivityClaim( @@ -1824,7 +1825,7 @@ describe("RandomBeacon - Relay", () => { 0, group.groupPubKey, inactiveMembersIndices, - groupThreshold + groupThreshold, ) await expect( @@ -1836,8 +1837,8 @@ describe("RandomBeacon - Relay", () => { signingMembersIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Corrupted members indices") } @@ -1846,7 +1847,7 @@ describe("RandomBeacon - Relay", () => { const inactiveMembersIndices: number[] = [] await assertInactiveMembersIndicesCorrupted( - inactiveMembersIndices + inactiveMembersIndices, ) }) }) @@ -1857,26 +1858,26 @@ describe("RandomBeacon - Relay", () => { it("should revert", async () => { const inactiveMembersIndices = Array.from( Array(65), - (_, i) => i + 1 + (_, i) => i + 1, ) await assertInactiveMembersIndicesCorrupted( - inactiveMembersIndices + inactiveMembersIndices, ) }) - } + }, ) context("when first inactive member index is zero", () => { it("should revert", async () => { const inactiveMembersIndices = Array.from( Array(64), - (_, i) => i + 1 + (_, i) => i + 1, ) inactiveMembersIndices[0] = 0 await assertInactiveMembersIndicesCorrupted( - inactiveMembersIndices + inactiveMembersIndices, ) }) }) @@ -1887,15 +1888,15 @@ describe("RandomBeacon - Relay", () => { it("should revert", async () => { const inactiveMembersIndices = Array.from( Array(64), - (_, i) => i + 1 + (_, i) => i + 1, ) inactiveMembersIndices[inactiveMembersIndices.length - 1] = 65 await assertInactiveMembersIndicesCorrupted( - inactiveMembersIndices + inactiveMembersIndices, ) }) - } + }, ) context( @@ -1904,16 +1905,16 @@ describe("RandomBeacon - Relay", () => { it("should revert", async () => { const inactiveMembersIndices = Array.from( Array(64), - (_, i) => i + 1 + (_, i) => i + 1, ) // eslint-disable-next-line prefer-destructuring inactiveMembersIndices[10] = inactiveMembersIndices[11] await assertInactiveMembersIndicesCorrupted( - inactiveMembersIndices + inactiveMembersIndices, ) }) - } + }, ) }) }) @@ -1942,8 +1943,8 @@ describe("RandomBeacon - Relay", () => { signingMembersIndices: emptyMemberIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Group is not active") }) }) @@ -1981,8 +1982,8 @@ describe("RandomBeacon - Relay", () => { signingMembersIndices: emptyMemberIndices, }, 0, - membersIDs - ) + membersIDs, + ), ).to.be.revertedWith("Group is not active") }) }) @@ -1999,8 +2000,8 @@ describe("RandomBeacon - Relay", () => { signingMembersIndices: emptyMemberIndices, }, 1, - membersIDs - ) // Initial nonce is `0`. + membersIDs, + ), // Initial nonce is `0`. ).to.be.revertedWith("Invalid nonce") }) }) @@ -2017,23 +2018,23 @@ describe("RandomBeacon - Relay", () => { signingMembersIndices: emptyMemberIndices, }, 0, - invalidMembersId - ) + invalidMembersId, + ), ).to.be.revertedWith("Invalid group members") }) }) }) - async function groupLifetimeOf(groupID: BigNumberish): Promise { - const groupData = await randomBeacon.callStatic["getGroup(uint64)"](groupID) + async function groupLifetimeOf(groupID: BigNumberish): Promise { + const groupData = await randomBeacon["getGroup(uint64)"].staticCall(groupID) const { groupLifetime } = await randomBeacon.groupCreationParameters() - return groupData.registrationBlockNumber.add(groupLifetime) + return groupData.registrationBlockNumber + groupLifetime } async function isGroupTerminated(groupID: BigNumberish): Promise { - const groupData = await randomBeacon.callStatic["getGroup(uint64)"](groupID) + const groupData = await randomBeacon["getGroup(uint64)"].staticCall(groupID) return groupData.terminated === true } diff --git a/solidity/random-beacon/test/RandomBeacon.Rewards.test.ts b/solidity/random-beacon/test/RandomBeacon.Rewards.test.ts index 8cd0e23e7d..a7003d5c3d 100644 --- a/solidity/random-beacon/test/RandomBeacon.Rewards.test.ts +++ b/solidity/random-beacon/test/RandomBeacon.Rewards.test.ts @@ -1,5 +1,5 @@ -/* eslint-disable @typescript-eslint/no-extra-semi */ -import { waffle, helpers } from "hardhat" +import { helpers } from "hardhat" +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" import { expect } from "chai" import { constants, randomBeaconDeployment } from "./fixtures" @@ -7,7 +7,7 @@ import { registerOperators } from "./utils/operators" import { createGroup } from "./utils/groups" import { signOperatorInactivityClaim } from "./utils/inactivity" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" import type { Operator } from "./utils/operators" import type { RandomBeacon, @@ -29,7 +29,7 @@ const fixture = async () => { contracts.randomBeacon as RandomBeacon, contracts.t as T, constants.groupSize, - 1 + 1, ) const randomBeacon = contracts.randomBeacon as RandomBeacon @@ -71,7 +71,7 @@ describe("RandomBeacon - Rewards", () => { sortitionPool, t, operators, - } = await waffle.loadFixture(fixture)) + } = await loadFixture(fixture)) ;[thirdParty] = await helpers.signers.getUnnamedSigners() ;({ deployer, governance } = await helpers.signers.getNamedSigners()) }) @@ -80,7 +80,7 @@ describe("RandomBeacon - Rewards", () => { context("when called for an unknown operator", () => { it("should revert", async () => { await expect( - randomBeacon.withdrawRewards(thirdParty.address) + randomBeacon.withdrawRewards(thirdParty.address), ).to.be.revertedWith("Unknown operator") }) }) @@ -95,14 +95,13 @@ describe("RandomBeacon - Rewards", () => { operator = operators[0].signer.address stakingProvider = await randomBeacon.operatorToStakingProvider(operator) - // eslint-disable-next-line @typescript-eslint/no-extra-semi ;({ beneficiary } = await staking.rolesOf(stakingProvider)) // Allocate sortition pool rewards await t.connect(deployer).mint(deployer.address, rewardAmount) await t .connect(deployer) - .approveAndCall(sortitionPool.address, rewardAmount, []) + .approveAndCall(await sortitionPool.getAddress(), rewardAmount, "0x") }) after(async () => { @@ -119,7 +118,7 @@ describe("RandomBeacon - Rewards", () => { const balanceBefore = await t.balanceOf(beneficiary) const tx = await randomBeacon.withdrawRewards(stakingProvider) const balanceAfter = await t.balanceOf(beneficiary) - const received = balanceAfter.sub(balanceBefore) + const received = balanceAfter - balanceBefore await expect(tx) .to.emit(randomBeacon, "RewardsWithdrawn") @@ -132,7 +131,7 @@ describe("RandomBeacon - Rewards", () => { context("when called for an unknown operator", () => { it("should revert", async () => { await expect( - randomBeacon.availableRewards(thirdParty.address) + randomBeacon.availableRewards(thirdParty.address), ).to.be.revertedWith("Unknown operator") }) }) @@ -147,14 +146,13 @@ describe("RandomBeacon - Rewards", () => { operator = operators[0].signer.address stakingProvider = await randomBeacon.operatorToStakingProvider(operator) - // eslint-disable-next-line @typescript-eslint/no-extra-semi ;({ beneficiary } = await staking.rolesOf(stakingProvider)) // Allocate sortition pool rewards await t.connect(deployer).mint(deployer.address, rewardAmount) await t .connect(deployer) - .approveAndCall(sortitionPool.address, rewardAmount, []) + .approveAndCall(await sortitionPool.getAddress(), rewardAmount, "0x") }) after(async () => { @@ -162,15 +160,14 @@ describe("RandomBeacon - Rewards", () => { }) it("should return the amount of available rewards", async () => { - let availableAmount = await randomBeacon.availableRewards( - stakingProvider - ) + let availableAmount = + await randomBeacon.availableRewards(stakingProvider) const balanceBefore = await t.balanceOf(beneficiary) await randomBeacon.withdrawRewards(stakingProvider) const balanceAfter = await t.balanceOf(beneficiary) - expect(availableAmount).to.equal(balanceAfter.sub(balanceBefore)) + expect(availableAmount).to.equal(balanceAfter - balanceBefore) availableAmount = await randomBeacon.availableRewards(stakingProvider) expect(availableAmount).to.equal(0) @@ -184,7 +181,7 @@ describe("RandomBeacon - Rewards", () => { await expect( randomBeacon .connect(thirdParty) - .withdrawIneligibleRewards(thirdParty.address) + .withdrawIneligibleRewards(thirdParty.address), ).to.be.revertedWith("Caller is not the governance") }) }) @@ -205,7 +202,7 @@ describe("RandomBeacon - Rewards", () => { 0, group.groupPubKey, inactiveMembersIndices, - 33 + 33, ) const claimSender = operators[0].signer @@ -217,14 +214,14 @@ describe("RandomBeacon - Rewards", () => { signingMembersIndices, }, 0, - operators.map((operator) => operator.id) + operators.map((operator) => operator.id), ) // Allocate sortition pool rewards await t.connect(deployer).mint(deployer.address, rewardAmount) await t .connect(deployer) - .approveAndCall(sortitionPool.address, rewardAmount, []) + .approveAndCall(await sortitionPool.getAddress(), rewardAmount, "0x") }) after(async () => { @@ -236,9 +233,8 @@ describe("RandomBeacon - Rewards", () => { // the balance of "ineligible rewards" available for withdrawal from // the Sortition Pool const operator = operators[0].signer.address - const stakingProvider = await randomBeacon.operatorToStakingProvider( - operator - ) + const stakingProvider = + await randomBeacon.operatorToStakingProvider(operator) await randomBeacon.withdrawRewards(stakingProvider) expect(await t.balanceOf(thirdParty.address)).to.equal(0) diff --git a/solidity/random-beacon/test/RandomBeaconChaosnet.test.ts b/solidity/random-beacon/test/RandomBeaconChaosnet.test.ts index f02443ea9a..5aac4f8ada 100644 --- a/solidity/random-beacon/test/RandomBeaconChaosnet.test.ts +++ b/solidity/random-beacon/test/RandomBeaconChaosnet.test.ts @@ -1,12 +1,9 @@ -/* eslint-disable @typescript-eslint/no-extra-semi */ - import { ethers, helpers } from "hardhat" import { expect } from "chai" -import { BigNumber } from "ethers" -import type { ContractTransaction } from "ethers" +import type { ContractTransactionResponse } from "ethers" import type { RandomBeaconChaosnet, CallbackContractStub } from "../typechain" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" const { createSnapshot, restoreSnapshot } = helpers.snapshot @@ -41,14 +38,14 @@ describe("RandomBeaconChaosnet", () => { await expect( randomBeaconChaosnet .connect(thirdParty) - .setRequesterAuthorization(requester.address, true) + .setRequesterAuthorization(requester.address, true), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when called by the owner", () => { context("when requester authorization set to true", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -64,7 +61,7 @@ describe("RandomBeaconChaosnet", () => { it("should mark the address as authorized", async () => { expect( - await randomBeaconChaosnet.authorizedRequesters(requester.address) + await randomBeaconChaosnet.authorizedRequesters(requester.address), ).to.equal(true) }) @@ -76,7 +73,7 @@ describe("RandomBeaconChaosnet", () => { }) context("when requester authorization set to false", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -97,7 +94,7 @@ describe("RandomBeaconChaosnet", () => { it("should mark the requester as deauthorized", async () => { expect( - await randomBeaconChaosnet.authorizedRequesters(requester.address) + await randomBeaconChaosnet.authorizedRequesters(requester.address), ).to.equal(false) }) @@ -116,7 +113,7 @@ describe("RandomBeaconChaosnet", () => { await expect( randomBeaconChaosnet .connect(thirdParty) - .requestRelayEntry(callbackContract.address) + .requestRelayEntry(await callbackContract.getAddress()), ).to.be.revertedWith("Requester must be authorized") }) }) @@ -132,7 +129,7 @@ describe("RandomBeaconChaosnet", () => { await randomBeaconChaosnet .connect(requester) - .requestRelayEntry(callbackContract.address) + .requestRelayEntry(await callbackContract.getAddress()) }) after(async () => { @@ -143,10 +140,10 @@ describe("RandomBeaconChaosnet", () => { expect(await callbackContract.lastEntry()).to.equal( // The entry is keccak-256 of the initial value stored in // the RandomBeaconChaosnet contract - BigNumber.from( + BigInt( "86322480231844907215266847458792959757192550318770676212332984" + - "332154459033029" - ) + "332154459033029", + ), ) }) }) @@ -163,11 +160,11 @@ describe("RandomBeaconChaosnet", () => { // by requesting a relay entry twice. await randomBeaconChaosnet .connect(requester) - .requestRelayEntry(callbackContract.address) + .requestRelayEntry(await callbackContract.getAddress()) await randomBeaconChaosnet .connect(requester) - .requestRelayEntry(callbackContract.address) + .requestRelayEntry(await callbackContract.getAddress()) }) after(async () => { @@ -178,10 +175,10 @@ describe("RandomBeaconChaosnet", () => { // The entry is keccak-256 calculated twice on the initial value // stored in the RandomBeaconChaosnet contract expect(await callbackContract.lastEntry()).to.equal( - BigNumber.from( + BigInt( "45055825411044151981109535788320043556123542984485670123474642" + - "322436340913380" - ) + "322436340913380", + ), ) }) }) diff --git a/solidity/random-beacon/test/RandomBeaconGovernance.test.ts b/solidity/random-beacon/test/RandomBeaconGovernance.test.ts index c91c444796..f485aa9a95 100644 --- a/solidity/random-beacon/test/RandomBeaconGovernance.test.ts +++ b/solidity/random-beacon/test/RandomBeaconGovernance.test.ts @@ -1,10 +1,12 @@ -import { ethers, waffle, helpers } from "hardhat" +import { ethers, helpers } from "hardhat" +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" import { expect } from "chai" +import requireResult from "./helpers/chain" import { randomBeaconDeployment, params } from "./fixtures" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" -import type { ContractTransaction, Signer } from "ethers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" +import type { ContractTransactionResponse, Signer } from "ethers" import type { RandomBeacon, RandomBeaconGovernance, @@ -15,7 +17,7 @@ const { createSnapshot, restoreSnapshot } = helpers.snapshot const governanceDelay = 604800 // 1 week -const ZERO_ADDRESS = ethers.constants.AddressZero +const ZERO_ADDRESS = ethers.ZeroAddress const fixture = async () => { const { governance } = await helpers.signers.getNamedSigners() @@ -40,7 +42,7 @@ describe("RandomBeaconGovernance", () => { before(async () => { [thirdParty, thirdPartyContract] = await helpers.signers.getUnnamedSigners() ;({ governance, randomBeaconGovernance, randomBeacon } = - await waffle.loadFixture(fixture)) + await loadFixture(fixture)) }) describe("constructor", () => { @@ -48,14 +50,14 @@ describe("RandomBeaconGovernance", () => { before(async () => { RandomBeaconGovernance = await ethers.getContractFactory( - "RandomBeaconGovernance" + "RandomBeaconGovernance", ) }) context("when random beacon is 0-address", () => { it("should revert", async () => { await expect( - RandomBeaconGovernance.deploy(ZERO_ADDRESS, 1) + RandomBeaconGovernance.deploy(ZERO_ADDRESS, 1), ).to.be.revertedWith("Zero-address reference") }) }) @@ -63,7 +65,7 @@ describe("RandomBeaconGovernance", () => { context("when governance delay is 0", () => { it("should revert", async () => { await expect( - RandomBeaconGovernance.deploy(randomBeacon.address, 0) + RandomBeaconGovernance.deploy(await randomBeacon.getAddress(), 0), ).to.be.revertedWith("No governance delay") }) }) @@ -75,13 +77,13 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginGovernanceDelayUpdate(1) + .beginGovernanceDelayUpdate(1), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -97,19 +99,22 @@ describe("RandomBeaconGovernance", () => { it("should not update the governance delay", async () => { expect(await randomBeaconGovernance.governanceDelay()).to.be.equal( - governanceDelay + governanceDelay, ) }) it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingGovernanceDelayUpdateTime() + await randomBeaconGovernance.getRemainingGovernanceDelayUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit GovernanceDelayUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit(randomBeaconGovernance, "GovernanceDelayUpdateStarted") .withArgs(1337, blockTimestamp) @@ -123,7 +128,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeGovernanceDelayUpdate() + .finalizeGovernanceDelayUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -133,7 +138,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeGovernanceDelayUpdate() + .finalizeGovernanceDelayUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -157,7 +162,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeGovernanceDelayUpdate() + .finalizeGovernanceDelayUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") }) }) @@ -165,7 +170,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -187,7 +192,7 @@ describe("RandomBeaconGovernance", () => { it("should update the governance delay", async () => { expect(await randomBeaconGovernance.governanceDelay()).to.be.equal( - 7331 + 7331, ) }) @@ -199,10 +204,10 @@ describe("RandomBeaconGovernance", () => { it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingGovernanceDelayUpdateTime() + randomBeaconGovernance.getRemainingGovernanceDelayUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -213,14 +218,14 @@ describe("RandomBeaconGovernance", () => { randomBeaconGovernance .connect(thirdParty) .beginRandomBeaconGovernanceTransfer( - "0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537" - ) + "0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537", + ), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -228,7 +233,7 @@ describe("RandomBeaconGovernance", () => { tx = await randomBeaconGovernance .connect(governance) .beginRandomBeaconGovernanceTransfer( - "0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537" + "0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537", ) }) @@ -241,36 +246,39 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .beginRandomBeaconGovernanceTransfer(ethers.constants.AddressZero) + .beginRandomBeaconGovernanceTransfer(ethers.ZeroAddress), ).to.be.revertedWith( - "New random beacon governance address cannot be zero" + "New random beacon governance address cannot be zero", ) }) }) it("should not transfer the governance", async () => { expect(await randomBeacon.governance()).to.be.equal( - randomBeaconGovernance.address + await randomBeaconGovernance.getAddress(), ) }) it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingRandomBeaconGovernanceTransferDelayTime() + await randomBeaconGovernance.getRemainingRandomBeaconGovernanceTransferDelayTime(), ).to.be.equal(governanceDelay) }) it("should emit RandomBeaconGovernanceTransferStarted", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( randomBeaconGovernance, - "RandomBeaconGovernanceTransferStarted" + "RandomBeaconGovernanceTransferStarted", ) .withArgs( "0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537", - blockTimestamp + blockTimestamp, ) }) }) @@ -282,7 +290,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeRandomBeaconGovernanceTransfer() + .finalizeRandomBeaconGovernanceTransfer(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -292,7 +300,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeRandomBeaconGovernanceTransfer() + .finalizeRandomBeaconGovernanceTransfer(), ).to.be.revertedWith("Change not initiated") }) }) @@ -304,7 +312,7 @@ describe("RandomBeaconGovernance", () => { await randomBeaconGovernance .connect(governance) .beginRandomBeaconGovernanceTransfer( - "0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537" + "0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537", ) await helpers.time.increaseTime(governanceDelay - 60) // -1min @@ -318,7 +326,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeRandomBeaconGovernanceTransfer() + .finalizeRandomBeaconGovernanceTransfer(), ).to.be.revertedWith("Governance delay has not elapsed") }) }) @@ -326,7 +334,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -334,7 +342,7 @@ describe("RandomBeaconGovernance", () => { await randomBeaconGovernance .connect(governance) .beginRandomBeaconGovernanceTransfer( - "0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537" + "0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537", ) await helpers.time.increaseTime(governanceDelay) @@ -350,7 +358,7 @@ describe("RandomBeaconGovernance", () => { it("should transfer random beacon governance", async () => { expect(await randomBeacon.governance()).to.be.equal( - "0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537" + "0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537", ) }) @@ -358,17 +366,17 @@ describe("RandomBeaconGovernance", () => { await expect(tx) .to.emit( randomBeaconGovernance, - "RandomBeaconGovernanceTransferred" + "RandomBeaconGovernanceTransferred", ) .withArgs("0x00Ea7D21bcCEeD400aCe08B583554aA619D3e537") }) it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingRandomBeaconGovernanceTransferDelayTime() + randomBeaconGovernance.getRemainingRandomBeaconGovernanceTransferDelayTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -378,7 +386,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginRelayEntrySoftTimeoutUpdate(1) + .beginRelayEntrySoftTimeoutUpdate(1), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -388,7 +396,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .beginRelayEntrySoftTimeoutUpdate(0) + .beginRelayEntrySoftTimeoutUpdate(0), ).to.be.revertedWith("Relay entry soft timeout must be > 0") }) }) @@ -411,7 +419,7 @@ describe("RandomBeaconGovernance", () => { }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -433,13 +441,16 @@ describe("RandomBeaconGovernance", () => { it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingRelayEntrySoftTimeoutUpdateTime() + await randomBeaconGovernance.getRemainingRelayEntrySoftTimeoutUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit the RelayEntrySoftTimeoutUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit(randomBeaconGovernance, "RelayEntrySoftTimeoutUpdateStarted") .withArgs(1, blockTimestamp) @@ -453,7 +464,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeRelayEntrySoftTimeoutUpdate() + .finalizeRelayEntrySoftTimeoutUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -463,7 +474,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeRelayEntrySoftTimeoutUpdate() + .finalizeRelayEntrySoftTimeoutUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -481,7 +492,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeRelayEntrySoftTimeoutUpdate() + .finalizeRelayEntrySoftTimeoutUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -491,7 +502,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -525,10 +536,10 @@ describe("RandomBeaconGovernance", () => { it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingRelayEntrySoftTimeoutUpdateTime() + randomBeaconGovernance.getRemainingRelayEntrySoftTimeoutUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -538,13 +549,13 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginRelayEntryHardTimeoutUpdate(123) + .beginRelayEntryHardTimeoutUpdate(123), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -566,13 +577,16 @@ describe("RandomBeaconGovernance", () => { it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingRelayEntryHardTimeoutUpdateTime() + await randomBeaconGovernance.getRemainingRelayEntryHardTimeoutUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit the RelayEntryHardTimeoutUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit(randomBeaconGovernance, "RelayEntryHardTimeoutUpdateStarted") .withArgs(123, blockTimestamp) @@ -586,7 +600,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeRelayEntryHardTimeoutUpdate() + .finalizeRelayEntryHardTimeoutUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -596,7 +610,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeRelayEntryHardTimeoutUpdate() + .finalizeRelayEntryHardTimeoutUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -614,7 +628,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeRelayEntryHardTimeoutUpdate() + .finalizeRelayEntryHardTimeoutUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -624,7 +638,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -658,10 +672,10 @@ describe("RandomBeaconGovernance", () => { it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingRelayEntryHardTimeoutUpdateTime() + randomBeaconGovernance.getRemainingRelayEntryHardTimeoutUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -671,7 +685,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginCallbackGasLimitUpdate(123) + .beginCallbackGasLimitUpdate(123), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -681,7 +695,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .beginCallbackGasLimitUpdate(0) + .beginCallbackGasLimitUpdate(0), ).to.be.revertedWith("Callback gas limit must be > 0 and <= 1000000") }) }) @@ -708,7 +722,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .beginCallbackGasLimitUpdate(1000001) + .beginCallbackGasLimitUpdate(1000001), ).to.be.revertedWith("Callback gas limit must be > 0 and <= 1000000") }) }) @@ -728,7 +742,7 @@ describe("RandomBeaconGovernance", () => { }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -749,13 +763,16 @@ describe("RandomBeaconGovernance", () => { it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingCallbackGasLimitUpdateTime() + await randomBeaconGovernance.getRemainingCallbackGasLimitUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit the CallbackGasLimitUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit(randomBeaconGovernance, "CallbackGasLimitUpdateStarted") .withArgs(123, blockTimestamp) @@ -769,7 +786,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeCallbackGasLimitUpdate() + .finalizeCallbackGasLimitUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -779,7 +796,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeCallbackGasLimitUpdate() + .finalizeCallbackGasLimitUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -797,7 +814,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeCallbackGasLimitUpdate() + .finalizeCallbackGasLimitUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -807,7 +824,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -840,10 +857,10 @@ describe("RandomBeaconGovernance", () => { it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingCallbackGasLimitUpdateTime() + randomBeaconGovernance.getRemainingCallbackGasLimitUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -853,7 +870,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginGroupCreationFrequencyUpdate(1) + .beginGroupCreationFrequencyUpdate(1), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -863,7 +880,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .beginGroupCreationFrequencyUpdate(0) + .beginGroupCreationFrequencyUpdate(0), ).to.be.revertedWith("Group creation frequency must be > 0") }) }) @@ -886,7 +903,7 @@ describe("RandomBeaconGovernance", () => { }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -904,23 +921,26 @@ describe("RandomBeaconGovernance", () => { const { groupCreationFrequency } = await randomBeacon.groupCreationParameters() expect(groupCreationFrequency).to.be.equal( - params.groupCreationFrequency + params.groupCreationFrequency, ) }) it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingGroupCreationFrequencyUpdateTime() + await randomBeaconGovernance.getRemainingGroupCreationFrequencyUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit the GroupCreationFrequencyUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( randomBeaconGovernance, - "GroupCreationFrequencyUpdateStarted" + "GroupCreationFrequencyUpdateStarted", ) .withArgs(1, blockTimestamp) }) @@ -933,7 +953,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeGroupCreationFrequencyUpdate() + .finalizeGroupCreationFrequencyUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -943,7 +963,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeGroupCreationFrequencyUpdate() + .finalizeGroupCreationFrequencyUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -961,7 +981,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeGroupCreationFrequencyUpdate() + .finalizeGroupCreationFrequencyUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -971,7 +991,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1005,10 +1025,10 @@ describe("RandomBeaconGovernance", () => { it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingGroupCreationFrequencyUpdateTime() + randomBeaconGovernance.getRemainingGroupCreationFrequencyUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -1020,7 +1040,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginGroupLifetimeUpdate(newGroupLifetime) + .beginGroupLifetimeUpdate(newGroupLifetime), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -1028,13 +1048,15 @@ describe("RandomBeaconGovernance", () => { context("when the update value is zero", () => { it("should revert", async () => { await expect( - randomBeaconGovernance.connect(governance).beginGroupLifetimeUpdate(0) + randomBeaconGovernance + .connect(governance) + .beginGroupLifetimeUpdate(0), ).to.be.revertedWith("Group lifetime must be greater than 0") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1055,13 +1077,16 @@ describe("RandomBeaconGovernance", () => { it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingGroupLifetimeUpdateTime() + await randomBeaconGovernance.getRemainingGroupLifetimeUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit the GroupLifetimeUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit(randomBeaconGovernance, "GroupLifetimeUpdateStarted") .withArgs(newGroupLifetime, blockTimestamp) @@ -1077,7 +1102,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeGroupLifetimeUpdate() + .finalizeGroupLifetimeUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -1087,7 +1112,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeGroupLifetimeUpdate() + .finalizeGroupLifetimeUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -1105,7 +1130,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeGroupLifetimeUpdate() + .finalizeGroupLifetimeUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -1115,7 +1140,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1148,10 +1173,10 @@ describe("RandomBeaconGovernance", () => { it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingGroupLifetimeUpdateTime() + randomBeaconGovernance.getRemainingGroupLifetimeUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -1161,7 +1186,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginDkgResultChallengePeriodLengthUpdate(11) + .beginDkgResultChallengePeriodLengthUpdate(11), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -1171,7 +1196,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .beginDkgResultChallengePeriodLengthUpdate(9) + .beginDkgResultChallengePeriodLengthUpdate(9), ).to.be.revertedWith("DKG result challenge period length must be >= 10") }) }) @@ -1194,7 +1219,7 @@ describe("RandomBeaconGovernance", () => { }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1212,23 +1237,26 @@ describe("RandomBeaconGovernance", () => { const { dkgResultChallengePeriodLength } = await randomBeacon.groupCreationParameters() expect(dkgResultChallengePeriodLength).to.be.equal( - params.dkgResultChallengePeriodLength + params.dkgResultChallengePeriodLength, ) }) it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingDkgResultChallengePeriodLengthUpdateTime() + await randomBeaconGovernance.getRemainingDkgResultChallengePeriodLengthUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit the DkgResultChallengePeriodLengthUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( randomBeaconGovernance, - "DkgResultChallengePeriodLengthUpdateStarted" + "DkgResultChallengePeriodLengthUpdateStarted", ) .withArgs(11, blockTimestamp) }) @@ -1241,7 +1269,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeDkgResultChallengePeriodLengthUpdate() + .finalizeDkgResultChallengePeriodLengthUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -1251,7 +1279,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeDkgResultChallengePeriodLengthUpdate() + .finalizeDkgResultChallengePeriodLengthUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -1269,7 +1297,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeDkgResultChallengePeriodLengthUpdate() + .finalizeDkgResultChallengePeriodLengthUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -1279,7 +1307,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1309,17 +1337,17 @@ describe("RandomBeaconGovernance", () => { await expect(tx) .to.emit( randomBeaconGovernance, - "DkgResultChallengePeriodLengthUpdated" + "DkgResultChallengePeriodLengthUpdated", ) .withArgs(11) }) it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingDkgResultChallengePeriodLengthUpdateTime() + randomBeaconGovernance.getRemainingDkgResultChallengePeriodLengthUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -1329,13 +1357,13 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginDkgResultChallengeExtraGasUpdate(1337) + .beginDkgResultChallengeExtraGasUpdate(1337), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1353,23 +1381,26 @@ describe("RandomBeaconGovernance", () => { const { dkgResultChallengeExtraGas } = await randomBeacon.groupCreationParameters() expect(dkgResultChallengeExtraGas).to.be.equal( - params.dkgResultChallengeExtraGas + params.dkgResultChallengeExtraGas, ) }) it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingDkgResultChallengeExtraGasUpdateTime() + await randomBeaconGovernance.getRemainingDkgResultChallengeExtraGasUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit the DkgResultChallengeExtraGasUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( randomBeaconGovernance, - "DkgResultChallengeExtraGasUpdateStarted" + "DkgResultChallengeExtraGasUpdateStarted", ) .withArgs(1337, blockTimestamp) }) @@ -1382,7 +1413,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeDkgResultChallengeExtraGasUpdate() + .finalizeDkgResultChallengeExtraGasUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -1392,7 +1423,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeDkgResultChallengeExtraGasUpdate() + .finalizeDkgResultChallengeExtraGasUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -1410,7 +1441,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeDkgResultChallengeExtraGasUpdate() + .finalizeDkgResultChallengeExtraGasUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -1420,7 +1451,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1450,17 +1481,17 @@ describe("RandomBeaconGovernance", () => { await expect(tx) .to.emit( randomBeaconGovernance, - "DkgResultChallengeExtraGasUpdated" + "DkgResultChallengeExtraGasUpdated", ) .withArgs(1337) }) it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingDkgResultChallengeExtraGasUpdateTime() + randomBeaconGovernance.getRemainingDkgResultChallengeExtraGasUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -1470,7 +1501,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginDkgResultSubmissionTimeoutUpdate(1) + .beginDkgResultSubmissionTimeoutUpdate(1), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -1480,7 +1511,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .beginDkgResultSubmissionTimeoutUpdate(0) + .beginDkgResultSubmissionTimeoutUpdate(0), ).to.be.revertedWith("DKG result submission timeout must be > 0") }) }) @@ -1503,7 +1534,7 @@ describe("RandomBeaconGovernance", () => { }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1521,23 +1552,26 @@ describe("RandomBeaconGovernance", () => { const { dkgResultSubmissionTimeout } = await randomBeacon.groupCreationParameters() expect(dkgResultSubmissionTimeout).to.be.equal( - params.dkgResultSubmissionTimeout + params.dkgResultSubmissionTimeout, ) }) it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingDkgResultSubmissionTimeoutUpdateTime() + await randomBeaconGovernance.getRemainingDkgResultSubmissionTimeoutUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit the DkgResultSubmissionTimeoutUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( randomBeaconGovernance, - "DkgResultSubmissionTimeoutUpdateStarted" + "DkgResultSubmissionTimeoutUpdateStarted", ) .withArgs(1, blockTimestamp) }) @@ -1550,7 +1584,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeDkgResultSubmissionTimeoutUpdate() + .finalizeDkgResultSubmissionTimeoutUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -1560,7 +1594,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeDkgResultSubmissionTimeoutUpdate() + .finalizeDkgResultSubmissionTimeoutUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -1578,7 +1612,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeDkgResultSubmissionTimeoutUpdate() + .finalizeDkgResultSubmissionTimeoutUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -1589,7 +1623,7 @@ describe("RandomBeaconGovernance", () => { "when the update process is initialized and governance delay passed", () => { const newValue = 234 - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1619,17 +1653,17 @@ describe("RandomBeaconGovernance", () => { await expect(tx) .to.emit( randomBeaconGovernance, - "DkgResultSubmissionTimeoutUpdated" + "DkgResultSubmissionTimeoutUpdated", ) .withArgs(newValue) }) it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingDkgResultSubmissionTimeoutUpdateTime() + randomBeaconGovernance.getRemainingDkgResultSubmissionTimeoutUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -1639,7 +1673,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginDkgSubmitterPrecedencePeriodLengthUpdate(1) + .beginDkgSubmitterPrecedencePeriodLengthUpdate(1), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -1649,9 +1683,9 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .beginDkgSubmitterPrecedencePeriodLengthUpdate(0) + .beginDkgSubmitterPrecedencePeriodLengthUpdate(0), ).to.be.revertedWith( - "DKG submitter precedence period length must be > 0" + "DKG submitter precedence period length must be > 0", ) }) }) @@ -1663,13 +1697,13 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .beginDkgSubmitterPrecedencePeriodLengthUpdate(1) + .beginDkgSubmitterPrecedencePeriodLengthUpdate(1), ).not.to.be.reverted await expect( randomBeaconGovernance .connect(governance) - .beginDkgSubmitterPrecedencePeriodLengthUpdate(2) + .beginDkgSubmitterPrecedencePeriodLengthUpdate(2), ).not.to.be.reverted await restoreSnapshot() @@ -1677,7 +1711,7 @@ describe("RandomBeaconGovernance", () => { }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1695,23 +1729,26 @@ describe("RandomBeaconGovernance", () => { const { dkgSubmitterPrecedencePeriodLength } = await randomBeacon.groupCreationParameters() expect(dkgSubmitterPrecedencePeriodLength).to.be.equal( - params.dkgSubmitterPrecedencePeriodLength + params.dkgSubmitterPrecedencePeriodLength, ) }) it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingDkgSubmitterPrecedencePeriodLengthUpdateTime() + await randomBeaconGovernance.getRemainingDkgSubmitterPrecedencePeriodLengthUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit the DkgSubmitterPrecedencePeriodLengthUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( randomBeaconGovernance, - "DkgSubmitterPrecedencePeriodLengthUpdateStarted" + "DkgSubmitterPrecedencePeriodLengthUpdateStarted", ) .withArgs(1, blockTimestamp) }) @@ -1724,7 +1761,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeDkgSubmitterPrecedencePeriodLengthUpdate() + .finalizeDkgSubmitterPrecedencePeriodLengthUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -1734,7 +1771,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeDkgSubmitterPrecedencePeriodLengthUpdate() + .finalizeDkgSubmitterPrecedencePeriodLengthUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -1752,7 +1789,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeDkgSubmitterPrecedencePeriodLengthUpdate() + .finalizeDkgSubmitterPrecedencePeriodLengthUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -1762,7 +1799,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1792,17 +1829,17 @@ describe("RandomBeaconGovernance", () => { await expect(tx) .to.emit( randomBeaconGovernance, - "DkgSubmitterPrecedencePeriodLengthUpdated" + "DkgSubmitterPrecedencePeriodLengthUpdated", ) .withArgs(1) }) it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingDkgSubmitterPrecedencePeriodLengthUpdateTime() + randomBeaconGovernance.getRemainingDkgSubmitterPrecedencePeriodLengthUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -1812,13 +1849,13 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginRelayEntrySubmissionFailureSlashingAmountUpdate(123) + .beginRelayEntrySubmissionFailureSlashingAmountUpdate(123), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1836,23 +1873,26 @@ describe("RandomBeaconGovernance", () => { const { relayEntrySubmissionFailureSlashingAmount } = await randomBeacon.slashingParameters() expect(relayEntrySubmissionFailureSlashingAmount).to.be.equal( - params.relayEntrySubmissionFailureSlashingAmount + params.relayEntrySubmissionFailureSlashingAmount, ) }) it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingRelayEntrySubmissionFailureSlashingAmountUpdateTime() + await randomBeaconGovernance.getRemainingRelayEntrySubmissionFailureSlashingAmountUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit the RelayEntrySubmissionFailureSlashingAmountUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( randomBeaconGovernance, - "RelayEntrySubmissionFailureSlashingAmountUpdateStarted" + "RelayEntrySubmissionFailureSlashingAmountUpdateStarted", ) .withArgs(123, blockTimestamp) }) @@ -1865,7 +1905,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeRelayEntrySubmissionFailureSlashingAmountUpdate() + .finalizeRelayEntrySubmissionFailureSlashingAmountUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -1875,7 +1915,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeRelayEntrySubmissionFailureSlashingAmountUpdate() + .finalizeRelayEntrySubmissionFailureSlashingAmountUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -1893,7 +1933,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeRelayEntrySubmissionFailureSlashingAmountUpdate() + .finalizeRelayEntrySubmissionFailureSlashingAmountUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -1903,7 +1943,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1933,17 +1973,17 @@ describe("RandomBeaconGovernance", () => { await expect(tx) .to.emit( randomBeaconGovernance, - "RelayEntrySubmissionFailureSlashingAmountUpdated" + "RelayEntrySubmissionFailureSlashingAmountUpdated", ) .withArgs(123) }) it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingRelayEntrySubmissionFailureSlashingAmountUpdateTime() + randomBeaconGovernance.getRemainingRelayEntrySubmissionFailureSlashingAmountUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -1953,13 +1993,13 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginUnauthorizedSigningSlashingAmountUpdate(123) + .beginUnauthorizedSigningSlashingAmountUpdate(123), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -1977,23 +2017,26 @@ describe("RandomBeaconGovernance", () => { const { unauthorizedSigningSlashingAmount } = await randomBeacon.slashingParameters() expect(unauthorizedSigningSlashingAmount).to.be.equal( - params.unauthorizedSigningSlashingAmount + params.unauthorizedSigningSlashingAmount, ) }) it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingUnauthorizedSigningSlashingAmountUpdateTime() + await randomBeaconGovernance.getRemainingUnauthorizedSigningSlashingAmountUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit the UnauthorizedSigningSlashingAmountUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( randomBeaconGovernance, - "UnauthorizedSigningSlashingAmountUpdateStarted" + "UnauthorizedSigningSlashingAmountUpdateStarted", ) .withArgs(123, blockTimestamp) }) @@ -2006,7 +2049,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeUnauthorizedSigningSlashingAmountUpdate() + .finalizeUnauthorizedSigningSlashingAmountUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -2016,7 +2059,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeUnauthorizedSigningSlashingAmountUpdate() + .finalizeUnauthorizedSigningSlashingAmountUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -2034,7 +2077,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeUnauthorizedSigningSlashingAmountUpdate() + .finalizeUnauthorizedSigningSlashingAmountUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -2044,7 +2087,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2074,17 +2117,17 @@ describe("RandomBeaconGovernance", () => { await expect(tx) .to.emit( randomBeaconGovernance, - "UnauthorizedSigningSlashingAmountUpdated" + "UnauthorizedSigningSlashingAmountUpdated", ) .withArgs(123) }) it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingUnauthorizedSigningSlashingAmountUpdateTime() + randomBeaconGovernance.getRemainingUnauthorizedSigningSlashingAmountUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -2094,13 +2137,13 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginMaliciousDkgResultSlashingAmountUpdate(123) + .beginMaliciousDkgResultSlashingAmountUpdate(123), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2118,23 +2161,26 @@ describe("RandomBeaconGovernance", () => { const { maliciousDkgResultSlashingAmount } = await randomBeacon.slashingParameters() expect(maliciousDkgResultSlashingAmount).to.be.equal( - params.maliciousDkgResultSlashingAmount + params.maliciousDkgResultSlashingAmount, ) }) it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingMaliciousDkgResultSlashingAmountUpdateTime() + await randomBeaconGovernance.getRemainingMaliciousDkgResultSlashingAmountUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit the MaliciousDkgResultSlashingAmountUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( randomBeaconGovernance, - "MaliciousDkgResultSlashingAmountUpdateStarted" + "MaliciousDkgResultSlashingAmountUpdateStarted", ) .withArgs(123, blockTimestamp) }) @@ -2147,7 +2193,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeMaliciousDkgResultSlashingAmountUpdate() + .finalizeMaliciousDkgResultSlashingAmountUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -2157,7 +2203,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeMaliciousDkgResultSlashingAmountUpdate() + .finalizeMaliciousDkgResultSlashingAmountUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -2175,7 +2221,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeMaliciousDkgResultSlashingAmountUpdate() + .finalizeMaliciousDkgResultSlashingAmountUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -2185,7 +2231,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2215,17 +2261,17 @@ describe("RandomBeaconGovernance", () => { await expect(tx) .to.emit( randomBeaconGovernance, - "MaliciousDkgResultSlashingAmountUpdated" + "MaliciousDkgResultSlashingAmountUpdated", ) .withArgs(123) }) it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingMaliciousDkgResultSlashingAmountUpdateTime() + randomBeaconGovernance.getRemainingMaliciousDkgResultSlashingAmountUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -2235,13 +2281,13 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginSortitionPoolRewardsBanDurationUpdate(123) + .beginSortitionPoolRewardsBanDurationUpdate(123), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2259,23 +2305,26 @@ describe("RandomBeaconGovernance", () => { const { sortitionPoolRewardsBanDuration } = await randomBeacon.rewardParameters() expect(sortitionPoolRewardsBanDuration).to.be.equal( - params.sortitionPoolRewardsBanDuration + params.sortitionPoolRewardsBanDuration, ) }) it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingSortitionPoolRewardsBanDurationUpdateTime() + await randomBeaconGovernance.getRemainingSortitionPoolRewardsBanDurationUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit the SortitionPoolRewardsBanDurationUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( randomBeaconGovernance, - "SortitionPoolRewardsBanDurationUpdateStarted" + "SortitionPoolRewardsBanDurationUpdateStarted", ) .withArgs(123, blockTimestamp) }) @@ -2288,7 +2337,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeSortitionPoolRewardsBanDurationUpdate() + .finalizeSortitionPoolRewardsBanDurationUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -2298,7 +2347,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeSortitionPoolRewardsBanDurationUpdate() + .finalizeSortitionPoolRewardsBanDurationUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -2316,7 +2365,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeSortitionPoolRewardsBanDurationUpdate() + .finalizeSortitionPoolRewardsBanDurationUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -2326,7 +2375,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2356,17 +2405,17 @@ describe("RandomBeaconGovernance", () => { await expect(tx) .to.emit( randomBeaconGovernance, - "SortitionPoolRewardsBanDurationUpdated" + "SortitionPoolRewardsBanDurationUpdated", ) .withArgs(123) }) it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingSortitionPoolRewardsBanDurationUpdateTime() + randomBeaconGovernance.getRemainingSortitionPoolRewardsBanDurationUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -2376,7 +2425,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginUnauthorizedSigningNotificationRewardMultiplierUpdate(100) + .beginUnauthorizedSigningNotificationRewardMultiplierUpdate(100), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -2386,13 +2435,13 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .beginUnauthorizedSigningNotificationRewardMultiplierUpdate(101) + .beginUnauthorizedSigningNotificationRewardMultiplierUpdate(101), ).to.be.revertedWith("Maximum value is 100") }) }) context("when the caller is the owner and value is correct", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2410,23 +2459,26 @@ describe("RandomBeaconGovernance", () => { const { unauthorizedSigningNotificationRewardMultiplier } = await randomBeacon.rewardParameters() expect(unauthorizedSigningNotificationRewardMultiplier).to.be.equal( - params.unauthorizedSigningNotificationRewardMultiplier + params.unauthorizedSigningNotificationRewardMultiplier, ) }) it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingUnauthorizedSigningNotificationRewardMultiplierUpdateTime() + await randomBeaconGovernance.getRemainingUnauthorizedSigningNotificationRewardMultiplierUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit the UnauthorizedSigningNotificationRewardMultiplierUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( randomBeaconGovernance, - "UnauthorizedSigningNotificationRewardMultiplierUpdateStarted" + "UnauthorizedSigningNotificationRewardMultiplierUpdateStarted", ) .withArgs(100, blockTimestamp) }) @@ -2439,7 +2491,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeUnauthorizedSigningNotificationRewardMultiplierUpdate() + .finalizeUnauthorizedSigningNotificationRewardMultiplierUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -2449,7 +2501,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeUnauthorizedSigningNotificationRewardMultiplierUpdate() + .finalizeUnauthorizedSigningNotificationRewardMultiplierUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -2467,7 +2519,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeUnauthorizedSigningNotificationRewardMultiplierUpdate() + .finalizeUnauthorizedSigningNotificationRewardMultiplierUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -2477,7 +2529,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2501,7 +2553,7 @@ describe("RandomBeaconGovernance", () => { const { unauthorizedSigningNotificationRewardMultiplier } = await randomBeacon.rewardParameters() expect(unauthorizedSigningNotificationRewardMultiplier).to.be.equal( - 100 + 100, ) }) @@ -2509,17 +2561,17 @@ describe("RandomBeaconGovernance", () => { await expect(tx) .to.emit( randomBeaconGovernance, - "UnauthorizedSigningNotificationRewardMultiplierUpdated" + "UnauthorizedSigningNotificationRewardMultiplierUpdated", ) .withArgs(100) }) it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingUnauthorizedSigningNotificationRewardMultiplierUpdateTime() + randomBeaconGovernance.getRemainingUnauthorizedSigningNotificationRewardMultiplierUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -2529,7 +2581,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginRelayEntryTimeoutNotificationRewardMultiplierUpdate(100) + .beginRelayEntryTimeoutNotificationRewardMultiplierUpdate(100), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -2539,13 +2591,13 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .beginRelayEntryTimeoutNotificationRewardMultiplierUpdate(101) + .beginRelayEntryTimeoutNotificationRewardMultiplierUpdate(101), ).to.be.revertedWith("Maximum value is 100") }) }) context("when the caller is the owner and value is correct", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2563,23 +2615,26 @@ describe("RandomBeaconGovernance", () => { const { relayEntryTimeoutNotificationRewardMultiplier } = await randomBeacon.rewardParameters() expect(relayEntryTimeoutNotificationRewardMultiplier).to.be.equal( - params.relayEntryTimeoutNotificationRewardMultiplier + params.relayEntryTimeoutNotificationRewardMultiplier, ) }) it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingRelayEntryTimeoutNotificationRewardMultiplierUpdateTime() + await randomBeaconGovernance.getRemainingRelayEntryTimeoutNotificationRewardMultiplierUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit the RelayEntryTimeoutNotificationRewardMultiplierUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( randomBeaconGovernance, - "RelayEntryTimeoutNotificationRewardMultiplierUpdateStarted" + "RelayEntryTimeoutNotificationRewardMultiplierUpdateStarted", ) .withArgs(100, blockTimestamp) }) @@ -2592,7 +2647,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeRelayEntryTimeoutNotificationRewardMultiplierUpdate() + .finalizeRelayEntryTimeoutNotificationRewardMultiplierUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -2602,7 +2657,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeRelayEntryTimeoutNotificationRewardMultiplierUpdate() + .finalizeRelayEntryTimeoutNotificationRewardMultiplierUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -2620,7 +2675,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeRelayEntryTimeoutNotificationRewardMultiplierUpdate() + .finalizeRelayEntryTimeoutNotificationRewardMultiplierUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -2630,7 +2685,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2661,17 +2716,17 @@ describe("RandomBeaconGovernance", () => { await expect(tx) .to.emit( randomBeaconGovernance, - "RelayEntryTimeoutNotificationRewardMultiplierUpdated" + "RelayEntryTimeoutNotificationRewardMultiplierUpdated", ) .withArgs(100) }) it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingRelayEntryTimeoutNotificationRewardMultiplierUpdateTime() + randomBeaconGovernance.getRemainingRelayEntryTimeoutNotificationRewardMultiplierUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -2681,13 +2736,13 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginMinimumAuthorizationUpdate(123) + .beginMinimumAuthorizationUpdate(123), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2703,19 +2758,22 @@ describe("RandomBeaconGovernance", () => { it("should not update the minimum authorization amount", async () => { expect(await randomBeacon.minimumAuthorization()).to.be.equal( - params.minimumAuthorization + params.minimumAuthorization, ) }) it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingMimimumAuthorizationUpdateTime() + await randomBeaconGovernance.getRemainingMimimumAuthorizationUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit the MinimumAuthorizationUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit(randomBeaconGovernance, "MinimumAuthorizationUpdateStarted") .withArgs(123, blockTimestamp) @@ -2729,7 +2787,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeMinimumAuthorizationUpdate() + .finalizeMinimumAuthorizationUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -2739,7 +2797,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeMinimumAuthorizationUpdate() + .finalizeMinimumAuthorizationUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -2757,7 +2815,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeMinimumAuthorizationUpdate() + .finalizeMinimumAuthorizationUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -2767,7 +2825,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2799,10 +2857,10 @@ describe("RandomBeaconGovernance", () => { it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingMimimumAuthorizationUpdateTime() + randomBeaconGovernance.getRemainingMimimumAuthorizationUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -2812,13 +2870,13 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginAuthorizationDecreaseDelayUpdate(123) + .beginAuthorizationDecreaseDelayUpdate(123), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2836,23 +2894,26 @@ describe("RandomBeaconGovernance", () => { const { authorizationDecreaseDelay } = await randomBeacon.authorizationParameters() expect(authorizationDecreaseDelay).to.be.equal( - params.authorizationDecreaseDelay + params.authorizationDecreaseDelay, ) }) it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingAuthorizationDecreaseDelayUpdateTime() + await randomBeaconGovernance.getRemainingAuthorizationDecreaseDelayUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit the AuthorizationDecreaseDelayUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( randomBeaconGovernance, - "AuthorizationDecreaseDelayUpdateStarted" + "AuthorizationDecreaseDelayUpdateStarted", ) .withArgs(123, blockTimestamp) }) @@ -2865,7 +2926,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeAuthorizationDecreaseDelayUpdate() + .finalizeAuthorizationDecreaseDelayUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -2875,7 +2936,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeAuthorizationDecreaseDelayUpdate() + .finalizeAuthorizationDecreaseDelayUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -2891,7 +2952,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeAuthorizationDecreaseDelayUpdate() + .finalizeAuthorizationDecreaseDelayUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -2901,7 +2962,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2931,17 +2992,17 @@ describe("RandomBeaconGovernance", () => { await expect(tx) .to.emit( randomBeaconGovernance, - "AuthorizationDecreaseDelayUpdated" + "AuthorizationDecreaseDelayUpdated", ) .withArgs(123) }) it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingAuthorizationDecreaseDelayUpdateTime() + randomBeaconGovernance.getRemainingAuthorizationDecreaseDelayUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -2951,13 +3012,13 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginAuthorizationDecreaseChangePeriodUpdate(123) + .beginAuthorizationDecreaseChangePeriodUpdate(123), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -2975,23 +3036,26 @@ describe("RandomBeaconGovernance", () => { const { authorizationDecreaseChangePeriod } = await randomBeacon.authorizationParameters() expect(authorizationDecreaseChangePeriod).to.be.equal( - params.authorizationDecreaseChangePeriod + params.authorizationDecreaseChangePeriod, ) }) it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingAuthorizationDecreaseChangePeriodUpdateTime() + await randomBeaconGovernance.getRemainingAuthorizationDecreaseChangePeriodUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit the AuthorizationDecreaseChangePeriodUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( randomBeaconGovernance, - "AuthorizationDecreaseChangePeriodUpdateStarted" + "AuthorizationDecreaseChangePeriodUpdateStarted", ) .withArgs(123, blockTimestamp) }) @@ -3004,7 +3068,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeAuthorizationDecreaseChangePeriodUpdate() + .finalizeAuthorizationDecreaseChangePeriodUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -3014,7 +3078,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeAuthorizationDecreaseChangePeriodUpdate() + .finalizeAuthorizationDecreaseChangePeriodUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -3030,7 +3094,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeAuthorizationDecreaseChangePeriodUpdate() + .finalizeAuthorizationDecreaseChangePeriodUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -3040,7 +3104,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -3070,17 +3134,17 @@ describe("RandomBeaconGovernance", () => { await expect(tx) .to.emit( randomBeaconGovernance, - "AuthorizationDecreaseChangePeriodUpdated" + "AuthorizationDecreaseChangePeriodUpdated", ) .withArgs(123) }) it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingAuthorizationDecreaseChangePeriodUpdateTime() + randomBeaconGovernance.getRemainingAuthorizationDecreaseChangePeriodUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -3090,13 +3154,13 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .setRequesterAuthorization(thirdPartyContract.address, true) + .setRequesterAuthorization(thirdPartyContract.address, true), ).to.be.revertedWith("Ownable: caller is not the owner") await expect( randomBeaconGovernance .connect(thirdParty) - .setRequesterAuthorization(thirdPartyContract.address, false) + .setRequesterAuthorization(thirdPartyContract.address, false), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -3104,7 +3168,7 @@ describe("RandomBeaconGovernance", () => { context("when the caller is the owner", () => { it("should update requester authorization", async () => { let isAuthorized = await randomBeacon.authorizedRequesters( - thirdPartyContract.address + thirdPartyContract.address, ) await expect(isAuthorized).to.be.false @@ -3113,7 +3177,7 @@ describe("RandomBeaconGovernance", () => { .setRequesterAuthorization(thirdPartyContract.address, true) isAuthorized = await randomBeacon.authorizedRequesters( - thirdPartyContract.address + thirdPartyContract.address, ) await expect(isAuthorized).to.be.true @@ -3122,7 +3186,7 @@ describe("RandomBeaconGovernance", () => { .setRequesterAuthorization(thirdPartyContract.address, false) isAuthorized = await randomBeacon.authorizedRequesters( - thirdPartyContract.address + thirdPartyContract.address, ) await expect(isAuthorized).to.be.false }) @@ -3135,7 +3199,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginDkgMaliciousResultNotificationRewardMultiplierUpdate(100) + .beginDkgMaliciousResultNotificationRewardMultiplierUpdate(100), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -3145,13 +3209,13 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .beginDkgMaliciousResultNotificationRewardMultiplierUpdate(101) + .beginDkgMaliciousResultNotificationRewardMultiplierUpdate(101), ).to.be.revertedWith("Maximum value is 100") }) }) context("when the caller is the owner and value is correct", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -3170,23 +3234,26 @@ describe("RandomBeaconGovernance", () => { await randomBeacon.rewardParameters() expect(dkgMaliciousResultNotificationRewardMultiplier).to.be.equal( - params.dkgMaliciousResultNotificationRewardMultiplier + params.dkgMaliciousResultNotificationRewardMultiplier, ) }) it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingDkgMaliciousResultNotificationRewardMultiplierUpdateTime() + await randomBeaconGovernance.getRemainingDkgMaliciousResultNotificationRewardMultiplierUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit the DkgMaliciousResultNotificationRewardMultiplierUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( randomBeaconGovernance, - "DkgMaliciousResultNotificationRewardMultiplierUpdateStarted" + "DkgMaliciousResultNotificationRewardMultiplierUpdateStarted", ) .withArgs(100, blockTimestamp) }) @@ -3199,7 +3266,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeDkgMaliciousResultNotificationRewardMultiplierUpdate() + .finalizeDkgMaliciousResultNotificationRewardMultiplierUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -3209,7 +3276,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeDkgMaliciousResultNotificationRewardMultiplierUpdate() + .finalizeDkgMaliciousResultNotificationRewardMultiplierUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -3227,7 +3294,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeDkgMaliciousResultNotificationRewardMultiplierUpdate() + .finalizeDkgMaliciousResultNotificationRewardMultiplierUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -3237,7 +3304,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -3261,7 +3328,7 @@ describe("RandomBeaconGovernance", () => { const { dkgMaliciousResultNotificationRewardMultiplier } = await randomBeacon.rewardParameters() expect(dkgMaliciousResultNotificationRewardMultiplier).to.be.equal( - 100 + 100, ) }) @@ -3269,17 +3336,17 @@ describe("RandomBeaconGovernance", () => { await expect(tx) .to.emit( randomBeaconGovernance, - "DkgMaliciousResultNotificationRewardMultiplierUpdated" + "DkgMaliciousResultNotificationRewardMultiplierUpdated", ) .withArgs(100) }) it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingDkgMaliciousResultNotificationRewardMultiplierUpdateTime() + randomBeaconGovernance.getRemainingDkgMaliciousResultNotificationRewardMultiplierUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -3289,13 +3356,13 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginDkgResultSubmissionGasUpdate(100) + .beginDkgResultSubmissionGasUpdate(100), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -3312,23 +3379,26 @@ describe("RandomBeaconGovernance", () => { it("should not update DKG result submission gas", async () => { const { dkgResultSubmissionGas } = await randomBeacon.gasParameters() expect(dkgResultSubmissionGas).to.be.equal( - params.dkgResultSubmissionGas + params.dkgResultSubmissionGas, ) }) it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingDkgResultSubmissionGasUpdateTime() + await randomBeaconGovernance.getRemainingDkgResultSubmissionGasUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit DkgResultSubmissionGasUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( randomBeaconGovernance, - "DkgResultSubmissionGasUpdateStarted" + "DkgResultSubmissionGasUpdateStarted", ) .withArgs(1337, blockTimestamp) }) @@ -3341,7 +3411,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeDkgResultSubmissionGasUpdate() + .finalizeDkgResultSubmissionGasUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -3351,7 +3421,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeDkgResultSubmissionGasUpdate() + .finalizeDkgResultSubmissionGasUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -3369,7 +3439,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeDkgResultSubmissionGasUpdate() + .finalizeDkgResultSubmissionGasUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -3379,7 +3449,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -3412,10 +3482,10 @@ describe("RandomBeaconGovernance", () => { it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingDkgResultSubmissionGasUpdateTime() + randomBeaconGovernance.getRemainingDkgResultSubmissionGasUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -3425,13 +3495,13 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginDkgResultApprovalGasOffsetUpdate(1337) + .beginDkgResultApprovalGasOffsetUpdate(1337), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -3449,23 +3519,26 @@ describe("RandomBeaconGovernance", () => { const { dkgResultApprovalGasOffset } = await randomBeacon.gasParameters() expect(dkgResultApprovalGasOffset).to.be.equal( - params.dkgResultApprovalGasOffset + params.dkgResultApprovalGasOffset, ) }) it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingDkgResultApprovalGasOffsetUpdateTime() + await randomBeaconGovernance.getRemainingDkgResultApprovalGasOffsetUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit the DkgResultApprovalGasOffsetUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( randomBeaconGovernance, - "DkgResultApprovalGasOffsetUpdateStarted" + "DkgResultApprovalGasOffsetUpdateStarted", ) .withArgs(1337, blockTimestamp) }) @@ -3478,7 +3551,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeDkgResultApprovalGasOffsetUpdate() + .finalizeDkgResultApprovalGasOffsetUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -3488,7 +3561,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeDkgResultApprovalGasOffsetUpdate() + .finalizeDkgResultApprovalGasOffsetUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -3506,7 +3579,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeDkgResultApprovalGasOffsetUpdate() + .finalizeDkgResultApprovalGasOffsetUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -3516,7 +3589,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -3546,17 +3619,17 @@ describe("RandomBeaconGovernance", () => { await expect(tx) .to.emit( randomBeaconGovernance, - "DkgResultApprovalGasOffsetUpdated" + "DkgResultApprovalGasOffsetUpdated", ) .withArgs(7331) }) it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingDkgResultApprovalGasOffsetUpdateTime() + randomBeaconGovernance.getRemainingDkgResultApprovalGasOffsetUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -3566,13 +3639,13 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginNotifyOperatorInactivityGasOffsetUpdate(100) + .beginNotifyOperatorInactivityGasOffsetUpdate(100), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -3590,23 +3663,26 @@ describe("RandomBeaconGovernance", () => { const { notifyOperatorInactivityGasOffset } = await randomBeacon.gasParameters() expect(notifyOperatorInactivityGasOffset).to.be.equal( - params.notifyOperatorInactivityGasOffset + params.notifyOperatorInactivityGasOffset, ) }) it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingNotifyOperatorInactivityGasOffsetUpdateTime() + await randomBeaconGovernance.getRemainingNotifyOperatorInactivityGasOffsetUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit the NotifyOperatorInactivityGasOffsetUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( randomBeaconGovernance, - "NotifyOperatorInactivityGasOffsetUpdateStarted" + "NotifyOperatorInactivityGasOffsetUpdateStarted", ) .withArgs(100, blockTimestamp) }) @@ -3619,7 +3695,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeNotifyOperatorInactivityGasOffsetUpdate() + .finalizeNotifyOperatorInactivityGasOffsetUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -3629,7 +3705,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeNotifyOperatorInactivityGasOffsetUpdate() + .finalizeNotifyOperatorInactivityGasOffsetUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -3647,7 +3723,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeNotifyOperatorInactivityGasOffsetUpdate() + .finalizeNotifyOperatorInactivityGasOffsetUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -3657,7 +3733,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -3687,17 +3763,17 @@ describe("RandomBeaconGovernance", () => { await expect(tx) .to.emit( randomBeaconGovernance, - "NotifyOperatorInactivityGasOffsetUpdated" + "NotifyOperatorInactivityGasOffsetUpdated", ) .withArgs(100) }) it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingNotifyOperatorInactivityGasOffsetUpdateTime() + randomBeaconGovernance.getRemainingNotifyOperatorInactivityGasOffsetUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -3707,13 +3783,13 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .beginRelayEntrySubmissionGasOffsetUpdate(997) + .beginRelayEntrySubmissionGasOffsetUpdate(997), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) context("when the caller is the owner", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -3731,23 +3807,26 @@ describe("RandomBeaconGovernance", () => { const { relayEntrySubmissionGasOffset } = await randomBeacon.gasParameters() expect(relayEntrySubmissionGasOffset).to.be.equal( - params.relayEntrySubmissionGasOffset + params.relayEntrySubmissionGasOffset, ) }) it("should start the governance delay timer", async () => { expect( - await randomBeaconGovernance.getRemainingRelayEntrySubmissionGasOffsetUpdateTime() + await randomBeaconGovernance.getRemainingRelayEntrySubmissionGasOffsetUpdateTime(), ).to.be.equal(governanceDelay) }) it("should emit the RelayEntrySubmissionGasOffsetUpdateStarted event", async () => { - const blockTimestamp = (await ethers.provider.getBlock(tx.blockNumber)) - .timestamp + const blockTimestamp = requireResult( + await ethers.provider.getBlock( + requireResult(await tx.wait()).blockNumber, + ), + ).timestamp await expect(tx) .to.emit( randomBeaconGovernance, - "RelayEntrySubmissionGasOffsetUpdateStarted" + "RelayEntrySubmissionGasOffsetUpdateStarted", ) .withArgs(997, blockTimestamp) }) @@ -3760,7 +3839,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .finalizeRelayEntrySubmissionGasOffsetUpdate() + .finalizeRelayEntrySubmissionGasOffsetUpdate(), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -3770,7 +3849,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeRelayEntrySubmissionGasOffsetUpdate() + .finalizeRelayEntrySubmissionGasOffsetUpdate(), ).to.be.revertedWith("Change not initiated") }) }) @@ -3788,7 +3867,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(governance) - .finalizeRelayEntrySubmissionGasOffsetUpdate() + .finalizeRelayEntrySubmissionGasOffsetUpdate(), ).to.be.revertedWith("Governance delay has not elapsed") await restoreSnapshot() @@ -3798,7 +3877,7 @@ describe("RandomBeaconGovernance", () => { context( "when the update process is initialized and governance delay passed", () => { - let tx: ContractTransaction + let tx: ContractTransactionResponse before(async () => { await createSnapshot() @@ -3828,17 +3907,17 @@ describe("RandomBeaconGovernance", () => { await expect(tx) .to.emit( randomBeaconGovernance, - "RelayEntrySubmissionGasOffsetUpdated" + "RelayEntrySubmissionGasOffsetUpdated", ) .withArgs(997) }) it("should reset the governance delay timer", async () => { await expect( - randomBeaconGovernance.getRemainingRelayEntrySubmissionGasOffsetUpdateTime() + randomBeaconGovernance.getRemainingRelayEntrySubmissionGasOffsetUpdateTime(), ).to.be.revertedWith("Change not initiated") }) - } + }, ) }) @@ -3848,7 +3927,7 @@ describe("RandomBeaconGovernance", () => { await expect( randomBeaconGovernance .connect(thirdParty) - .withdrawIneligibleRewards(thirdParty.address) + .withdrawIneligibleRewards(thirdParty.address), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) diff --git a/solidity/random-beacon/test/Reimbursable.test.ts b/solidity/random-beacon/test/Reimbursable.test.ts index e112ef98f8..4486e094c1 100644 --- a/solidity/random-beacon/test/Reimbursable.test.ts +++ b/solidity/random-beacon/test/Reimbursable.test.ts @@ -1,7 +1,7 @@ import { ethers, helpers } from "hardhat" import { expect } from "chai" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" import type { ReimbursableImplStub } from "../typechain" describe("Reimbursable", () => { @@ -12,19 +12,16 @@ describe("Reimbursable", () => { let contractToUpdate: SignerWithAddress before(async () => { - // eslint-disable-next-line @typescript-eslint/no-extra-semi ;({ deployer } = await helpers.signers.getNamedSigners()) - - // eslint-disable-next-line @typescript-eslint/no-extra-semi ;[admin, thirdParty, contractToUpdate] = await helpers.signers.getUnnamedSigners() const ReimbursableImplStub = await ethers.getContractFactory( "ReimbursableImplStub", - deployer + deployer, ) reimbursableImplStub = (await ReimbursableImplStub.deploy( - admin.address + admin.address, )) as ReimbursableImplStub }) @@ -34,7 +31,7 @@ describe("Reimbursable", () => { await expect( reimbursableImplStub .connect(deployer) - .updateReimbursementPool(contractToUpdate.address) + .updateReimbursementPool(contractToUpdate.address), ).to.be.revertedWith("Caller is not the admin") }) }) @@ -44,7 +41,7 @@ describe("Reimbursable", () => { await expect( reimbursableImplStub .connect(thirdParty) - .updateReimbursementPool(contractToUpdate.address) + .updateReimbursementPool(contractToUpdate.address), ).to.be.revertedWith("Caller is not the admin") }) }) @@ -56,7 +53,7 @@ describe("Reimbursable", () => { .updateReimbursementPool(contractToUpdate.address) expect(await reimbursableImplStub.reimbursementPool()).to.be.equal( - contractToUpdate.address + contractToUpdate.address, ) }) @@ -64,7 +61,7 @@ describe("Reimbursable", () => { await expect( reimbursableImplStub .connect(admin) - .updateReimbursementPool(contractToUpdate.address) + .updateReimbursementPool(contractToUpdate.address), ) .to.emit(reimbursableImplStub, "ReimbursementPoolUpdated") .withArgs(contractToUpdate.address) diff --git a/solidity/random-beacon/test/ReimbursementPool.test.ts b/solidity/random-beacon/test/ReimbursementPool.test.ts index 32bca34671..577537eb10 100644 --- a/solidity/random-beacon/test/ReimbursementPool.test.ts +++ b/solidity/random-beacon/test/ReimbursementPool.test.ts @@ -1,17 +1,18 @@ /* eslint-disable @typescript-eslint/no-unused-expressions */ -import { ethers, waffle, helpers, deployments } from "hardhat" +import { ethers, helpers, deployments } from "hardhat" import { expect } from "chai" +import requireResult from "./helpers/chain" import { params } from "./fixtures" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" -import type { ContractTransaction } from "ethers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" +import type { ContractTransactionResponse } from "ethers" import type { ReimbursementPool } from "../typechain" -const ZERO_ADDRESS = ethers.constants.AddressZero +const ZERO_ADDRESS = ethers.ZeroAddress const { createSnapshot, restoreSnapshot } = helpers.snapshot -const { provider } = waffle +const { provider } = ethers describe("ReimbursementPool", () => { let owner: SignerWithAddress @@ -22,10 +23,7 @@ describe("ReimbursementPool", () => { // prettier-ignore before(async () => { - // eslint-disable-next-line @typescript-eslint/no-extra-semi ;({ deployer: owner } = await helpers.signers.getNamedSigners()) - - // eslint-disable-next-line @typescript-eslint/no-extra-semi ;[thirdParty, thirdPartyContract, refundee] = await helpers.signers.getUnnamedSigners() }) @@ -38,44 +36,40 @@ describe("ReimbursementPool", () => { context("when a third party funds a reimbursment pool", () => { it("should send ETH to the Reimbursment Pool", async () => { let reimbursementPoolBalance = await provider.getBalance( - reimbursementPool.address + await reimbursementPool.getAddress(), ) expect(reimbursementPoolBalance).to.be.equal(0) await thirdParty.sendTransaction({ - to: reimbursementPool.address, - value: ethers.utils.parseEther("1.0"), // Send 1.0 ETH + to: await reimbursementPool.getAddress(), + value: ethers.parseEther("1.0"), }) reimbursementPoolBalance = await provider.getBalance( - reimbursementPool.address + await reimbursementPool.getAddress(), ) - expect(reimbursementPoolBalance).to.be.equal( - ethers.utils.parseEther("1.0") - ) + expect(reimbursementPoolBalance).to.be.equal(ethers.parseEther("1.0")) }) }) context("when the owner funds a reimbursment pool", () => { it("should send ETH to the Reimbursment Pool", async () => { let reimbursementPoolBalance = await provider.getBalance( - reimbursementPool.address + await reimbursementPool.getAddress(), ) expect(reimbursementPoolBalance).to.be.equal(0) await owner.sendTransaction({ - to: reimbursementPool.address, - value: ethers.utils.parseEther("1.0"), // Send 1.0 ETH + to: await reimbursementPool.getAddress(), + value: ethers.parseEther("1.0"), }) reimbursementPoolBalance = await provider.getBalance( - reimbursementPool.address + await reimbursementPool.getAddress(), ) - expect(reimbursementPoolBalance).to.be.equal( - ethers.utils.parseEther("1.0") - ) + expect(reimbursementPoolBalance).to.be.equal(ethers.parseEther("1.0")) }) }) }) @@ -83,8 +77,8 @@ describe("ReimbursementPool", () => { describe("withdrawAll", () => { beforeEach(async () => { await thirdParty.sendTransaction({ - to: reimbursementPool.address, - value: ethers.utils.parseEther("10.0"), // Send 10.0 ETH + to: await reimbursementPool.getAddress(), + value: ethers.parseEther("10.0"), }) }) @@ -93,7 +87,7 @@ describe("ReimbursementPool", () => { await expect( reimbursementPool .connect(thirdParty) - .withdrawAll(thirdPartyContract.address) + .withdrawAll(thirdPartyContract.address), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -101,47 +95,42 @@ describe("ReimbursementPool", () => { context("when widhrawing all the funds as an owner", () => { it("should withdraw entire ETH balance", async () => { let reimbursementPoolBalance = await provider.getBalance( - reimbursementPool.address - ) - expect(reimbursementPoolBalance).to.be.equal( - ethers.utils.parseEther("10.0") + await reimbursementPool.getAddress(), ) + expect(reimbursementPoolBalance).to.be.equal(ethers.parseEther("10.0")) const thirdPartyBalanceBefore = await provider.getBalance( - thirdParty.address + thirdParty.address, ) await reimbursementPool.connect(owner).withdrawAll(thirdParty.address) reimbursementPoolBalance = await provider.getBalance( - reimbursementPool.address + await reimbursementPool.getAddress(), ) expect(reimbursementPoolBalance).to.be.equal(0) const thirdPartyBalanceAfter = await provider.getBalance( - thirdParty.address - ) - const thirdPartyBalanceDiff = thirdPartyBalanceAfter.sub( - thirdPartyBalanceBefore - ) - expect(thirdPartyBalanceDiff).to.be.equal( - ethers.utils.parseEther("10.0") + thirdParty.address, ) + const thirdPartyBalanceDiff = + thirdPartyBalanceAfter - thirdPartyBalanceBefore + expect(thirdPartyBalanceDiff).to.be.equal(ethers.parseEther("10.0")) }) it("should emit FundsWithdrawn event", async () => { await expect( - reimbursementPool.connect(owner).withdrawAll(thirdParty.address) + reimbursementPool.connect(owner).withdrawAll(thirdParty.address), ) .to.emit(reimbursementPool, "FundsWithdrawn") - .withArgs(ethers.utils.parseEther("10.0"), thirdParty.address) + .withArgs(ethers.parseEther("10.0"), thirdParty.address) }) }) context("when receiver is zero address", () => { it("should revert", async () => { await expect( - reimbursementPool.connect(owner).withdrawAll(ZERO_ADDRESS) + reimbursementPool.connect(owner).withdrawAll(ZERO_ADDRESS), ).to.be.revertedWith("Receiver's address cannot be zero") }) }) @@ -152,8 +141,8 @@ describe("ReimbursementPool", () => { await createSnapshot() await thirdParty.sendTransaction({ - to: reimbursementPool.address, - value: ethers.utils.parseEther("10.0"), // Send 10.0 ETH + to: await reimbursementPool.getAddress(), + value: ethers.parseEther("10.0"), }) }) @@ -166,10 +155,7 @@ describe("ReimbursementPool", () => { await expect( reimbursementPool .connect(thirdParty) - .withdraw( - ethers.utils.parseEther("2.0"), - thirdPartyContract.address - ) + .withdraw(ethers.parseEther("2.0"), thirdPartyContract.address), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -177,53 +163,46 @@ describe("ReimbursementPool", () => { context("when widhrawing funds as an owner", () => { it("should withdraw ETH balance", async () => { let reimbursementPoolBalance = await provider.getBalance( - reimbursementPool.address - ) - expect(reimbursementPoolBalance).to.be.equal( - ethers.utils.parseEther("10.0") + await reimbursementPool.getAddress(), ) + expect(reimbursementPoolBalance).to.be.equal(ethers.parseEther("10.0")) const thirdPartyBalanceBefore = await provider.getBalance( - thirdParty.address + thirdParty.address, ) await reimbursementPool .connect(owner) - .withdraw(ethers.utils.parseEther("2.0"), thirdParty.address) + .withdraw(ethers.parseEther("2.0"), thirdParty.address) reimbursementPoolBalance = await provider.getBalance( - reimbursementPool.address - ) - expect(reimbursementPoolBalance).to.be.equal( - ethers.utils.parseEther("8.0") + await reimbursementPool.getAddress(), ) + expect(reimbursementPoolBalance).to.be.equal(ethers.parseEther("8.0")) const thirdPartyBalanceAfter = await provider.getBalance( - thirdParty.address - ) - const thirdPartyBalanceDiff = thirdPartyBalanceAfter.sub( - thirdPartyBalanceBefore - ) - expect(thirdPartyBalanceDiff).to.be.equal( - ethers.utils.parseEther("2.0") + thirdParty.address, ) + const thirdPartyBalanceDiff = + thirdPartyBalanceAfter - thirdPartyBalanceBefore + expect(thirdPartyBalanceDiff).to.be.equal(ethers.parseEther("2.0")) }) it("should emit FundsWithdrawn event", async () => { await expect( reimbursementPool .connect(owner) - .withdraw(ethers.utils.parseEther("2.0"), thirdParty.address) + .withdraw(ethers.parseEther("2.0"), thirdParty.address), ) .to.emit(reimbursementPool, "FundsWithdrawn") - .withArgs(ethers.utils.parseEther("2.0"), thirdParty.address) + .withArgs(ethers.parseEther("2.0"), thirdParty.address) }) }) context("when receiver is zero address", () => { it("should revert", async () => { await expect( - reimbursementPool.connect(owner).withdraw(42, ZERO_ADDRESS) + reimbursementPool.connect(owner).withdraw(42, ZERO_ADDRESS), ).to.be.revertedWith("Receiver's address cannot be zero") }) }) @@ -233,7 +212,7 @@ describe("ReimbursementPool", () => { await expect( reimbursementPool .connect(owner) - .withdraw(ethers.utils.parseEther("42.0"), ZERO_ADDRESS) + .withdraw(ethers.parseEther("42.0"), ZERO_ADDRESS), ).to.be.revertedWith("Insufficient contract balance") }) }) @@ -244,8 +223,8 @@ describe("ReimbursementPool", () => { await createSnapshot() await thirdParty.sendTransaction({ - to: reimbursementPool.address, - value: ethers.utils.parseEther("10.0"), // Send 10.0 ETH + to: await reimbursementPool.getAddress(), + value: ethers.parseEther("10.0"), }) }) @@ -258,7 +237,7 @@ describe("ReimbursementPool", () => { await expect( reimbursementPool .connect(thirdParty) - .refund(ethers.utils.parseEther("2.0"), thirdParty.address) + .refund(ethers.parseEther("2.0"), thirdParty.address), ).to.be.revertedWith("Contract is not authorized for a refund") }) }) @@ -279,7 +258,7 @@ describe("ReimbursementPool", () => { context("when tx gas price is lower than the max gas price", () => { it("should refund based on tx.gasprice", async () => { const refundeeBalanceBefore = await provider.getBalance( - refundee.address + refundee.address, ) const tx = await reimbursementPool @@ -287,14 +266,14 @@ describe("ReimbursementPool", () => { .refund(50000, refundee.address) const refundeeBalanceAfter = await provider.getBalance( - refundee.address - ) - const refundeeBalanceDiff = refundeeBalanceAfter.sub( - refundeeBalanceBefore + refundee.address, ) + const refundeeBalanceDiff = + refundeeBalanceAfter - refundeeBalanceBefore // consumed gas: 50k + 40.8k = 90.8k // refund: 90.8k * tx.gasPrice - const expectedRefund = ethers.BigNumber.from(90800).mul(tx.gasPrice) + const expectedRefund = + 90800n * requireResult(await tx.wait()).gasPrice expect(refundeeBalanceDiff).to.be.equal(expectedRefund) }) @@ -302,7 +281,7 @@ describe("ReimbursementPool", () => { await expect( reimbursementPool .connect(thirdPartyContract) - .refund(50000, refundee.address) + .refund(50000, refundee.address), ).not.to.emit(reimbursementPool, "SendingEtherFailed") }) }) @@ -315,10 +294,10 @@ describe("ReimbursementPool", () => { await reimbursementPool .connect(owner) - .setMaxGasPrice(ethers.utils.parseUnits("1.0", "gwei")) + .setMaxGasPrice(ethers.parseUnits("1.0", "gwei")) const refundeeBalanceBefore = await provider.getBalance( - refundee.address + refundee.address, ) await reimbursementPool @@ -326,14 +305,13 @@ describe("ReimbursementPool", () => { .refund(50000, refundee.address) const refundeeBalanceAfter = await provider.getBalance( - refundee.address - ) - const refundeeBalanceDiff = refundeeBalanceAfter.sub( - refundeeBalanceBefore + refundee.address, ) + const refundeeBalanceDiff = + refundeeBalanceAfter - refundeeBalanceBefore // gas spent + static gas => 50k + 40.8k expect(refundeeBalanceDiff).to.be.eq( - ethers.utils.parseUnits("90800", "gwei") + ethers.parseUnits("90800", "gwei"), ) }) }) @@ -343,20 +321,20 @@ describe("ReimbursementPool", () => { await expect( reimbursementPool .connect(thirdPartyContract) - .refund(50000, ZERO_ADDRESS) + .refund(50000, ZERO_ADDRESS), ).to.be.revertedWith("Receiver's address cannot be zero") }) }) context("when no funds available in the pool", () => { - let tx: Promise + let tx: Promise beforeEach(async () => { await createSnapshot() await reimbursementPool .connect(owner) - .setMaxGasPrice(ethers.utils.parseUnits("1.0", "gwei")) + .setMaxGasPrice(ethers.parseUnits("1.0", "gwei")) await reimbursementPool.connect(owner).withdrawAll(thirdParty.address) @@ -377,10 +355,7 @@ describe("ReimbursementPool", () => { // gas spent + static gas => 50k + 40.8k await expect(tx) .to.emit(reimbursementPool, "SendingEtherFailed") - .withArgs( - ethers.utils.parseUnits("90800", "gwei"), - refundee.address - ) + .withArgs(ethers.parseUnits("90800", "gwei"), refundee.address) }) }) }) @@ -392,7 +367,7 @@ describe("ReimbursementPool", () => { await expect( reimbursementPool .connect(thirdParty) - .authorize(thirdPartyContract.address) + .authorize(thirdPartyContract.address), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -431,7 +406,7 @@ describe("ReimbursementPool", () => { await expect( reimbursementPool .connect(thirdParty) - .unauthorize(thirdPartyContract.address) + .unauthorize(thirdPartyContract.address), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -456,7 +431,7 @@ describe("ReimbursementPool", () => { context("when the caller is not the owner", () => { it("should revert", async () => { await expect( - reimbursementPool.connect(thirdParty).setStaticGas(42) + reimbursementPool.connect(thirdParty).setStaticGas(42), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -464,7 +439,7 @@ describe("ReimbursementPool", () => { context("when the caller is the owner", () => { it("should set the static gas cost", async () => { expect(await reimbursementPool.staticGas()).to.be.equal( - params.reimbursementPoolStaticGas + params.reimbursementPoolStaticGas, ) const tx = await reimbursementPool.connect(owner).setStaticGas(42000) @@ -482,7 +457,7 @@ describe("ReimbursementPool", () => { context("when the caller is not the owner", () => { it("should revert", async () => { await expect( - reimbursementPool.connect(thirdParty).setMaxGasPrice(42) + reimbursementPool.connect(thirdParty).setMaxGasPrice(42), ).to.be.revertedWith("Ownable: caller is not the owner") }) }) @@ -490,9 +465,9 @@ describe("ReimbursementPool", () => { context("when the caller is the owner", () => { it("should set the max gas price", async () => { expect(await reimbursementPool.maxGasPrice()).to.be.equal( - params.reimbursementPoolMaxGasPrice + params.reimbursementPoolMaxGasPrice, ) - const newMaxGasPrice = ethers.utils.parseUnits("21", "gwei") + const newMaxGasPrice = ethers.parseUnits("21", "gwei") const tx = await reimbursementPool .connect(owner) @@ -503,7 +478,7 @@ describe("ReimbursementPool", () => { .withArgs(newMaxGasPrice) expect(await reimbursementPool.maxGasPrice()).to.be.equal( - newMaxGasPrice + newMaxGasPrice, ) }) }) diff --git a/solidity/random-beacon/test/behaviors/authorization.ts b/solidity/random-beacon/test/behaviors/authorization.ts new file mode 100644 index 0000000000..0278a403bb --- /dev/null +++ b/solidity/random-beacon/test/behaviors/authorization.ts @@ -0,0 +1,41 @@ +import { expect } from "chai" + +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" +import type { RandomBeacon } from "../../typechain" + +const MAX_UINT64 = BigInt("18446744073709551615") // 2^64 - 1 + +export interface OverwritePreviousRequestContext { + randomBeacon: RandomBeacon + stakingProvider: SignerWithAddress + deauthorizingSecond: bigint +} + +export interface RequireUpdatingPoolContext { + randomBeacon: RandomBeacon + stakingProvider: SignerWithAddress +} + +export function shouldOverwritePreviousRequest( + getContext: () => OverwritePreviousRequestContext, +): void { + it("should overwrite the previous request", async () => { + const { randomBeacon, stakingProvider, deauthorizingSecond } = getContext() + expect( + await randomBeacon.pendingAuthorizationDecrease(stakingProvider.address), + ).to.be.equal(deauthorizingSecond) + }) +} + +export function shouldRequireUpdatingPoolBeforeApproving( + getContext: () => RequireUpdatingPoolContext, +): void { + it("should require updating the pool before approving", async () => { + const { randomBeacon, stakingProvider } = getContext() + expect( + await randomBeacon.remainingAuthorizationDecreaseDelay( + stakingProvider.address, + ), + ).to.equal(MAX_UINT64) + }) +} diff --git a/solidity/random-beacon/test/fixtures/index.ts b/solidity/random-beacon/test/fixtures/index.ts index 8872d8c9db..04f9276117 100644 --- a/solidity/random-beacon/test/fixtures/index.ts +++ b/solidity/random-beacon/test/fixtures/index.ts @@ -1,7 +1,7 @@ import { ethers, helpers, deployments } from "hardhat" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" -import type { Contract } from "ethers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" +import type { BaseContract } from "ethers" import type { SortitionPool, BeaconDkgValidator as DKGValidator, @@ -52,7 +52,7 @@ export const params = { authorizationDecreaseDelay: 403_200, authorizationDecreaseChangePeriod: 403_200, reimbursementPoolStaticGas: 40_800, - reimbursementPoolMaxGasPrice: ethers.utils.parseUnits("500", "gwei"), + reimbursementPoolMaxGasPrice: ethers.parseUnits("500", "gwei"), dkgResultSubmissionGas: 237_650, dkgResultApprovalGasOffset: 41_500, notifyOperatorInactivityGasOffset: 54_500, @@ -60,13 +60,13 @@ export const params = { } export interface DeployedContracts { - [key: string]: Contract + [key: string]: BaseContract } export async function blsDeployment(): Promise { const BLS = await ethers.getContractFactory("BLS") const bls = await BLS.deploy() - await bls.deployed() + await bls.waitForDeployment() const contracts: DeployedContracts = { bls } @@ -83,7 +83,7 @@ export async function randomBeaconDeployment(): Promise { const { deployer, chaosnetOwner } = await helpers.signers.getNamedSigners() const sortitionPool: SortitionPool = await helpers.contracts.getContract( - "BeaconSortitionPool" + "BeaconSortitionPool", ) const randomBeaconGovernance: RandomBeaconGovernance = await helpers.contracts.getContract("RandomBeaconGovernance") @@ -92,13 +92,12 @@ export async function randomBeaconDeployment(): Promise { await helpers.contracts.getContract("ReimbursementPool") await deployer.sendTransaction({ - to: reimbursementPool.address, - value: ethers.utils.parseEther("100.0"), // Send 100.0 ETH + to: await reimbursementPool.getAddress(), + value: ethers.parseEther("100.0"), }) - const randomBeacon: RandomBeaconStub = await helpers.contracts.getContract( - "RandomBeacon" - ) + const randomBeacon: RandomBeaconStub = + await helpers.contracts.getContract("RandomBeacon") await updateTokenStakingParams(t, staking, deployer) await setFixtureParameters(randomBeacon) @@ -120,12 +119,14 @@ export async function randomBeaconDeployment(): Promise { async function updateTokenStakingParams( t: T, staking: TokenStaking, - deployer: SignerWithAddress + deployer: SignerWithAddress, ) { // initialNotifierTreasury should be configured high enough to execute all the // slashing in test suites. const initialNotifierTreasury = to1e18(9_000_000) // 9MM T - await t.connect(deployer).approve(staking.address, initialNotifierTreasury) + await t + .connect(deployer) + .approve(await staking.getAddress(), initialNotifierTreasury) // Compatibility: Threshold TokenStaking variant may not expose these methods. const stakingAsRecord = staking.connect(deployer) as unknown as Record< @@ -133,12 +134,12 @@ async function updateTokenStakingParams( (...args: unknown[]) => Promise > - if (typeof stakingAsRecord.pushNotificationReward === "function") { + if (staking.interface.getFunction("pushNotificationReward") !== null) { await stakingAsRecord.pushNotificationReward(initialNotifierTreasury) } - if (typeof stakingAsRecord.setNotificationReward === "function") { + if (staking.interface.getFunction("setNotificationReward") !== null) { await stakingAsRecord.setNotificationReward( - constants.tokenStakingNotificationReward + constants.tokenStakingNotificationReward, ) } } @@ -157,7 +158,7 @@ async function setFixtureParameters(randomBeacon: RandomBeaconStub) { await randomBeaconGovernance .connect(governance) .beginAuthorizationDecreaseChangePeriodUpdate( - params.authorizationDecreaseChangePeriod + params.authorizationDecreaseChangePeriod, ) await randomBeaconGovernance @@ -173,22 +174,22 @@ async function setFixtureParameters(randomBeacon: RandomBeaconStub) { await randomBeaconGovernance .connect(governance) .beginSortitionPoolRewardsBanDurationUpdate( - params.sortitionPoolRewardsBanDuration + params.sortitionPoolRewardsBanDuration, ) await randomBeaconGovernance .connect(governance) .beginRelayEntryTimeoutNotificationRewardMultiplierUpdate( - params.relayEntryTimeoutNotificationRewardMultiplier + params.relayEntryTimeoutNotificationRewardMultiplier, ) await randomBeaconGovernance .connect(governance) .beginUnauthorizedSigningNotificationRewardMultiplierUpdate( - params.unauthorizedSigningNotificationRewardMultiplier + params.unauthorizedSigningNotificationRewardMultiplier, ) await randomBeaconGovernance .connect(governance) .beginDkgMaliciousResultNotificationRewardMultiplierUpdate( - params.dkgMaliciousResultNotificationRewardMultiplier + params.dkgMaliciousResultNotificationRewardMultiplier, ) await randomBeaconGovernance @@ -200,7 +201,7 @@ async function setFixtureParameters(randomBeacon: RandomBeaconStub) { await randomBeaconGovernance .connect(governance) .beginDkgResultChallengePeriodLengthUpdate( - params.dkgResultChallengePeriodLength + params.dkgResultChallengePeriodLength, ) await randomBeaconGovernance .connect(governance) @@ -208,23 +209,23 @@ async function setFixtureParameters(randomBeacon: RandomBeaconStub) { await randomBeaconGovernance .connect(governance) .beginDkgSubmitterPrecedencePeriodLengthUpdate( - params.dkgSubmitterPrecedencePeriodLength + params.dkgSubmitterPrecedencePeriodLength, ) await randomBeaconGovernance .connect(governance) .beginRelayEntrySubmissionFailureSlashingAmountUpdate( - params.relayEntrySubmissionFailureSlashingAmount + params.relayEntrySubmissionFailureSlashingAmount, ) await randomBeaconGovernance .connect(governance) .beginMaliciousDkgResultSlashingAmountUpdate( - params.maliciousDkgResultSlashingAmount + params.maliciousDkgResultSlashingAmount, ) await randomBeaconGovernance .connect(governance) .beginUnauthorizedSigningSlashingAmountUpdate( - params.unauthorizedSigningSlashingAmount + params.unauthorizedSigningSlashingAmount, ) await helpers.time.increaseTime(params.governanceDelay) diff --git a/solidity/random-beacon/test/helpers/chain.ts b/solidity/random-beacon/test/helpers/chain.ts new file mode 100644 index 0000000000..4c71d8e6e4 --- /dev/null +++ b/solidity/random-beacon/test/helpers/chain.ts @@ -0,0 +1,5 @@ +/** Fail explicitly when a local test's block or mined receipt is unavailable. */ +export default function requireResult(result: T | null): T { + if (result === null) throw new Error("Expected a non-null chain response") + return result +} diff --git a/solidity/random-beacon/test/helpers/mock.test.ts b/solidity/random-beacon/test/helpers/mock.test.ts index 8e3700fb72..4066c9d8d5 100644 --- a/solidity/random-beacon/test/helpers/mock.test.ts +++ b/solidity/random-beacon/test/helpers/mock.test.ts @@ -1,6 +1,7 @@ import { ethers } from "hardhat" import { expect } from "chai" +import requireResult from "./chain" import { createMock, expectCalledWith } from "./mock" import type { Mock } from "./mock" @@ -15,7 +16,7 @@ describe("MockContract", () => { const factory = await ethers.getContractFactory("MockTargetConsumer") consumer = (await factory.deploy(target.address)) as MockTargetConsumer - await consumer.deployed() + await consumer.waitForDeployment() }) describe("view functions reached by STATICCALL", () => { @@ -92,9 +93,9 @@ describe("MockContract", () => { it("reverts every call to the function", async () => { await target.doThing.reverts("nope") - await expect( - consumer.doThing(ethers.constants.AddressZero, 1) - ).to.be.revertedWith("nope") + await expect(consumer.doThing(ethers.ZeroAddress, 1)).to.be.revertedWith( + "nope", + ) }) it("reverts only the matching arguments", async () => { @@ -150,7 +151,7 @@ describe("MockContract", () => { it("counts each function separately", async () => { await target.doThing.returns(true) - await consumer.doThing(ethers.constants.AddressZero, 1) + await consumer.doThing(ethers.ZeroAddress, 1) await consumer.noReturn(1) expect(await target.doThing.callCount()).to.equal(1) @@ -161,13 +162,13 @@ describe("MockContract", () => { describe("reset", () => { it("clears recorded calls and configured responses for one function", async () => { await target.doThing.returns(true) - await consumer.doThing(ethers.constants.AddressZero, 1) + await consumer.doThing(ethers.ZeroAddress, 1) await target.doThing.reset() expect(await target.doThing.callCount()).to.equal(0) // The configured `true` is gone, so the call answers with empty data. - await consumer.doThing(ethers.constants.AddressZero, 1) + await consumer.doThing(ethers.ZeroAddress, 1) expect(await consumer.lastResult()).to.equal(false) }) @@ -215,10 +216,10 @@ describe("MockContract", () => { // `msg.sender == someContract`. const factory = await ethers.getContractFactory("MockTargetConsumer") const other = await factory.deploy(target.address) - await other.deployed() + await other.waitForDeployment() const tx = await other.connect(target.wallet).noReturn(1) - const receipt = await tx.wait() + const receipt = requireResult(await tx.wait()) expect(receipt.from).to.equal(target.address) }) @@ -226,9 +227,7 @@ describe("MockContract", () => { describe("address option", () => { it("deploys at a requested address", async () => { - const address = ethers.utils.getAddress( - `0x${"ab".repeat(20)}`.toLowerCase() - ) + const address = ethers.getAddress(`0x${"ab".repeat(20)}`.toLowerCase()) const pinned = await createMock("IMockTarget", { address }) @@ -237,7 +236,7 @@ describe("MockContract", () => { const factory = await ethers.getContractFactory("MockTargetConsumer") const pinnedConsumer = await factory.deploy(address) - await pinnedConsumer.deployed() + await pinnedConsumer.waitForDeployment() expect(await pinnedConsumer.readValueThroughStaticCall(1)).to.equal(7) }) @@ -250,7 +249,7 @@ describe("MockContract", () => { // real ecdsaWalletRegistry and relay. `hardhat_setCode` replaces the code // and leaves the storage, so a mock keeping its state at slots 0, 1, 2... // would read that leftover as its own. - const address = ethers.utils.getAddress(`0x${"cd".repeat(20)}`) + const address = ethers.getAddress(`0x${"cd".repeat(20)}`) const garbage = "0xdeadbeef00000000000000000000000000000000000000000000000000000001" @@ -258,10 +257,10 @@ describe("MockContract", () => { Array.from({ length: 8 }, (_, slot) => ethers.provider.send("hardhat_setStorageAt", [ address, - ethers.utils.hexValue(slot), + ethers.toQuantity(slot), garbage, - ]) - ) + ]), + ), ) const pinned = await createMock("IMockTarget", { address }) @@ -272,7 +271,7 @@ describe("MockContract", () => { const factory = await ethers.getContractFactory("MockTargetConsumer") const pinnedConsumer = await factory.deploy(address) - await pinnedConsumer.deployed() + await pinnedConsumer.waitForDeployment() expect(await pinnedConsumer.readValueThroughStaticCall(1)).to.equal(7) }) diff --git a/solidity/random-beacon/test/helpers/mock.ts b/solidity/random-beacon/test/helpers/mock.ts index ec2e8d75eb..2bd11a450b 100644 --- a/solidity/random-beacon/test/helpers/mock.ts +++ b/solidity/random-beacon/test/helpers/mock.ts @@ -7,10 +7,18 @@ /* eslint-disable no-underscore-dangle */ import { ethers, artifacts } from "hardhat" import { expect } from "chai" -import { BigNumber } from "ethers" -import type { BigNumberish, Contract, Signer } from "ethers" -import type { FunctionFragment, Interface, ParamType } from "ethers/lib/utils" +import requireResult from "./chain" + +import type { + BaseContract, + BigNumberish, + Signer, + FunctionFragment, + Interface, + ParamType, +} from "ethers" +import type { MockContract } from "../../typechain" /** * Programmable contract mock, replacing `@defi-wonderland/smock`. @@ -57,7 +65,8 @@ import type { FunctionFragment, Interface, ParamType } from "ethers/lib/utils" * the machine happens to be. */ async function withoutAdvancingTime(write: () => Promise): Promise { - const { timestamp } = await ethers.provider.getBlock("latest") + const block = requireResult(await ethers.provider.getBlock("latest")) + const { timestamp } = block await ethers.provider.send("evm_setNextBlockTimestamp", [timestamp]) return write() } @@ -67,7 +76,7 @@ export interface MockCall { /** Decoded arguments, in declaration order. */ args: unknown[] /** `msg.value` the call carried, as smock's `getCall(n).value` did. */ - value: BigNumber + value: bigint } /** Configuration and inspection handle for one function of a mock. */ @@ -95,8 +104,10 @@ export interface MockedFunction { getCalls(): Promise } -export type Mock = { - [K in keyof T]: T[K] extends (...args: never[]) => unknown +export type Mock = { + [K in keyof Omit]: T[K] extends ( + ...args: never[] + ) => unknown ? T[K] & MockedFunction : T[K] } & { @@ -104,14 +115,14 @@ export type Mock = { /** Signer that sends from the mock's own address, as smock's `fake.wallet` did. */ wallet: Signer /** Underlying deployed `MockContract`, for anything this helper does not wrap. */ - mockContract: Contract + mockContract: MockContract /** * The mocked interface bound to `signer`, as smock's `FakeContract.connect` * was. smock's fake extended `ethers.Contract` and inherited this; the proxy * here resolves only the mocked ABI and the keys above, so without it * `mock.connect(someone)` is `undefined`. */ - connect(signer: Signer): Contract + connect(signer: Signer): T /** Drops all configured responses and all recorded calls. */ reset(): Promise /** @@ -125,11 +136,17 @@ export type Mock = { } /** Selectors of `MockContract`'s own administrative entry points. */ +function functionFragments(iface: Interface): FunctionFragment[] { + const fragments: FunctionFragment[] = [] + iface.forEachFunction((fragment) => fragments.push(fragment)) + return fragments +} + function adminSelectors(mockInterface: Interface): Set { return new Set( - Object.keys(mockInterface.functions) - .filter((signature) => signature.startsWith("__mock__")) - .map((signature) => mockInterface.getSighash(signature)) + functionFragments(mockInterface) + .filter((fragment) => fragment.name.startsWith("__mock__")) + .map((fragment) => fragment.selector), ) } @@ -143,17 +160,18 @@ function adminSelectors(mockInterface: Interface): Set { function assertNoSelectorCollision( target: Interface, mockInterface: Interface, - targetName: string + targetName: string, ): void { const reserved = adminSelectors(mockInterface) - Object.keys(target.functions).forEach((signature) => { - const selector = target.getSighash(signature) + functionFragments(target).forEach((fragment) => { + const signature = fragment.format() + const { selector } = fragment if (reserved.has(selector)) { throw new Error( `${targetName}.${signature} has selector ${selector}, which collides ` + "with a MockContract administrative function. This mock cannot " + - "represent that interface." + "represent that interface.", ) } }) @@ -162,7 +180,7 @@ function assertNoSelectorCollision( function fragmentsByName(target: Interface): Map { const byName = new Map() - Object.values(target.functions).forEach((fragment) => { + functionFragments(target).forEach((fragment) => { const existing = byName.get(fragment.name) if (existing) { existing.push(fragment) @@ -182,12 +200,12 @@ function fragmentsByName(target: Interface): Map { function resolveFragment( fragments: FunctionFragment[], name: string, - targetName: string + targetName: string, ): FunctionFragment { if (fragments.length > 1) { throw new Error( `${targetName}.${name} is overloaded (${fragments.length} signatures). ` + - "Address it through the mock's mockContract handle instead." + "Address it through the mock's mockContract handle instead.", ) } @@ -202,21 +220,21 @@ function resolveFragment( * layout. */ function zeroValueFor(type: ParamType): unknown { - if (type.baseType === "array") { + if (type.isArray()) { if (type.arrayLength === -1) { return [] } return Array.from({ length: type.arrayLength }, () => - zeroValueFor(type.arrayChildren) + zeroValueFor(type.arrayChildren), ) } - if (type.baseType === "tuple") { + if (type.isTuple()) { return type.components.map((component) => zeroValueFor(component)) } if (type.baseType === "address") { - return ethers.constants.AddressZero + return ethers.ZeroAddress } if (type.baseType === "bool") { @@ -249,7 +267,10 @@ function zeroValueFor(type: ParamType): unknown { * those positionally, so they are mapped back by output name. A single-output * function is different: an object there is a struct, and the coder handles it. */ -function toPositional(outputs: ParamType[], value: unknown): unknown[] { +function toPositional( + outputs: readonly ParamType[], + value: unknown, +): unknown[] { if (outputs.length === 1) { return [value] } @@ -261,7 +282,7 @@ function toPositional(outputs: ParamType[], value: unknown): unknown[] { if (value !== null && typeof value === "object") { const named = value as Record return outputs.map((output, index) => - output.name && output.name in named ? named[output.name] : named[index] + output.name && output.name in named ? named[output.name] : named[index], ) } @@ -269,13 +290,13 @@ function toPositional(outputs: ParamType[], value: unknown): unknown[] { } function encodeReturn(fragment: FunctionFragment, value: unknown): string { - if (fragment.outputs === null || fragment.outputs.length === 0) { + if (fragment.outputs == null || fragment.outputs.length === 0) { return "0x" } - return ethers.utils.defaultAbiCoder.encode( + return ethers.AbiCoder.defaultAbiCoder().encode( fragment.outputs, - toPositional(fragment.outputs, value) + toPositional(fragment.outputs, value), ) } @@ -285,8 +306,8 @@ function encodeRevert(reason?: string): string { } return ( - ethers.utils.id("Error(string)").slice(0, 10) + - ethers.utils.defaultAbiCoder.encode(["string"], [reason]).slice(2) + ethers.id("Error(string)").slice(0, 10) + + ethers.AbiCoder.defaultAbiCoder().encode(["string"], [reason]).slice(2) ) } @@ -300,18 +321,20 @@ function encodeRevert(reason?: string): string { * @returns A handle exposing each of `target`'s functions with `returns`, * `whenCalledWith`, `reverts`, `reset`, `callCount` and `getCall`. */ -export async function createMock( +export async function createMock( target: string, - options: { address?: string } = {} + options: { address?: string } = {}, ): Promise> { const targetArtifact = await artifacts.readArtifact(target) - const targetInterface = new ethers.utils.Interface(targetArtifact.abi) + const targetInterface = new ethers.Interface(targetArtifact.abi) const mockFactory = await ethers.getContractFactory("MockContract") // Deploying is a transaction too, and a mock is routinely created inside a // `before` hook after the test has already captured a baseline timestamp. - let mockContract = await withoutAdvancingTime(() => mockFactory.deploy()) - await mockContract.deployed() + let mockContract: MockContract = await withoutAdvancingTime(() => + mockFactory.deploy(), + ) + await mockContract.waitForDeployment() assertNoSelectorCollision(targetInterface, mockContract.interface, target) @@ -321,27 +344,25 @@ export async function createMock( // configuration below — the base returns, the non-recording flags, and // later every `returns`/`whenCalledWith` — is storage. Configuring first // and relocating afterwards left a pinned mock with none of it. - const code = await ethers.provider.getCode(mockContract.address) + const code = await ethers.provider.getCode(await mockContract.getAddress()) await ethers.provider.send("hardhat_setCode", [options.address, code]) - mockContract = mockContract.attach(options.address) + mockContract = await ethers.getContractAt("MockContract", options.address) } // Install the response of last resort for every function, so an unstubbed // one answers with a correctly sized zero instead of reverting the caller. - const baseFragments = Object.values(targetInterface.functions) - const baseSelectors = baseFragments.map((fragment) => - targetInterface.getSighash(fragment) - ) + const baseFragments = functionFragments(targetInterface) + const baseSelectors = baseFragments.map((fragment) => fragment.selector) const baseReturns = baseFragments.map((fragment) => - fragment.outputs === null || fragment.outputs.length === 0 + fragment.outputs == null || fragment.outputs.length === 0 ? "0x" - : ethers.utils.defaultAbiCoder.encode( + : ethers.AbiCoder.defaultAbiCoder().encode( fragment.outputs, - fragment.outputs.map((output) => zeroValueFor(output)) - ) + fragment.outputs.map((output) => zeroValueFor(output)), + ), ) await withoutAdvancingTime(() => - mockContract.__mock__setBaseReturns(baseSelectors, baseReturns) + mockContract.__mock__setBaseReturns(baseSelectors, baseReturns), ) // Flag the read-only functions. Solidity reaches them by STATICCALL, where @@ -352,29 +373,28 @@ export async function createMock( .filter( (fragment) => fragment.stateMutability === "view" || - fragment.stateMutability === "pure" + fragment.stateMutability === "pure", ) - .map((fragment) => targetInterface.getSighash(fragment)) + .map((fragment) => fragment.selector) if (nonRecordingSelectors.length > 0) { await withoutAdvancingTime(() => - mockContract.__mock__setNonRecordingSelectors(nonRecordingSelectors) + mockContract.__mock__setNonRecordingSelectors(nonRecordingSelectors), ) } - await ethers.provider.send("hardhat_impersonateAccount", [ - mockContract.address, - ]) + const address = await mockContract.getAddress() + await ethers.provider.send("hardhat_impersonateAccount", [address]) await ethers.provider.send("hardhat_setBalance", [ - mockContract.address, + address, "0x21e19e0c9bab2400000", // 10_000 ETH, so the mock can pay for its own sends ]) - const wallet = await ethers.getSigner(mockContract.address) + const wallet = await ethers.getSigner(address) const byName = fragmentsByName(targetInterface) function buildFunction(name: string): MockedFunction { const fragment = resolveFragment(byName.get(name) ?? [], name, target) - const selector = targetInterface.getSighash(fragment) + const { selector } = fragment const readOnly = fragment.stateMutability === "view" || fragment.stateMutability === "pure" @@ -386,7 +406,7 @@ export async function createMock( `${target}.${name} is ${fragment.stateMutability}, so Solidity ` + "reaches it by STATICCALL and the mock cannot record the call. " + "Assert on the state-changing function that consumed the value " + - "instead." + "instead.", ) } } @@ -394,7 +414,7 @@ export async function createMock( const setForCalldata = async ( args: unknown[], behaviour: "return" | "revert", - payload: unknown + payload: unknown, ): Promise => { let callData: string try { @@ -415,7 +435,7 @@ export async function createMock( console.warn( `mock: ${target}.${name} whenCalledWith(...) arguments cannot be ` + "encoded for this signature, so the entry can never match and " + - `is being skipped: ${(error as Error).message.split("(")[0].trim()}` + `is being skipped: ${(error as Error).message.split("(")[0].trim()}`, ) return } @@ -424,18 +444,18 @@ export async function createMock( behaviour === "return" ? mockContract.__mock__setReturnForCalldata( callData, - encodeReturn(fragment, payload) + encodeReturn(fragment, payload), ) : mockContract.__mock__setRevertForCalldata( callData, - encodeRevert(payload as string | undefined) - ) + encodeRevert(payload as string | undefined), + ), ) } - const decodeCall = (callData: string, value: BigNumber): MockCall => ({ + const decodeCall = (callData: string, value: bigint): MockCall => ({ args: Array.from( - targetInterface.decodeFunctionData(fragment, callData) + targetInterface.decodeFunctionData(fragment, callData), ) as unknown[], value, }) @@ -445,8 +465,8 @@ export async function createMock( await withoutAdvancingTime(() => mockContract.__mock__setReturnForSelector( selector, - encodeReturn(fragment, value) - ) + encodeReturn(fragment, value), + ), ) }, @@ -454,8 +474,8 @@ export async function createMock( await withoutAdvancingTime(() => mockContract.__mock__setRevertForSelector( selector, - encodeRevert(reason) - ) + encodeRevert(reason), + ), ) }, @@ -468,7 +488,7 @@ export async function createMock( async reset(): Promise { await withoutAdvancingTime(() => - mockContract.__mock__resetSelector(selector) + mockContract.__mock__resetSelector(selector), ) }, @@ -487,7 +507,7 @@ export async function createMock( mockContract.__mock__callForSelectorAt(selector, index), mockContract.__mock__callValueForSelectorAt(selector, index), ]) - return decodeCall(callData as string, value as BigNumber) + return decodeCall(callData as string, value as bigint) }, async getCalls(): Promise { @@ -499,12 +519,12 @@ export async function createMock( for (let i = 0; i < Number(count); i++) { // Sequential on purpose: ordering is the point of this accessor. - // eslint-disable-next-line no-await-in-loop + const [callData, value] = await Promise.all([ mockContract.__mock__callForSelectorAt(selector, i), mockContract.__mock__callValueForSelectorAt(selector, i), ]) - calls.push(decodeCall(callData as string, value as BigNumber)) + calls.push(decodeCall(callData as string, value as bigint)) } return calls @@ -514,28 +534,28 @@ export async function createMock( const functions = new Map() const readContract = new ethers.Contract( - mockContract.address, + address, targetArtifact.abi, - ethers.provider + ethers.provider, ) const handle = { - address: mockContract.address, + address, wallet, mockContract, - connect(signer: Signer): Contract { + connect(signer: Signer): T { return new ethers.Contract( - mockContract.address, + address, targetArtifact.abi, - signer - ) + signer, + ) as unknown as T }, async reset(): Promise { await withoutAdvancingTime(() => mockContract.__mock__reset()) }, async setRecording(enabled: boolean): Promise { await withoutAdvancingTime(() => - mockContract.__mock__setRecording(enabled) + mockContract.__mock__setRecording(enabled), ) }, } @@ -557,7 +577,7 @@ export async function createMock( const callable = (...args: unknown[]) => readContract[property](...args) functions.set( property, - Object.assign(callable, buildFunction(property)) as MockedFunction + Object.assign(callable, buildFunction(property)) as MockedFunction, ) } @@ -585,7 +605,7 @@ async function counted(fn: MockedFunction): Promise { export async function expectCalled(fn: MockedFunction): Promise { const count = await counted(fn) expect(count, "expected the function to have been called").to.be.greaterThan( - 0 + 0, ) } @@ -613,13 +633,9 @@ export async function expectCalledTwice(fn: MockedFunction): Promise { /** * Puts one recorded or expected argument into a comparable form. * - * The two sides never arrive in the same representation. ethers decodes an ABI - * integer to a `BigNumber` above 48 bits and to a plain `number` at or below - * it, so a `uint256` argument reaches this as a `BigNumber` while the - * `uint32` getter the test compared it against yields a `number`; and a struct - * or dynamic array puts both one level down, where the previous top-level-only - * check never looked. smock compared `BigNumberish` values numerically at any - * depth, so both shapes used to pass. + * ethers v6 decodes every ABI integer as a bigint, while test expectations + * can contain ordinary numbers. Arrays and structs can nest those values, + * so numeric comparison is normalized recursively. * * Numerics are wrapped rather than rendered bare, so that a genuine string * argument of `"100"` still fails against a numeric `100`. Everything else — @@ -628,9 +644,6 @@ export async function expectCalledTwice(fn: MockedFunction): Promise { * real mismatch. */ function normalizeForComparison(value: unknown): unknown { - if (BigNumber.isBigNumber(value)) { - return { numeric: value.toString() } - } if (typeof value === "number" || typeof value === "bigint") { return { numeric: value.toString() } } @@ -642,7 +655,7 @@ function normalizeForComparison(value: unknown): unknown { export async function expectCalledOnceWith( fn: MockedFunction, - args: unknown[] + args: unknown[], ): Promise { expect(await counted(fn), "expected exactly one call").to.equal(1) @@ -652,7 +665,7 @@ export async function expectCalledOnceWith( args.forEach((expected, index) => { const actual = call.args[index] expect(normalizeForComparison(actual), `argument ${index}`).to.deep.equal( - normalizeForComparison(expected) + normalizeForComparison(expected), ) }) } @@ -666,7 +679,7 @@ export async function expectCalledOnceWith( */ export async function expectCalledWith( fn: MockedFunction, - args: unknown[] + args: unknown[], ): Promise { const calls = await fn.getCalls() @@ -677,7 +690,7 @@ export async function expectCalledWith( expect( seen, - `expected a call with ${calls.length} recorded, none matching` + `expected a call with ${calls.length} recorded, none matching`, ).to.deep.include(wanted) } diff --git a/solidity/random-beacon/test/mocks/staking.ts b/solidity/random-beacon/test/mocks/staking.ts index 8475883d16..e1ff72d4a3 100644 --- a/solidity/random-beacon/test/mocks/staking.ts +++ b/solidity/random-beacon/test/mocks/staking.ts @@ -5,10 +5,10 @@ import type { RandomBeacon, TokenStaking } from "../../typechain" // eslint-disable-next-line import/prefer-default-export export async function fakeTokenStaking( - randomBeacon: RandomBeacon + randomBeacon: RandomBeacon, ): Promise> { const tokenStaking = await createMock("TokenStaking", { - address: await randomBeacon.callStatic.staking(), + address: await randomBeacon.staking.staticCall(), }) return tokenStaking diff --git a/solidity/random-beacon/test/system/e2e.test.ts b/solidity/random-beacon/test/system/e2e.test.ts index 127c5dcf45..39b905141a 100644 --- a/solidity/random-beacon/test/system/e2e.test.ts +++ b/solidity/random-beacon/test/system/e2e.test.ts @@ -1,6 +1,8 @@ -import { ethers, waffle, helpers } from "hardhat" +import { ethers, helpers } from "hardhat" +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" import { expect } from "chai" +import requireResult from "../helpers/chain" import { constants, dkgState, @@ -15,7 +17,7 @@ import { import blsData from "../data/bls" import { registerOperators } from "../utils/operators" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" import type { RandomBeacon, RandomBeaconStub, @@ -23,10 +25,10 @@ import type { RandomBeaconGovernance, } from "../../typechain" -const ZERO_ADDRESS = ethers.constants.AddressZero +const ZERO_ADDRESS = ethers.ZeroAddress const { mineBlocks, mineBlocksTo } = helpers.time -const { keccak256 } = ethers.utils +const { keccak256 } = ethers const fixture = async () => { const contracts = await randomBeaconDeployment() @@ -37,7 +39,7 @@ const fixture = async () => { contracts.randomBeacon as RandomBeacon, contracts.t as T, constants.groupSize, - 1 + 1, ) const randomBeacon = contracts.randomBeacon as RandomBeaconStub & RandomBeacon @@ -77,7 +79,7 @@ describe("System -- e2e", () => { let governance: SignerWithAddress before(async () => { - const contracts = await waffle.loadFixture(fixture) + const contracts = await loadFixture(fixture) ;({ governance } = await helpers.signers.getNamedSigners()) ;[requester] = await helpers.signers.getUnnamedSigners() @@ -106,35 +108,39 @@ describe("System -- e2e", () => { it("should create 3 new groups", async () => { expect(await randomBeacon.getGroupCreationState()).to.be.equal( - dkgState.IDLE + dkgState.IDLE, ) const [genesisTx, genesisSeed] = await genesis(randomBeacon) expect(await randomBeacon.getGroupCreationState()).to.be.equal( - dkgState.KEY_GENERATION + dkgState.KEY_GENERATION, ) // pass key generation state and transition to awaiting result state - await mineBlocksTo(genesisTx.blockNumber + constants.offchainDkgTime + 1) + await mineBlocksTo( + requireResult(await genesisTx.wait()).blockNumber + + constants.offchainDkgTime + + 1, + ) expect(await randomBeacon.getGroupCreationState()).to.be.equal( - dkgState.AWAITING_RESULT + dkgState.AWAITING_RESULT, ) let dkgResult = await signAndSubmitCorrectDkgResult( randomBeacon, groupPubKeys[groupPubKeyCounter], genesisSeed, - genesisTx.blockNumber, - noMisbehaved + requireResult(await genesisTx.wait()).blockNumber, + noMisbehaved, ) groupMembers.push(dkgResult.members) await mineBlocks(params.dkgResultChallengePeriodLength) expect(await randomBeacon.getGroupCreationState()).to.be.equal( - dkgState.CHALLENGE + dkgState.CHALLENGE, ) await randomBeacon @@ -152,32 +158,32 @@ describe("System -- e2e", () => { if (i % groupCreationFrequency === 0) { groupPubKeyCounter += 1 expect(await randomBeacon.getGroupCreationState()).to.be.equal( - dkgState.KEY_GENERATION + dkgState.KEY_GENERATION, ) await mineBlocksTo( - txSubmitRelayEntry.blockNumber + constants.offchainDkgTime + 1 + requireResult(await txSubmitRelayEntry.wait()).blockNumber + + constants.offchainDkgTime + + 1, ) expect(await randomBeacon.getGroupCreationState()).to.be.equal( - dkgState.AWAITING_RESULT + dkgState.AWAITING_RESULT, ) dkgResult = await signAndSubmitCorrectDkgResult( randomBeacon, groupPubKeys[groupPubKeyCounter], - ethers.BigNumber.from( - ethers.utils.keccak256(blsData.groupSignatures[i - 1]) - ), - txSubmitRelayEntry.blockNumber, - noMisbehaved + BigInt(ethers.keccak256(blsData.groupSignatures[i - 1])), + requireResult(await txSubmitRelayEntry.wait()).blockNumber, + noMisbehaved, ) groupMembers.push(dkgResult.members) await mineBlocks(params.dkgResultChallengePeriodLength) expect(await randomBeacon.getGroupCreationState()).to.be.equal( - dkgState.CHALLENGE + dkgState.CHALLENGE, ) await randomBeacon @@ -185,7 +191,7 @@ describe("System -- e2e", () => { .approveDkgResult(dkgResult.dkgResult) expect(await randomBeacon.getGroupCreationState()).to.be.equal( - dkgState.IDLE + dkgState.IDLE, ) } } diff --git a/solidity/random-beacon/test/tasks/initialize.test.ts b/solidity/random-beacon/test/tasks/initialize.test.ts new file mode 100644 index 0000000000..4381e75428 --- /dev/null +++ b/solidity/random-beacon/test/tasks/initialize.test.ts @@ -0,0 +1,92 @@ +import hre, { deployments, ethers, helpers } from "hardhat" +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" +import { expect } from "chai" + +import type { RandomBeacon, TokenStaking, T } from "../../typechain" + +async function initializedOperator() { + await deployments.fixture() + const [owner, provider, operator] = (await ethers.getSigners()).slice(10) + const args = { + owner: owner.address, + provider: provider.address, + operator: operator.address, + amount: 1_000_000, + authorization: 500_000, + } + await hre.run("initialize", args) + return { + args, + staking: await helpers.contracts.getContract("TokenStaking"), + beacon: await helpers.contracts.getContract("RandomBeacon"), + token: await helpers.contracts.getContract("T"), + } +} + +async function operatorWithDefaultAuthorization() { + await deployments.fixture() + const [owner, provider, operator] = (await ethers.getSigners()).slice(10) + const args = { + owner: owner.address, + provider: provider.address, + operator: operator.address, + amount: 1_000_000, + } + await hre.run("initialize", args) + return { + args, + staking: await helpers.contracts.getContract("TokenStaking"), + beacon: await helpers.contracts.getContract("RandomBeacon"), + } +} + +describe("Initialization tasks", () => { + it("mints, stakes, authorizes and registers an operator", async () => { + const { args, staking, beacon, token } = + await loadFixture(initializedOperator) + expect((await staking.stakes(args.provider)).tStake).to.equal( + ethers.parseEther("1000000"), + ) + expect( + await staking.authorizedStake(args.provider, await beacon.getAddress()), + ).to.equal(ethers.parseEther("500000")) + expect(await beacon.operatorToStakingProvider(args.operator)).to.equal( + args.provider, + ) + expect(await token.balanceOf(args.owner)).to.equal(0n) + }) + + it("does not send another transaction when stake and registration already match", async () => { + const { args } = await loadFixture(initializedOperator) + const before = await ethers.provider.getBlockNumber() + await hre.run("initialize:staking", args) + await hre.run("authorize:beacon", args) + await hre.run("register:beacon", args) + // Re-run the full initialize task, exercising add_beta_operator too. + await hre.run("initialize", args) + expect(await ethers.provider.getBlockNumber()).to.equal(before) + }) + + it("tops up an existing stake and increases authorization", async () => { + const { args, staking, beacon, token } = + await loadFixture(initializedOperator) + await hre.run("initialize:staking", { ...args, amount: 1_200_000 }) + await hre.run("authorize:beacon", { ...args, authorization: 700_000 }) + expect((await staking.stakes(args.provider)).tStake).to.equal( + ethers.parseEther("1200000"), + ) + expect( + await staking.authorizedStake(args.provider, await beacon.getAddress()), + ).to.equal(ethers.parseEther("700000")) + expect(await token.balanceOf(args.owner)).to.equal(0n) + }) + + it("defaults authorization to the beacon's minimumAuthorization", async () => { + const { args, staking, beacon } = await loadFixture( + operatorWithDefaultAuthorization, + ) + expect( + await staking.authorizedStake(args.provider, await beacon.getAddress()), + ).to.equal(await beacon.minimumAuthorization()) + }) +}) diff --git a/solidity/random-beacon/test/utils/dkg.test.ts b/solidity/random-beacon/test/utils/dkg.test.ts index 752949915d..0e85221b09 100644 --- a/solidity/random-beacon/test/utils/dkg.test.ts +++ b/solidity/random-beacon/test/utils/dkg.test.ts @@ -12,8 +12,11 @@ describe("hashDKGMembers", () => { const expectedMembers = members const actualHash = hashDKGMembers(members, misbehavedMembers) - const expectedHash = ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode(["uint32[]"], [expectedMembers]) + const expectedHash = ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( + ["uint32[]"], + [expectedMembers], + ), ) expect(expectedHash).to.be.equal(actualHash) @@ -28,8 +31,11 @@ describe("hashDKGMembers", () => { const expectedMembers = [101, 102, 103, 104, 105, 106, 107, 108, 109] const actualHash = hashDKGMembers(members, misbehavedMembers) - const expectedHash = ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode(["uint32[]"], [expectedMembers]) + const expectedHash = ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( + ["uint32[]"], + [expectedMembers], + ), ) expect(expectedHash).to.be.equal(actualHash) @@ -44,8 +50,11 @@ describe("hashDKGMembers", () => { const expectedMembers = [100, 101, 102, 103, 104, 105, 106, 107, 108] const actualHash = hashDKGMembers(members, misbehavedMembers) - const expectedHash = ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode(["uint32[]"], [expectedMembers]) + const expectedHash = ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( + ["uint32[]"], + [expectedMembers], + ), ) expect(expectedHash).to.be.equal(actualHash) @@ -60,8 +69,11 @@ describe("hashDKGMembers", () => { const expectedMembers = [100, 102, 103, 104, 106, 108, 109] const actualHash = hashDKGMembers(members, misbehavedMembers) - const expectedHash = ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode(["uint32[]"], [expectedMembers]) + const expectedHash = ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( + ["uint32[]"], + [expectedMembers], + ), ) expect(expectedHash).to.be.equal(actualHash) @@ -76,12 +88,15 @@ describe("hashDKGMembers", () => { const expectedMembers = members const actualHash = hashDKGMembers(members, misbehavedMembers) - const expectedHash = ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode(["uint32[]"], [expectedMembers]) + const expectedHash = ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( + ["uint32[]"], + [expectedMembers], + ), ) expect(expectedHash).to.be.equal(actualHash) }) - } + }, ) }) diff --git a/solidity/random-beacon/test/utils/dkg.ts b/solidity/random-beacon/test/utils/dkg.ts index afd7c91c4d..fc736b7972 100644 --- a/solidity/random-beacon/test/utils/dkg.ts +++ b/solidity/random-beacon/test/utils/dkg.ts @@ -1,20 +1,21 @@ -import { ethers, waffle } from "hardhat" +import { ethers } from "hardhat" import { expect } from "chai" -import { BigNumber } from "ethers" + +import requireResult from "../helpers/chain" // eslint-disable-next-line import/no-cycle import { selectGroup } from "./groups" import type { Operator } from "./operators" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" import type { RandomBeacon, SortitionPool } from "../../typechain" -import type { ContractTransaction } from "ethers" +import type { ContractTransactionResponse } from "ethers" import type { BeaconDkg as DKG, DkgResultSubmittedEvent, -} from "../../typechain/BeaconDkg" +} from "../../typechain/contracts/libraries/BeaconDkg" -const { provider } = waffle +const { provider } = ethers // default Hardhat's networks blockchain, see https://hardhat.org/config/ export const hardhatNetworkId = 31337 @@ -22,20 +23,22 @@ export const hardhatNetworkId = 31337 export const noMisbehaved: number[] = [] export async function genesis( - randomBeacon: RandomBeacon -): Promise<[ContractTransaction, BigNumber]> { + randomBeacon: RandomBeacon, +): Promise<[ContractTransactionResponse, bigint]> { const tx = await randomBeacon.genesis() - const expectedSeed = ethers.BigNumber.from( - ethers.utils.keccak256( - ethers.utils.solidityPack( + const receipt = requireResult(await tx.wait()) + + const expectedSeed = BigInt( + ethers.keccak256( + ethers.solidityPacked( ["uint256", "uint256"], [ "31415926535897932384626433832795028841971693993751058209749445923078164062862", - tx.blockNumber, - ] - ) - ) + receipt.blockNumber, + ], + ), + ), ) return [tx, expectedSeed] @@ -47,23 +50,23 @@ export async function genesis( export async function signAndSubmitCorrectDkgResult( randomBeacon: RandomBeacon, groupPublicKey: string, - seed: BigNumber, + seed: bigint, startBlock: number, misbehavedIndices: number[], submitterIndex = 1, membersHash?: string, - numberOfSignatures = 33 + numberOfSignatures = 33, ): Promise<{ - transaction: ContractTransaction + transaction: ContractTransactionResponse dkgResult: DKG.ResultStruct dkgResultHash: string members: number[] submitter: SignerWithAddress - submitterInitialBalance: BigNumber + submitterInitialBalance: bigint }> { const sortitionPool = (await ethers.getContractAt( "SortitionPool", - await randomBeacon.sortitionPool() + await randomBeacon.sortitionPool(), )) as SortitionPool return signAndSubmitArbitraryDkgResult( @@ -74,7 +77,7 @@ export async function signAndSubmitCorrectDkgResult( misbehavedIndices, submitterIndex, membersHash, - numberOfSignatures + numberOfSignatures, ) } @@ -89,14 +92,14 @@ export async function signAndSubmitArbitraryDkgResult( misbehavedIndices: number[], submitterIndex = 1, groupMembersHash?: string, - numberOfSignatures = 33 + numberOfSignatures = 33, ): Promise<{ - transaction: ContractTransaction + transaction: ContractTransactionResponse dkgResult: DKG.ResultStruct dkgResultHash: string members: number[] submitter: SignerWithAddress - submitterInitialBalance: BigNumber + submitterInitialBalance: bigint }> { const { members, signingMembersIndices, signaturesBytes } = await signDkgResult( @@ -104,7 +107,7 @@ export async function signAndSubmitArbitraryDkgResult( groupPublicKey, misbehavedIndices, startBlock, - numberOfSignatures + numberOfSignatures, ) let membersHash = groupMembersHash @@ -122,18 +125,18 @@ export async function signAndSubmitArbitraryDkgResult( membersHash, } - const dkgResultHash = ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode( + const dkgResultHash = ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( [ "(uint256 submitterMemberIndex, bytes groupPubKey, uint8[] misbehavedMembersIndices, bytes signatures, uint256[] signingMembersIndices, uint32[] members, bytes32 membersHash)", ], - [dkgResult] - ) + [dkgResult], + ), ) const submitter = signers[submitterIndex - 1].signer const submitterInitialBalance = await provider.getBalance( - await submitter.getAddress() + await submitter.getAddress(), ) const transaction = await randomBeacon @@ -160,9 +163,9 @@ export async function signAndSubmitUnrecoverableDkgResult( startBlock: number, misbehavedIndices: number[], submitterIndex = 1, - numberOfSignatures = 33 + numberOfSignatures = 33, ): Promise<{ - transaction: ContractTransaction + transaction: ContractTransactionResponse dkgResult: DKG.ResultStruct dkgResultHash: string members: number[] @@ -173,12 +176,12 @@ export async function signAndSubmitUnrecoverableDkgResult( groupPublicKey, misbehavedIndices, startBlock, - numberOfSignatures + numberOfSignatures, ) const signatureHexStrLength = 2 * 65 const unrecoverableSignatures = `0x${"a".repeat( - signatureHexStrLength * numberOfSignatures + signatureHexStrLength * numberOfSignatures, )}` const membersHash = hashDKGMembers(members, misbehavedIndices) @@ -193,13 +196,13 @@ export async function signAndSubmitUnrecoverableDkgResult( membersHash, } - const dkgResultHash = ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode( + const dkgResultHash = ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( [ "(uint256 submitterMemberIndex, bytes groupPubKey, uint8[] misbehavedMembersIndices, bytes signatures, uint256[] signingMembersIndices, uint32[] members, bytes32 membersHash)", ], - [dkgResult] - ) + [dkgResult], + ), ) const submitter = signers[submitterIndex - 1].signer @@ -216,17 +219,17 @@ export async function signDkgResult( groupPublicKey: string, misbehavedMembersIndices: number[], startBlock: number, - numberOfSignatures: number + numberOfSignatures: number, ): Promise<{ members: number[] signingMembersIndices: number[] signaturesBytes: string }> { - const resultHash = ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode( + const resultHash = ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( ["uint256", "bytes", "uint8[]", "uint256"], - [hardhatNetworkId, groupPublicKey, misbehavedMembersIndices, startBlock] - ) + [hardhatNetworkId, groupPublicKey, misbehavedMembersIndices, startBlock], + ), ) const members: number[] = [] @@ -246,13 +249,13 @@ export async function signDkgResult( signingMembersIndices.push(signerIndex) const signature = await ethersSigner.signMessage( - ethers.utils.arrayify(resultHash) + ethers.getBytes(resultHash), ) signatures.push(signature) } - const signaturesBytes: string = ethers.utils.hexConcat(signatures) + const signaturesBytes: string = ethers.concat(signatures) return { members, signingMembersIndices, signaturesBytes } } @@ -260,7 +263,7 @@ export async function signDkgResult( // Creates a members hash that actively participated in dkg export function hashDKGMembers( members: number[], - misbehavedMembersIndices: number[] + misbehavedMembersIndices: number[], ): string { if (misbehavedMembersIndices.length > 0) { const activeDkgMembers = [...members] @@ -270,86 +273,89 @@ export function hashDKGMembers( } } - return ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode(["uint32[]"], [activeDkgMembers]) + return ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( + ["uint32[]"], + [activeDkgMembers], + ), ) } - return ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode(["uint32[]"], [members]) + return ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode(["uint32[]"], [members]), ) } export interface DkgResultSubmittedEventArgs { resultHash: string - seed: BigNumber + seed: bigint result: DKG.ResultStruct } -// This is a workaround for a bug in ethereum-waffle library that doesn't let -// verify events that have an array nested in a struct. -// See: https://github.com/EthWorks/Waffle/issues/245 +// Compare each field explicitly so nested arrays in the result struct produce +// useful assertion failures. export async function expectDkgResultSubmittedEvent( - tx: ContractTransaction, - expectedArgs: DkgResultSubmittedEventArgs + tx: ContractTransactionResponse, + expectedArgs: DkgResultSubmittedEventArgs, ): Promise { const eventName = "DkgResultSubmitted" - const event: DkgResultSubmittedEvent = (await tx.wait()).events.find( - (e) => e.event === eventName - ) as unknown as DkgResultSubmittedEvent + const event = requireResult(await tx.wait()).logs.find( + (log): log is DkgResultSubmittedEvent.Log => + log instanceof ethers.EventLog && log.eventName === eventName, + ) - await expect(event, `Event ${eventName} not emitted`).to.be.not.null + if (!event) { + throw new Error(`Event ${eventName} not emitted`) + } const actualArgs = event.args await expect(actualArgs.length, "invalid event args length").to.be.equal( - Object.keys(expectedArgs).length + Object.keys(expectedArgs).length, ) await expect( actualArgs.result.length, - "invalid result args length" + "invalid result args length", ).to.be.equal(Object.keys(expectedArgs.result).length) await expect(actualArgs.resultHash, "invalid resultHash").to.be.equal( - expectedArgs.resultHash + expectedArgs.resultHash, ) await expect(actualArgs.seed, "invalid seed").to.be.equal(expectedArgs.seed) await expect( actualArgs.result.submitterMemberIndex, - "invalid submitterMemberIndex" + "invalid submitterMemberIndex", ).to.be.equal(expectedArgs.result.submitterMemberIndex) await expect( actualArgs.result.groupPubKey, - "invalid groupPubKey" + "invalid groupPubKey", ).to.be.equal(expectedArgs.result.groupPubKey) await expect( actualArgs.result.misbehavedMembersIndices, - "invalid misbehavedMembersIndices" - ).to.be.deep.equal(expectedArgs.result.misbehavedMembersIndices) + "invalid misbehavedMembersIndices", + ).to.be.deep.equal(expectedArgs.result.misbehavedMembersIndices.map(BigInt)) await expect(actualArgs.result.signatures, "invalid signatures").to.be.equal( - expectedArgs.result.signatures + expectedArgs.result.signatures, ) await expect( actualArgs.result.signingMembersIndices, - "invalid signingMembersIndices" - ).to.be.deep.equal( - expectedArgs.result.signingMembersIndices.map(BigNumber.from) - ) + "invalid signingMembersIndices", + ).to.be.deep.equal(expectedArgs.result.signingMembersIndices.map(BigInt)) await expect(actualArgs.result.members, "invalid members").to.be.deep.equal( - expectedArgs.result.members + expectedArgs.result.members.map(BigInt), ) await expect( actualArgs.result.membersHash, - "invalid membersHash" + "invalid membersHash", ).to.be.equal(expectedArgs.result.membersHash) } diff --git a/solidity/random-beacon/test/utils/groups.ts b/solidity/random-beacon/test/utils/groups.ts index b4208f45d7..ed5774d6c3 100644 --- a/solidity/random-beacon/test/utils/groups.ts +++ b/solidity/random-beacon/test/utils/groups.ts @@ -1,23 +1,28 @@ +import { toBeHex } from "ethers" import { helpers, ethers } from "hardhat" +import requireResult from "../helpers/chain" import { constants, params } from "../fixtures" import blsData from "../data/bls" // eslint-disable-next-line import/no-cycle import { noMisbehaved, signAndSubmitArbitraryDkgResult } from "./dkg" -import type { BigNumber, BigNumberish } from "ethers" +import type { BigNumberish } from "ethers" import type { Operator } from "./operators" import type { RandomBeacon, SortitionPool } from "../../typechain" -const { keccak256, defaultAbiCoder } = ethers.utils +const { keccak256 } = ethers +const defaultAbiCoder = ethers.AbiCoder.defaultAbiCoder() const { mineBlocks } = helpers.time export async function createGroup( randomBeacon: RandomBeacon, - signers: Operator[] + signers: Operator[], ): Promise { - const { blockNumber: startBlock } = await randomBeacon.genesis() + const { blockNumber: startBlock } = requireResult( + await (await randomBeacon.genesis()).wait(), + ) await mineBlocks(constants.offchainDkgTime) @@ -26,7 +31,7 @@ export async function createGroup( blsData.groupPubKey, signers, startBlock, - noMisbehaved + noMisbehaved, ) await mineBlocks(params.dkgResultChallengePeriodLength) @@ -36,21 +41,22 @@ export async function createGroup( export async function selectGroup( sortitionPool: SortitionPool, - seed: BigNumber + seed: bigint, ): Promise { - const identifiers = await sortitionPool.selectGroup( - constants.groupSize, - ethers.utils.hexZeroPad(seed.toHexString(), 32) + // Copy the immutable ethers Result before passing these IDs to another call. + const identifiers = Array.from( + await sortitionPool.selectGroup( + constants.groupSize, + ethers.zeroPadValue(toBeHex(seed), 32), + ), ) const addresses = await sortitionPool.getIDOperators(identifiers) return Promise.all( - identifiers.map( - async (identifier, i): Promise => ({ - id: identifier, - signer: await ethers.getSigner(addresses[i]), - }) - ) + identifiers.map(async (identifier, i): Promise => ({ + id: Number(identifier), + signer: await ethers.getSigner(addresses[i]), + })), ) } diff --git a/solidity/random-beacon/test/utils/inactivity.ts b/solidity/random-beacon/test/utils/inactivity.ts index eb474e0a0a..055e1d3aa2 100644 --- a/solidity/random-beacon/test/utils/inactivity.ts +++ b/solidity/random-beacon/test/utils/inactivity.ts @@ -11,16 +11,16 @@ export async function signOperatorInactivityClaim( nonce: number, groupPubKey: string, inactiveMembersIndices: number[], - numberOfSignatures: number + numberOfSignatures: number, ): Promise<{ signatures: string signingMembersIndices: number[] }> { - const messageHash = ethers.utils.keccak256( - ethers.utils.defaultAbiCoder.encode( + const messageHash = ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( ["uint256", "uint256", "bytes", "uint8[]"], - [hardhatNetworkId, nonce, groupPubKey, inactiveMembersIndices] - ) + [hardhatNetworkId, nonce, groupPubKey, inactiveMembersIndices], + ), ) const signingMembersIndices: number[] = [] @@ -37,16 +37,16 @@ export async function signOperatorInactivityClaim( signingMembersIndices.push(signerIndex) const ethersSigner = signers[i].signer - // eslint-disable-next-line no-await-in-loop + const signature = await ethersSigner.signMessage( - ethers.utils.arrayify(messageHash) + ethers.getBytes(messageHash), ) signatures.push(signature) } return { - signatures: ethers.utils.hexConcat(signatures), + signatures: ethers.concat(signatures), signingMembersIndices, } } diff --git a/solidity/random-beacon/test/utils/operators.ts b/solidity/random-beacon/test/utils/operators.ts index cae7ff39d6..ea695b4dda 100644 --- a/solidity/random-beacon/test/utils/operators.ts +++ b/solidity/random-beacon/test/utils/operators.ts @@ -3,8 +3,8 @@ import { ethers, helpers } from "hardhat" import { params } from "../fixtures" import { testConfig } from "../../hardhat.config" -import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" -import type { BigNumber, BigNumberish, Contract } from "ethers" +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers" +import type { BigNumberish, Contract } from "ethers" import type { RandomBeacon, RandomBeaconStub, @@ -14,7 +14,7 @@ import type { } from "../../typechain" /** Minimal ABI for TokenStaking methods omitted from the generated Typechain ABI. */ -const legacyTokenStakingIface = new ethers.utils.Interface([ +const legacyTokenStakingIface = new ethers.Interface([ "function stake(address,address,address,uint96)", "function increaseAuthorization(address,address,uint96)", "function approveApplication(address)", @@ -23,10 +23,10 @@ const legacyTokenStakingIface = new ethers.utils.Interface([ ]) export function legacyTokenStakingAt( - staking: Pick, - signer: SignerWithAddress + staking: Pick, + signer: SignerWithAddress, ): Contract { - return new ethers.Contract(staking.address, legacyTokenStakingIface, signer) + return new ethers.Contract(staking, legacyTokenStakingIface, signer) } export type OperatorID = number @@ -37,28 +37,28 @@ export async function registerOperators( t: T, numberOfOperators = testConfig.operatorsCount, unnamedSignersOffset = testConfig.nonStakingAccountsCount, - stakeAmount: BigNumber = params.minimumAuthorization + stakeAmount: bigint = params.minimumAuthorization, ): Promise { const operators: Operator[] = [] const sortitionPool: SortitionPool = await ethers.getContractAt( "SortitionPool", - await randomBeacon.sortitionPool() + await randomBeacon.sortitionPool(), ) const staking: TokenStaking = await ethers.getContractAt( "TokenStaking", - await randomBeacon.staking() + await randomBeacon.staking(), ) const signers = (await helpers.signers.getUnnamedSigners()).slice( - unnamedSignersOffset + unnamedSignersOffset, ) // We use unique accounts for each staking role for each operator. if (signers.length < numberOfOperators * 5) { throw new Error( - "not enough unnamed signers; update hardhat network's configuration account count" + "not enough unnamed signers; update hardhat network's configuration account count", ) } @@ -78,7 +78,7 @@ export async function registerOperators( stakingProvider, stakeAmount, beneficiary, - authorizer + authorizer, ) await randomBeacon @@ -87,7 +87,7 @@ export async function registerOperators( await randomBeacon.connect(operator).joinSortitionPool() - const id = await sortitionPool.getOperatorID(operator.address) + const id = Number(await sortitionPool.getOperatorID(operator.address)) operators.push({ id, signer: operator }) } @@ -103,23 +103,23 @@ export async function stake( stakingProvider: SignerWithAddress, stakeAmount: BigNumberish, beneficiary = stakingProvider, - authorizer = stakingProvider + authorizer = stakingProvider, ): Promise { const { deployer } = await helpers.signers.getNamedSigners() await t.connect(deployer).mint(owner.address, stakeAmount) - await t.connect(owner).approve(staking.address, stakeAmount) + await t.connect(owner).approve(await staking.getAddress(), stakeAmount) await legacyTokenStakingAt(staking, owner).stake( stakingProvider.address, beneficiary.address, authorizer.address, - stakeAmount + stakeAmount, ) await legacyTokenStakingAt(staking, authorizer).increaseAuthorization( stakingProvider.address, - randomBeacon.address, - stakeAmount + await randomBeacon.getAddress(), + stakeAmount, ) } diff --git a/solidity/random-beacon/test/utils/submission.ts b/solidity/random-beacon/test/utils/submission.ts index 579e229658..db5df03c0f 100644 --- a/solidity/random-beacon/test/utils/submission.ts +++ b/solidity/random-beacon/test/utils/submission.ts @@ -1,25 +1,22 @@ -import { BigNumber } from "ethers" - import { constants } from "../fixtures" import type { BigNumberish } from "ethers" -/* eslint-disable import/prefer-default-export */ export function firstEligibleIndex( seed: BigNumberish, - groupSize?: number + groupSize?: number, ): number { // eslint-disable-next-line no-param-reassign if (!groupSize) groupSize = constants.groupSize - return BigNumber.from(seed).mod(groupSize).add(1).toNumber() + return Number((BigInt(seed) % BigInt(groupSize)) + 1n) } export function shiftEligibleIndex( // eslint-disable-next-line @typescript-eslint/no-shadow firstEligibleIndex: number, shift: number, - groupSize?: number + groupSize?: number, ): number { // eslint-disable-next-line no-param-reassign if (!groupSize) groupSize = constants.groupSize diff --git a/solidity/random-beacon/test/utils/wait-for-confirmations.test.ts b/solidity/random-beacon/test/utils/wait-for-confirmations.test.ts new file mode 100644 index 0000000000..060aff4d3b --- /dev/null +++ b/solidity/random-beacon/test/utils/wait-for-confirmations.test.ts @@ -0,0 +1,53 @@ +import assert from "assert/strict" +import { ethers } from "hardhat" +import { expect } from "chai" +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" + +import waitForConfirmations from "../../utils/wait-for-confirmations" + +async function sentTransaction() { + const [signer] = await ethers.getSigners() + return signer.sendTransaction({ to: signer.address, value: 0 }) +} + +describe("deployment confirmations", () => { + it("retrieves a confirmed transaction through the Hardhat ethers v6 provider", async () => { + const transaction = await loadFixture(sentTransaction) + const receipt = await waitForConfirmations( + ethers.provider, + transaction.hash, + 1, + 5_000, + ) + expect(receipt.hash).to.equal(transaction.hash) + expect(receipt.status).to.equal(1) + }) + + it("waits for the requested number of confirmations", async () => { + const transaction = await loadFixture(sentTransaction) + const pending = waitForConfirmations( + ethers.provider, + transaction.hash, + 2, + 5_000, + ) + await ethers.provider.send("evm_mine", []) + const receipt = await pending + expect(await receipt.confirmations()).to.be.at.least(2) + }) + + it("fails if the additional confirmation does not arrive before the timeout", async () => { + const transaction = await loadFixture(sentTransaction) + await assert.rejects( + waitForConfirmations(ethers.provider, transaction.hash, 2, 50), + (error: unknown) => ethers.isError(error, "TIMEOUT"), + ) + }) + + it("fails if the saved deployment transaction cannot be found", async () => { + await assert.rejects( + waitForConfirmations(ethers.provider, ethers.ZeroHash, 1, 5_000), + /Deployment transaction .* was not found/, + ) + }) +}) diff --git a/solidity/random-beacon/tsconfig.export.json b/solidity/random-beacon/tsconfig.export.json index 7832a5ea32..b8d7b23967 100644 --- a/solidity/random-beacon/tsconfig.export.json +++ b/solidity/random-beacon/tsconfig.export.json @@ -2,7 +2,9 @@ "extends": "./tsconfig.json", "exclude": ["./test", "./typechain"], "compilerOptions": { - "target": "es5", + "target": "ES2020", + // hardhat-deploy v1 requires the published deployment scripts. + "module": "CommonJS", "outDir": "export" } } diff --git a/solidity/random-beacon/tsconfig.json b/solidity/random-beacon/tsconfig.json index aab3f5a425..83a81ca8b4 100644 --- a/solidity/random-beacon/tsconfig.json +++ b/solidity/random-beacon/tsconfig.json @@ -10,8 +10,28 @@ "./tasks" ], "compilerOptions": { + "strict": true, + // ts-node also needs an explicit target; its fallback is ES5. + "target": "ES2020", + // TypeScript 6 stopped including every `node_modules/@types` package + // automatically, which silently drops the mocha and chai globals. These + // are the three that contribute globals here. + "types": ["mocha", "chai", "node"], + // Required by TypeScript 6 once a project spans several top-level + // directories. `--noEmit` does not need it, but ts-node's emit path does, + // so hardhat will not start without it. + "rootDir": ".", + // Two deprecations are silenced here, both belonging to the published + // `export/` bundle that `prepack` builds through tsconfig.export.json: + // `target: es5` itself, and `downlevelIteration`, which still changes + // emit at that target. Both are removed in TypeScript 7, so the export + // target has to be raised before then; doing it is its own change, and + // guessing that the option is inert would alter an artifact downstream + // packages consume. + "ignoreDeprecations": "6.0", "esModuleInterop": true, + "downlevelIteration": true, "noImplicitAny": true, - "downlevelIteration": true + "skipLibCheck": true } } diff --git a/solidity/random-beacon/types/TokenStaking.extensions.d.ts b/solidity/random-beacon/types/TokenStaking.extensions.d.ts index 20e2f798fc..ba29076216 100644 --- a/solidity/random-beacon/types/TokenStaking.extensions.d.ts +++ b/solidity/random-beacon/types/TokenStaking.extensions.d.ts @@ -12,37 +12,37 @@ declare module "../typechain/TokenStaking" { beneficiary: string, authorizer: string, amount: BigNumberish, - overrides?: CallOverrides + overrides?: CallOverrides, ): Promise approveApplication( application: string, - overrides?: CallOverrides + overrides?: CallOverrides, ): Promise increaseAuthorization( stakingProvider: string, application: string, amount: BigNumberish, - overrides?: CallOverrides + overrides?: CallOverrides, ): Promise topUp( stakingProvider: string, amount: BigNumberish, - overrides?: CallOverrides + overrides?: CallOverrides, ): Promise processSlashing( count: BigNumberish, - overrides?: CallOverrides + overrides?: CallOverrides, ): Promise getSlashingQueueLength(overrides?: CallOverrides): Promise slashingQueue( index: BigNumberish, - overrides?: CallOverrides + overrides?: CallOverrides, ): Promise< [string, BigNumber] & { stakingProvider: string; amount: BigNumber } > @@ -51,7 +51,7 @@ declare module "../typechain/TokenStaking" { stakingProvider: string, application: string, amount: BigNumberish, - overrides?: CallOverrides + overrides?: CallOverrides, ): Promise } } diff --git a/solidity/random-beacon/utils/wait-for-confirmations.ts b/solidity/random-beacon/utils/wait-for-confirmations.ts new file mode 100644 index 0000000000..b3a939c588 --- /dev/null +++ b/solidity/random-beacon/utils/wait-for-confirmations.ts @@ -0,0 +1,35 @@ +import type { Provider, TransactionReceipt } from "ethers" + +/** Wait through the transaction response; Hardhat's ethers v6 provider does not implement waitForTransaction. */ +export default async function waitForConfirmations( + provider: Pick, + transactionHash: string, + confirmations = 2, + timeout = 300_000, +): Promise { + const pollInterval = 2_000 + const deadline = Date.now() + timeout + // ethers v5 waitForTransaction polled, so a load-balanced endpoint that does + // not see the just-mined transaction yet must not fail the deployment. + let transaction = await provider.getTransaction(transactionHash) + while (!transaction) { + const remaining = deadline - Date.now() + if (remaining <= 0) { + throw new Error(`Deployment transaction ${transactionHash} was not found`) + } + await new Promise((resolve) => { + setTimeout(resolve, Math.min(pollInterval, remaining)) + }) + transaction = await provider.getTransaction(transactionHash) + } + const receipt = await transaction.wait( + confirmations, + Math.max(deadline - Date.now(), 1), + ) + if (!receipt) { + throw new Error( + `Deployment transaction ${transactionHash} is not confirmed`, + ) + } + return receipt +} diff --git a/solidity/random-beacon/yarn.lock b/solidity/random-beacon/yarn.lock index f0a575f9c5..439c8ff74f 100644 --- a/solidity/random-beacon/yarn.lock +++ b/solidity/random-beacon/yarn.lock @@ -5,19 +5,51 @@ __metadata: version: 8 cacheKey: 10c0 -"@adraffy/ens-normalize@npm:^1.11.0": +"@adraffy/ens-normalize@npm:1.11.1, @adraffy/ens-normalize@npm:^1.11.0": version: 1.11.1 resolution: "@adraffy/ens-normalize@npm:1.11.1" checksum: 10c0/b364e2a57131db278ebf2f22d1a1ac6d8aea95c49dd2bbbc1825870b38aa91fd8816aba580a1f84edc50a45eb6389213dacfd1889f32893afc8549a82d304767 languageName: node linkType: hard -"@babel/code-frame@npm:7.12.11": - version: 7.12.11 - resolution: "@babel/code-frame@npm:7.12.11" +"@aws-crypto/sha256-js@npm:1.2.2": + version: 1.2.2 + resolution: "@aws-crypto/sha256-js@npm:1.2.2" + dependencies: + "@aws-crypto/util": "npm:^1.2.2" + "@aws-sdk/types": "npm:^3.1.0" + tslib: "npm:^1.11.1" + checksum: 10c0/f4e8593cfbc48591413f00c744569b21e5ed5fab0e27fa4b59c517f2024ca4f46fab7b3874f2a207ceeef8feefc22d143a82d6c6bfe5303ea717f579d8d7ad0a + languageName: node + linkType: hard + +"@aws-crypto/util@npm:^1.2.2": + version: 1.2.2 + resolution: "@aws-crypto/util@npm:1.2.2" + dependencies: + "@aws-sdk/types": "npm:^3.1.0" + "@aws-sdk/util-utf8-browser": "npm:^3.0.0" + tslib: "npm:^1.11.1" + checksum: 10c0/ade8843bf13529b1854f64d6bbb23f30b46330743c8866adfd2105d830e30ce837a868eaaf41c4c2381d27e9d225d3a0a7558ee1eee022f0192916e33bfb654c + languageName: node + linkType: hard + +"@aws-sdk/types@npm:^3.1.0": + version: 3.974.5 + resolution: "@aws-sdk/types@npm:3.974.5" + dependencies: + "@smithy/types": "npm:^4.17.2" + tslib: "npm:^2.6.2" + checksum: 10c0/803aaaa1c0675dcb564803993f3c47d96302fad461af8af80e75afc40c72228ebf669593c18e44ca09fc5acf0d1bd25966261de07844d8f11ad82aa2650252d0 + languageName: node + linkType: hard + +"@aws-sdk/util-utf8-browser@npm:^3.0.0": + version: 3.259.0 + resolution: "@aws-sdk/util-utf8-browser@npm:3.259.0" dependencies: - "@babel/highlight": "npm:^7.10.4" - checksum: 10c0/836ffd155506768e991d6dd8c51db37cad5958ed1c8e0a2329ccd9527165d5c752e943d66a5c3c92ffd45f343419f0742e7636629a529f4fbd5303e3637746b9 + tslib: "npm:^2.3.1" + checksum: 10c0/ff56ff252c0ea22b760b909ba5bbe9ca59a447066097e73b1e2ae50a6d366631ba560c373ec4e83b3e225d16238eeaf8def210fdbf135070b3dd3ceb1cc2ef9a languageName: node linkType: hard @@ -30,6 +62,17 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.27.1": + version: 7.29.7 + resolution: "@babel/code-frame@npm:7.29.7" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.29.7" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.1.1" + checksum: 10c0/169fc2080169a40c1760155eaaaf739bcb882df0bec76a83adbda5493645bc17270a3434b8848c494b1933e96fe1d147370001e3cda09a39f43ae30f08ef2069 + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.14.5": version: 7.15.7 resolution: "@babel/helper-validator-identifier@npm:7.15.7" @@ -37,7 +80,14 @@ __metadata: languageName: node linkType: hard -"@babel/highlight@npm:^7.10.4, @babel/highlight@npm:^7.14.5": +"@babel/helper-validator-identifier@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-validator-identifier@npm:7.29.7" + checksum: 10c0/4795354e7ae0dcafa72de1cd04ec51252dc1498517170beaf019e03effc5b7bf13c6b21a3949a77e07b8125be7f106ed1131350d8ebd4566ae874094a726d62b + languageName: node + linkType: hard + +"@babel/highlight@npm:^7.14.5": version: 7.14.5 resolution: "@babel/highlight@npm:7.14.5" dependencies: @@ -48,22 +98,39 @@ __metadata: languageName: node linkType: hard -"@babel/runtime-corejs3@npm:^7.10.2": - version: 7.15.4 - resolution: "@babel/runtime-corejs3@npm:7.15.4" +"@bytecodealliance/preview2-shim@npm:0.17.0": + version: 0.17.0 + resolution: "@bytecodealliance/preview2-shim@npm:0.17.0" + checksum: 10c0/a2cb46dd0e14319ec4c6b89cc6e629884a98120c70fc831131bc0941e03b8a40b35cd7d5bf4440653ac3658a73484a0be0a7066bfb4d2c43adc122488279c10b + languageName: node + linkType: hard + +"@bytecodealliance/preview2-shim@npm:^0.19.0": + version: 0.19.0 + resolution: "@bytecodealliance/preview2-shim@npm:0.19.0" + checksum: 10c0/c15b6aff80dfcb8cd2c2fb532f7b5a35bef0031d1df1f08064d8ef591668621ce379e5a285a3f48d2de5101fbc5a8e6badc935eaaa97eeb9ccb73d60c280c74d + languageName: node + linkType: hard + +"@cacheable/memory@npm:^2.2.0": + version: 2.2.0 + resolution: "@cacheable/memory@npm:2.2.0" dependencies: - core-js-pure: "npm:^3.16.0" - regenerator-runtime: "npm:^0.13.4" - checksum: 10c0/3b86b5c3aaf3c4d0211caf5adbb630ab3be05523adf2ece75b13911524b102ebf87107f95e5d39c3ee69ce8e727c479b9f0b96c492c59c93ccf2283523126ffe + "@cacheable/utils": "npm:^2.5.0" + "@keyv/bigmap": "npm:^1.3.1" + hookified: "npm:^1.15.1" + keyv: "npm:^5.6.0" + checksum: 10c0/c74889eb09871be0696065778fff013a498ddc73b538d113c2cb6ece361746f2959fbddfa4ce03ce53c9259998be05949e393212e72413dbd07616744eabd261 languageName: node linkType: hard -"@babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.11.2": - version: 7.15.4 - resolution: "@babel/runtime@npm:7.15.4" +"@cacheable/utils@npm:^2.5.0": + version: 2.5.0 + resolution: "@cacheable/utils@npm:2.5.0" dependencies: - regenerator-runtime: "npm:^0.13.4" - checksum: 10c0/2e366347254c9d3e738641d88a086cdfb1de516111e50ebbe9e6b5d8ed78d41819cf991fc0804fa50e04ae7a2157cc28ef3b4180781af5fecfe65310d7ebf301 + hashery: "npm:^1.5.1" + keyv: "npm:^5.6.0" + checksum: 10c0/99e901accd71eeb0bce91484d6c66d7ef2c731b541561eb5dc9ea7fed78bdc0b65e5dd2a80edde50191143bcfc5f238fc4742475b32e82d43b43eea224038e35 languageName: node linkType: hard @@ -90,103 +157,104 @@ __metadata: languageName: node linkType: hard -"@ensdomains/ens@npm:^0.4.4": - version: 0.4.5 - resolution: "@ensdomains/ens@npm:0.4.5" +"@cspotcode/source-map-support@npm:^0.8.0": + version: 0.8.1 + resolution: "@cspotcode/source-map-support@npm:0.8.1" + dependencies: + "@jridgewell/trace-mapping": "npm:0.3.9" + checksum: 10c0/05c5368c13b662ee4c122c7bfbe5dc0b613416672a829f3e78bc49a357a197e0218d6e74e7c66cfcd04e15a179acab080bd3c69658c9fbefd0e1ccd950a07fc6 + languageName: node + linkType: hard + +"@emnapi/core@npm:1.10.0": + version: 1.10.0 + resolution: "@emnapi/core@npm:1.10.0" dependencies: - bluebird: "npm:^3.5.2" - eth-ens-namehash: "npm:^2.0.8" - solc: "npm:^0.4.20" - testrpc: "npm:0.0.1" - web3-utils: "npm:^1.0.0-beta.31" - checksum: 10c0/15a77b5db73550546e6684cb6f8105170c9c113e3dc128ee718eabd3c2b1d13fdeb5791fa79c7b149b5b83b6e00040b7320c27796b7970fae66e8d3e5cce6561 + "@emnapi/wasi-threads": "npm:1.2.1" + tslib: "npm:^2.4.0" + checksum: 10c0/f51d08227857b60632de7714d708124f0e100a1462dde6df8221760939aa3204a73193830371830fac0716f3ccd2129f2cac1b17cd7d7958bc4da9018a296edb languageName: node linkType: hard -"@ensdomains/resolver@npm:^0.2.4": - version: 0.2.4 - resolution: "@ensdomains/resolver@npm:0.2.4" - checksum: 10c0/8bd21f82c3f122f56d7198cf671c08204cca2cb531fd5074fd558d625afa8a15828e92738bf80b9961575a92e4fe627208edd3f87a04c6a0fa47531c91ef0639 +"@emnapi/runtime@npm:1.10.0": + version: 1.10.0 + resolution: "@emnapi/runtime@npm:1.10.0" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/953f14991d1aefb92ee6f8eb27dea725e484791a53a0cb5f47d9e0087b9a2c929ff2e92adf95af15d6ad456db6300c6b761ebf72b50a875b874a83520b3ba093 languageName: node linkType: hard -"@eslint/eslintrc@npm:^0.4.3": - version: 0.4.3 - resolution: "@eslint/eslintrc@npm:0.4.3" +"@emnapi/wasi-threads@npm:1.2.1": + version: 1.2.1 + resolution: "@emnapi/wasi-threads@npm:1.2.1" dependencies: - ajv: "npm:^6.12.4" - debug: "npm:^4.1.1" - espree: "npm:^7.3.0" - globals: "npm:^13.9.0" - ignore: "npm:^4.0.6" - import-fresh: "npm:^3.2.1" - js-yaml: "npm:^3.13.1" - minimatch: "npm:^3.0.4" - strip-json-comments: "npm:^3.1.1" - checksum: 10c0/0eed93369f72ef044686d07824742121f9b95153ff34f4614e4e69d64332ee68c84eb70da851a9005bb76b3d1d64ad76c2e6293a808edc0f7dfb883689ca136d + tslib: "npm:^2.4.0" + checksum: 10c0/32fcfa81ab396533b2ec1f4082b1ff779a05d9c836bbbd3f4398405b0e6814c0d9503b7993130e37bc6941dbc1ded49f55e9700ae9ca4e803bab2b5bc5deb331 languageName: node linkType: hard -"@ethereum-waffle/chai@npm:^3.4.0": - version: 3.4.1 - resolution: "@ethereum-waffle/chai@npm:3.4.1" +"@eslint-community/eslint-utils@npm:^4.8.0, @eslint-community/eslint-utils@npm:^4.9.1": + version: 4.10.1 + resolution: "@eslint-community/eslint-utils@npm:4.10.1" dependencies: - "@ethereum-waffle/provider": "npm:^3.4.0" - ethers: "npm:^5.4.7" - checksum: 10c0/fcdee204eed7bf52c9d8d7208fa6a47501c7b8bb484e37760880bae262dd5d93b8dcab89342d679aeb18ead3baa339e30bed93a97cd2b8a42d31d38768381a7b + eslint-visitor-keys: "npm:^3.4.3" + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + checksum: 10c0/b514586655698bc6b74db72a496c77e813c78b63e36a83429845ac7057dd77113b0b6c31e6e590d5baaeee2abae6ea22363a41209bcafa078d895ab83ce83011 languageName: node linkType: hard -"@ethereum-waffle/compiler@npm:^3.4.0": - version: 3.4.0 - resolution: "@ethereum-waffle/compiler@npm:3.4.0" - dependencies: - "@resolver-engine/imports": "npm:^0.3.3" - "@resolver-engine/imports-fs": "npm:^0.3.3" - "@typechain/ethers-v5": "npm:^2.0.0" - "@types/mkdirp": "npm:^0.5.2" - "@types/node-fetch": "npm:^2.5.5" - ethers: "npm:^5.0.1" - mkdirp: "npm:^0.5.1" - node-fetch: "npm:^2.6.1" - solc: "npm:^0.6.3" - ts-generator: "npm:^0.1.1" - typechain: "npm:^3.0.0" - checksum: 10c0/ca1a61310133bc9f979b8ff16719588bad79a16b9d72e1c139b143088591c8009199c77bac3f73ca2185441bd5185f62e3d5d61c617a709243e5e7fa6bcc86c6 +"@eslint-community/regexpp@npm:^4.12.2": + version: 4.12.2 + resolution: "@eslint-community/regexpp@npm:4.12.2" + checksum: 10c0/fddcbc66851b308478d04e302a4d771d6917a0b3740dc351513c0da9ca2eab8a1adf99f5e0aa7ab8b13fa0df005c81adeee7e63a92f3effd7d367a163b721c2d + languageName: node + linkType: hard + +"@eslint/config-array@npm:^0.23.5": + version: 0.23.5 + resolution: "@eslint/config-array@npm:0.23.5" + dependencies: + "@eslint/object-schema": "npm:^3.0.5" + debug: "npm:^4.3.1" + minimatch: "npm:^10.2.4" + checksum: 10c0/b24833c4c76e78ee075d306cd3f095db46b2db0f90cc13a6ee6e4275f9889731c05bf5403ab5fefb79c756e07ac9184ed0e04570341382f9eccbccc80e6d1a0c languageName: node linkType: hard -"@ethereum-waffle/ens@npm:^3.3.0": - version: 3.3.0 - resolution: "@ethereum-waffle/ens@npm:3.3.0" +"@eslint/config-helpers@npm:^0.7.0": + version: 0.7.0 + resolution: "@eslint/config-helpers@npm:0.7.0" dependencies: - "@ensdomains/ens": "npm:^0.4.4" - "@ensdomains/resolver": "npm:^0.2.4" - ethers: "npm:^5.0.1" - checksum: 10c0/7d71331d6ff1d89167ee224fdf2feb48095bb3fc5081a150b2575e5672b16b043c2a4818a01291647d9e508f255fcd4171a4ceb4d97bcc8ae1617d75a5974209 + "@eslint/core": "npm:^1.2.1" + checksum: 10c0/fd40d57d6f1db49f7b647048b88a433dc7f6522ef3edf855a43cb526ef4fc40622ceed0dc8de2e03d254f30f8e035370570de1d4bd8e7c2b1200131451e0d331 languageName: node linkType: hard -"@ethereum-waffle/mock-contract@npm:^3.3.0": - version: 3.3.0 - resolution: "@ethereum-waffle/mock-contract@npm:3.3.0" +"@eslint/core@npm:^1.2.1": + version: 1.2.1 + resolution: "@eslint/core@npm:1.2.1" dependencies: - "@ethersproject/abi": "npm:^5.0.1" - ethers: "npm:^5.0.1" - checksum: 10c0/b688ab3c4cd6d00876cb528fb5b829fc7bdf0de9e45377830a9e5c632b854c7a36f950de25a138a1dacef117f683efe19a16e7e258e7b6d5c7700b006b7c1197 + "@types/json-schema": "npm:^7.0.15" + checksum: 10c0/10979b40588ecfef771fcb5013a542a35fb30692cc95a65f3481b0b36fbd89f5679efeb30d57f4eed35203d859aabace2a620177d6c536f71b299a1af2f3398f languageName: node linkType: hard -"@ethereum-waffle/provider@npm:^3.4.0": - version: 3.4.0 - resolution: "@ethereum-waffle/provider@npm:3.4.0" +"@eslint/object-schema@npm:^3.0.5": + version: 3.0.5 + resolution: "@eslint/object-schema@npm:3.0.5" + checksum: 10c0/1db337431f520b99e9edda64ef5fafd7ec6a029843eeb608753025125b6649d861d843cffafafd3c4e37926d7d5f9ec0c6a8e3665c13c3da2144e8132892e92e + languageName: node + linkType: hard + +"@eslint/plugin-kit@npm:^0.7.3": + version: 0.7.3 + resolution: "@eslint/plugin-kit@npm:0.7.3" dependencies: - "@ethereum-waffle/ens": "npm:^3.3.0" - ethers: "npm:^5.0.1" - ganache-core: "npm:^2.13.2" - patch-package: "npm:^6.2.2" - postinstall-postinstall: "npm:^2.1.0" - checksum: 10c0/3936f6ca43b382bc7882a2ccd2f70caf8f6ee1a7dab5612372bfe1840c3f11f4b636bbe0032d99cb1906d9d6094e73b376c1e58a60c86ff5700c1af3e2ac314a + "@eslint/core": "npm:^1.2.1" + levn: "npm:^0.4.1" + checksum: 10c0/2daebaedcfbd261478e8b87dfb46d3118f48277c19eb298483ebc6f3b438e9688b86ddca13b3aeb08dfb06be00fb6073506852386aa124645c1170e7e33d140c languageName: node linkType: hard @@ -209,40 +277,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/abi@npm:5.0.0-beta.153": - version: 5.0.0-beta.153 - resolution: "@ethersproject/abi@npm:5.0.0-beta.153" - dependencies: - "@ethersproject/address": "npm:>=5.0.0-beta.128" - "@ethersproject/bignumber": "npm:>=5.0.0-beta.130" - "@ethersproject/bytes": "npm:>=5.0.0-beta.129" - "@ethersproject/constants": "npm:>=5.0.0-beta.128" - "@ethersproject/hash": "npm:>=5.0.0-beta.128" - "@ethersproject/keccak256": "npm:>=5.0.0-beta.127" - "@ethersproject/logger": "npm:>=5.0.0-beta.129" - "@ethersproject/properties": "npm:>=5.0.0-beta.131" - "@ethersproject/strings": "npm:>=5.0.0-beta.130" - checksum: 10c0/56a6b04596f75f5ac11f68963f1a3bef628732fd9e5ccc6d5752b1c1bf8fb8cdfae02aeacf5087cd40cd52d76d63d936850af55cd984e862c6998410031bef54 - languageName: node - linkType: hard - -"@ethersproject/abi@npm:5.4.1, @ethersproject/abi@npm:^5.0.1, @ethersproject/abi@npm:^5.1.2, @ethersproject/abi@npm:^5.4.0": - version: 5.4.1 - resolution: "@ethersproject/abi@npm:5.4.1" - dependencies: - "@ethersproject/address": "npm:^5.4.0" - "@ethersproject/bignumber": "npm:^5.4.0" - "@ethersproject/bytes": "npm:^5.4.0" - "@ethersproject/constants": "npm:^5.4.0" - "@ethersproject/hash": "npm:^5.4.0" - "@ethersproject/keccak256": "npm:^5.4.0" - "@ethersproject/logger": "npm:^5.4.0" - "@ethersproject/properties": "npm:^5.4.0" - "@ethersproject/strings": "npm:^5.4.0" - checksum: 10c0/22a01c2fabbc01941e317c98eedc23abb58a63a78d190754799de2a6aa862118aab5350846c599800bfcb90a3271aa68d3ebc5b06beb0a4c2f764dadb6af2085 - languageName: node - linkType: hard - "@ethersproject/abi@npm:5.7.0, @ethersproject/abi@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/abi@npm:5.7.0" @@ -260,46 +294,35 @@ __metadata: languageName: node linkType: hard -"@ethersproject/abstract-provider@npm:5.4.1, @ethersproject/abstract-provider@npm:^5.4.0": - version: 5.4.1 - resolution: "@ethersproject/abstract-provider@npm:5.4.1" - dependencies: - "@ethersproject/bignumber": "npm:^5.4.0" - "@ethersproject/bytes": "npm:^5.4.0" - "@ethersproject/logger": "npm:^5.4.0" - "@ethersproject/networks": "npm:^5.4.0" - "@ethersproject/properties": "npm:^5.4.0" - "@ethersproject/transactions": "npm:^5.4.0" - "@ethersproject/web": "npm:^5.4.0" - checksum: 10c0/c000bc2becc097906fe2574d7a125f310bb488a069d65e5bf2fe1dd37add0db92540fc1269a190b1f5f6db04269f8c351087890d315bb3d23e5dcfbbbc6ae2ac - languageName: node - linkType: hard - -"@ethersproject/abstract-provider@npm:5.7.0, @ethersproject/abstract-provider@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/abstract-provider@npm:5.7.0" +"@ethersproject/abi@npm:5.8.0, @ethersproject/abi@npm:^5.1.2, @ethersproject/abi@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/abi@npm:5.8.0" dependencies: - "@ethersproject/bignumber": "npm:^5.7.0" - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/logger": "npm:^5.7.0" - "@ethersproject/networks": "npm:^5.7.0" - "@ethersproject/properties": "npm:^5.7.0" - "@ethersproject/transactions": "npm:^5.7.0" - "@ethersproject/web": "npm:^5.7.0" - checksum: 10c0/a5708e2811b90ddc53d9318ce152511a32dd4771aa2fb59dbe9e90468bb75ca6e695d958bf44d13da684dc3b6aab03f63d425ff7591332cb5d7ddaf68dff7224 + "@ethersproject/address": "npm:^5.8.0" + "@ethersproject/bignumber": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/constants": "npm:^5.8.0" + "@ethersproject/hash": "npm:^5.8.0" + "@ethersproject/keccak256": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + "@ethersproject/strings": "npm:^5.8.0" + checksum: 10c0/6b759247a2f43ecc1548647d0447d08de1e946dfc7e71bfb014fa2f749c1b76b742a1d37394660ebab02ff8565674b3593fdfa011e16a5adcfc87ca4d85af39c languageName: node linkType: hard -"@ethersproject/abstract-signer@npm:5.4.1, @ethersproject/abstract-signer@npm:^5.4.0": - version: 5.4.1 - resolution: "@ethersproject/abstract-signer@npm:5.4.1" +"@ethersproject/abstract-provider@npm:5.8.0": + version: 5.8.0 + resolution: "@ethersproject/abstract-provider@npm:5.8.0" dependencies: - "@ethersproject/abstract-provider": "npm:^5.4.0" - "@ethersproject/bignumber": "npm:^5.4.0" - "@ethersproject/bytes": "npm:^5.4.0" - "@ethersproject/logger": "npm:^5.4.0" - "@ethersproject/properties": "npm:^5.4.0" - checksum: 10c0/4012070ffa6277aedb34717a61ed40e839323240f14aa0a9546fd048e2ec0c73c47d12be9c9b37113fa2bb96f49336a58bb51c359191c897f74a1bbb7a026b4f + "@ethersproject/bignumber": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/networks": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + "@ethersproject/transactions": "npm:^5.8.0" + "@ethersproject/web": "npm:^5.8.0" + checksum: 10c0/9c183da1d037b272ff2b03002c3d801088d0534f88985f4983efc5f3ebd59b05f04bc05db97792fe29ddf87eeba3c73416e5699615f183126f85f877ea6c8637 languageName: node linkType: hard @@ -316,16 +339,16 @@ __metadata: languageName: node linkType: hard -"@ethersproject/address@npm:5.4.0, @ethersproject/address@npm:>=5.0.0-beta.128, @ethersproject/address@npm:^5.4.0": - version: 5.4.0 - resolution: "@ethersproject/address@npm:5.4.0" +"@ethersproject/abstract-signer@npm:5.8.0, @ethersproject/abstract-signer@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/abstract-signer@npm:5.8.0" dependencies: - "@ethersproject/bignumber": "npm:^5.4.0" - "@ethersproject/bytes": "npm:^5.4.0" - "@ethersproject/keccak256": "npm:^5.4.0" - "@ethersproject/logger": "npm:^5.4.0" - "@ethersproject/rlp": "npm:^5.4.0" - checksum: 10c0/c383ecc2f895cd512a6eec52a3c740de0188a08318f57359eaa90e1166a95cb2fba4bdb2e00468e118bb2949faf830713a93d0338340185d438b08fa10d9ea1c + "@ethersproject/abstract-provider": "npm:^5.8.0" + "@ethersproject/bignumber": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + checksum: 10c0/143f32d7cb0bc7064e45674d4a9dffdb90d6171425d20e8de9dc95765be960534bae7246ead400e6f52346624b66569d9585d790eedd34b0b6b7f481ec331cc2 languageName: node linkType: hard @@ -342,6 +365,19 @@ __metadata: languageName: node linkType: hard +"@ethersproject/address@npm:5.8.0, @ethersproject/address@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/address@npm:5.8.0" + dependencies: + "@ethersproject/bignumber": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/keccak256": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/rlp": "npm:^5.8.0" + checksum: 10c0/8bac8a4b567c75c1abc00eeca08c200de1a2d5cf76d595dc04fa4d7bff9ffa5530b2cdfc5e8656cfa8f6fa046de54be47620a092fb429830a8ddde410b9d50bc + languageName: node + linkType: hard + "@ethersproject/address@npm:^5.0.2": version: 5.6.1 resolution: "@ethersproject/address@npm:5.6.1" @@ -355,15 +391,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/base64@npm:5.4.0, @ethersproject/base64@npm:^5.4.0": - version: 5.4.0 - resolution: "@ethersproject/base64@npm:5.4.0" - dependencies: - "@ethersproject/bytes": "npm:^5.4.0" - checksum: 10c0/3c9092ae873a6fd88239ef808448720544e88aade1b549e97d19b8a1f4f0c0bc05870fd0cc03c312413f395d432a59f5a6228be0204528ed5865fc521093bbfa - languageName: node - linkType: hard - "@ethersproject/base64@npm:5.7.0, @ethersproject/base64@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/base64@npm:5.7.0" @@ -373,13 +400,12 @@ __metadata: languageName: node linkType: hard -"@ethersproject/basex@npm:5.4.0, @ethersproject/basex@npm:^5.4.0": - version: 5.4.0 - resolution: "@ethersproject/basex@npm:5.4.0" +"@ethersproject/base64@npm:5.8.0, @ethersproject/base64@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/base64@npm:5.8.0" dependencies: - "@ethersproject/bytes": "npm:^5.4.0" - "@ethersproject/properties": "npm:^5.4.0" - checksum: 10c0/6827e049777b36bbeb33554b028de58b90bcdcb98dad7e619767545ce98d9b2e0207368627b09c294c5d364d4ffd49f99635ca4a47d8d3574d1b86a9a307e498 + "@ethersproject/bytes": "npm:^5.8.0" + checksum: 10c0/60ae6d1e2367d70f4090b717852efe62075442ae59aeac9bb1054fe8306a2de8ef0b0561e7fb4666ecb1f8efa1655d683dd240675c3a25d6fa867245525a63ca languageName: node linkType: hard @@ -393,14 +419,13 @@ __metadata: languageName: node linkType: hard -"@ethersproject/bignumber@npm:5.4.2, @ethersproject/bignumber@npm:>=5.0.0-beta.130, @ethersproject/bignumber@npm:^5.4.0": - version: 5.4.2 - resolution: "@ethersproject/bignumber@npm:5.4.2" +"@ethersproject/basex@npm:5.8.0, @ethersproject/basex@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/basex@npm:5.8.0" dependencies: - "@ethersproject/bytes": "npm:^5.4.0" - "@ethersproject/logger": "npm:^5.4.0" - bn.js: "npm:^4.11.9" - checksum: 10c0/335a149c91e7f5bf706375b095f48e4691f62979fdcdf4116026b3a27895c97d6d729c44b87818935520895a8a31fc41582546e47f4ce80fe80766e4676f9570 + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + checksum: 10c0/46a94ba9678fc458ab0bee4a0af9f659f1d3f5df5bb98485924fe8ecbd46eda37d81f95f882243d56f0f5efe051b0749163f5056e48ff836c5fba648754d4956 languageName: node linkType: hard @@ -415,7 +440,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/bignumber@npm:^5.8.0": +"@ethersproject/bignumber@npm:5.8.0, @ethersproject/bignumber@npm:^5.8.0": version: 5.8.0 resolution: "@ethersproject/bignumber@npm:5.8.0" dependencies: @@ -426,15 +451,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/bytes@npm:5.4.0, @ethersproject/bytes@npm:>=5.0.0-beta.129, @ethersproject/bytes@npm:^5.4.0": - version: 5.4.0 - resolution: "@ethersproject/bytes@npm:5.4.0" - dependencies: - "@ethersproject/logger": "npm:^5.4.0" - checksum: 10c0/757d90a9dc068e9624f7beb3907c8cb1a9ba9b34e2012e541c4e6ee0f8d06e9a4b7dd5bb09546ed050557666ae63bb2afa422fb5498bc73b83c0add48d466549 - languageName: node - linkType: hard - "@ethersproject/bytes@npm:5.7.0, @ethersproject/bytes@npm:^5.6.1, @ethersproject/bytes@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/bytes@npm:5.7.0" @@ -444,7 +460,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/bytes@npm:^5.8.0": +"@ethersproject/bytes@npm:5.8.0, @ethersproject/bytes@npm:^5.8.0": version: 5.8.0 resolution: "@ethersproject/bytes@npm:5.8.0" dependencies: @@ -453,15 +469,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/constants@npm:5.4.0, @ethersproject/constants@npm:>=5.0.0-beta.128, @ethersproject/constants@npm:^5.4.0": - version: 5.4.0 - resolution: "@ethersproject/constants@npm:5.4.0" - dependencies: - "@ethersproject/bignumber": "npm:^5.4.0" - checksum: 10c0/ee4522f518c3f9a997e501a54454015e8a5ae6ec866e7b5c57a689770c12c20c0baf282a35e2ca1cc6621e52639c6ae021154220a824b97a09228dde42cdc9b5 - languageName: node - linkType: hard - "@ethersproject/constants@npm:5.7.0, @ethersproject/constants@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/constants@npm:5.7.0" @@ -471,7 +478,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/constants@npm:^5.8.0": +"@ethersproject/constants@npm:5.8.0, @ethersproject/constants@npm:^5.8.0": version: 5.8.0 resolution: "@ethersproject/constants@npm:5.8.0" dependencies: @@ -480,24 +487,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/contracts@npm:5.4.1": - version: 5.4.1 - resolution: "@ethersproject/contracts@npm:5.4.1" - dependencies: - "@ethersproject/abi": "npm:^5.4.0" - "@ethersproject/abstract-provider": "npm:^5.4.0" - "@ethersproject/abstract-signer": "npm:^5.4.0" - "@ethersproject/address": "npm:^5.4.0" - "@ethersproject/bignumber": "npm:^5.4.0" - "@ethersproject/bytes": "npm:^5.4.0" - "@ethersproject/constants": "npm:^5.4.0" - "@ethersproject/logger": "npm:^5.4.0" - "@ethersproject/properties": "npm:^5.4.0" - "@ethersproject/transactions": "npm:^5.4.0" - checksum: 10c0/8bdd8a8f46b44d971971d2b11c3a64ab02a79082e78550b98f145f9d4347056642fe74b179b5243d1a7fef4e57c2167f531d255920065eea41ffc042eca82685 - languageName: node - linkType: hard - "@ethersproject/contracts@npm:5.7.0": version: 5.7.0 resolution: "@ethersproject/contracts@npm:5.7.0" @@ -516,19 +505,21 @@ __metadata: languageName: node linkType: hard -"@ethersproject/hash@npm:5.4.0, @ethersproject/hash@npm:>=5.0.0-beta.128, @ethersproject/hash@npm:^5.4.0": - version: 5.4.0 - resolution: "@ethersproject/hash@npm:5.4.0" +"@ethersproject/contracts@npm:5.8.0, @ethersproject/contracts@npm:^5.7.0": + version: 5.8.0 + resolution: "@ethersproject/contracts@npm:5.8.0" dependencies: - "@ethersproject/abstract-signer": "npm:^5.4.0" - "@ethersproject/address": "npm:^5.4.0" - "@ethersproject/bignumber": "npm:^5.4.0" - "@ethersproject/bytes": "npm:^5.4.0" - "@ethersproject/keccak256": "npm:^5.4.0" - "@ethersproject/logger": "npm:^5.4.0" - "@ethersproject/properties": "npm:^5.4.0" - "@ethersproject/strings": "npm:^5.4.0" - checksum: 10c0/5adc1e3cbf734ab541e25042ce1d29e46b198c0f2d0cbfc1cfc85f57ecfea6d7f12ac9d60fccd94da8fce5cafe31526b32a5769ff95d5b3773b6531cfc762698 + "@ethersproject/abi": "npm:^5.8.0" + "@ethersproject/abstract-provider": "npm:^5.8.0" + "@ethersproject/abstract-signer": "npm:^5.8.0" + "@ethersproject/address": "npm:^5.8.0" + "@ethersproject/bignumber": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/constants": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + "@ethersproject/transactions": "npm:^5.8.0" + checksum: 10c0/49961b92334c4f2fab5f4da8f3119e97c1dc39cc8695e3043931757968213f5e732c00bf896193cf0186dcb33101dcd6efb70690dee0dd2cfbfd3843f55485aa languageName: node linkType: hard @@ -549,23 +540,20 @@ __metadata: languageName: node linkType: hard -"@ethersproject/hdnode@npm:5.4.0, @ethersproject/hdnode@npm:^5.4.0": - version: 5.4.0 - resolution: "@ethersproject/hdnode@npm:5.4.0" +"@ethersproject/hash@npm:5.8.0, @ethersproject/hash@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/hash@npm:5.8.0" dependencies: - "@ethersproject/abstract-signer": "npm:^5.4.0" - "@ethersproject/basex": "npm:^5.4.0" - "@ethersproject/bignumber": "npm:^5.4.0" - "@ethersproject/bytes": "npm:^5.4.0" - "@ethersproject/logger": "npm:^5.4.0" - "@ethersproject/pbkdf2": "npm:^5.4.0" - "@ethersproject/properties": "npm:^5.4.0" - "@ethersproject/sha2": "npm:^5.4.0" - "@ethersproject/signing-key": "npm:^5.4.0" - "@ethersproject/strings": "npm:^5.4.0" - "@ethersproject/transactions": "npm:^5.4.0" - "@ethersproject/wordlists": "npm:^5.4.0" - checksum: 10c0/9b04638f507e9e7ae7be86948054904036ab497b33ae9e44f51294854e1850532130687332d1c5c91d7748c27b453080f7c672efa6fcd4460e947117db29babd + "@ethersproject/abstract-signer": "npm:^5.8.0" + "@ethersproject/address": "npm:^5.8.0" + "@ethersproject/base64": "npm:^5.8.0" + "@ethersproject/bignumber": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/keccak256": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + "@ethersproject/strings": "npm:^5.8.0" + checksum: 10c0/72a287d4d70fae716827587339ffb449b8c23ef8728db6f8a661f359f7cb1e5ffba5b693c55e09d4e7162bf56af4a0e98a334784e0706d98102d1a5786241537 languageName: node linkType: hard @@ -589,24 +577,23 @@ __metadata: languageName: node linkType: hard -"@ethersproject/json-wallets@npm:5.4.0, @ethersproject/json-wallets@npm:^5.4.0": - version: 5.4.0 - resolution: "@ethersproject/json-wallets@npm:5.4.0" +"@ethersproject/hdnode@npm:5.8.0, @ethersproject/hdnode@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/hdnode@npm:5.8.0" dependencies: - "@ethersproject/abstract-signer": "npm:^5.4.0" - "@ethersproject/address": "npm:^5.4.0" - "@ethersproject/bytes": "npm:^5.4.0" - "@ethersproject/hdnode": "npm:^5.4.0" - "@ethersproject/keccak256": "npm:^5.4.0" - "@ethersproject/logger": "npm:^5.4.0" - "@ethersproject/pbkdf2": "npm:^5.4.0" - "@ethersproject/properties": "npm:^5.4.0" - "@ethersproject/random": "npm:^5.4.0" - "@ethersproject/strings": "npm:^5.4.0" - "@ethersproject/transactions": "npm:^5.4.0" - aes-js: "npm:3.0.0" - scrypt-js: "npm:3.0.1" - checksum: 10c0/abda169f5097ff0a30fed60db46759e31f416c434616547358cced6126d4f5c330f815a01572615f9a75e3101289e5457a820fb715abe82eabcd5fafc29cec74 + "@ethersproject/abstract-signer": "npm:^5.8.0" + "@ethersproject/basex": "npm:^5.8.0" + "@ethersproject/bignumber": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/pbkdf2": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + "@ethersproject/sha2": "npm:^5.8.0" + "@ethersproject/signing-key": "npm:^5.8.0" + "@ethersproject/strings": "npm:^5.8.0" + "@ethersproject/transactions": "npm:^5.8.0" + "@ethersproject/wordlists": "npm:^5.8.0" + checksum: 10c0/da0ac7d60e76a76471be1f4f3bba3f28a24165dc3b63c6930a9ec24481e9f8b23936e5fc96363b3591cdfda4381d4623f25b06898b89bf5530b158cb5ea58fdd languageName: node linkType: hard @@ -631,13 +618,24 @@ __metadata: languageName: node linkType: hard -"@ethersproject/keccak256@npm:5.4.0, @ethersproject/keccak256@npm:>=5.0.0-beta.127, @ethersproject/keccak256@npm:^5.4.0": - version: 5.4.0 - resolution: "@ethersproject/keccak256@npm:5.4.0" +"@ethersproject/json-wallets@npm:5.8.0, @ethersproject/json-wallets@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/json-wallets@npm:5.8.0" dependencies: - "@ethersproject/bytes": "npm:^5.4.0" - js-sha3: "npm:0.5.7" - checksum: 10c0/61c9bd5037e10f56475c16325e4652338f0002f69d30902a8a5ed09a2eeccf7aa5c2de144828ae077def84c5d74ede73778d7d947d0bc68592a7934540549ff2 + "@ethersproject/abstract-signer": "npm:^5.8.0" + "@ethersproject/address": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/hdnode": "npm:^5.8.0" + "@ethersproject/keccak256": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/pbkdf2": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + "@ethersproject/random": "npm:^5.8.0" + "@ethersproject/strings": "npm:^5.8.0" + "@ethersproject/transactions": "npm:^5.8.0" + aes-js: "npm:3.0.0" + scrypt-js: "npm:3.0.1" + checksum: 10c0/6c5cac87bdfac9ac47bf6ac25168a85865dc02e398e97f83820568c568a8cb27cf13a3a5d482f71a2534c7d704a3faa46023bb7ebe8737872b376bec1b66c67b languageName: node linkType: hard @@ -651,10 +649,13 @@ __metadata: languageName: node linkType: hard -"@ethersproject/logger@npm:5.4.1, @ethersproject/logger@npm:>=5.0.0-beta.129, @ethersproject/logger@npm:^5.4.0": - version: 5.4.1 - resolution: "@ethersproject/logger@npm:5.4.1" - checksum: 10c0/614c3fe834bebd03d723f3b05a8ce106560733b1758a7b3bc3b6e5a777e6aaebf9608974ecc2cd96f42e2b521e343ec01ad0df48c78e011f4656caaccec8f151 +"@ethersproject/keccak256@npm:5.8.0, @ethersproject/keccak256@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/keccak256@npm:5.8.0" + dependencies: + "@ethersproject/bytes": "npm:^5.8.0" + js-sha3: "npm:0.8.0" + checksum: 10c0/cd93ac6a5baf842313cde7de5e6e2c41feeea800db9e82955f96e7f3462d2ac6a6a29282b1c9e93b84ce7c91eec02347043c249fd037d6051214275bfc7fe99f languageName: node linkType: hard @@ -665,22 +666,13 @@ __metadata: languageName: node linkType: hard -"@ethersproject/logger@npm:^5.8.0": +"@ethersproject/logger@npm:5.8.0, @ethersproject/logger@npm:^5.8.0": version: 5.8.0 resolution: "@ethersproject/logger@npm:5.8.0" checksum: 10c0/7f39f33e8f254ee681d4778bb71ce3c5de248e1547666f85c43bfbc1c18996c49a31f969f056b66d23012f2420f2d39173107284bc41eb98d0482ace1d06403e languageName: node linkType: hard -"@ethersproject/networks@npm:5.4.2, @ethersproject/networks@npm:^5.4.0": - version: 5.4.2 - resolution: "@ethersproject/networks@npm:5.4.2" - dependencies: - "@ethersproject/logger": "npm:^5.4.0" - checksum: 10c0/02ee9fbbe08a1766a43ac46b4f0cbf941f723475ebf91e3d17974d94cf4893616caf3005d7703bf25522431286d663d80f341ee913e08945c31345bb710da4ce - languageName: node - linkType: hard - "@ethersproject/networks@npm:5.7.1, @ethersproject/networks@npm:^5.7.0": version: 5.7.1 resolution: "@ethersproject/networks@npm:5.7.1" @@ -690,13 +682,12 @@ __metadata: languageName: node linkType: hard -"@ethersproject/pbkdf2@npm:5.4.0, @ethersproject/pbkdf2@npm:^5.4.0": - version: 5.4.0 - resolution: "@ethersproject/pbkdf2@npm:5.4.0" +"@ethersproject/networks@npm:5.8.0, @ethersproject/networks@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/networks@npm:5.8.0" dependencies: - "@ethersproject/bytes": "npm:^5.4.0" - "@ethersproject/sha2": "npm:^5.4.0" - checksum: 10c0/06f217e7925cbd5aa52330a535998e183a03a39563f53d19e7ef71e58f41d898a1e8ca2e93d24d23524a5f80aeec00b6a43845357259a152effc35b16090e07f + "@ethersproject/logger": "npm:^5.8.0" + checksum: 10c0/3f23bcc4c3843cc9b7e4b9f34df0a1f230b24dc87d51cdad84552302159a84d7899cd80c8a3d2cf8007b09ac373a5b10407007adde23d4c4881a4d6ee6bc4b9c languageName: node linkType: hard @@ -710,12 +701,13 @@ __metadata: languageName: node linkType: hard -"@ethersproject/properties@npm:5.4.1, @ethersproject/properties@npm:>=5.0.0-beta.131, @ethersproject/properties@npm:^5.4.0": - version: 5.4.1 - resolution: "@ethersproject/properties@npm:5.4.1" +"@ethersproject/pbkdf2@npm:5.8.0, @ethersproject/pbkdf2@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/pbkdf2@npm:5.8.0" dependencies: - "@ethersproject/logger": "npm:^5.4.0" - checksum: 10c0/ebd147c5755c0464e671976fb6c9cc748bf85d5f5f41cc23b89e286a4c17831b5bd4c0bae21a82ddbdd6756409fc174b298c06a2c97fb7cfd31f48e915bc8285 + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/sha2": "npm:^5.8.0" + checksum: 10c0/0397cf5370cfd568743c3e46ac431f1bd425239baa2691689f1430997d44d310cef5051ea9ee53fabe444f96aced8d6324b41da698e8d7021389dce36251e7e9 languageName: node linkType: hard @@ -728,30 +720,12 @@ __metadata: languageName: node linkType: hard -"@ethersproject/providers@npm:5.4.5": - version: 5.4.5 - resolution: "@ethersproject/providers@npm:5.4.5" - dependencies: - "@ethersproject/abstract-provider": "npm:^5.4.0" - "@ethersproject/abstract-signer": "npm:^5.4.0" - "@ethersproject/address": "npm:^5.4.0" - "@ethersproject/basex": "npm:^5.4.0" - "@ethersproject/bignumber": "npm:^5.4.0" - "@ethersproject/bytes": "npm:^5.4.0" - "@ethersproject/constants": "npm:^5.4.0" - "@ethersproject/hash": "npm:^5.4.0" - "@ethersproject/logger": "npm:^5.4.0" - "@ethersproject/networks": "npm:^5.4.0" - "@ethersproject/properties": "npm:^5.4.0" - "@ethersproject/random": "npm:^5.4.0" - "@ethersproject/rlp": "npm:^5.4.0" - "@ethersproject/sha2": "npm:^5.4.0" - "@ethersproject/strings": "npm:^5.4.0" - "@ethersproject/transactions": "npm:^5.4.0" - "@ethersproject/web": "npm:^5.4.0" - bech32: "npm:1.1.4" - ws: "npm:7.4.6" - checksum: 10c0/e4b9d4e56d9f098bf769e5e64c36919fe47fe1715cbe8d72d6ceb41b8af68455e4f0818dacd7837c6be76cc9c58f91cbfc4cc3298f7ced16c2edfdb54e8dbce5 +"@ethersproject/properties@npm:5.8.0, @ethersproject/properties@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/properties@npm:5.8.0" + dependencies: + "@ethersproject/logger": "npm:^5.8.0" + checksum: 10c0/20256d7eed65478a38dabdea4c3980c6591b7b75f8c45089722b032ceb0e1cd3dd6dd60c436cfe259337e6909c28d99528c172d06fc74bbd61be8eb9e68be2e6 languageName: node linkType: hard @@ -783,13 +757,31 @@ __metadata: languageName: node linkType: hard -"@ethersproject/random@npm:5.4.0, @ethersproject/random@npm:^5.4.0": - version: 5.4.0 - resolution: "@ethersproject/random@npm:5.4.0" +"@ethersproject/providers@npm:5.8.0, @ethersproject/providers@npm:^5.7.2": + version: 5.8.0 + resolution: "@ethersproject/providers@npm:5.8.0" dependencies: - "@ethersproject/bytes": "npm:^5.4.0" - "@ethersproject/logger": "npm:^5.4.0" - checksum: 10c0/5c38194ba4606ee6420386c889f035130b214f381ad3c18dba3c644fc873fb95bfb2153bac37a7918058443e678c6b67f87a92fa36bb4a8c46f5be790546122d + "@ethersproject/abstract-provider": "npm:^5.8.0" + "@ethersproject/abstract-signer": "npm:^5.8.0" + "@ethersproject/address": "npm:^5.8.0" + "@ethersproject/base64": "npm:^5.8.0" + "@ethersproject/basex": "npm:^5.8.0" + "@ethersproject/bignumber": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/constants": "npm:^5.8.0" + "@ethersproject/hash": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/networks": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + "@ethersproject/random": "npm:^5.8.0" + "@ethersproject/rlp": "npm:^5.8.0" + "@ethersproject/sha2": "npm:^5.8.0" + "@ethersproject/strings": "npm:^5.8.0" + "@ethersproject/transactions": "npm:^5.8.0" + "@ethersproject/web": "npm:^5.8.0" + bech32: "npm:1.1.4" + ws: "npm:8.18.0" + checksum: 10c0/893dba429443bbf0a3eadef850e772ad1c706cf17ae6ae48b73467a23b614a3f461e9004850e24439b5c73d30e9259bc983f0f90a911ba11af749e6384fd355a languageName: node linkType: hard @@ -803,13 +795,13 @@ __metadata: languageName: node linkType: hard -"@ethersproject/rlp@npm:5.4.0, @ethersproject/rlp@npm:^5.4.0": - version: 5.4.0 - resolution: "@ethersproject/rlp@npm:5.4.0" +"@ethersproject/random@npm:5.8.0, @ethersproject/random@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/random@npm:5.8.0" dependencies: - "@ethersproject/bytes": "npm:^5.4.0" - "@ethersproject/logger": "npm:^5.4.0" - checksum: 10c0/e7b410e248f13d5d9a9f55e8043021940fdff726546a4d091a60cfabee2826d59115a3e610aa520440b0c4bbee7e9cc21f1fc07814a94669a17cf375efd87098 + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + checksum: 10c0/e44c010715668fc29383141ae16cd2ec00c34a434d47e23338e740b8c97372515d95d3b809b969eab2055c19e92b985ca591d326fbb71270c26333215f9925d1 languageName: node linkType: hard @@ -823,14 +815,13 @@ __metadata: languageName: node linkType: hard -"@ethersproject/sha2@npm:5.4.0, @ethersproject/sha2@npm:^5.4.0": - version: 5.4.0 - resolution: "@ethersproject/sha2@npm:5.4.0" +"@ethersproject/rlp@npm:5.8.0, @ethersproject/rlp@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/rlp@npm:5.8.0" dependencies: - "@ethersproject/bytes": "npm:^5.4.0" - "@ethersproject/logger": "npm:^5.4.0" - hash.js: "npm:1.1.7" - checksum: 10c0/7bab0d64f0b7fda6822800f938da0a278d7f71c3240744b56a11e943a19ff8f393c2e274b88e931fd7ade49113f19f758d607e04fc94ffd42177ade101d34fdd + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + checksum: 10c0/db742ec9c1566d6441242cc2c2ae34c1e5304d48e1fe62bc4e53b1791f219df211e330d2de331e0e4f74482664e205c2e4220e76138bd71f1ec07884e7f5221b languageName: node linkType: hard @@ -845,17 +836,14 @@ __metadata: languageName: node linkType: hard -"@ethersproject/signing-key@npm:5.4.0, @ethersproject/signing-key@npm:^5.4.0": - version: 5.4.0 - resolution: "@ethersproject/signing-key@npm:5.4.0" +"@ethersproject/sha2@npm:5.8.0, @ethersproject/sha2@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/sha2@npm:5.8.0" dependencies: - "@ethersproject/bytes": "npm:^5.4.0" - "@ethersproject/logger": "npm:^5.4.0" - "@ethersproject/properties": "npm:^5.4.0" - bn.js: "npm:^4.11.9" - elliptic: "npm:6.5.4" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" hash.js: "npm:1.1.7" - checksum: 10c0/de76689633a6eb1feb43f518255596b4da9ff0f9888fffd1f3b08e69f6f24b673c2aa571e1050b5bba61c68b07c7976237c36a1e29ab25f79de610dd15ba3c51 + checksum: 10c0/eab941907b7d40ee8436acaaedee32306ed4de2cb9ab37543bc89b1dd2a78f28c8da21efd848525fa1b04a78575be426cfca28f5392f4d28ce6c84e7c26a9421 languageName: node linkType: hard @@ -873,16 +861,17 @@ __metadata: languageName: node linkType: hard -"@ethersproject/solidity@npm:5.4.0": - version: 5.4.0 - resolution: "@ethersproject/solidity@npm:5.4.0" +"@ethersproject/signing-key@npm:5.8.0, @ethersproject/signing-key@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/signing-key@npm:5.8.0" dependencies: - "@ethersproject/bignumber": "npm:^5.4.0" - "@ethersproject/bytes": "npm:^5.4.0" - "@ethersproject/keccak256": "npm:^5.4.0" - "@ethersproject/sha2": "npm:^5.4.0" - "@ethersproject/strings": "npm:^5.4.0" - checksum: 10c0/30f99181988f13ffacdace47356ac336b556125aa9790983d6d65895fb3908edfac917db3dc63600af4c56e64b3052870b86608c678b337040cbe81648a1c434 + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + bn.js: "npm:^5.2.1" + elliptic: "npm:6.6.1" + hash.js: "npm:1.1.7" + checksum: 10c0/a7ff6cd344b0609737a496b6d5b902cf5528ed5a7ce2c0db5e7b69dc491d1810d1d0cd51dddf9dc74dd562ab4961d76e982f1750359b834c53c202e85e4c8502 languageName: node linkType: hard @@ -900,14 +889,17 @@ __metadata: languageName: node linkType: hard -"@ethersproject/strings@npm:5.4.0, @ethersproject/strings@npm:>=5.0.0-beta.130, @ethersproject/strings@npm:^5.4.0": - version: 5.4.0 - resolution: "@ethersproject/strings@npm:5.4.0" +"@ethersproject/solidity@npm:5.8.0, @ethersproject/solidity@npm:^5.7.0": + version: 5.8.0 + resolution: "@ethersproject/solidity@npm:5.8.0" dependencies: - "@ethersproject/bytes": "npm:^5.4.0" - "@ethersproject/constants": "npm:^5.4.0" - "@ethersproject/logger": "npm:^5.4.0" - checksum: 10c0/24c41487fbbf767e798c46462ef25be1cf379bc79477595ad364ce599e8c968aab73a9a8b6dedcaeffc4fbe2a1a418260124b384e57f7b46a17d7ed10266bf82 + "@ethersproject/bignumber": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/keccak256": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/sha2": "npm:^5.8.0" + "@ethersproject/strings": "npm:^5.8.0" + checksum: 10c0/5b5e0531bcec1d919cfbd261694694c8999ca5c379c1bb276ec779b896d299bb5db8ed7aa5652eb2c7605fe66455832b56ef123dec07f6ddef44231a7aa6fe6c languageName: node linkType: hard @@ -922,20 +914,14 @@ __metadata: languageName: node linkType: hard -"@ethersproject/transactions@npm:5.4.0, @ethersproject/transactions@npm:^5.0.0-beta.135, @ethersproject/transactions@npm:^5.4.0": - version: 5.4.0 - resolution: "@ethersproject/transactions@npm:5.4.0" +"@ethersproject/strings@npm:5.8.0, @ethersproject/strings@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/strings@npm:5.8.0" dependencies: - "@ethersproject/address": "npm:^5.4.0" - "@ethersproject/bignumber": "npm:^5.4.0" - "@ethersproject/bytes": "npm:^5.4.0" - "@ethersproject/constants": "npm:^5.4.0" - "@ethersproject/keccak256": "npm:^5.4.0" - "@ethersproject/logger": "npm:^5.4.0" - "@ethersproject/properties": "npm:^5.4.0" - "@ethersproject/rlp": "npm:^5.4.0" - "@ethersproject/signing-key": "npm:^5.4.0" - checksum: 10c0/28fe783d4e9344407621f2f1b887147888b624cc6cee9ebb3c51c876570ea77fa24e5be37a3313d85ccda8d186a3fa1259dd871c708fae71a0c50ceeb512ba74 + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/constants": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + checksum: 10c0/6db39503c4be130110612b6d593a381c62657e41eebf4f553247ebe394fda32cdf74ff645daee7b7860d209fd02c7e909a95b1f39a2f001c662669b9dfe81d00 languageName: node linkType: hard @@ -956,14 +942,20 @@ __metadata: languageName: node linkType: hard -"@ethersproject/units@npm:5.4.0": - version: 5.4.0 - resolution: "@ethersproject/units@npm:5.4.0" +"@ethersproject/transactions@npm:5.8.0, @ethersproject/transactions@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/transactions@npm:5.8.0" dependencies: - "@ethersproject/bignumber": "npm:^5.4.0" - "@ethersproject/constants": "npm:^5.4.0" - "@ethersproject/logger": "npm:^5.4.0" - checksum: 10c0/f376fad78c99c13ac51924b28f415651b9af40f9eeb336a5cfd8f5654f2ad4f62b57ab8d22cddb68d14a14deb3921dbccb8bb2ea4e9b7a8f5f4a5838a3eb38b9 + "@ethersproject/address": "npm:^5.8.0" + "@ethersproject/bignumber": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/constants": "npm:^5.8.0" + "@ethersproject/keccak256": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + "@ethersproject/rlp": "npm:^5.8.0" + "@ethersproject/signing-key": "npm:^5.8.0" + checksum: 10c0/dd32f090df5945313aafa8430ce76834479750d6655cb786c3b65ec841c94596b14d3c8c59ee93eed7b4f32f27d321a9b8b43bc6bb51f7e1c6694f82639ffe68 languageName: node linkType: hard @@ -978,7 +970,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/units@npm:^5.7.0": +"@ethersproject/units@npm:5.8.0, @ethersproject/units@npm:^5.7.0": version: 5.8.0 resolution: "@ethersproject/units@npm:5.8.0" dependencies: @@ -989,29 +981,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/wallet@npm:5.4.0": - version: 5.4.0 - resolution: "@ethersproject/wallet@npm:5.4.0" - dependencies: - "@ethersproject/abstract-provider": "npm:^5.4.0" - "@ethersproject/abstract-signer": "npm:^5.4.0" - "@ethersproject/address": "npm:^5.4.0" - "@ethersproject/bignumber": "npm:^5.4.0" - "@ethersproject/bytes": "npm:^5.4.0" - "@ethersproject/hash": "npm:^5.4.0" - "@ethersproject/hdnode": "npm:^5.4.0" - "@ethersproject/json-wallets": "npm:^5.4.0" - "@ethersproject/keccak256": "npm:^5.4.0" - "@ethersproject/logger": "npm:^5.4.0" - "@ethersproject/properties": "npm:^5.4.0" - "@ethersproject/random": "npm:^5.4.0" - "@ethersproject/signing-key": "npm:^5.4.0" - "@ethersproject/transactions": "npm:^5.4.0" - "@ethersproject/wordlists": "npm:^5.4.0" - checksum: 10c0/c188ed407ef191d7b1f857cc5d8388b10911164658ed8b798f5f5d6787fbe96cc471eb701965ddb59d1d6ec57493aea042f93319c2c08920a4f771f4a2470a8d - languageName: node - linkType: hard - "@ethersproject/wallet@npm:5.7.0": version: 5.7.0 resolution: "@ethersproject/wallet@npm:5.7.0" @@ -1035,16 +1004,26 @@ __metadata: languageName: node linkType: hard -"@ethersproject/web@npm:5.4.0, @ethersproject/web@npm:^5.4.0": - version: 5.4.0 - resolution: "@ethersproject/web@npm:5.4.0" +"@ethersproject/wallet@npm:5.8.0, @ethersproject/wallet@npm:^5.7.0": + version: 5.8.0 + resolution: "@ethersproject/wallet@npm:5.8.0" dependencies: - "@ethersproject/base64": "npm:^5.4.0" - "@ethersproject/bytes": "npm:^5.4.0" - "@ethersproject/logger": "npm:^5.4.0" - "@ethersproject/properties": "npm:^5.4.0" - "@ethersproject/strings": "npm:^5.4.0" - checksum: 10c0/b71caefbe4fd851d2b6fa7008e3f81074d718f6829e98d0d4046b8fe32fa0543fa77c7fa49e5efc3304b4b46c691cdeb550f2e1a1a3cca3a821a40a07866a5a1 + "@ethersproject/abstract-provider": "npm:^5.8.0" + "@ethersproject/abstract-signer": "npm:^5.8.0" + "@ethersproject/address": "npm:^5.8.0" + "@ethersproject/bignumber": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/hash": "npm:^5.8.0" + "@ethersproject/hdnode": "npm:^5.8.0" + "@ethersproject/json-wallets": "npm:^5.8.0" + "@ethersproject/keccak256": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + "@ethersproject/random": "npm:^5.8.0" + "@ethersproject/signing-key": "npm:^5.8.0" + "@ethersproject/transactions": "npm:^5.8.0" + "@ethersproject/wordlists": "npm:^5.8.0" + checksum: 10c0/6da450872dda3d9008bad3ccf8467816a63429241e51c66627647123c0fe5625494c4f6c306e098eb8419cc5702ac017d41f5161af5ff670a41fe5d199883c09 languageName: node linkType: hard @@ -1061,16 +1040,16 @@ __metadata: languageName: node linkType: hard -"@ethersproject/wordlists@npm:5.4.0, @ethersproject/wordlists@npm:^5.4.0": - version: 5.4.0 - resolution: "@ethersproject/wordlists@npm:5.4.0" +"@ethersproject/web@npm:5.8.0, @ethersproject/web@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/web@npm:5.8.0" dependencies: - "@ethersproject/bytes": "npm:^5.4.0" - "@ethersproject/hash": "npm:^5.4.0" - "@ethersproject/logger": "npm:^5.4.0" - "@ethersproject/properties": "npm:^5.4.0" - "@ethersproject/strings": "npm:^5.4.0" - checksum: 10c0/ad3c1c2f60bf7914c7beaf0a9d3731eaafc2d630d2e247d385aa52c8c4795e73549f0eca04428113df8a2238b38ba5837687fbb92522a2423fb5fef613252f6c + "@ethersproject/base64": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + "@ethersproject/strings": "npm:^5.8.0" + checksum: 10c0/e3cd547225638db6e94fcd890001c778d77adb0d4f11a7f8c447e961041678f3fbfaffe77a962c7aa3f6597504232442e7015f2335b1788508a108708a30308a languageName: node linkType: hard @@ -1087,6 +1066,19 @@ __metadata: languageName: node linkType: hard +"@ethersproject/wordlists@npm:5.8.0, @ethersproject/wordlists@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/wordlists@npm:5.8.0" + dependencies: + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/hash": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + "@ethersproject/strings": "npm:^5.8.0" + checksum: 10c0/e230a2ba075006bc3a2538e096003e43ef9ba453317f37a4d99638720487ec447c1fa61a592c80483f8a8ad6466511cf4cf5c49cf84464a1679999171ce311f4 + languageName: node + linkType: hard + "@fastify/busboy@npm:^2.0.0": version: 2.1.1 resolution: "@fastify/busboy@npm:2.1.1" @@ -1101,21 +1093,51 @@ __metadata: languageName: node linkType: hard -"@humanwhocodes/config-array@npm:^0.5.0": - version: 0.5.0 - resolution: "@humanwhocodes/config-array@npm:0.5.0" +"@humanfs/core@npm:^0.19.2": + version: 0.19.2 + resolution: "@humanfs/core@npm:0.19.2" dependencies: - "@humanwhocodes/object-schema": "npm:^1.2.0" - debug: "npm:^4.1.1" - minimatch: "npm:^3.0.4" - checksum: 10c0/217fac9e03492361825a2bf761d4bb7ec6d10002a10f7314142245eb13ac9d123523d24d5619c3c4159af215c7b3e583ed386108e227014bef4efbf9caca8ccc + "@humanfs/types": "npm:^0.15.0" + checksum: 10c0/d0a1d52d7b30c27d49475a53072d1510b81c5803e44b342fb8faf3887f1aa27593a1e6dc76a45268e7892d3f4e198146659281f6b6d55eacf3fd5a38bac30c5c languageName: node linkType: hard -"@humanwhocodes/object-schema@npm:^1.2.0": - version: 1.2.0 - resolution: "@humanwhocodes/object-schema@npm:1.2.0" - checksum: 10c0/2129b319392f3c72fbebe6a1b657039ef40b7a51b9ee532fac5bbd05421b456302a64c78778d8cb5384aa8fad7e5cf179ceee7608d81b3d6876e394c25cfe996 +"@humanfs/node@npm:^0.16.6": + version: 0.16.8 + resolution: "@humanfs/node@npm:0.16.8" + dependencies: + "@humanfs/core": "npm:^0.19.2" + "@humanfs/types": "npm:^0.15.0" + "@humanwhocodes/retry": "npm:^0.4.0" + checksum: 10c0/56140579db811af4e160b195d45d0f29acf644d192c93fe24c9e594ebf06f19dfc157494a07c84540b8a071c0e4b37209c2362765d31734f4d0be869c2422e25 + languageName: node + linkType: hard + +"@humanfs/types@npm:^0.15.0": + version: 0.15.0 + resolution: "@humanfs/types@npm:0.15.0" + checksum: 10c0/fc26b9a024b0e55f7eaf64036df94345bf5d36d6a41ef80ef38e78f1f7430ce26cf435af736adae58913baae18eac3f38c18739054a3d379102015978eae862e + languageName: node + linkType: hard + +"@humanwhocodes/module-importer@npm:^1.0.1": + version: 1.0.1 + resolution: "@humanwhocodes/module-importer@npm:1.0.1" + checksum: 10c0/909b69c3b86d482c26b3359db16e46a32e0fb30bd306a3c176b8313b9e7313dba0f37f519de6aa8b0a1921349e505f259d19475e123182416a506d7f87e7f529 + languageName: node + linkType: hard + +"@humanwhocodes/momoa@npm:^2.0.4": + version: 2.0.4 + resolution: "@humanwhocodes/momoa@npm:2.0.4" + checksum: 10c0/ff081fb5239eb23ae40c59bd51e8128d34b043be3b7c2adb2522cdff51b01ec3129e57d5a24a1eb3a082159d5b41fddfbaffc4cf46cae4fe11a51393f60424fd + languageName: node + linkType: hard + +"@humanwhocodes/retry@npm:^0.4.0, @humanwhocodes/retry@npm:^0.4.2": + version: 0.4.3 + resolution: "@humanwhocodes/retry@npm:0.4.3" + checksum: 10c0/3775bb30087d4440b3f7406d5a057777d90e4b9f435af488a4923ef249e93615fb78565a85f173a186a076c7706a81d0d57d563a2624e4de2c5c9c66c486ce42 languageName: node linkType: hard @@ -1142,29 +1164,67 @@ __metadata: languageName: node linkType: hard -"@keep-network/hardhat-helpers@npm:^0.6.0-pre.15": - version: 0.6.0-pre.15 - resolution: "@keep-network/hardhat-helpers@npm:0.6.0-pre.15" +"@jridgewell/resolve-uri@npm:^3.0.3": + version: 3.1.2 + resolution: "@jridgewell/resolve-uri@npm:3.1.2" + checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e + languageName: node + linkType: hard + +"@jridgewell/sourcemap-codec@npm:^1.4.10": + version: 1.6.0 + resolution: "@jridgewell/sourcemap-codec@npm:1.6.0" + checksum: 10c0/b5be700e45a775f218589c3466c4ffea630582b4988657652da464e5ab8a7d18bf928ee4fd2363fb346ede4bea9c6ff0bae05a538358c4565ece6199531b5f72 + languageName: node + linkType: hard + +"@jridgewell/trace-mapping@npm:0.3.9": + version: 0.3.9 + resolution: "@jridgewell/trace-mapping@npm:0.3.9" + dependencies: + "@jridgewell/resolve-uri": "npm:^3.0.3" + "@jridgewell/sourcemap-codec": "npm:^1.4.10" + checksum: 10c0/fa425b606d7c7ee5bfa6a31a7b050dd5814b4082f318e0e4190f991902181b4330f43f4805db1dd4f2433fd0ed9cc7a7b9c2683f1deeab1df1b0a98b1e24055b + languageName: node + linkType: hard + +"@keep-network/hardhat-helpers@npm:0.7.2": + version: 0.7.2 + resolution: "@keep-network/hardhat-helpers@npm:0.7.2" + peerDependencies: + "@nomicfoundation/hardhat-ethers": ^3.0.5 + "@nomicfoundation/hardhat-verify": ^2.0.3 + "@openzeppelin/hardhat-upgrades": ^3.0.2 + ethers: ^6.10.0 + hardhat: ^2.19.4 + hardhat-deploy: ^0.11.45 + checksum: 10c0/55949a24dd5425629cd914d17c60aaced658c84820f5eb6cfb27ab8e1e231afc17d3a360b03700ebde11c10013e7eee8fe3f45bc7866121c80ffbdaf1f6d9185 + languageName: node + linkType: hard + +"@keep-network/hardhat-helpers@patch:@keep-network/hardhat-helpers@npm%3A0.7.2#~/.yarn/patches/@keep-network-hardhat-helpers-npm-0.7.2-086cf3da54.patch": + version: 0.7.2 + resolution: "@keep-network/hardhat-helpers@patch:@keep-network/hardhat-helpers@npm%3A0.7.2#~/.yarn/patches/@keep-network-hardhat-helpers-npm-0.7.2-086cf3da54.patch::version=0.7.2&hash=b77b8f" peerDependencies: - "@nomiclabs/hardhat-ethers": ^2.1.0 - "@nomiclabs/hardhat-etherscan": ^3.1.0 - "@openzeppelin/hardhat-upgrades": ^1.20.0 - ethers: ^5.6.9 - hardhat: ^2.10.0 - hardhat-deploy: ^0.11.11 - checksum: 10c0/584803efa4aac6b81f8be9e24dab48ecd838adb33d8d54baeb4394ba92210d6cba40e12317604b25452fb4028cb2815194681469a526bea4a304749110854bf2 + "@nomicfoundation/hardhat-ethers": ^3.0.5 + "@nomicfoundation/hardhat-verify": ^2.0.3 + "@openzeppelin/hardhat-upgrades": ^3.0.2 + ethers: ^6.10.0 + hardhat: ^2.19.4 + hardhat-deploy: ^0.11.45 + checksum: 10c0/5705dad93a94d9f571853a325c7134bf2bddcb2fd9811e330e1744033449628175adc2b9e60c0987622b9a465b2744fa8f766ef7114ffee8370b920b4ad5d4c0 languageName: node linkType: hard -"@keep-network/hardhat-local-networks-config@npm:^0.1.0-pre.0": - version: 0.1.0-pre.0 - resolution: "@keep-network/hardhat-local-networks-config@npm:0.1.0-pre.0" +"@keep-network/hardhat-local-networks-config@github:threshold-network/hardhat-local-networks-config#6dff5bc8648127ca5d8696c321076bddb6d4142a": + version: 0.1.0-tlabs.0 + resolution: "@keep-network/hardhat-local-networks-config@https://github.com/threshold-network/hardhat-local-networks-config.git#commit=6dff5bc8648127ca5d8696c321076bddb6d4142a" dependencies: deepmerge: "npm:^4.2.2" untildify: "npm:^4.0.0" peerDependencies: hardhat: ^2.0.8 - checksum: 10c0/05d1a2764c41b9701c3031bc467b9571081c53f54a761c7c5d25c9cd31162af980dfd3a18f9bc8ae3696f93e88e8effa64c67e3081ffe28a68914fa930bf3a93 + checksum: 10c0/c6fe0ab5ded18f1275d3e4f0c3a9b30cc68450354faff40e7c78bbaf329486a24fb80f30dc9bf88017afb7a627fc57ef8faf909160454ab40149785b190dba09 languageName: node linkType: hard @@ -1172,61 +1232,93 @@ __metadata: version: 0.0.0-use.local resolution: "@keep-network/random-beacon@workspace:." dependencies: - "@keep-network/hardhat-helpers": "npm:^0.6.0-pre.15" - "@keep-network/hardhat-local-networks-config": "npm:^0.1.0-pre.0" - "@keep-network/sortition-pools": "npm:^2.0.0-pre.16" - "@nomiclabs/hardhat-ethers": "npm:^2.0.6" - "@nomiclabs/hardhat-etherscan": "npm:^3.1.0" - "@nomiclabs/hardhat-waffle": "npm:^2.0.1" + "@keep-network/hardhat-helpers": "patch:@keep-network/hardhat-helpers@npm%3A0.7.2#~/.yarn/patches/@keep-network-hardhat-helpers-npm-0.7.2-086cf3da54.patch" + "@keep-network/hardhat-local-networks-config": "github:threshold-network/hardhat-local-networks-config#6dff5bc8648127ca5d8696c321076bddb6d4142a" + "@nomicfoundation/hardhat-chai-matchers": "npm:^2.1.2" + "@nomicfoundation/hardhat-ethers": "npm:^3.1.3" + "@nomicfoundation/hardhat-network-helpers": "npm:^1.1.2" + "@nomicfoundation/hardhat-verify": "npm:^2.1.3" "@openzeppelin/contracts": "npm:4.7.3" - "@openzeppelin/hardhat-upgrades": "npm:^1.20.0" - "@tenderly/hardhat-tenderly": "npm:1.0.12" - "@thesis-co/eslint-config": "https://codeload.github.com/thesis/eslint-config/tar.gz/e63608fab2a1ad5c8fe89873bf0d4d4f9ef4a081" - "@thesis/solidity-contracts": "github:thesis/solidity-contracts#4985bcf" + "@openzeppelin/hardhat-upgrades": "patch:@openzeppelin/hardhat-upgrades@npm%3A2.5.1#~/.yarn/patches/@openzeppelin-hardhat-upgrades-npm-2.5.1-etherscan-v2.patch" + "@stylistic/eslint-plugin": "npm:^5.10.0" + "@tenderly/hardhat-tenderly": "npm:2.1.1" "@threshold-network/solidity-contracts": "npm:1.3.0-dev.14" - "@typechain/ethers-v5": "npm:^9.0.0" - "@typechain/hardhat": "npm:^4.0.0" - "@types/chai": "npm:^4.2.22" - "@types/mocha": "npm:^9.0.0" - "@types/node": "npm:^16.10.5" + "@typechain/ethers-v6": "patch:@typechain/ethers-v6@npm%3A0.5.1#~/.yarn/patches/@typechain-ethers-v6-npm-0.5.1-e825560376.patch" + "@typechain/hardhat": "npm:^9.1.0" + "@types/chai": "npm:^4.3.20" + "@types/mocha": "npm:^10.0.10" + "@types/node": "npm:^24.13.3" chai: "npm:^4.3.4" - eslint: "npm:^7.32.0" - ethereum-waffle: "npm:^3.4.0" - ethers: "npm:^5.4.7" + eslint: "npm:^10.10.0" + eslint-import-resolver-typescript: "npm:^4.4.5" + eslint-plugin-import-x: "npm:^4.17.1" + eslint-plugin-no-only-tests: "npm:^3.4.0" + ethers: "npm:^6.17.0" fs-extra: "npm:^11.2.0" + globals: "npm:^17.12.0" hardhat: "npm:2.29.0" hardhat-contract-sizer: "npm:^2.5.1" hardhat-dependency-compiler: "npm:^1.1.2" - hardhat-deploy: "npm:^0.11.11" + hardhat-deploy: "npm:^1.0.4" hardhat-gas-reporter: "npm:^2.3.0" - prettier: "npm:^2.4.1" - prettier-plugin-solidity: "npm:^1.0.0-beta.18" - solhint: "npm:^3.3.6" - solhint-config-keep: "https://codeload.github.com/keep-network/solhint-config-keep/tar.gz/5e1751e58c0f1c507305ffc8c7f6c58047657ada" + prettier: "npm:^3.9.6" + prettier-plugin-solidity: "npm:^2.4.1" + solhint: "npm:^6.2.4" solidity-docgen: "npm:^0.6.0-beta.35" ts-node: "npm:^10.2.1" - typechain: "npm:^7.0.0" - typescript: "npm:^4.4.3" + typechain: "npm:^8.3.2" + typescript: "npm:^6.0.3" + typescript-eslint: "npm:^8.70.0" languageName: unknown linkType: soft -"@keep-network/sortition-pools@npm:^2.0.0-pre.16": - version: 2.0.0-pre.16 - resolution: "@keep-network/sortition-pools@npm:2.0.0-pre.16" +"@keyv/bigmap@npm:^1.3.1": + version: 1.3.1 + resolution: "@keyv/bigmap@npm:1.3.1" dependencies: - "@openzeppelin/contracts": "npm:^4.3.2" - "@thesis/solidity-contracts": "github:thesis/solidity-contracts#4985bcf" - checksum: 10c0/eb101f0de70db7f02d94e4e1cf5cbf4547f04f53c52f23c1c6081c09f1ee1efa03214f9694e094ed745502e3a9115405bafeb4da95349d6d1cdecee29ac90837 + hashery: "npm:^1.4.0" + hookified: "npm:^1.15.0" + peerDependencies: + keyv: ^5.6.0 + checksum: 10c0/acc6a4a5edf462ce23e95672ab4bfaf7cd1941dff6bf3a2f671ce467961ace1fac9d3eb75a9ed9a8e92012e00a7d8b16ad1677bc539a52c3ad0cec31473e2349 languageName: node linkType: hard -"@noble/ciphers@npm:^1.3.0": - version: 1.3.0 - resolution: "@noble/ciphers@npm:1.3.0" +"@keyv/serialize@npm:^1.1.1": + version: 1.1.1 + resolution: "@keyv/serialize@npm:1.1.1" + checksum: 10c0/b0008cae4a54400c3abf587b8cc2474c6f528ee58969ce6cf9cb07a04006f80c73c85971d6be6544408318a2bc40108236a19a82aea0a6de95aae49533317374 + languageName: node + linkType: hard + +"@napi-rs/wasm-runtime@npm:^1.1.4": + version: 1.2.3 + resolution: "@napi-rs/wasm-runtime@npm:1.2.3" + dependencies: + "@tybys/wasm-util": "npm:^0.10.3" + peerDependencies: + "@emnapi/core": ^1.7.1 || ^2.0.0-alpha.4 + "@emnapi/runtime": ^1.7.1 || ^2.0.0-alpha.4 + checksum: 10c0/6da0a4bf9df79e9abfb3e3d462f6a5d42889be39426040038c9dd5925865585d7dbd06dd439c2ffc20f49ef2751412da5bd748cfb3c5b049142d72c0550f6f79 + languageName: node + linkType: hard + +"@noble/ciphers@npm:^1.3.0": + version: 1.3.0 + resolution: "@noble/ciphers@npm:1.3.0" checksum: 10c0/3ba6da645ce45e2f35e3b2e5c87ceba86b21dfa62b9466ede9edfb397f8116dae284f06652c0cd81d99445a2262b606632e868103d54ecc99fd946ae1af8cd37 languageName: node linkType: hard +"@noble/curves@npm:1.2.0": + version: 1.2.0 + resolution: "@noble/curves@npm:1.2.0" + dependencies: + "@noble/hashes": "npm:1.3.2" + checksum: 10c0/0bac7d1bbfb3c2286910b02598addd33243cb97c3f36f987ecc927a4be8d7d88e0fcb12b0f0ef8a044e7307d1844dd5c49bb724bfa0a79c8ec50ba60768c97f6 + languageName: node + linkType: hard + "@noble/curves@npm:1.4.2, @noble/curves@npm:~1.4.0": version: 1.4.2 resolution: "@noble/curves@npm:1.4.2" @@ -1270,6 +1362,13 @@ __metadata: languageName: node linkType: hard +"@noble/hashes@npm:1.3.2": + version: 1.3.2 + resolution: "@noble/hashes@npm:1.3.2" + checksum: 10c0/2482cce3bce6a596626f94ca296e21378e7a5d4c09597cbc46e65ffacc3d64c8df73111f2265444e36a3168208628258bbbaccba2ef24f65f58b2417638a20e7 + languageName: node + linkType: hard + "@noble/hashes@npm:1.4.0, @noble/hashes@npm:~1.4.0": version: 1.4.0 resolution: "@noble/hashes@npm:1.4.0" @@ -1298,33 +1397,6 @@ __metadata: languageName: node linkType: hard -"@nodelib/fs.scandir@npm:2.1.5": - version: 2.1.5 - resolution: "@nodelib/fs.scandir@npm:2.1.5" - dependencies: - "@nodelib/fs.stat": "npm:2.0.5" - run-parallel: "npm:^1.1.9" - checksum: 10c0/732c3b6d1b1e967440e65f284bd06e5821fedf10a1bea9ed2bb75956ea1f30e08c44d3def9d6a230666574edbaf136f8cfd319c14fd1f87c66e6a44449afb2eb - languageName: node - linkType: hard - -"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2": - version: 2.0.5 - resolution: "@nodelib/fs.stat@npm:2.0.5" - checksum: 10c0/88dafe5e3e29a388b07264680dc996c17f4bda48d163a9d4f5c1112979f0ce8ec72aa7116122c350b4e7976bc5566dc3ddb579be1ceaacc727872eb4ed93926d - languageName: node - linkType: hard - -"@nodelib/fs.walk@npm:^1.2.3": - version: 1.2.8 - resolution: "@nodelib/fs.walk@npm:1.2.8" - dependencies: - "@nodelib/fs.scandir": "npm:2.1.5" - fastq: "npm:^1.6.0" - checksum: 10c0/db9de047c3bb9b51f9335a7bb46f4fcfb6829fb628318c12115fbaf7d369bfce71c15b103d1fc3b464812d936220ee9bc1c8f762d032c9f6be9acc99249095b1 - languageName: node - linkType: hard - "@nomicfoundation/edr-darwin-arm64@npm:0.12.0-next.23": version: 0.12.0-next.23 resolution: "@nomicfoundation/edr-darwin-arm64@npm:0.12.0-next.23" @@ -1389,6 +1461,84 @@ __metadata: languageName: node linkType: hard +"@nomicfoundation/hardhat-chai-matchers@npm:^2.1.2": + version: 2.1.2 + resolution: "@nomicfoundation/hardhat-chai-matchers@npm:2.1.2" + dependencies: + "@types/chai-as-promised": "npm:^7.1.3" + chai-as-promised: "npm:^7.1.1" + deep-eql: "npm:^4.0.1" + ordinal: "npm:^1.0.3" + peerDependencies: + "@nomicfoundation/hardhat-ethers": ^3.1.0 + chai: ^4.2.0 + ethers: ^6.14.0 + hardhat: ^2.26.0 + checksum: 10c0/ed51e9d5e20869fc50f13ee7c8ad65e9531a6222a8b19c1afe21c28d563c8d2361c2f6f36a0c8a7b4e9b6c9c8df9f1878d6512b27919e18ea4e71bf28249bf86 + languageName: node + linkType: hard + +"@nomicfoundation/hardhat-ethers@npm:^3.0.4, @nomicfoundation/hardhat-ethers@npm:^3.1.3": + version: 3.1.3 + resolution: "@nomicfoundation/hardhat-ethers@npm:3.1.3" + dependencies: + debug: "npm:^4.1.1" + lodash.isequal: "npm:^4.5.0" + peerDependencies: + ethers: ^6.14.0 + hardhat: ^2.28.0 + checksum: 10c0/77a20741634a4028324cf329cac28205eff4a318ab92b0f42af4e714ebaab97a760bdba551fec446f4cea171a8964a6a89d19f33105fb8c8538d779a8a975093 + languageName: node + linkType: hard + +"@nomicfoundation/hardhat-network-helpers@npm:^1.1.2": + version: 1.1.2 + resolution: "@nomicfoundation/hardhat-network-helpers@npm:1.1.2" + dependencies: + ethereumjs-util: "npm:^7.1.4" + peerDependencies: + hardhat: ^2.26.0 + checksum: 10c0/00fb7392bc0a0c3df635a52fe350ae5e5a71610f3718e11e6b17753f6723231c81def37a19933cd96174cbc5362c0168c8fa98ea73910d46dd9d4bbba0c7990f + languageName: node + linkType: hard + +"@nomicfoundation/hardhat-verify@npm:^2.1.3": + version: 2.1.3 + resolution: "@nomicfoundation/hardhat-verify@npm:2.1.3" + dependencies: + "@ethersproject/abi": "npm:^5.1.2" + "@ethersproject/address": "npm:^5.0.2" + cbor: "npm:^8.1.0" + debug: "npm:^4.1.1" + lodash.clonedeep: "npm:^4.5.0" + picocolors: "npm:^1.1.0" + semver: "npm:^6.3.0" + table: "npm:^6.8.0" + undici: "npm:^5.14.0" + peerDependencies: + hardhat: ^2.26.0 + checksum: 10c0/daf420f4fdbbcbfe117077c5950d39ba5126bc57abc360ba2de55756bce4a455fe53f61ad0edcd04c9e2440cc3f8197631c586cfe5ad781efa5da2f79d7ccd19 + languageName: node + linkType: hard + +"@nomicfoundation/slang@npm:1.3.8": + version: 1.3.8 + resolution: "@nomicfoundation/slang@npm:1.3.8" + dependencies: + "@bytecodealliance/preview2-shim": "npm:^0.19.0" + checksum: 10c0/ec97aff9bc16bffcecddaca99e1c264e3b54138f148c72b41e033c17a269e62c6862ed05efee42a1f4f6bdda5726f0c804cdea56279630c26f529d35266c255d + languageName: node + linkType: hard + +"@nomicfoundation/slang@npm:^0.18.3": + version: 0.18.3 + resolution: "@nomicfoundation/slang@npm:0.18.3" + dependencies: + "@bytecodealliance/preview2-shim": "npm:0.17.0" + checksum: 10c0/68036dd38f953451c4b5825600cd44f46931608a9905811fb1d977fac00be5f16b1a39f2f2a0c65f4bbd064d81c05f44f5cd79e626798035815511de89c3b6d0 + languageName: node + linkType: hard + "@nomicfoundation/solidity-analyzer-darwin-arm64@npm:0.1.2": version: 0.1.2 resolution: "@nomicfoundation/solidity-analyzer-darwin-arm64@npm:0.1.2" @@ -1468,51 +1618,6 @@ __metadata: languageName: node linkType: hard -"@nomiclabs/hardhat-ethers@npm:^2.0.6": - version: 2.0.6 - resolution: "@nomiclabs/hardhat-ethers@npm:2.0.6" - peerDependencies: - ethers: ^5.0.0 - hardhat: ^2.0.0 - checksum: 10c0/f8bad2d51f05bc65ebd0061e80a3a3e9f3731bdabde3881aa913c94868916c01c3bef4835a170538a56544cd361f7dc06bdf38e6c46ca20e29c854c0038da8d5 - languageName: node - linkType: hard - -"@nomiclabs/hardhat-etherscan@npm:^3.1.0": - version: 3.1.0 - resolution: "@nomiclabs/hardhat-etherscan@npm:3.1.0" - dependencies: - "@ethersproject/abi": "npm:^5.1.2" - "@ethersproject/address": "npm:^5.0.2" - cbor: "npm:^5.0.2" - chalk: "npm:^2.4.2" - debug: "npm:^4.1.1" - fs-extra: "npm:^7.0.1" - lodash: "npm:^4.17.11" - semver: "npm:^6.3.0" - table: "npm:^6.8.0" - undici: "npm:^5.4.0" - peerDependencies: - hardhat: ^2.0.4 - checksum: 10c0/62079b8f39520ac3f62842a448039eb1ed181c27ea27f298f1d2d601e46ec9854099a74e042ed84260961f61445faaae676c051cb0a54fe1b43f85f3e8a11edd - languageName: node - linkType: hard - -"@nomiclabs/hardhat-waffle@npm:^2.0.1": - version: 2.0.1 - resolution: "@nomiclabs/hardhat-waffle@npm:2.0.1" - dependencies: - "@types/sinon-chai": "npm:^3.2.3" - "@types/web3": "npm:1.0.19" - peerDependencies: - "@nomiclabs/hardhat-ethers": ^2.0.0 - ethereum-waffle: ^3.2.0 - ethers: ^5.0.0 - hardhat: ^2.0.0 - checksum: 10c0/409d70274b83f454b60749b5003afa3a585b1a1fce98f3ae2338006d43bd17f47deedba09bfa69b5d9fac1ae133168877e7848420d326f05765081bacc61dab9 - languageName: node - linkType: hard - "@npmcli/agent@npm:^4.0.0": version: 4.0.0 resolution: "@npmcli/agent@npm:4.0.0" @@ -1556,7 +1661,7 @@ __metadata: languageName: node linkType: hard -"@openzeppelin/contracts@npm:^4.1.0, @openzeppelin/contracts@npm:^4.3.2": +"@openzeppelin/contracts@npm:^4.1.0": version: 4.9.1 resolution: "@openzeppelin/contracts@npm:4.9.1" checksum: 10c0/bdf5626424c8f1efaf5ee9e4e042ec20ec0d86d1aceaa1c79e909f57c1811c85f2164064a795737dbc84dfb3eae1c5365fe87cd331eafd2798cd6c49cd1ad8d3 @@ -1570,40 +1675,127 @@ __metadata: languageName: node linkType: hard -"@openzeppelin/hardhat-upgrades@npm:^1.20.0": - version: 1.20.0 - resolution: "@openzeppelin/hardhat-upgrades@npm:1.20.0" +"@openzeppelin/defender-admin-client@npm:^1.52.0": + version: 1.54.6 + resolution: "@openzeppelin/defender-admin-client@npm:1.54.6" + dependencies: + "@openzeppelin/defender-base-client": "npm:1.54.6" + axios: "npm:^1.4.0" + ethers: "npm:^5.7.2" + lodash: "npm:^4.17.19" + node-fetch: "npm:^2.6.0" + checksum: 10c0/784d7d0eee87916546654f8265f0823401b18f34f0c168daa5c3c353000b5a8e595edc26a384a5f4052dedf2602947e58620442c6f1f46760bfb99a77a5ae69d + languageName: node + linkType: hard + +"@openzeppelin/defender-base-client@npm:1.54.6, @openzeppelin/defender-base-client@npm:^1.52.0": + version: 1.54.6 + resolution: "@openzeppelin/defender-base-client@npm:1.54.6" + dependencies: + amazon-cognito-identity-js: "npm:^6.0.1" + async-retry: "npm:^1.3.3" + axios: "npm:^1.4.0" + lodash: "npm:^4.17.19" + node-fetch: "npm:^2.6.0" + checksum: 10c0/adeac961ae8e06e620ff6ff227090180613fbad233bbed962ae1d1769f1a936cdba24b952a1c10fec69bf9695a7faf7572fe86fd174198b86e26706391784bef + languageName: node + linkType: hard + +"@openzeppelin/defender-sdk-base-client@npm:^1.15.2, @openzeppelin/defender-sdk-base-client@npm:^1.8.0": + version: 1.15.2 + resolution: "@openzeppelin/defender-sdk-base-client@npm:1.15.2" + dependencies: + amazon-cognito-identity-js: "npm:^6.3.6" + async-retry: "npm:^1.3.3" + checksum: 10c0/cb1f5a286564b7f4da0c6f4b21f032b7e09697c2e476c2cf3d957287bc9dc880d0f1c2a4b21d42bc8246a99ea117ce39cfff6fd18f20ca63ac3dc859a43b62a1 + languageName: node + linkType: hard + +"@openzeppelin/defender-sdk-deploy-client@npm:^1.8.0": + version: 1.15.2 + resolution: "@openzeppelin/defender-sdk-deploy-client@npm:1.15.2" + dependencies: + "@openzeppelin/defender-sdk-base-client": "npm:^1.15.2" + axios: "npm:^1.7.2" + lodash: "npm:^4.17.21" + checksum: 10c0/af3db2976d14bdeb7b24e109209a37fcd98ab14176ebd62f0543d0dff552fd9359b382e35c2698315e195c42f55b2bc52b2aea0f598a070ac0a24274a1ba93d9 + languageName: node + linkType: hard + +"@openzeppelin/hardhat-upgrades@npm:2.5.1": + version: 2.5.1 + resolution: "@openzeppelin/hardhat-upgrades@npm:2.5.1" + dependencies: + "@openzeppelin/defender-admin-client": "npm:^1.52.0" + "@openzeppelin/defender-base-client": "npm:^1.52.0" + "@openzeppelin/defender-sdk-base-client": "npm:^1.8.0" + "@openzeppelin/defender-sdk-deploy-client": "npm:^1.8.0" + "@openzeppelin/upgrades-core": "npm:^1.31.2" + chalk: "npm:^4.1.0" + debug: "npm:^4.1.1" + ethereumjs-util: "npm:^7.1.5" + proper-lockfile: "npm:^4.1.1" + undici: "npm:^5.14.0" + peerDependencies: + "@nomicfoundation/hardhat-ethers": ^3.0.0 + "@nomicfoundation/hardhat-verify": ^1.1.0 + ethers: ^6.6.0 + hardhat: ^2.0.2 + peerDependenciesMeta: + "@nomicfoundation/hardhat-verify": + optional: true + bin: + migrate-oz-cli-project: dist/scripts/migrate-oz-cli-project.js + checksum: 10c0/3c032048a2d58fd59a1287234c5d045e7b231afb6ed3d906f9d5751b93f29dd5f1cbfdd0898c62cc8397ca111a98b7fa032cc93929adbc2072d1ad8bfbcded72 + languageName: node + linkType: hard + +"@openzeppelin/hardhat-upgrades@patch:@openzeppelin/hardhat-upgrades@npm%3A2.5.1#~/.yarn/patches/@openzeppelin-hardhat-upgrades-npm-2.5.1-etherscan-v2.patch": + version: 2.5.1 + resolution: "@openzeppelin/hardhat-upgrades@patch:@openzeppelin/hardhat-upgrades@npm%3A2.5.1#~/.yarn/patches/@openzeppelin-hardhat-upgrades-npm-2.5.1-etherscan-v2.patch::version=2.5.1&hash=6d2f71" dependencies: - "@openzeppelin/upgrades-core": "npm:^1.18.0" + "@openzeppelin/defender-admin-client": "npm:^1.52.0" + "@openzeppelin/defender-base-client": "npm:^1.52.0" + "@openzeppelin/defender-sdk-base-client": "npm:^1.8.0" + "@openzeppelin/defender-sdk-deploy-client": "npm:^1.8.0" + "@openzeppelin/upgrades-core": "npm:^1.31.2" chalk: "npm:^4.1.0" debug: "npm:^4.1.1" + ethereumjs-util: "npm:^7.1.5" proper-lockfile: "npm:^4.1.1" + undici: "npm:^5.14.0" peerDependencies: - "@nomiclabs/hardhat-ethers": ^2.0.0 - "@nomiclabs/hardhat-etherscan": ^3.1.0 - ethers: ^5.0.5 + "@nomicfoundation/hardhat-ethers": ^3.0.0 + "@nomicfoundation/hardhat-verify": ^1.1.0 + ethers: ^6.6.0 hardhat: ^2.0.2 peerDependenciesMeta: - "@nomiclabs/harhdat-etherscan": + "@nomicfoundation/hardhat-verify": optional: true bin: migrate-oz-cli-project: dist/scripts/migrate-oz-cli-project.js - checksum: 10c0/5c8cfeaf6e05a7a3aada40f12ae8367fdd590ead623b2f30ade59cf2b6e29bd92f9b105e2f00beec6a5933969f789a644c7563048b4c1e4f6c14ad50143766a5 + checksum: 10c0/8a15e1ed75c3833f501bca1b53baf56babc4d6055576e92d3b18752a92352dbe7a39c7836d49bff0ba786c7c2fc842773da70aee8a7765c7fed8dd2530295dd4 languageName: node linkType: hard -"@openzeppelin/upgrades-core@npm:^1.18.0": - version: 1.19.1 - resolution: "@openzeppelin/upgrades-core@npm:1.19.1" +"@openzeppelin/upgrades-core@npm:^1.31.2": + version: 1.46.0 + resolution: "@openzeppelin/upgrades-core@npm:1.46.0" dependencies: - cbor: "npm:^8.0.0" + "@nomicfoundation/slang": "npm:^0.18.3" + bignumber.js: "npm:^9.1.2" + cbor: "npm:^10.0.0" chalk: "npm:^4.1.0" - compare-versions: "npm:^5.0.0" + compare-versions: "npm:^6.0.0" debug: "npm:^4.1.1" ethereumjs-util: "npm:^7.0.3" + minimatch: "npm:^10.2.5" + minimist: "npm:^1.2.7" proper-lockfile: "npm:^4.1.1" - solidity-ast: "npm:^0.4.15" - checksum: 10c0/a46d72034bf0599a5fc2be424dccaac3baeaca24bbe8d95da014e5b5cc1ca2ffec5a0b69ee215ad23eacbf51d873e60dd6c2776f07eb475e5471f2562d02876c + solidity-ast: "npm:^0.4.60" + bin: + openzeppelin-upgrades-core: dist/cli/cli.js + checksum: 10c0/11b938ef442cecb8441a8022f67b5fb3e87e84f521b8d33d2b1f94ef954382f8538e59afa58e23cd5ec29f39446ea67f428d30416b8a03671dc509aff87167e4 languageName: node linkType: hard @@ -1614,48 +1806,30 @@ __metadata: languageName: node linkType: hard -"@resolver-engine/core@npm:^0.3.3": - version: 0.3.3 - resolution: "@resolver-engine/core@npm:0.3.3" - dependencies: - debug: "npm:^3.1.0" - is-url: "npm:^1.2.4" - request: "npm:^2.85.0" - checksum: 10c0/a562d412b2976b36be85878112518e85cb32a024334bb191f9657adb7e38f264c0b91429a954e7e097bb5c8fc54c6df76840cd43590c73be4dc7932150eb6e01 - languageName: node - linkType: hard - -"@resolver-engine/fs@npm:^0.3.3": - version: 0.3.3 - resolution: "@resolver-engine/fs@npm:0.3.3" - dependencies: - "@resolver-engine/core": "npm:^0.3.3" - debug: "npm:^3.1.0" - checksum: 10c0/4f21e8633eb5225aeb24ca3f0ebf74129cbb497d704ed473c5f49bfc3d4b7c33a4a02decc966b7b4d654b517a4a88661cc2b84784cf6d394c1e1e5d49f371cc7 +"@pnpm/config.env-replace@npm:^1.1.0": + version: 1.1.0 + resolution: "@pnpm/config.env-replace@npm:1.1.0" + checksum: 10c0/4cfc4a5c49ab3d0c6a1f196cfd4146374768b0243d441c7de8fa7bd28eaab6290f514b98490472cc65dbd080d34369447b3e9302585e1d5c099befd7c8b5e55f languageName: node linkType: hard -"@resolver-engine/imports-fs@npm:^0.3.3": - version: 0.3.3 - resolution: "@resolver-engine/imports-fs@npm:0.3.3" +"@pnpm/network.ca-file@npm:^1.0.1": + version: 1.0.2 + resolution: "@pnpm/network.ca-file@npm:1.0.2" dependencies: - "@resolver-engine/fs": "npm:^0.3.3" - "@resolver-engine/imports": "npm:^0.3.3" - debug: "npm:^3.1.0" - checksum: 10c0/bcbd1e11f10550353ba4b82f29a5d9026d9f6cb625ccaaaf52898542fee832d11fc3eedaaf5089a5f6b0e3213c810233209f8e345b19c6a9994f58d6fec1adeb + graceful-fs: "npm:4.2.10" + checksum: 10c0/95f6e0e38d047aca3283550719155ce7304ac00d98911e4ab026daedaf640a63bd83e3d13e17c623fa41ac72f3801382ba21260bcce431c14fbbc06430ecb776 languageName: node linkType: hard -"@resolver-engine/imports@npm:^0.3.3": - version: 0.3.3 - resolution: "@resolver-engine/imports@npm:0.3.3" +"@pnpm/npm-conf@npm:^3.0.2": + version: 3.0.3 + resolution: "@pnpm/npm-conf@npm:3.0.3" dependencies: - "@resolver-engine/core": "npm:^0.3.3" - debug: "npm:^3.1.0" - hosted-git-info: "npm:^2.6.0" - path-browserify: "npm:^1.0.0" - url: "npm:^0.11.0" - checksum: 10c0/efdb3996ebaac05702edfa35ff4a9f53e4ef141e91ea534ce84becc65371638091b0c2e912f020ee5b654fb32a60b29591a3ea769af9ed70b9f8039bd278f571 + "@pnpm/config.env-replace": "npm:^1.1.0" + "@pnpm/network.ca-file": "npm:^1.0.1" + config-chain: "npm:^1.1.11" + checksum: 10c0/74a276b4acf609edd60300afef3e5c632ecf9f3e9b9da486314edd0478964815f4a03e9c9b1e0cb1f38e2acfef07e5c2d3211527b8f97a0c44cbb040f2755e5c languageName: node linkType: hard @@ -1825,99 +1999,72 @@ __metadata: languageName: node linkType: hard -"@sindresorhus/is@npm:^0.14.0": - version: 0.14.0 - resolution: "@sindresorhus/is@npm:0.14.0" - checksum: 10c0/7247aa9314d4fc3df9b3f63d8b5b962a89c7600a5db1f268546882bfc4d31a975a899f5f42a09dd41a11e58636e6402f7c40f92df853aee417247bb11faee9a0 - languageName: node - linkType: hard - -"@sinonjs/commons@npm:^1.7.0": - version: 1.8.3 - resolution: "@sinonjs/commons@npm:1.8.3" - dependencies: - type-detect: "npm:4.0.8" - checksum: 10c0/e4d2471feb19f735654f798fcdf389b90fab5913da609f566b04c4cdd9131a97e897d565251d35389aeebcca70a22ab4ed2291c7f7927706ead12e4f94841bf1 - languageName: node - linkType: hard - -"@sinonjs/fake-timers@npm:^7.1.0": - version: 7.1.2 - resolution: "@sinonjs/fake-timers@npm:7.1.2" - dependencies: - "@sinonjs/commons": "npm:^1.7.0" - checksum: 10c0/c94de47ff2eceb2a7009c970f932509e81e474b555ea994343aea4c87aed26844ba298a70d585c0769e63fe379ebae6aaad61d37b3bca71f740a8d3d49f1bc27 +"@sindresorhus/is@npm:^5.2.0": + version: 5.6.0 + resolution: "@sindresorhus/is@npm:5.6.0" + checksum: 10c0/66727344d0c92edde5760b5fd1f8092b717f2298a162a5f7f29e4953e001479927402d9d387e245fb9dc7d3b37c72e335e93ed5875edfc5203c53be8ecba1b52 languageName: node linkType: hard -"@solidity-parser/parser@npm:^0.13.2": - version: 0.13.2 - resolution: "@solidity-parser/parser@npm:0.13.2" +"@smithy/types@npm:^4.17.2": + version: 4.18.0 + resolution: "@smithy/types@npm:4.18.0" dependencies: - antlr4ts: "npm:^0.5.0-alpha.4" - checksum: 10c0/bb26201e7bd34bb52b6cae54dfd593a42b18ca1011530c30eb91d47cdebd7e6f6c1be6099a33f314a6cc5e5351e4c50c12c7335bc1f1078d7c6555ac8804d317 + tslib: "npm:^2.6.2" + checksum: 10c0/f948eaf2c6004ce919a5a203615da4d2d4923465df764c2f6ab982fcacde10c81e1fd23c40f983387459ffdad056f8e827ebecaa776a4331ed4f6431ad8bdd34 languageName: node linkType: hard -"@solidity-parser/parser@npm:^0.20.1": +"@solidity-parser/parser@npm:^0.20.1, @solidity-parser/parser@npm:^0.20.2": version: 0.20.2 resolution: "@solidity-parser/parser@npm:0.20.2" checksum: 10c0/23b0b7ed343a4fa55cb8621cf4fc81b0bdd791a4ee7e96ced7778db07de66d4e418db2c2dc1525b1f82fc0310ac829c78382327292b37e35cb30a19961fcb429 languageName: node linkType: hard -"@szmarczak/http-timer@npm:^1.1.2": - version: 1.1.2 - resolution: "@szmarczak/http-timer@npm:1.1.2" - dependencies: - defer-to-connect: "npm:^1.0.1" - checksum: 10c0/0594140e027ce4e98970c6d176457fcbff80900b1b3101ac0d08628ca6d21d70e0b94c6aaada94d4f76c1423fcc7195af83da145ce0fd556fc0595ca74a17b8b - languageName: node - linkType: hard - -"@tenderly/hardhat-tenderly@npm:1.0.12": - version: 1.0.12 - resolution: "@tenderly/hardhat-tenderly@npm:1.0.12" +"@stylistic/eslint-plugin@npm:^5.10.0": + version: 5.10.0 + resolution: "@stylistic/eslint-plugin@npm:5.10.0" dependencies: - axios: "npm:^0.21.1" - fs-extra: "npm:^9.0.1" - js-yaml: "npm:^3.14.0" + "@eslint-community/eslint-utils": "npm:^4.9.1" + "@typescript-eslint/types": "npm:^8.56.0" + eslint-visitor-keys: "npm:^4.2.1" + espree: "npm:^10.4.0" + estraverse: "npm:^5.3.0" + picomatch: "npm:^4.0.3" peerDependencies: - hardhat: ^2.0.3 - checksum: 10c0/6834011e41215508f7086767ed4e32e0d7d4300c70d8a9e4e511c86b9cf40972a7f380d8abd9fc6d0162558ee03171d3442f8f2eab7303d9680c55d1d8683de6 + eslint: ^9.0.0 || ^10.0.0 + checksum: 10c0/2cc6e592d5b2ab691290cc39ed377c0f6226667b367ffc6a0bf3a4bf6dd36b011d17c83f377600a48946f6bb037390b35a8b3c273b3c40d161c00b44512a129e languageName: node linkType: hard -"@thesis-co/eslint-config@https://codeload.github.com/thesis/eslint-config/tar.gz/e63608fab2a1ad5c8fe89873bf0d4d4f9ef4a081": - version: 0.2.0 - resolution: "@thesis-co/eslint-config@https://codeload.github.com/thesis/eslint-config/tar.gz/e63608fab2a1ad5c8fe89873bf0d4d4f9ef4a081" - dependencies: - "@thesis-co/prettier-config": "github:thesis/prettier-config" - "@typescript-eslint/eslint-plugin": "npm:^4.32.0" - "@typescript-eslint/parser": "npm:^4.32.0" - eslint-config-airbnb: "npm:^18.2.1" - eslint-config-airbnb-base: "npm:^14.2.1" - eslint-config-airbnb-typescript: "npm:^14.0.0" - eslint-config-prettier: "npm:^8.3.0" - eslint-plugin-import: "npm:^2.23.4" - eslint-plugin-jsx-a11y: "npm:^6.4.1" - eslint-plugin-no-only-tests: "npm:^2.6.0" - eslint-plugin-prettier: "npm:^4.0.0" - eslint-plugin-react: "npm:^7.25.2" - eslint-plugin-react-hooks: "npm:^4.2.0" - peerDependencies: - eslint: ">=6.8.0" - eslint-plugin-import: ^2.18.2 - checksum: 10c0/1d0318c18dfd7ecf032ff892d2fd6c050788fe939a29d0146edb4de8bd9c23f721b8ce4aa15fddc7792be9df1f3e543c647eb92f54af0270d127521525747fbd +"@szmarczak/http-timer@npm:^5.0.1": + version: 5.0.1 + resolution: "@szmarczak/http-timer@npm:5.0.1" + dependencies: + defer-to-connect: "npm:^2.0.1" + checksum: 10c0/4629d2fbb2ea67c2e9dc03af235c0991c79ebdddcbc19aed5d5732fb29ce01c13331e9b1a491584b9069bd6ecde6581dcbf871f11b7eefdebbab34de6cf2197e languageName: node linkType: hard -"@thesis-co/prettier-config@github:thesis/prettier-config": - version: 0.0.1 - resolution: "@thesis-co/prettier-config@https://github.com/thesis/prettier-config.git#commit=a1a333e7ac49928a0f6ed39421906dd1e46ab0f3" +"@tenderly/hardhat-tenderly@npm:2.1.1": + version: 2.1.1 + resolution: "@tenderly/hardhat-tenderly@npm:2.1.1" + dependencies: + "@ethersproject/bignumber": "npm:^5.7.0" + "@nomicfoundation/hardhat-ethers": "npm:^3.0.4" + axios: "npm:^0.27.2" + ethers: "npm:^6.8.1" + fs-extra: "npm:^10.1.0" + hardhat-deploy: "npm:^0.11.43" + tenderly: "npm:^0.8.0" + ts-node: "npm:^10.9.1" + tslog: "npm:^4.3.1" + typescript: "npm:^5.2.2" peerDependencies: - prettier: ^2.3.0 - checksum: 10c0/3b267cb14cdf519d38cbc6708903e7bb8397f10db0fe44f8b5e72cd8aa646f86bf42b3a47ea3c4ea6ec761329a7d4ddf371860833a58d6b0de114edf1e783bbb + ethers: ^6.8.1 + hardhat: ^2.19.0 + checksum: 10c0/f51fdef7e3b857d5f7f6bc0f139f2b565641dc9f31805376245d65af815493a79cf60a6888f3a70f0d29c55eabed4fe972e7ab6ac138a13d4fb71046d60a671f languageName: node linkType: hard @@ -1941,6 +2088,17 @@ __metadata: languageName: node linkType: hard +"@threshold-network/solidity-contracts@patch:@threshold-network/solidity-contracts@npm%3A1.3.0-dev.14#./.yarn/patches/@threshold-network-solidity-contracts-npm-1.3.0-dev.14-ethers-v6.patch::locator=%40keep-network%2Frandom-beacon%40workspace%3A.": + version: 1.3.0-dev.14 + resolution: "@threshold-network/solidity-contracts@patch:@threshold-network/solidity-contracts@npm%3A1.3.0-dev.14#./.yarn/patches/@threshold-network-solidity-contracts-npm-1.3.0-dev.14-ethers-v6.patch::version=1.3.0-dev.14&hash=fd9350&locator=%40keep-network%2Frandom-beacon%40workspace%3A." + dependencies: + "@openzeppelin/contracts": "npm:~4.5.0" + "@openzeppelin/contracts-upgradeable": "npm:~4.5.2" + "@thesis/solidity-contracts": "github:thesis/solidity-contracts#4985bcf" + checksum: 10c0/a6a7d2facb4e5ee695b55706dfe2c47eeca68bc3e73a3e76eaffa4df5e677360a33282101a25209aada1d83c1234839a013f93d784bb9a9c435b24f1d3cbf902 + languageName: node + linkType: hard + "@tsconfig/node10@npm:^1.0.7": version: 1.0.8 resolution: "@tsconfig/node10@npm:1.0.8" @@ -1969,49 +2127,58 @@ __metadata: languageName: node linkType: hard -"@typechain/ethers-v5@npm:^2.0.0": - version: 2.0.0 - resolution: "@typechain/ethers-v5@npm:2.0.0" +"@tybys/wasm-util@npm:^0.10.3": + version: 0.10.3 + resolution: "@tybys/wasm-util@npm:0.10.3" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/fd2bd2a79c6cd8c79ed1cf7a0fa375c64589264c88a27acaf9756d556b453ea222b62a4f68dd2fbb8b3a78b6bab3b1f4fb2431b6afc6aeda8344b53a521a1cd3 + languageName: node + linkType: hard + +"@typechain/ethers-v6@npm:0.5.1": + version: 0.5.1 + resolution: "@typechain/ethers-v6@npm:0.5.1" dependencies: - ethers: "npm:^5.0.2" + lodash: "npm:^4.17.15" + ts-essentials: "npm:^7.0.1" peerDependencies: - ethers: ^5.0.0 - typechain: ^3.0.0 - checksum: 10c0/882a82e59f8aa4f7bb070ed0cbfb68be96b8b813656296cdaac130d8efce58231708f91d3f38dd3d1819f8875b0b5e713151ca064ce158601fc6c2b696036dd8 + ethers: 6.x + typechain: ^8.3.2 + typescript: ">=4.7.0" + checksum: 10c0/f3c80151c07e01adbf520e0854426649edb0ee540920569487dd8da7eca2fa8615710f4c0eda008e7afdf255fbb8dfdebf721a5d324a4dffeb087611d9bd64b9 languageName: node linkType: hard -"@typechain/ethers-v5@npm:^9.0.0": - version: 9.0.0 - resolution: "@typechain/ethers-v5@npm:9.0.0" +"@typechain/ethers-v6@patch:@typechain/ethers-v6@npm%3A0.5.1#~/.yarn/patches/@typechain-ethers-v6-npm-0.5.1-e825560376.patch": + version: 0.5.1 + resolution: "@typechain/ethers-v6@patch:@typechain/ethers-v6@npm%3A0.5.1#~/.yarn/patches/@typechain-ethers-v6-npm-0.5.1-e825560376.patch::version=0.5.1&hash=496509" dependencies: lodash: "npm:^4.17.15" ts-essentials: "npm:^7.0.1" peerDependencies: - "@ethersproject/abi": ^5.0.0 - "@ethersproject/bytes": ^5.0.0 - "@ethersproject/providers": ^5.0.0 - ethers: ^5.1.3 - typechain: ^7.0.0 - typescript: ">=4.0.0" - checksum: 10c0/4aa3d0669a3d5a2cab14a39d4d3e5bc616ee909dd90b9e01be211a0c05759c67af9118a4530515db47c8a7b3a1a5a06a26daa9d14ea24766feb7c043b636c4d8 + ethers: 6.x + typechain: ^8.3.2 + typescript: ">=4.7.0" + checksum: 10c0/cbf3447ec6ac2351df39f69c11066d8f3e48d1c9792281127499cc53da66b537db97e4a4385c925ab9c2fe04ea25912a126bd71f28564a93343d4f1c901f764b languageName: node linkType: hard -"@typechain/hardhat@npm:^4.0.0": - version: 4.0.0 - resolution: "@typechain/hardhat@npm:4.0.0" +"@typechain/hardhat@npm:^9.1.0": + version: 9.1.0 + resolution: "@typechain/hardhat@npm:9.1.0" dependencies: fs-extra: "npm:^9.1.0" peerDependencies: - hardhat: ^2.0.10 - lodash: ^4.17.15 - typechain: ^7.0.0 - checksum: 10c0/f1004bfb11e08ea786a930401be0d22bab58eb1ee3c8901baa8cd467e45fe8a451d6f1e6b86d53ac84338c9fd3b7f422184d68274cbf7877196e695e2e301238 + "@typechain/ethers-v6": ^0.5.1 + ethers: ^6.1.0 + hardhat: ^2.9.9 + typechain: ^8.3.2 + checksum: 10c0/3a1220efefc7b02ca335696167f6c5332a33ff3fbf9f20552468566a1760f76bc88d330683e97ca6213eb9518a2a901391c31c84c0548006b72bd2ec62d4af9c languageName: node linkType: hard -"@types/bn.js@npm:*, @types/bn.js@npm:^5.1.0": +"@types/bn.js@npm:^5.1.0": version: 5.1.0 resolution: "@types/bn.js@npm:5.1.0" dependencies: @@ -2020,68 +2187,61 @@ __metadata: languageName: node linkType: hard -"@types/bn.js@npm:^4.11.3, @types/bn.js@npm:^4.11.5": - version: 4.11.6 - resolution: "@types/bn.js@npm:4.11.6" +"@types/chai-as-promised@npm:^7.1.3": + version: 7.1.8 + resolution: "@types/chai-as-promised@npm:7.1.8" dependencies: - "@types/node": "npm:*" - checksum: 10c0/a5a19dafc106b1b2ab35c2024ca37b9d0938dced11cb1cca7d119de5a0dd5f54db525c82cb1392843fc921677452efcbbdce3aa96ecc1457d3de6e266915ebd0 + "@types/chai": "npm:*" + checksum: 10c0/c0a19cffe8d3f406b2cb9ba17f5f0efe318b14f27896d807b3199cc2231c16a4b5b6c464fdf2a939214de481de58cffd46c240539d3d4ece18659277d71ccc23 languageName: node linkType: hard -"@types/chai@npm:*, @types/chai@npm:^4.2.22": +"@types/chai@npm:*": version: 4.2.22 resolution: "@types/chai@npm:4.2.22" checksum: 10c0/e26c6f35b02b84c45262971a171c03561ad63a8190d527e2cb02311bf0e27b09adb6cf515101cd5bebe1de43927c5f28a71c0fca8842c4331a41da40968c82e8 languageName: node linkType: hard -"@types/json-schema@npm:^7.0.7": - version: 7.0.9 - resolution: "@types/json-schema@npm:7.0.9" - checksum: 10c0/46a9e92b7922495a50f55632d802f7e7ab2dffd76b3f894baf7b28012e73983df832977bedd748aa9a2bc8400c6e8659ca39faf6ccd93d71d41d5b0293338a0e +"@types/chai@npm:^4.3.20": + version: 4.3.20 + resolution: "@types/chai@npm:4.3.20" + checksum: 10c0/4601189d611752e65018f1ecadac82e94eed29f348e1d5430e5681a60b01e1ecf855d9bcc74ae43b07394751f184f6970fac2b5561fc57a1f36e93a0f5ffb6e8 languageName: node linkType: hard -"@types/json5@npm:^0.0.29": - version: 0.0.29 - resolution: "@types/json5@npm:0.0.29" - checksum: 10c0/6bf5337bc447b706bb5b4431d37686aa2ea6d07cfd6f79cc31de80170d6ff9b1c7384a9c0ccbc45b3f512bae9e9f75c2e12109806a15331dc94e8a8db6dbb4ac +"@types/esrecurse@npm:^4.3.1": + version: 4.3.1 + resolution: "@types/esrecurse@npm:4.3.1" + checksum: 10c0/90dad74d5da3ad27606d8e8e757322f33171cfeaa15ad558b615cf71bb2a516492d18f55f4816384685a3eb2412142e732bbae9a4a7cd2cf3deb7572aa4ebe03 languageName: node linkType: hard -"@types/keyv@npm:^3.1.1": - version: 3.1.4 - resolution: "@types/keyv@npm:3.1.4" - dependencies: - "@types/node": "npm:*" - checksum: 10c0/ff8f54fc49621210291f815fe5b15d809fd7d032941b3180743440bd507ecdf08b9e844625fa346af568c84bf34114eb378dcdc3e921a08ba1e2a08d7e3c809c +"@types/estree@npm:^1.0.6, @types/estree@npm:^1.0.8": + version: 1.0.9 + resolution: "@types/estree@npm:1.0.9" + checksum: 10c0/3ad3286ca2988cd550dafb8f2ad599c8474868e954fa601a36655bdfefd8039f7c714b8c1c7f2ae219ffbd58bd4660e66fa7479a0120fc02d4777057d4865387 languageName: node linkType: hard -"@types/mkdirp@npm:^0.5.2": - version: 0.5.2 - resolution: "@types/mkdirp@npm:0.5.2" - dependencies: - "@types/node": "npm:*" - checksum: 10c0/c3c6c9bdd1f13b2f114dd34122fd2b030220398501a2727bfe0442615a363dd8f3a89aa4e6d25727ee44c8478fb451aefef82e72184dc1bd04e48334808f37dd +"@types/http-cache-semantics@npm:^4.0.2": + version: 4.2.0 + resolution: "@types/http-cache-semantics@npm:4.2.0" + checksum: 10c0/82dd33cbe7d4843f1e884a251c6a12d385b62274353b9db167462e7fbffdbb3a83606f9952203017c5b8cabbd7b9eef0cf240a3a9dedd20f69875c9701939415 languageName: node linkType: hard -"@types/mocha@npm:^9.0.0": - version: 9.0.0 - resolution: "@types/mocha@npm:9.0.0" - checksum: 10c0/82501aa1453ffe204d94f0a975e2ff266bfe38fb66a788a6c1fd72db3b7707534fb28f60b99eee128b22df7efa2b3064c57e749ec5f142d294854bb43f3da82d +"@types/json-schema@npm:^7.0.15": + version: 7.0.15 + resolution: "@types/json-schema@npm:7.0.15" + checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db languageName: node linkType: hard -"@types/node-fetch@npm:^2.5.5": - version: 2.5.12 - resolution: "@types/node-fetch@npm:2.5.12" - dependencies: - "@types/node": "npm:*" - form-data: "npm:^3.0.0" - checksum: 10c0/aaa69c354e596f9e293136ac43c9e5d91503415fb4eddfae3a9689153f0f033863bbd627e700b3f419ce14d06303e18e1d61b788d9085411f1fc12fc56afe356 +"@types/mocha@npm:^10.0.10": + version: 10.0.10 + resolution: "@types/mocha@npm:10.0.10" + checksum: 10c0/d2b8c48138cde6923493e42b38e839695eb42edd04629abe480a8f34c0e3f50dd82a55832c2e8d2b6e6f9e4deb492d7d733e600fbbdd5a0ceccbcfc6844ff9d5 languageName: node linkType: hard @@ -2092,17 +2252,21 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^12.12.6": - version: 12.20.25 - resolution: "@types/node@npm:12.20.25" - checksum: 10c0/0df9f6ca83c0a7f79b31e33ba0bd0fd6a8df8ffeb0025fac4bbf9c8d37187f7ad275493c40796e990aba6ab51165e77da7eff634845db491ceb395d7fd99f7a6 +"@types/node@npm:22.7.5": + version: 22.7.5 + resolution: "@types/node@npm:22.7.5" + dependencies: + undici-types: "npm:~6.19.2" + checksum: 10c0/cf11f74f1a26053ec58066616e3a8685b6bcd7259bc569738b8f752009f9f0f7f85a1b2d24908e5b0f752482d1e8b6babdf1fbb25758711ec7bb9500bfcd6e60 languageName: node linkType: hard -"@types/node@npm:^16.10.5": - version: 16.10.5 - resolution: "@types/node@npm:16.10.5" - checksum: 10c0/393f10b7c8928cfd5c0353628f062773752970105366aecd3df010d974cef311e06b672702f090492f9048e81eabc8b37031ba1dd172e3ca9620cec1c74c64dc +"@types/node@npm:^24.13.3": + version: 24.13.3 + resolution: "@types/node@npm:24.13.3" + dependencies: + undici-types: "npm:~7.18.0" + checksum: 10c0/a5bc08f49b9581dcdca90e02cd77197a3c799840807664942e5cd5161a553d4d2ae8064f7e3294410d748d7d098b5c1848be7fa50c06f29c4193ab16be4e59eb languageName: node linkType: hard @@ -2123,183 +2287,315 @@ __metadata: linkType: hard "@types/qs@npm:^6.9.7": - version: 6.9.7 - resolution: "@types/qs@npm:6.9.7" - checksum: 10c0/157eb05f4c75790b0ebdcf7b0547ff117feabc8cda03c3cac3d3ea82bb19a1912e76a411df3eb0bdd01026a9770f07bc0e7e3fbe39ebb31c1be4564c16be35f1 + version: 6.14.0 + resolution: "@types/qs@npm:6.14.0" + checksum: 10c0/5b3036df6e507483869cdb3858201b2e0b64b4793dc4974f188caa5b5732f2333ab9db45c08157975054d3b070788b35088b4bc60257ae263885016ee2131310 languageName: node linkType: hard -"@types/resolve@npm:^0.0.8": - version: 0.0.8 - resolution: "@types/resolve@npm:0.0.8" +"@types/secp256k1@npm:^4.0.1": + version: 4.0.3 + resolution: "@types/secp256k1@npm:4.0.3" dependencies: "@types/node": "npm:*" - checksum: 10c0/ead6902f01e7240918e6f6dabf0e2bc37035492b1da16f605bbd1e153c17d0639df77981b2ec042480361be76c9e967543287d9b312cd668ed9123524994c344 + checksum: 10c0/56822201fad7677a30f732cd3eb94651bb2797bd4e876ff5ec6a3d5c419a11b97ec18ff38ae86bbb945f578ed3d29856221375e1dcbc4ba640020049fcf9535c languageName: node linkType: hard -"@types/responselike@npm:^1.0.0": - version: 1.0.3 - resolution: "@types/responselike@npm:1.0.3" +"@typescript-eslint/eslint-plugin@npm:8.70.0": + version: 8.70.0 + resolution: "@typescript-eslint/eslint-plugin@npm:8.70.0" dependencies: - "@types/node": "npm:*" - checksum: 10c0/a58ba341cb9e7d74f71810a88862da7b2a6fa42e2a1fc0ce40498f6ea1d44382f0640117057da779f74c47039f7166bf48fad02dc876f94e005c7afa50f5e129 + "@eslint-community/regexpp": "npm:^4.12.2" + "@typescript-eslint/scope-manager": "npm:8.70.0" + "@typescript-eslint/type-utils": "npm:8.70.0" + "@typescript-eslint/utils": "npm:8.70.0" + "@typescript-eslint/visitor-keys": "npm:8.70.0" + ignore: "npm:^7.0.5" + natural-compare: "npm:^1.4.0" + ts-api-utils: "npm:^2.5.0" + peerDependencies: + "@typescript-eslint/parser": ^8.70.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/e69f6f697493f4b5cb0411498edd63d75afb3e6881c632f9b23c416e64dd06458956ae489a253f0d08b90645b935a32a509d1e2b17068974a2a34a5c2b3f334b languageName: node linkType: hard -"@types/secp256k1@npm:^4.0.1": - version: 4.0.3 - resolution: "@types/secp256k1@npm:4.0.3" +"@typescript-eslint/parser@npm:8.70.0": + version: 8.70.0 + resolution: "@typescript-eslint/parser@npm:8.70.0" dependencies: - "@types/node": "npm:*" - checksum: 10c0/56822201fad7677a30f732cd3eb94651bb2797bd4e876ff5ec6a3d5c419a11b97ec18ff38ae86bbb945f578ed3d29856221375e1dcbc4ba640020049fcf9535c + "@typescript-eslint/scope-manager": "npm:8.70.0" + "@typescript-eslint/types": "npm:8.70.0" + "@typescript-eslint/typescript-estree": "npm:8.70.0" + "@typescript-eslint/visitor-keys": "npm:8.70.0" + debug: "npm:^4.4.3" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/6d35e0cad56902295599c3da7e4f4c97ebf6f19fcc4333100ad05ef757ba9c431db9cdbd886b6748eb88afd0bc64f8c1c7a81b37589bbd4cc346f6e9eb4e3d12 languageName: node linkType: hard -"@types/sinon-chai@npm:^3.2.3": - version: 3.2.5 - resolution: "@types/sinon-chai@npm:3.2.5" +"@typescript-eslint/project-service@npm:8.70.0": + version: 8.70.0 + resolution: "@typescript-eslint/project-service@npm:8.70.0" dependencies: - "@types/chai": "npm:*" - "@types/sinon": "npm:*" - checksum: 10c0/c2457c19a52a35ae79620a505fd914430b90719451359ac8bdf4060c2743c2de67110f359a36ae9a79b201e4b71f2661bbbc15eb085e50789be38d33f2eeb349 + "@typescript-eslint/tsconfig-utils": "npm:^8.70.0" + "@typescript-eslint/types": "npm:^8.70.0" + debug: "npm:^4.4.3" + peerDependencies: + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/eb7d0b4c91015e9aa47672ba20dfda0717e5fa09afa7e28f25b5d7b7b0cd8af4b394f94c3a1528358a7d8c8be4165ed4291a345cbe19bb137a24c6a4f006b398 languageName: node linkType: hard -"@types/sinon@npm:*": - version: 10.0.4 - resolution: "@types/sinon@npm:10.0.4" +"@typescript-eslint/scope-manager@npm:8.70.0": + version: 8.70.0 + resolution: "@typescript-eslint/scope-manager@npm:8.70.0" dependencies: - "@sinonjs/fake-timers": "npm:^7.1.0" - checksum: 10c0/f0e8950739f277a72f6d7aaca65bc0a00cd249217e6f0b47baee5b984a8eb7ae603eb179cb8f46c5f38bf62725d1b210d846be03bb54f93d62a90f75731abe98 + "@typescript-eslint/types": "npm:8.70.0" + "@typescript-eslint/visitor-keys": "npm:8.70.0" + checksum: 10c0/ca05825fb16266d90e73bd1745407f719fc6d5fdb33045cdae21d3259f13c9b54d8b956d5c64a3eb83baff7690527fb16d01a2d7318379f97fb79a1cbf8ca103 languageName: node linkType: hard -"@types/underscore@npm:*": - version: 1.11.3 - resolution: "@types/underscore@npm:1.11.3" - checksum: 10c0/b56d61fab06845c04977f4ed846e8a01ad26a727b590d7d2b5fabe577b0003ccbdc5e4ee562e0f5d898d4500d57ca478e8c68d92e03f2ae0801233ea79caf28e +"@typescript-eslint/tsconfig-utils@npm:8.70.0, @typescript-eslint/tsconfig-utils@npm:^8.70.0": + version: 8.70.0 + resolution: "@typescript-eslint/tsconfig-utils@npm:8.70.0" + peerDependencies: + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/925df7c1fbb4e8050dda3fa3dad4a6f515a1f7f2b43f5c145d9eaac856adb84bba04eb5038cc0f78c2307c1df4e2d64dbb4e2e47abffa4844e25cfe62ce402cf languageName: node linkType: hard -"@types/web3@npm:1.0.19": - version: 1.0.19 - resolution: "@types/web3@npm:1.0.19" +"@typescript-eslint/type-utils@npm:8.70.0": + version: 8.70.0 + resolution: "@typescript-eslint/type-utils@npm:8.70.0" dependencies: - "@types/bn.js": "npm:*" - "@types/underscore": "npm:*" - checksum: 10c0/b7ef3f2e03552dfec7ab17228bfa43e19c3dee24aa0ee01297ac6f3d0826d19a9a88beeb0ec4d969a146865b4fc07b201b57bb7c636355c4f3f2b423ba54674b + "@typescript-eslint/types": "npm:8.70.0" + "@typescript-eslint/typescript-estree": "npm:8.70.0" + "@typescript-eslint/utils": "npm:8.70.0" + debug: "npm:^4.4.3" + ts-api-utils: "npm:^2.5.0" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/b745dc16a9ae50fc1bf7880388425d05d7d1775d23819dfcbdbe5930829fb426d7a011a9848494f427f61e236a4deeb9e8f0fd60db4b7a717a791c8454d63584 languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^4.32.0": - version: 4.33.0 - resolution: "@typescript-eslint/eslint-plugin@npm:4.33.0" - dependencies: - "@typescript-eslint/experimental-utils": "npm:4.33.0" - "@typescript-eslint/scope-manager": "npm:4.33.0" - debug: "npm:^4.3.1" - functional-red-black-tree: "npm:^1.0.1" - ignore: "npm:^5.1.8" - regexpp: "npm:^3.1.0" - semver: "npm:^7.3.5" - tsutils: "npm:^3.21.0" - peerDependencies: - "@typescript-eslint/parser": ^4.0.0 - eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/c1e1e424e257fa6e5e8b18d7ff77e8a983a761f4acc0cd58ebd31de8ec56c8c472689989cff0290eee41457662a1e664b555cf74bfc1b37bdf8c87ccac2a4663 +"@typescript-eslint/types@npm:8.70.0, @typescript-eslint/types@npm:^8.56.0, @typescript-eslint/types@npm:^8.70.0": + version: 8.70.0 + resolution: "@typescript-eslint/types@npm:8.70.0" + checksum: 10c0/e3f98d0c0e708fcadebb3b457bf3f38a2512220b6bc9823212cacf310377539fb3c24f9e9e754d13b611a3ac6028a0bba16d02eeef03198c65e7ba605bb2036d languageName: node linkType: hard -"@typescript-eslint/experimental-utils@npm:4.33.0": - version: 4.33.0 - resolution: "@typescript-eslint/experimental-utils@npm:4.33.0" +"@typescript-eslint/typescript-estree@npm:8.70.0": + version: 8.70.0 + resolution: "@typescript-eslint/typescript-estree@npm:8.70.0" dependencies: - "@types/json-schema": "npm:^7.0.7" - "@typescript-eslint/scope-manager": "npm:4.33.0" - "@typescript-eslint/types": "npm:4.33.0" - "@typescript-eslint/typescript-estree": "npm:4.33.0" - eslint-scope: "npm:^5.1.1" - eslint-utils: "npm:^3.0.0" + "@typescript-eslint/project-service": "npm:8.70.0" + "@typescript-eslint/tsconfig-utils": "npm:8.70.0" + "@typescript-eslint/types": "npm:8.70.0" + "@typescript-eslint/visitor-keys": "npm:8.70.0" + debug: "npm:^4.4.3" + minimatch: "npm:^10.2.2" + semver: "npm:^7.7.3" + tinyglobby: "npm:^0.2.15" + ts-api-utils: "npm:^2.5.0" peerDependencies: - eslint: "*" - checksum: 10c0/bb2a48c9df21ef06ccbcd083753b8c51b30a46cde67ab56d278b30ad7868d2e07641e51b6f7fb54437dcb7aff134fac44708e730e2b8f6e43027fefe8629bcb9 + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/11e6c9c0108184902bc229376cce00eb81ee2b88a7cc3bf02a8c159bf59b2c7af21d2b330976b1751fedd5c27e257731b0d60840268299582c458c2a0a29525e languageName: node linkType: hard -"@typescript-eslint/parser@npm:^4.32.0": - version: 4.33.0 - resolution: "@typescript-eslint/parser@npm:4.33.0" +"@typescript-eslint/utils@npm:8.70.0": + version: 8.70.0 + resolution: "@typescript-eslint/utils@npm:8.70.0" dependencies: - "@typescript-eslint/scope-manager": "npm:4.33.0" - "@typescript-eslint/types": "npm:4.33.0" - "@typescript-eslint/typescript-estree": "npm:4.33.0" - debug: "npm:^4.3.1" + "@eslint-community/eslint-utils": "npm:^4.9.1" + "@typescript-eslint/scope-manager": "npm:8.70.0" + "@typescript-eslint/types": "npm:8.70.0" + "@typescript-eslint/typescript-estree": "npm:8.70.0" peerDependencies: - eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/d6f91479b2c0d0ff20ac2dbc7540b28c175fd834a220a4f227209f6c74c55401ac6bd41b2bb4cf40b3ba7761075ccded2019bfc6096c2e4f273bd4ae86c44172 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/15353ecd0c5e29057e5846c6b84de601b679448e01293dbf1ae7dbe94ab6d4b586f8690a262630522441307fafad01ab3b0b46a85eb71907c19a2f124d7bba3f languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:4.33.0": - version: 4.33.0 - resolution: "@typescript-eslint/scope-manager@npm:4.33.0" +"@typescript-eslint/visitor-keys@npm:8.70.0": + version: 8.70.0 + resolution: "@typescript-eslint/visitor-keys@npm:8.70.0" dependencies: - "@typescript-eslint/types": "npm:4.33.0" - "@typescript-eslint/visitor-keys": "npm:4.33.0" - checksum: 10c0/1dfe65777eeb430c1ef778bdad35e6065d4b3075ddb2639d0747d8db93c02eebf6832ba82388a7f80662e0e9f61f1922fe939b53a20889e11fb9f80c4029c6b7 + "@typescript-eslint/types": "npm:8.70.0" + eslint-visitor-keys: "npm:^5.0.0" + checksum: 10c0/43fe28dc1045a686deead8c9334f6e9d8b3fa8f84917147aabd9747783b8bc531254a95a9bfb33355b25cf5ec9a72c62bcde313f13869d7a5e5603d96be593a9 languageName: node linkType: hard -"@typescript-eslint/types@npm:4.33.0": - version: 4.33.0 - resolution: "@typescript-eslint/types@npm:4.33.0" - checksum: 10c0/6c94780a589eca7a75ae2b014f320bc412b50794c39ab04889918bb39a40e72584b65c8c0b035330cb0599579afaa3adccee40701f63cf39c0e89299de199d4b +"@unrs/resolver-binding-android-arm-eabi@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-android-arm-eabi@npm:1.12.2" + conditions: os=android & cpu=arm languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:4.33.0": - version: 4.33.0 - resolution: "@typescript-eslint/typescript-estree@npm:4.33.0" - dependencies: - "@typescript-eslint/types": "npm:4.33.0" - "@typescript-eslint/visitor-keys": "npm:4.33.0" - debug: "npm:^4.3.1" - globby: "npm:^11.0.3" - is-glob: "npm:^4.0.1" - semver: "npm:^7.3.5" - tsutils: "npm:^3.21.0" - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/67609a7bdd680136765d103dec4b8afb38a17436e8a5cd830da84f62c6153c3acba561da3b9e2140137b1a0bcbbfc19d4256c692f7072acfebcff88db079e22b +"@unrs/resolver-binding-android-arm64@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-android-arm64@npm:1.12.2" + conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:4.33.0": - version: 4.33.0 - resolution: "@typescript-eslint/visitor-keys@npm:4.33.0" - dependencies: - "@typescript-eslint/types": "npm:4.33.0" - eslint-visitor-keys: "npm:^2.0.0" - checksum: 10c0/95b3904db6113ef365892567d47365e6af3708e6fa905743426036f99e1b7fd4a275facec5d939afecb618369f9d615e379d39f96b8936f469e75507c41c249c +"@unrs/resolver-binding-darwin-arm64@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-darwin-arm64@npm:1.12.2" + conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@yarnpkg/lockfile@npm:^1.1.0": - version: 1.1.0 - resolution: "@yarnpkg/lockfile@npm:1.1.0" - checksum: 10c0/0bfa50a3d756623d1f3409bc23f225a1d069424dbc77c6fd2f14fb377390cd57ec703dc70286e081c564be9051ead9ba85d81d66a3e68eeb6eb506d4e0c0fbda +"@unrs/resolver-binding-darwin-x64@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-darwin-x64@npm:1.12.2" + conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"abbrev@npm:^4.0.0": +"@unrs/resolver-binding-freebsd-x64@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-freebsd-x64@npm:1.12.2" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-arm-gnueabihf@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-arm-gnueabihf@npm:1.12.2" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-arm-musleabihf@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-arm-musleabihf@npm:1.12.2" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-arm64-gnu@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-arm64-gnu@npm:1.12.2" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-arm64-musl@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-arm64-musl@npm:1.12.2" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-loong64-gnu@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-loong64-gnu@npm:1.12.2" + conditions: os=linux & cpu=loong64 & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-loong64-musl@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-loong64-musl@npm:1.12.2" + conditions: os=linux & cpu=loong64 & libc=musl + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-ppc64-gnu@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-ppc64-gnu@npm:1.12.2" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-riscv64-gnu@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-riscv64-gnu@npm:1.12.2" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-riscv64-musl@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-riscv64-musl@npm:1.12.2" + conditions: os=linux & cpu=riscv64 & libc=musl + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-s390x-gnu@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-s390x-gnu@npm:1.12.2" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-x64-gnu@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-x64-gnu@npm:1.12.2" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-x64-musl@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-linux-x64-musl@npm:1.12.2" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@unrs/resolver-binding-openharmony-arm64@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-openharmony-arm64@npm:1.12.2" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + +"@unrs/resolver-binding-wasm32-wasi@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-wasm32-wasi@npm:1.12.2" + dependencies: + "@emnapi/core": "npm:1.10.0" + "@emnapi/runtime": "npm:1.10.0" + "@napi-rs/wasm-runtime": "npm:^1.1.4" + conditions: cpu=wasm32 + languageName: node + linkType: hard + +"@unrs/resolver-binding-win32-arm64-msvc@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-win32-arm64-msvc@npm:1.12.2" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@unrs/resolver-binding-win32-ia32-msvc@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-win32-ia32-msvc@npm:1.12.2" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@unrs/resolver-binding-win32-x64-msvc@npm:1.12.2": + version: 1.12.2 + resolution: "@unrs/resolver-binding-win32-x64-msvc@npm:1.12.2" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"abbrev@npm:^4.0.0": version: 4.0.0 resolution: "abbrev@npm:4.0.0" checksum: 10c0/b4cc16935235e80702fc90192e349e32f8ef0ed151ef506aa78c81a7c455ec18375c4125414b99f84b2e055199d66383e787675f0bcd87da7a4dbd59f9eac1d5 @@ -2336,53 +2632,7 @@ __metadata: languageName: node linkType: hard -"abstract-leveldown@npm:3.0.0": - version: 3.0.0 - resolution: "abstract-leveldown@npm:3.0.0" - dependencies: - xtend: "npm:~4.0.0" - checksum: 10c0/51ba7656eb2aaf65997989027daf1652ce202dddbba45576be5ad63828d499e3f5f3192b32f874430557e4d69097dd8c2933570eb9a2b8fc26770ccf91cfd98a - languageName: node - linkType: hard - -"abstract-leveldown@npm:^2.4.1, abstract-leveldown@npm:~2.7.1": - version: 2.7.2 - resolution: "abstract-leveldown@npm:2.7.2" - dependencies: - xtend: "npm:~4.0.0" - checksum: 10c0/3739af5a612e63988d5c28feb0e81fb3c510a1cece0a978313d15d43a9bd4b326be8f0e42d74815117612f549bf9e6de34f633af1d1ea0c1ccc3e495640dcca4 - languageName: node - linkType: hard - -"abstract-leveldown@npm:^5.0.0, abstract-leveldown@npm:~5.0.0": - version: 5.0.0 - resolution: "abstract-leveldown@npm:5.0.0" - dependencies: - xtend: "npm:~4.0.0" - checksum: 10c0/48a54c29e7ba9ea87353443344ddd00548acb1d45131d059de82554dcccd451b226999e0d934c4a9bff252fbd75167531e8acc431b6f36b374eff0edefbae201 - languageName: node - linkType: hard - -"abstract-leveldown@npm:~2.6.0": - version: 2.6.3 - resolution: "abstract-leveldown@npm:2.6.3" - dependencies: - xtend: "npm:~4.0.0" - checksum: 10c0/db2860eecc9c973472820a0336c830b1168ebf08f43d0ee5be86e0c858e58b1bff4fd6172b4e15dc0404b69ab13e7f5339e914c224d3746c3f19b6db98339238 - languageName: node - linkType: hard - -"accepts@npm:~1.3.8": - version: 1.3.8 - resolution: "accepts@npm:1.3.8" - dependencies: - mime-types: "npm:~2.1.34" - negotiator: "npm:0.6.3" - checksum: 10c0/3a35c5f5586cfb9a21163ca47a5f77ac34fa8ceb5d17d2fa2c0d81f41cbd7f8c6fa52c77e2c039acc0f4d09e71abdc51144246900f6bef5e3c4b333f77d89362 - languageName: node - linkType: hard - -"acorn-jsx@npm:^5.0.0, acorn-jsx@npm:^5.3.1": +"acorn-jsx@npm:^5.3.2": version: 5.3.2 resolution: "acorn-jsx@npm:5.3.2" peerDependencies: @@ -2398,21 +2648,12 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^6.0.7": - version: 6.4.2 - resolution: "acorn@npm:6.4.2" - bin: - acorn: bin/acorn - checksum: 10c0/52a72d5d785fa64a95880f2951021a38954f8f69a4944dfeab6fb1449b0f02293eae109a56d55b58ff31a90a00d16a804658a12db8ef834c20b3d1201fe5ba5b - languageName: node - linkType: hard - -"acorn@npm:^7.4.0": - version: 7.4.1 - resolution: "acorn@npm:7.4.1" +"acorn@npm:^8.15.0, acorn@npm:^8.16.0": + version: 8.18.0 + resolution: "acorn@npm:8.18.0" bin: acorn: bin/acorn - checksum: 10c0/bd0b2c2b0f334bbee48828ff897c12bd2eb5898d03bf556dcc8942022cec795ac5bb5b6b585e2de687db6231faf07e096b59a361231dd8c9344d5df5f7f0e526 + checksum: 10c0/be771be2135cc07910cf76f444ad514d7dcfd6d4a8026e597e93155275abc8ef61eee12211d52146e9d962874269b634f397464942087be013c89d0c54c5f8e5 languageName: node linkType: hard @@ -2439,10 +2680,10 @@ __metadata: languageName: node linkType: hard -"aes-js@npm:^3.1.1": - version: 3.1.2 - resolution: "aes-js@npm:3.1.2" - checksum: 10c0/2568cc67af66fd9d41de25dc73d49ae810269c7648bbb1928b9f84d8fd6ddb4e39ed506d1be6794f5ffd567aadea75fc6895ef34d2b70b764f539f72a6a2baeb +"aes-js@npm:4.0.0-beta.5": + version: 4.0.0-beta.5 + resolution: "aes-js@npm:4.0.0-beta.5" + checksum: 10c0/444f4eefa1e602cbc4f2a3c644bc990f93fd982b148425fee17634da510586fc09da940dcf8ace1b2d001453c07ff042e55f7a0482b3cc9372bf1ef75479090c languageName: node linkType: hard @@ -2472,15 +2713,15 @@ __metadata: languageName: node linkType: hard -"ajv@npm:^6.10.0, ajv@npm:^6.10.2, ajv@npm:^6.12.3, ajv@npm:^6.12.4, ajv@npm:^6.6.1, ajv@npm:^6.9.1": - version: 6.12.6 - resolution: "ajv@npm:6.12.6" +"ajv@npm:^6.14.0": + version: 6.15.0 + resolution: "ajv@npm:6.15.0" dependencies: fast-deep-equal: "npm:^3.1.1" fast-json-stable-stringify: "npm:^2.0.0" json-schema-traverse: "npm:^0.4.1" uri-js: "npm:^4.2.2" - checksum: 10c0/41e23642cbe545889245b9d2a45854ebba51cda6c778ebced9649420d9205f2efb39cb43dbc41e358409223b1ea43303ae4839db682c848b891e4811da1a5a71 + checksum: 10c0/67966499dd272ecde1c2e467084411132891523d057487587879d39ac04207f4351b7b2324c83198013967fbfa632c1612adc960114a30770fbe07a0773b32c2 languageName: node linkType: hard @@ -2496,6 +2737,31 @@ __metadata: languageName: node linkType: hard +"ajv@npm:^8.18.0": + version: 8.20.0 + resolution: "ajv@npm:8.20.0" + dependencies: + fast-deep-equal: "npm:^3.1.3" + fast-uri: "npm:^3.0.1" + json-schema-traverse: "npm:^1.0.0" + require-from-string: "npm:^2.0.2" + checksum: 10c0/5df9a1c8f83863cde1bd3a9ddb426f599718f88e3dc9153616c79fb28e0be455335830d7f21d745576519f057b371352daa31047b6a33d7036fe08777d60cf2a + languageName: node + linkType: hard + +"amazon-cognito-identity-js@npm:^6.0.1, amazon-cognito-identity-js@npm:^6.3.6": + version: 6.3.21 + resolution: "amazon-cognito-identity-js@npm:6.3.21" + dependencies: + "@aws-crypto/sha256-js": "npm:1.2.2" + buffer: "npm:4.9.2" + fast-base64-decode: "npm:^1.0.0" + isomorphic-unfetch: "npm:^3.0.0" + js-cookie: "npm:^3.0.7" + checksum: 10c0/c7541a70f5fc7a9cdc9642dec5c223420c4719219a24eab05decb1292741ebd82e4746dccc396f26436550896f5aa249311c4628f2b0f40ef4b436d50c05a16d + languageName: node + linkType: hard + "ansi-align@npm:^3.0.0": version: 3.0.1 resolution: "ansi-align@npm:3.0.1" @@ -2512,13 +2778,6 @@ __metadata: languageName: node linkType: hard -"ansi-escapes@npm:^3.2.0": - version: 3.2.0 - resolution: "ansi-escapes@npm:3.2.0" - checksum: 10c0/084e1ce38139ad2406f18a8e7efe2b850ddd06ce3c00f633392d1ce67756dab44fe290e573d09ef3c9a0cb13c12881e0e35a8f77a017d39a0a4ab85ae2fae04f - languageName: node - linkType: hard - "ansi-escapes@npm:^4.3.0": version: 4.3.2 resolution: "ansi-escapes@npm:4.3.2" @@ -2528,27 +2787,6 @@ __metadata: languageName: node linkType: hard -"ansi-regex@npm:^2.0.0": - version: 2.1.1 - resolution: "ansi-regex@npm:2.1.1" - checksum: 10c0/78cebaf50bce2cb96341a7230adf28d804611da3ce6bf338efa7b72f06cc6ff648e29f80cd95e582617ba58d5fdbec38abfeed3500a98bce8381a9daec7c548b - languageName: node - linkType: hard - -"ansi-regex@npm:^3.0.0": - version: 3.0.0 - resolution: "ansi-regex@npm:3.0.0" - checksum: 10c0/c6a2b226d009965decc65d330b953290039f0f2b31d200516a9a79b6010f5f8f9d6acbaa0917d925c578df0c0feaddcb56569aad05776f99e2918116d4233121 - languageName: node - linkType: hard - -"ansi-regex@npm:^4.1.0": - version: 4.1.1 - resolution: "ansi-regex@npm:4.1.1" - checksum: 10c0/d36d34234d077e8770169d980fed7b2f3724bfa2a01da150ccd75ef9707c80e883d27cdf7a0eac2f145ac1d10a785a8a855cffd05b85f778629a0db62e7033da - languageName: node - linkType: hard - "ansi-regex@npm:^5.0.1": version: 5.0.1 resolution: "ansi-regex@npm:5.0.1" @@ -2563,14 +2801,7 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^2.2.1": - version: 2.2.1 - resolution: "ansi-styles@npm:2.2.1" - checksum: 10c0/7c68aed4f1857389e7a12f85537ea5b40d832656babbf511cc7ecd9efc52889b9c3e5653a71a6aade783c3c5e0aa223ad4ff8e83c27ac8a666514e6c79068cab - languageName: node - linkType: hard - -"ansi-styles@npm:^3.2.0, ansi-styles@npm:^3.2.1": +"ansi-styles@npm:^3.2.1": version: 3.2.1 resolution: "ansi-styles@npm:3.2.1" dependencies: @@ -2595,20 +2826,6 @@ __metadata: languageName: node linkType: hard -"antlr4@npm:4.7.1": - version: 4.7.1 - resolution: "antlr4@npm:4.7.1" - checksum: 10c0/384ffb8c048065af1284323b6fbacb47ad588b52c398a232d9f3702552897aad124386ef2704d8fb773e319da44197cac603a88044475f13f3917b10703eae47 - languageName: node - linkType: hard - -"antlr4ts@npm:^0.5.0-alpha.4": - version: 0.5.0-alpha.4 - resolution: "antlr4ts@npm:0.5.0-alpha.4" - checksum: 10c0/26a43d6769178fdf1b79ed2001f123fd49843e335f9a3687b63c090ab2024632fbac60a73b3f8289044c206edeb5d19c36b02603b018d8eaf3be3ce30136102f - languageName: node - linkType: hard - "anymatch@npm:~3.1.2": version: 3.1.3 resolution: "anymatch@npm:3.1.3" @@ -2626,15 +2843,6 @@ __metadata: languageName: node linkType: hard -"argparse@npm:^1.0.7": - version: 1.0.10 - resolution: "argparse@npm:1.0.10" - dependencies: - sprintf-js: "npm:~1.0.2" - checksum: 10c0/b2972c5c23c63df66bca144dbc65d180efa74f25f8fd9b7d9a0a6c88ae839db32df3d54770dcb6460cf840d232b60695d1a6b1053f599d84e73f7437087712de - languageName: node - linkType: hard - "argparse@npm:^2.0.1": version: 2.0.1 resolution: "argparse@npm:2.0.1" @@ -2642,55 +2850,6 @@ __metadata: languageName: node linkType: hard -"aria-query@npm:^4.2.2": - version: 4.2.2 - resolution: "aria-query@npm:4.2.2" - dependencies: - "@babel/runtime": "npm:^7.10.2" - "@babel/runtime-corejs3": "npm:^7.10.2" - checksum: 10c0/7e224fbbb4de8210c5d8cbaf0e1a22caa78f2068bf231f4c75302bd77eeba1c3e3b97912080535140be60174720d2ac817e5d6fec18592951b4b6488d4da7cdc - languageName: node - linkType: hard - -"arr-diff@npm:^4.0.0": - version: 4.0.0 - resolution: "arr-diff@npm:4.0.0" - checksum: 10c0/67b80067137f70c89953b95f5c6279ad379c3ee39f7143578e13bd51580a40066ee2a55da066e22d498dce10f68c2d70056d7823f972fab99dfbf4c78d0bc0f7 - languageName: node - linkType: hard - -"arr-flatten@npm:^1.1.0": - version: 1.1.0 - resolution: "arr-flatten@npm:1.1.0" - checksum: 10c0/bef53be02ed3bc58f202b3861a5b1eb6e1ae4fecf39c3ad4d15b1e0433f941077d16e019a33312d820844b0661777322acbb7d0c447b04d9bdf7d6f9c532548a - languageName: node - linkType: hard - -"arr-union@npm:^3.1.0": - version: 3.1.0 - resolution: "arr-union@npm:3.1.0" - checksum: 10c0/7d5aa05894e54aa93c77c5726c1dd5d8e8d3afe4f77983c0aa8a14a8a5cbe8b18f0cf4ecaa4ac8c908ef5f744d2cbbdaa83fd6e96724d15fea56cfa7f5efdd51 - languageName: node - linkType: hard - -"array-back@npm:^1.0.3, array-back@npm:^1.0.4": - version: 1.0.4 - resolution: "array-back@npm:1.0.4" - dependencies: - typical: "npm:^2.6.0" - checksum: 10c0/2151398fcc418e77bae3d936ab7c543fd313843df3ddafe5799c9d9d90ff7dd75a08b5ca540356054f32110d4bfd30e13cb4a516771eecb286fe3e60c3cc472a - languageName: node - linkType: hard - -"array-back@npm:^2.0.0": - version: 2.0.0 - resolution: "array-back@npm:2.0.0" - dependencies: - typical: "npm:^2.6.1" - checksum: 10c0/51b49a283235b2d98666a35b29563cf87ce1aa86b5426158da3f4919c3e566e1ecb1154f53804aa4bcc5d8759cab81815fe7acdf730e874ad1943d246a4663a5 - languageName: node - linkType: hard - "array-back@npm:^3.0.1, array-back@npm:^3.1.0": version: 3.1.0 resolution: "array-back@npm:3.1.0" @@ -2705,90 +2864,6 @@ __metadata: languageName: node linkType: hard -"array-flatten@npm:1.1.1": - version: 1.1.1 - resolution: "array-flatten@npm:1.1.1" - checksum: 10c0/806966c8abb2f858b08f5324d9d18d7737480610f3bd5d3498aaae6eb5efdc501a884ba019c9b4a8f02ff67002058749d05548fd42fa8643f02c9c7f22198b91 - languageName: node - linkType: hard - -"array-includes@npm:^3.1.1, array-includes@npm:^3.1.3": - version: 3.1.4 - resolution: "array-includes@npm:3.1.4" - dependencies: - call-bind: "npm:^1.0.2" - define-properties: "npm:^1.1.3" - es-abstract: "npm:^1.19.1" - get-intrinsic: "npm:^1.1.1" - is-string: "npm:^1.0.7" - checksum: 10c0/04c05682b45c1d58b9ad91296b3b91550c66196aae3076a42a0bb9094c00a9c3e4178520d13b093baab3313d862725a4596554da31989b12882be2073df038ac - languageName: node - linkType: hard - -"array-union@npm:^2.1.0": - version: 2.1.0 - resolution: "array-union@npm:2.1.0" - checksum: 10c0/429897e68110374f39b771ec47a7161fc6a8fc33e196857c0a396dc75df0b5f65e4d046674db764330b6bb66b39ef48dd7c53b6a2ee75cfb0681e0c1a7033962 - languageName: node - linkType: hard - -"array-unique@npm:^0.3.2": - version: 0.3.2 - resolution: "array-unique@npm:0.3.2" - checksum: 10c0/dbf4462cdba8a4b85577be07705210b3d35be4b765822a3f52962d907186617638ce15e0603a4fefdcf82f4cbbc9d433f8cbbd6855148a68872fa041b6474121 - languageName: node - linkType: hard - -"array.prototype.flat@npm:^1.2.4": - version: 1.2.5 - resolution: "array.prototype.flat@npm:1.2.5" - dependencies: - call-bind: "npm:^1.0.2" - define-properties: "npm:^1.1.3" - es-abstract: "npm:^1.19.0" - checksum: 10c0/91f3a8f8a74552ffb8f001ff26aaacf2baedf8bf9334cee9ac440ffb095f05df40f88c78384d004d4999b5876b30a6520a77dd9e5bccf065d68d7f3910e5ed6e - languageName: node - linkType: hard - -"array.prototype.flatmap@npm:^1.2.4": - version: 1.2.5 - resolution: "array.prototype.flatmap@npm:1.2.5" - dependencies: - call-bind: "npm:^1.0.0" - define-properties: "npm:^1.1.3" - es-abstract: "npm:^1.19.0" - checksum: 10c0/dc58f602a8ab7871739e08f4a25b71ddbfbaa84c73b7e6eb203f4943c2f3b28c41ef313de2515b95cb059408b33699cb9abca89a1d3c4701e2ba7b25e07b4256 - languageName: node - linkType: hard - -"asn1.js@npm:^5.2.0": - version: 5.4.1 - resolution: "asn1.js@npm:5.4.1" - dependencies: - bn.js: "npm:^4.0.0" - inherits: "npm:^2.0.1" - minimalistic-assert: "npm:^1.0.0" - safer-buffer: "npm:^2.1.0" - checksum: 10c0/b577232fa6069cc52bb128e564002c62b2b1fe47f7137bdcd709c0b8495aa79cee0f8cc458a831b2d8675900eea0d05781b006be5e1aa4f0ae3577a73ec20324 - languageName: node - linkType: hard - -"asn1@npm:~0.2.3": - version: 0.2.6 - resolution: "asn1@npm:0.2.6" - dependencies: - safer-buffer: "npm:~2.1.0" - checksum: 10c0/00c8a06c37e548762306bcb1488388d2f76c74c36f70c803f0c081a01d3bdf26090fc088cd812afc5e56a6d49e33765d451a5f8a68ab9c2b087eba65d2e980e0 - languageName: node - linkType: hard - -"assert-plus@npm:1.0.0, assert-plus@npm:^1.0.0": - version: 1.0.0 - resolution: "assert-plus@npm:1.0.0" - checksum: 10c0/b194b9d50c3a8f872ee85ab110784911e696a4d49f7ee6fc5fb63216dedbefd2c55999c70cb2eaeb4cf4a0e0338b44e9ace3627117b5bf0d42460e9132f21b91 - languageName: node - linkType: hard - "assertion-error@npm:^1.1.0": version: 1.1.0 resolution: "assertion-error@npm:1.1.0" @@ -2796,34 +2871,13 @@ __metadata: languageName: node linkType: hard -"assign-symbols@npm:^1.0.0": - version: 1.0.0 - resolution: "assign-symbols@npm:1.0.0" - checksum: 10c0/29a654b8a6da6889a190d0d0efef4b1bfb5948fa06cbc245054aef05139f889f2f7c75b989917e3fde853fc4093b88048e4de8578a73a76f113d41bfd66e5775 - languageName: node - linkType: hard - -"ast-parents@npm:0.0.1": +"ast-parents@npm:^0.0.1": version: 0.0.1 resolution: "ast-parents@npm:0.0.1" checksum: 10c0/f170166a5d43526f26be95754773822f63d4f45e5ccf83949290ef09919cff6a45d30f9e85ea4a2648b9cd757c18f246ec0cf050094c3b686722c2e6136edfe2 languageName: node linkType: hard -"ast-types-flow@npm:^0.0.7": - version: 0.0.7 - resolution: "ast-types-flow@npm:0.0.7" - checksum: 10c0/f381529f2da535949ba6cceddbdfaa33b4d5105842e147ec63582f560ea9ecc1a08f66457664f3109841d3053641fa8b9fa94ba607f1ea9f6c804fe5dee44a1d - languageName: node - linkType: hard - -"astral-regex@npm:^1.0.0": - version: 1.0.0 - resolution: "astral-regex@npm:1.0.0" - checksum: 10c0/ca460207a19d84c65671e1a85940101522d42f31a450cdb8f93b3464e6daeaf4b58a362826a6c11c57e6cd1976403d197abb0447cfc2087993a29b35c6d63b63 - languageName: node - linkType: hard - "astral-regex@npm:^2.0.0": version: 2.0.0 resolution: "astral-regex@npm:2.0.0" @@ -2831,15 +2885,6 @@ __metadata: languageName: node linkType: hard -"async-eventemitter@npm:^0.2.2": - version: 0.2.4 - resolution: "async-eventemitter@npm:0.2.4" - dependencies: - async: "npm:^2.4.0" - checksum: 10c0/ce761d1837d454efb456bd2bd5b0db0e100f600d66d9a07a9f7772e0cfd5ad3029bb07385310bd1c7d65603735b755ba457a2f8ed47fb1314a6fe275dd69a322 - languageName: node - linkType: hard - "async-function@npm:^1.0.0": version: 1.0.0 resolution: "async-function@npm:1.0.0" @@ -2854,35 +2899,12 @@ __metadata: languageName: node linkType: hard -"async-limiter@npm:~1.0.0": - version: 1.0.1 - resolution: "async-limiter@npm:1.0.1" - checksum: 10c0/0693d378cfe86842a70d4c849595a0bb50dc44c11649640ca982fa90cbfc74e3cc4753b5a0847e51933f2e9c65ce8e05576e75e5e1fd963a086e673735b35969 - languageName: node - linkType: hard - -"async@npm:2.6.2": - version: 2.6.2 - resolution: "async@npm:2.6.2" - dependencies: - lodash: "npm:^4.17.11" - checksum: 10c0/5be49173e35ef8230e32a0278c9183f0477590d83c67877ad66fe404901e8f11991b9255ac39fd5f8d381677c6fc10ae3ec95c73ca4d64c9920709eb231cf39b - languageName: node - linkType: hard - -"async@npm:^1.4.2": - version: 1.5.2 - resolution: "async@npm:1.5.2" - checksum: 10c0/9ee84592c393aad1047d1223004317ecc65a9a3f76101e0f4614a0818eac962e666510353400a3c9ea158df540579a293f486f3578e918c5e90a0f5ed52e8aea - languageName: node - linkType: hard - -"async@npm:^2.0.1, async@npm:^2.1.2, async@npm:^2.4.0, async@npm:^2.5.0, async@npm:^2.6.1": - version: 2.6.3 - resolution: "async@npm:2.6.3" +"async-retry@npm:^1.3.3": + version: 1.3.3 + resolution: "async-retry@npm:1.3.3" dependencies: - lodash: "npm:^4.17.14" - checksum: 10c0/06c917c74a55f9036ff79dedfc51dfc9c52c2dee2f80866b600495d2fd3037251dbcfde6592f23fc47398c44d844174004e0ee532f94c32a888bb89fd1cf0f25 + retry: "npm:0.13.1" + checksum: 10c0/cabced4fb46f8737b95cc88dc9c0ff42656c62dc83ce0650864e891b6c155a063af08d62c446269b51256f6fbcb69a6563b80e76d0ea4a5117b0c0377b6b19d8 languageName: node linkType: hard @@ -2900,11391 +2922,4907 @@ __metadata: languageName: node linkType: hard -"atob@npm:^2.1.2": - version: 2.1.2 - resolution: "atob@npm:2.1.2" - bin: - atob: bin/atob.js - checksum: 10c0/ada635b519dc0c576bb0b3ca63a73b50eefacf390abb3f062558342a8d68f2db91d0c8db54ce81b0d89de3b0f000de71f3ae7d761fd7d8cc624278fe443d6c7e +"axios@npm:^1.8.4": + version: 1.20.0 + resolution: "axios@npm:1.20.0" + dependencies: + follow-redirects: "npm:^1.16.0" + form-data: "npm:^4.0.6" + https-proxy-agent: "npm:^5.0.1" + proxy-from-env: "npm:^2.1.0" + checksum: 10c0/976088acf532286356f4c2e65df1ef47ba7da3936d83e928d0d64357bbf5370456abd3eb5826c15df322335fcb1fe200d4a84b4fcf20ffccdd63b40d80fa495c languageName: node linkType: hard -"aws-sign2@npm:~0.7.0": - version: 0.7.0 - resolution: "aws-sign2@npm:0.7.0" - checksum: 10c0/021d2cc5547d4d9ef1633e0332e746a6f447997758b8b68d6fb33f290986872d2bff5f0c37d5832f41a7229361f093cd81c40898d96ed153493c0fb5cd8575d2 +"balanced-match@npm:^1.0.0": + version: 1.0.2 + resolution: "balanced-match@npm:1.0.2" + checksum: 10c0/9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee languageName: node linkType: hard -"aws4@npm:^1.8.0": - version: 1.11.0 - resolution: "aws4@npm:1.11.0" - checksum: 10c0/00c32a5dc0f864a731e26406fa7d51595e09359dd8f9c813fa3122e3833f564bf95b78cdf6acf8b5d0462403d7c73ce5f22ad19050d75b17019c7978f970c4fa +"balanced-match@npm:^4.0.2": + version: 4.0.4 + resolution: "balanced-match@npm:4.0.4" + checksum: 10c0/07e86102a3eb2ee2a6a1a89164f29d0dbaebd28f2ca3f5ca786f36b8b23d9e417eb3be45a4acf754f837be5ac0a2317de90d3fcb7f4f4dc95720a1f36b26a17b languageName: node linkType: hard -"axe-core@npm:^4.0.2": - version: 4.3.3 - resolution: "axe-core@npm:4.3.3" - checksum: 10c0/567c752b5fa6462931bab54826412a20642e80559570c9708f9654ccc4c531cff324bd9bd1de0e35903e9f1b8d63ce39bff3d7415b2382a379fbdd2739ce857a - languageName: node - linkType: hard - -"axios@npm:^0.21.1": - version: 0.21.4 - resolution: "axios@npm:0.21.4" - dependencies: - follow-redirects: "npm:^1.14.0" - checksum: 10c0/fbcff55ec68f71f02d3773d467db2fcecdf04e749826c82c2427a232f9eba63242150a05f15af9ef15818352b814257541155de0281f8fb2b7e8a5b79f7f2142 - languageName: node - linkType: hard - -"axios@npm:^1.6.7": - version: 1.18.1 - resolution: "axios@npm:1.18.1" +"base-x@npm:^3.0.2": + version: 3.0.9 + resolution: "base-x@npm:3.0.9" dependencies: - follow-redirects: "npm:^1.16.0" - form-data: "npm:^4.0.5" - https-proxy-agent: "npm:^5.0.1" - proxy-from-env: "npm:^2.1.0" - checksum: 10c0/9d9378a3af0d0ad730a52ad9d15ec7201f3926ad6e7e8bbffc5ae21ca2835ad11d1d9598698f5dd9718917486039f55ea1d7dc23d8e44fa827a55cc3262c02fc + safe-buffer: "npm:^5.0.1" + checksum: 10c0/e6bbeae30b24f748b546005affb710c5fbc8b11a83f6cd0ca999bd1ab7ad3a22e42888addc40cd145adc4edfe62fcfab4ebc91da22e4259aae441f95a77aee1a languageName: node linkType: hard -"axobject-query@npm:^2.2.0": - version: 2.2.0 - resolution: "axobject-query@npm:2.2.0" - checksum: 10c0/75e173c4f8477814a03c46b5864810c0d62d15515e3e1067093d934b77d2dd68704a4e5141e190e305fee9630405c1ea013642f50ed476b27d8d79033c489ce9 +"base64-js@npm:^1.0.2": + version: 1.5.1 + resolution: "base64-js@npm:1.5.1" + checksum: 10c0/f23823513b63173a001030fae4f2dabe283b99a9d324ade3ad3d148e218134676f1ee8568c877cd79ec1c53158dcf2d2ba527a97c606618928ba99dd930102bf languageName: node linkType: hard -"babel-code-frame@npm:^6.26.0": - version: 6.26.0 - resolution: "babel-code-frame@npm:6.26.0" - dependencies: - chalk: "npm:^1.1.3" - esutils: "npm:^2.0.2" - js-tokens: "npm:^3.0.2" - checksum: 10c0/7fecc128e87578cf1b96e78d2b25e0b260e202bdbbfcefa2eac23b7f8b7b2f7bc9276a14599cde14403cc798cc2a38e428e2cab50b77658ab49228b09ae92473 - languageName: node - linkType: hard - -"babel-core@npm:^6.0.14, babel-core@npm:^6.26.0": - version: 6.26.3 - resolution: "babel-core@npm:6.26.3" - dependencies: - babel-code-frame: "npm:^6.26.0" - babel-generator: "npm:^6.26.0" - babel-helpers: "npm:^6.24.1" - babel-messages: "npm:^6.23.0" - babel-register: "npm:^6.26.0" - babel-runtime: "npm:^6.26.0" - babel-template: "npm:^6.26.0" - babel-traverse: "npm:^6.26.0" - babel-types: "npm:^6.26.0" - babylon: "npm:^6.18.0" - convert-source-map: "npm:^1.5.1" - debug: "npm:^2.6.9" - json5: "npm:^0.5.1" - lodash: "npm:^4.17.4" - minimatch: "npm:^3.0.4" - path-is-absolute: "npm:^1.0.1" - private: "npm:^0.1.8" - slash: "npm:^1.0.0" - source-map: "npm:^0.5.7" - checksum: 10c0/10292649779f8c33d1908f5671c92ca9df036c9e1b9f35f97e7f62c9da9e3a146ee069f94fc401283ce129ba980f34a30339f137c512f3e62ddd354653b2da0e +"bech32@npm:1.1.4": + version: 1.1.4 + resolution: "bech32@npm:1.1.4" + checksum: 10c0/5f62ca47b8df99ace9c0e0d8deb36a919d91bf40066700aaa9920a45f86bb10eb56d537d559416fd8703aa0fb60dddb642e58f049701e7291df678b2033e5ee5 languageName: node linkType: hard -"babel-generator@npm:^6.26.0": - version: 6.26.1 - resolution: "babel-generator@npm:6.26.1" +"better-ajv-errors@npm:^2.0.2": + version: 2.0.3 + resolution: "better-ajv-errors@npm:2.0.3" dependencies: - babel-messages: "npm:^6.23.0" - babel-runtime: "npm:^6.26.0" - babel-types: "npm:^6.26.0" - detect-indent: "npm:^4.0.0" - jsesc: "npm:^1.3.0" - lodash: "npm:^4.17.4" - source-map: "npm:^0.5.7" - trim-right: "npm:^1.0.1" - checksum: 10c0/d5f9d20c6f7d8644dc41ee57d48c98a78d24d5b74dc305cc518d6e0872d4fa73c5fd8d47ec00e3515858eaf3c3e512a703cdbc184ff0061af5979bc206618555 + "@babel/code-frame": "npm:^7.27.1" + "@humanwhocodes/momoa": "npm:^2.0.4" + chalk: "npm:^4.1.2" + jsonpointer: "npm:^5.0.1" + leven: "npm:^3.1.0 < 4" + peerDependencies: + ajv: 4.11.8 - 8 + checksum: 10c0/168f6ff274c1b71a897d0267a3a4c52a5e70e33b3d858d8c455b42e2da1abdf9a8d31cba09572bbd549778774a4f5c1cb2a1cec52f5298c9f7fb77f3cdfb95ba languageName: node linkType: hard -"babel-helper-builder-binary-assignment-operator-visitor@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-helper-builder-binary-assignment-operator-visitor@npm:6.24.1" - dependencies: - babel-helper-explode-assignable-expression: "npm:^6.24.1" - babel-runtime: "npm:^6.22.0" - babel-types: "npm:^6.24.1" - checksum: 10c0/97c3828554d057e7a9cd1a0dc61b7897f964a831300c4996fa8039aa4dba3b4e645b7b44b07d3887f79eaf0c26a0cc03397cb7a686517311c30919516a12e143 +"bignumber.js@npm:^9.1.2": + version: 9.3.1 + resolution: "bignumber.js@npm:9.3.1" + checksum: 10c0/61342ba5fe1c10887f0ecf5be02ff6709271481aff48631f86b4d37d55a99b87ce441cfd54df3d16d10ee07ceab7e272fc0be430c657ffafbbbf7b7d631efb75 languageName: node linkType: hard -"babel-helper-call-delegate@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-helper-call-delegate@npm:6.24.1" - dependencies: - babel-helper-hoist-variables: "npm:^6.24.1" - babel-runtime: "npm:^6.22.0" - babel-traverse: "npm:^6.24.1" - babel-types: "npm:^6.24.1" - checksum: 10c0/3a605d86b9c0b2036a98c90f8ae947be1463d9436b53442c67bf624ca018cd544760774d0091052f16d1fa409d9f31c300e11c1bd85a7478c99ae87562b344c5 +"binary-extensions@npm:^2.0.0": + version: 2.2.0 + resolution: "binary-extensions@npm:2.2.0" + checksum: 10c0/d73d8b897238a2d3ffa5f59c0241870043aa7471335e89ea5e1ff48edb7c2d0bb471517a3e4c5c3f4c043615caa2717b5f80a5e61e07503d51dc85cb848e665d languageName: node linkType: hard -"babel-helper-define-map@npm:^6.24.1": - version: 6.26.0 - resolution: "babel-helper-define-map@npm:6.26.0" - dependencies: - babel-helper-function-name: "npm:^6.24.1" - babel-runtime: "npm:^6.26.0" - babel-types: "npm:^6.26.0" - lodash: "npm:^4.17.4" - checksum: 10c0/3d5ed5ff64633f96a438f0edaca8bd104f54a11cab65ccd7e2202a249c8a074032e7df19abeafaad0c7be69a465d005d19ff94cca688a16f9ce21c7657ef6ac0 +"blakejs@npm:^1.1.0": + version: 1.2.1 + resolution: "blakejs@npm:1.2.1" + checksum: 10c0/c284557ce55b9c70203f59d381f1b85372ef08ee616a90162174d1291a45d3e5e809fdf9edab6e998740012538515152471dc4f1f9dbfa974ba2b9c1f7b9aad7 languageName: node linkType: hard -"babel-helper-explode-assignable-expression@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-helper-explode-assignable-expression@npm:6.24.1" - dependencies: - babel-runtime: "npm:^6.22.0" - babel-traverse: "npm:^6.24.1" - babel-types: "npm:^6.24.1" - checksum: 10c0/73276a1e8e2f394ef5463df17c70b1df805be5eb6880d814abe66d192a0c4b90a6f3965097de0c42778fc076374727f81dfcbcf30c1b09de09826f80356f53b2 +"bn.js@npm:^4.11.1, bn.js@npm:^4.11.9": + version: 4.12.0 + resolution: "bn.js@npm:4.12.0" + checksum: 10c0/9736aaa317421b6b3ed038ff3d4491935a01419ac2d83ddcfebc5717385295fcfcf0c57311d90fe49926d0abbd7a9dbefdd8861e6129939177f7e67ebc645b21 languageName: node linkType: hard -"babel-helper-function-name@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-helper-function-name@npm:6.24.1" - dependencies: - babel-helper-get-function-arity: "npm:^6.24.1" - babel-runtime: "npm:^6.22.0" - babel-template: "npm:^6.24.1" - babel-traverse: "npm:^6.24.1" - babel-types: "npm:^6.24.1" - checksum: 10c0/fdffc9efaf5e6ce181b3fc415c45733db44085e34e5b38bda58275e77498dc9a367377c2fa32b168a91a407c1eda54b5642d8c46ec65bfd33ab617cae24746b9 +"bn.js@npm:^5.1.2": + version: 5.2.0 + resolution: "bn.js@npm:5.2.0" + checksum: 10c0/67e17b1934d9c7a73aed9b89222dc8c1c8e3aff46cca6609b8c2ab04fa22c6b8db42c7774b039d09fa63136d8866b777ab88af0d64d8ea3839a94e69193a6b13 languageName: node linkType: hard -"babel-helper-get-function-arity@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-helper-get-function-arity@npm:6.24.1" - dependencies: - babel-runtime: "npm:^6.22.0" - babel-types: "npm:^6.24.1" - checksum: 10c0/f73610307c4f92a0393db3072e67ff0585f161b86e90d5f09a8e62e3b4a5a227eab6927275a147ee5617589aaabea1781ec2cde6ab81d2bc1d0b165dadfa0ede +"bn.js@npm:^5.2.1": + version: 5.2.1 + resolution: "bn.js@npm:5.2.1" + checksum: 10c0/bed3d8bd34ec89dbcf9f20f88bd7d4a49c160fda3b561c7bb227501f974d3e435a48fb9b61bc3de304acab9215a3bda0803f7017ffb4d0016a0c3a740a283caa languageName: node linkType: hard -"babel-helper-hoist-variables@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-helper-hoist-variables@npm:6.24.1" +"boxen@npm:^5.1.2": + version: 5.1.2 + resolution: "boxen@npm:5.1.2" dependencies: - babel-runtime: "npm:^6.22.0" - babel-types: "npm:^6.24.1" - checksum: 10c0/adac32e99ec452f3d9eb0a8f3eb455d3106a3c998954a41187f75c0363e22f48dbf0073221341cb26ee3f9a45115e2d3b29d00c7b4abc75c8dfa5c780eb330bd + ansi-align: "npm:^3.0.0" + camelcase: "npm:^6.2.0" + chalk: "npm:^4.1.0" + cli-boxes: "npm:^2.2.1" + string-width: "npm:^4.2.2" + type-fest: "npm:^0.20.2" + widest-line: "npm:^3.1.0" + wrap-ansi: "npm:^7.0.0" + checksum: 10c0/71f31c2eb3dcacd5fce524ae509e0cc90421752e0bfbd0281fd3352871d106c462a0f810c85f2fdb02f3a9fab2d7a84e9718b4999384d651b76104ebe5d2c024 languageName: node linkType: hard -"babel-helper-optimise-call-expression@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-helper-optimise-call-expression@npm:6.24.1" +"brace-expansion@npm:^1.1.7": + version: 1.1.11 + resolution: "brace-expansion@npm:1.1.11" dependencies: - babel-runtime: "npm:^6.22.0" - babel-types: "npm:^6.24.1" - checksum: 10c0/8741daab0fa48384e16c47d15f591ddcceb2b5e664048468d8f4f88f67cc2eb0a47ed2969d7034cadf6091f33a5aac51726d924c200b73e49ae8f2c224d3d1c9 + balanced-match: "npm:^1.0.0" + concat-map: "npm:0.0.1" + checksum: 10c0/695a56cd058096a7cb71fb09d9d6a7070113c7be516699ed361317aca2ec169f618e28b8af352e02ab4233fb54eb0168460a40dc320bab0034b36ab59aaad668 languageName: node linkType: hard -"babel-helper-regex@npm:^6.24.1": - version: 6.26.0 - resolution: "babel-helper-regex@npm:6.26.0" +"brace-expansion@npm:^2.0.2": + version: 2.1.2 + resolution: "brace-expansion@npm:2.1.2" dependencies: - babel-runtime: "npm:^6.26.0" - babel-types: "npm:^6.26.0" - lodash: "npm:^4.17.4" - checksum: 10c0/144c868a7a46171ce98a0b49c8c8e42acacad705ecc81c6ccfb9ca99228a0b60d1fe841b1821a8e63c1102938b697deed0db836f6588fcb3e7a2167a513491ec + balanced-match: "npm:^1.0.0" + checksum: 10c0/5442ecab84045d21826268bc56c81a6ef4215327ee1f5ee153f67928e93f7a915d130ecec9966623143277fa3cce036ebb50020024bcc4d78853cdd6af9a19f8 languageName: node linkType: hard -"babel-helper-remap-async-to-generator@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-helper-remap-async-to-generator@npm:6.24.1" +"brace-expansion@npm:^5.0.5": + version: 5.0.5 + resolution: "brace-expansion@npm:5.0.5" dependencies: - babel-helper-function-name: "npm:^6.24.1" - babel-runtime: "npm:^6.22.0" - babel-template: "npm:^6.24.1" - babel-traverse: "npm:^6.24.1" - babel-types: "npm:^6.24.1" - checksum: 10c0/e851e753d5eaa70deb0bf8558f8360eb86a990a5287b5955b6071e8e3a58935c947fd2df1dcbeff02fc7870a8a022bd6c72d1fb11fd69b59211dbce8f7c4d3ea + balanced-match: "npm:^4.0.2" + checksum: 10c0/4d238e14ed4f5cc9c07285550a41cef23121ca08ba99fa9eb5b55b580dcb6bf868b8210aa10526bdc9f8dc97f33ca2a7259039c4cc131a93042beddb424c48e3 languageName: node linkType: hard -"babel-helper-replace-supers@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-helper-replace-supers@npm:6.24.1" +"brace-expansion@npm:^5.0.8": + version: 5.0.9 + resolution: "brace-expansion@npm:5.0.9" dependencies: - babel-helper-optimise-call-expression: "npm:^6.24.1" - babel-messages: "npm:^6.23.0" - babel-runtime: "npm:^6.22.0" - babel-template: "npm:^6.24.1" - babel-traverse: "npm:^6.24.1" - babel-types: "npm:^6.24.1" - checksum: 10c0/1fbc1a263b4f9e5fec38589176b5297564383f0adb1961d41d2d4fea50b75058759ca2df6fb5e148aad7f964629dd8b80472c5bddfe5260726c9420ba0541895 + balanced-match: "npm:^4.0.2" + checksum: 10c0/3dea38884a1c3c8b1c9c44a7402a0c76fca460f70cffb3127242b0b4cbf4472019e022ade021eec44838ff19f1dac2625dfd11dd459d7e1e055b0698a8d52fec languageName: node linkType: hard -"babel-helpers@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-helpers@npm:6.24.1" +"braces@npm:~3.0.2": + version: 3.0.2 + resolution: "braces@npm:3.0.2" dependencies: - babel-runtime: "npm:^6.22.0" - babel-template: "npm:^6.24.1" - checksum: 10c0/bbd082e42adaa9c584242515e8c5b1e861108e03ed9517f0b600189e1c1041376ab6a15c71265a2cc095c5af4bd15cfc97158e30ce95a81cbfcea1bfd81ce3e6 + fill-range: "npm:^7.0.1" + checksum: 10c0/321b4d675791479293264019156ca322163f02dc06e3c4cab33bb15cd43d80b51efef69b0930cfde3acd63d126ebca24cd0544fa6f261e093a0fb41ab9dda381 languageName: node linkType: hard -"babel-messages@npm:^6.23.0": - version: 6.23.0 - resolution: "babel-messages@npm:6.23.0" - dependencies: - babel-runtime: "npm:^6.22.0" - checksum: 10c0/d4fd6414ee5bb1aa0dad6d8d2c4ffaa66331ec5a507959e11f56b19a683566e2c1e7a4d0b16cfef58ea4cc07db8acf5ff3dc8b25c585407cff2e09ac60553401 +"brorand@npm:^1.1.0": + version: 1.1.0 + resolution: "brorand@npm:1.1.0" + checksum: 10c0/6f366d7c4990f82c366e3878492ba9a372a73163c09871e80d82fb4ae0d23f9f8924cb8a662330308206e6b3b76ba1d528b4601c9ef73c2166b440b2ea3b7571 languageName: node linkType: hard -"babel-plugin-check-es2015-constants@npm:^6.22.0": - version: 6.22.0 - resolution: "babel-plugin-check-es2015-constants@npm:6.22.0" - dependencies: - babel-runtime: "npm:^6.22.0" - checksum: 10c0/647cd5d43b00ed296c344e54fcb75ea7523943c2ac77420aeed2ff22e6a0ead7b9f571d008bfb5f24781de077a34ef06cd1e0b15336b010ef35c323c0e80d58b +"brotli-wasm@npm:^2.0.1": + version: 2.0.1 + resolution: "brotli-wasm@npm:2.0.1" + checksum: 10c0/d7a4135f4b45474422cc01f2b817f2075efbbfe7239bda973387f62415fa0102c6a6bbdfef744f7583b5113e2b1a25ee8c638f0fa2fe41042fb4b1737daa9df9 languageName: node linkType: hard -"babel-plugin-syntax-async-functions@npm:^6.8.0": - version: 6.13.0 - resolution: "babel-plugin-syntax-async-functions@npm:6.13.0" - checksum: 10c0/6705603d286d19af9a79e5174c774a8fcbf6b66a154db52993b352183b16d935c499ff0ee1d6f32ebcda897ffb5dd554cbcb1ff00419302ef5c54b1d6edd13af +"browser-stdout@npm:^1.3.1": + version: 1.3.1 + resolution: "browser-stdout@npm:1.3.1" + checksum: 10c0/c40e482fd82be872b6ea7b9f7591beafbf6f5ba522fe3dade98ba1573a1c29a11101564993e4eb44e5488be8f44510af072df9a9637c739217eb155ceb639205 languageName: node linkType: hard -"babel-plugin-syntax-exponentiation-operator@npm:^6.8.0": - version: 6.13.0 - resolution: "babel-plugin-syntax-exponentiation-operator@npm:6.13.0" - checksum: 10c0/2eaa79ee92356140c6a1f84079a1c75cf2c1436b6030e3b59a5193a75dfaa760698f2fc14392adeb69981611e1ec2acb7631d9192a366a7f51f0362d2459544f +"browserify-aes@npm:^1.2.0": + version: 1.2.0 + resolution: "browserify-aes@npm:1.2.0" + dependencies: + buffer-xor: "npm:^1.0.3" + cipher-base: "npm:^1.0.0" + create-hash: "npm:^1.1.0" + evp_bytestokey: "npm:^1.0.3" + inherits: "npm:^2.0.1" + safe-buffer: "npm:^5.0.1" + checksum: 10c0/967f2ae60d610b7b252a4cbb55a7a3331c78293c94b4dd9c264d384ca93354c089b3af9c0dd023534efdc74ffbc82510f7ad4399cf82bc37bc07052eea485f18 languageName: node linkType: hard -"babel-plugin-syntax-trailing-function-commas@npm:^6.22.0": - version: 6.22.0 - resolution: "babel-plugin-syntax-trailing-function-commas@npm:6.22.0" - checksum: 10c0/b68353cef2dfc699f0a9a8947454bdcd620a8788d66c744e631fccaecd10ba26a1922ac9ed2c99c1daceefe22fde8ff91d199f4e6c78fd592d67f6bb107372da +"bs58@npm:^4.0.0": + version: 4.0.1 + resolution: "bs58@npm:4.0.1" + dependencies: + base-x: "npm:^3.0.2" + checksum: 10c0/613a1b1441e754279a0e3f44d1faeb8c8e838feef81e550efe174ff021dd2e08a4c9ae5805b52dfdde79f97b5c0918c78dd24a0eb726c4a94365f0984a0ffc65 languageName: node linkType: hard -"babel-plugin-transform-async-to-generator@npm:^6.22.0": - version: 6.24.1 - resolution: "babel-plugin-transform-async-to-generator@npm:6.24.1" +"bs58check@npm:^2.1.2": + version: 2.1.2 + resolution: "bs58check@npm:2.1.2" dependencies: - babel-helper-remap-async-to-generator: "npm:^6.24.1" - babel-plugin-syntax-async-functions: "npm:^6.8.0" - babel-runtime: "npm:^6.22.0" - checksum: 10c0/39474a3c146e81a9021a176421188f7fbce466827824689581f368cf854f411b2ffef66a07decca08ef7250ba2def13a6a954c318182b4348bf87ad3c184c63f + bs58: "npm:^4.0.0" + create-hash: "npm:^1.1.0" + safe-buffer: "npm:^5.1.2" + checksum: 10c0/5d33f319f0d7abbe1db786f13f4256c62a076bc8d184965444cb62ca4206b2c92bee58c93bce57150ffbbbe00c48838ac02e6f384e0da8215cac219c0556baa9 languageName: node linkType: hard -"babel-plugin-transform-es2015-arrow-functions@npm:^6.22.0": - version: 6.22.0 - resolution: "babel-plugin-transform-es2015-arrow-functions@npm:6.22.0" - dependencies: - babel-runtime: "npm:^6.22.0" - checksum: 10c0/ec98038d8b23dae4cf0dbd59d44b491fcfad5f0ca856a49e769144893b5e5faea95f5a0336709183f8b7c542cdb3227f8856c94e47f59bdd53bb2f7b46161569 +"buffer-from@npm:^1.0.0": + version: 1.1.2 + resolution: "buffer-from@npm:1.1.2" + checksum: 10c0/124fff9d66d691a86d3b062eff4663fe437a9d9ee4b47b1b9e97f5a5d14f6d5399345db80f796827be7c95e70a8e765dd404b7c3ff3b3324f98e9b0c8826cc34 languageName: node linkType: hard -"babel-plugin-transform-es2015-block-scoped-functions@npm:^6.22.0": - version: 6.22.0 - resolution: "babel-plugin-transform-es2015-block-scoped-functions@npm:6.22.0" - dependencies: - babel-runtime: "npm:^6.22.0" - checksum: 10c0/9e548c9a27b8fc62286a076f82a406f80eb8eacf05cd8953f6eaf0dea1241a884b387153fb5b04a424abe8e9455731e060fe80b2a10cc7a4fe7807506469f3d7 +"buffer-xor@npm:^1.0.3": + version: 1.0.3 + resolution: "buffer-xor@npm:1.0.3" + checksum: 10c0/fd269d0e0bf71ecac3146187cfc79edc9dbb054e2ee69b4d97dfb857c6d997c33de391696d04bdd669272751fa48e7872a22f3a6c7b07d6c0bc31dbe02a4075c languageName: node linkType: hard -"babel-plugin-transform-es2015-block-scoping@npm:^6.23.0": - version: 6.26.0 - resolution: "babel-plugin-transform-es2015-block-scoping@npm:6.26.0" +"buffer@npm:4.9.2": + version: 4.9.2 + resolution: "buffer@npm:4.9.2" dependencies: - babel-runtime: "npm:^6.26.0" - babel-template: "npm:^6.26.0" - babel-traverse: "npm:^6.26.0" - babel-types: "npm:^6.26.0" - lodash: "npm:^4.17.4" - checksum: 10c0/0fb82ad13f68dbc202d53ed693a9306833572e341058dee4f2756763101c46b8b3af51abd75cd00e3c5aaf958146bb49e9e5e3df367a92bbd318030dc72d8342 + base64-js: "npm:^1.0.2" + ieee754: "npm:^1.1.4" + isarray: "npm:^1.0.0" + checksum: 10c0/dc443d7e7caab23816b58aacdde710b72f525ad6eecd7d738fcaa29f6d6c12e8d9c13fed7219fd502be51ecf0615f5c077d4bdc6f9308dde2e53f8e5393c5b21 languageName: node linkType: hard -"babel-plugin-transform-es2015-classes@npm:^6.23.0": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-classes@npm:6.24.1" - dependencies: - babel-helper-define-map: "npm:^6.24.1" - babel-helper-function-name: "npm:^6.24.1" - babel-helper-optimise-call-expression: "npm:^6.24.1" - babel-helper-replace-supers: "npm:^6.24.1" - babel-messages: "npm:^6.23.0" - babel-runtime: "npm:^6.22.0" - babel-template: "npm:^6.24.1" - babel-traverse: "npm:^6.24.1" - babel-types: "npm:^6.24.1" - checksum: 10c0/7304406fc9cfd342a1c8f4f78c681d333371718142e948d0961d40289cbaf0a00120ce63d6b066ae391833e2a973ebc018ca7eca57783c5cc4cef436efa76149 +"bytes@npm:3.1.0": + version: 3.1.0 + resolution: "bytes@npm:3.1.0" + checksum: 10c0/7034f475b006b9a8a37c7ecaa0947d0be181feb6d3d5231984e4c14e01c587a47e0fe85f66c630689fa6a046cfa498b6891f5af8022357e52db09365f1dfb625 languageName: node linkType: hard -"babel-plugin-transform-es2015-computed-properties@npm:^6.22.0": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-computed-properties@npm:6.24.1" +"cacache@npm:^20.0.1": + version: 20.0.4 + resolution: "cacache@npm:20.0.4" dependencies: - babel-runtime: "npm:^6.22.0" - babel-template: "npm:^6.24.1" - checksum: 10c0/a3bd718579bd46e5ede21fa114f8c42b528f58e537b9abdbb9d0b023f88ad7afb64bedbc92acc849e52d1859b6634fe72cf13d6e689e9a88c9890addbbb99ff1 + "@npmcli/fs": "npm:^5.0.0" + fs-minipass: "npm:^3.0.0" + glob: "npm:^13.0.0" + lru-cache: "npm:^11.1.0" + minipass: "npm:^7.0.3" + minipass-collect: "npm:^2.0.1" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + p-map: "npm:^7.0.2" + ssri: "npm:^13.0.0" + checksum: 10c0/539bf4020e44ba9ca5afc2ec435623ed7e0dd80c020097677e6b4a0545df5cc9d20b473212d01209c8b4aea43c0d095af0bb6da97bcb991642ea6fac0d7c462b languageName: node linkType: hard -"babel-plugin-transform-es2015-destructuring@npm:^6.23.0": - version: 6.23.0 - resolution: "babel-plugin-transform-es2015-destructuring@npm:6.23.0" - dependencies: - babel-runtime: "npm:^6.22.0" - checksum: 10c0/10d253683e35b8d2e8b3c1e3580d3350646132213656eebc688b616c1552544cd2594bdff2b876588f3f1f7eb5a7e06cdeed954f4b8daa37bc80d23c1c283c5e +"cacheable-lookup@npm:^7.0.0": + version: 7.0.0 + resolution: "cacheable-lookup@npm:7.0.0" + checksum: 10c0/63a9c144c5b45cb5549251e3ea774c04d63063b29e469f7584171d059d3a88f650f47869a974e2d07de62116463d742c287a81a625e791539d987115cb081635 languageName: node linkType: hard -"babel-plugin-transform-es2015-duplicate-keys@npm:^6.22.0": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-duplicate-keys@npm:6.24.1" +"cacheable-request@npm:^10.2.8": + version: 10.2.14 + resolution: "cacheable-request@npm:10.2.14" dependencies: - babel-runtime: "npm:^6.22.0" - babel-types: "npm:^6.24.1" - checksum: 10c0/1345ada032baf9c06034ea8741ece0c93e0ba1fa7bd7db438133a6d6d7f1122a652960d239ed1e940b467c9185ca1221e0f2fdf031ef1c419e43d7497707de99 + "@types/http-cache-semantics": "npm:^4.0.2" + get-stream: "npm:^6.0.1" + http-cache-semantics: "npm:^4.1.1" + keyv: "npm:^4.5.3" + mimic-response: "npm:^4.0.0" + normalize-url: "npm:^8.0.0" + responselike: "npm:^3.0.0" + checksum: 10c0/41b6658db369f20c03128227ecd219ca7ac52a9d24fc0f499cc9aa5d40c097b48b73553504cebd137024d957c0ddb5b67cf3ac1439b136667f3586257763f88d languageName: node linkType: hard -"babel-plugin-transform-es2015-for-of@npm:^6.23.0": - version: 6.23.0 - resolution: "babel-plugin-transform-es2015-for-of@npm:6.23.0" +"cacheable@npm:^2.5.0": + version: 2.5.0 + resolution: "cacheable@npm:2.5.0" dependencies: - babel-runtime: "npm:^6.22.0" - checksum: 10c0/e52e59a9d53b59923b5b2f255c7a87906d701ffe76c8fa190bf029d955db3e39d7a1e7e17102a921b9c9266de50a2a665c59d4dd031ac09b7e7430449509eaaa + "@cacheable/memory": "npm:^2.2.0" + "@cacheable/utils": "npm:^2.5.0" + hookified: "npm:^1.15.0" + keyv: "npm:^5.6.0" + qified: "npm:^0.10.1" + checksum: 10c0/ad4086a60ed327196901c16360312705e35bfde5118457449cfabaf4ece0fecad046985ea8b66b3ece46dd469cb33798d87e1dac3ed2c00746578054bccbf74d languageName: node linkType: hard -"babel-plugin-transform-es2015-function-name@npm:^6.22.0": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-function-name@npm:6.24.1" +"call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2": + version: 1.0.2 + resolution: "call-bind-apply-helpers@npm:1.0.2" dependencies: - babel-helper-function-name: "npm:^6.24.1" - babel-runtime: "npm:^6.22.0" - babel-types: "npm:^6.24.1" - checksum: 10c0/cba67f94ad1e1b197f89ca70f2c08fc3e8fcfee1bbeba3dc75628586139248195582b70f440c0ab7de08c4bdff497d8ca47f7f541e15b6b4491e992b4563b7f0 + es-errors: "npm:^1.3.0" + function-bind: "npm:^1.1.2" + checksum: 10c0/47bd9901d57b857590431243fea704ff18078b16890a6b3e021e12d279bbf211d039155e27d7566b374d49ee1f8189344bac9833dec7a20cdec370506361c938 languageName: node linkType: hard -"babel-plugin-transform-es2015-literals@npm:^6.22.0": - version: 6.22.0 - resolution: "babel-plugin-transform-es2015-literals@npm:6.22.0" +"call-bound@npm:^1.0.2": + version: 1.0.4 + resolution: "call-bound@npm:1.0.4" dependencies: - babel-runtime: "npm:^6.22.0" - checksum: 10c0/4a9ece4efcd2719abefc41e7b40292aa2a7ba7233c5233a7b21d856b1cb4cb000613239178ee5972eaf9f774db5cc76de372c393dbc38816f4143108c8a7ff25 + call-bind-apply-helpers: "npm:^1.0.2" + get-intrinsic: "npm:^1.3.0" + checksum: 10c0/f4796a6a0941e71c766aea672f63b72bc61234c4f4964dc6d7606e3664c307e7d77845328a8f3359ce39ddb377fed67318f9ee203dea1d47e46165dcf2917644 languageName: node linkType: hard -"babel-plugin-transform-es2015-modules-amd@npm:^6.22.0, babel-plugin-transform-es2015-modules-amd@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-modules-amd@npm:6.24.1" - dependencies: - babel-plugin-transform-es2015-modules-commonjs: "npm:^6.24.1" - babel-runtime: "npm:^6.22.0" - babel-template: "npm:^6.24.1" - checksum: 10c0/f779ca5454dc5e5bd7e570832d7b8ae1c3b13fab8f79940f45a1d46e67db7bb8b0b803a999240a61b0443bf6f920cf54d67a48db4a3a719a7046051c73e6156a +"callsites@npm:^3.0.0": + version: 3.1.0 + resolution: "callsites@npm:3.1.0" + checksum: 10c0/fff92277400eb06c3079f9e74f3af120db9f8ea03bad0e84d9aede54bbe2d44a56cccb5f6cf12211f93f52306df87077ecec5b712794c5a9b5dac6d615a3f301 languageName: node linkType: hard -"babel-plugin-transform-es2015-modules-commonjs@npm:^6.23.0, babel-plugin-transform-es2015-modules-commonjs@npm:^6.24.1": - version: 6.26.2 - resolution: "babel-plugin-transform-es2015-modules-commonjs@npm:6.26.2" - dependencies: - babel-plugin-transform-strict-mode: "npm:^6.24.1" - babel-runtime: "npm:^6.26.0" - babel-template: "npm:^6.26.0" - babel-types: "npm:^6.26.0" - checksum: 10c0/fb8eb5afb8c88585834311a217efb1975443b2424102ec515b401c9bbb3ebe42ca16f64ff544c5bf87448145a0aed009adce3511fd264ffb0ccd19a51ed0106f +"camelcase@npm:^6.0.0, camelcase@npm:^6.2.0": + version: 6.3.0 + resolution: "camelcase@npm:6.3.0" + checksum: 10c0/0d701658219bd3116d12da3eab31acddb3f9440790c0792e0d398f0a520a6a4058018e546862b6fba89d7ae990efaeb97da71e1913e9ebf5a8b5621a3d55c710 languageName: node linkType: hard -"babel-plugin-transform-es2015-modules-systemjs@npm:^6.23.0": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-modules-systemjs@npm:6.24.1" +"cbor@npm:^10.0.0": + version: 10.0.12 + resolution: "cbor@npm:10.0.12" dependencies: - babel-helper-hoist-variables: "npm:^6.24.1" - babel-runtime: "npm:^6.22.0" - babel-template: "npm:^6.24.1" - checksum: 10c0/7e617b5485c8d52d27ef7588f2b67351220e0d7cdf14fb59bd509ba9e868a1483f0bc63e2cb0eba4caee02d1b00d7a0bd5550c575606e98ca9cb24573444a302 + nofilter: "npm:^3.0.2" + checksum: 10c0/4c197d783415cade31565725a5e6b2b967d856285eacdb0b5f5ec0687d93c12f2ee9c6cc05aa7be02e8bbf0fe3ba40d22be69b56bd2ab1be2cc0a59370f14246 languageName: node linkType: hard -"babel-plugin-transform-es2015-modules-umd@npm:^6.23.0": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-modules-umd@npm:6.24.1" +"cbor@npm:^8.1.0": + version: 8.1.0 + resolution: "cbor@npm:8.1.0" dependencies: - babel-plugin-transform-es2015-modules-amd: "npm:^6.24.1" - babel-runtime: "npm:^6.22.0" - babel-template: "npm:^6.24.1" - checksum: 10c0/360108427f696f40ad20f476a3798faba3a59d16783aa2b49397e7369b6d1f9fcc1dd24ff5a3b16b6ddfc4e58ae4f1ef2ec768443d8649ffde9599072a9d5c25 + nofilter: "npm:^3.1.0" + checksum: 10c0/a836e2e7ea0efb1b9c4e5a4be906c57113d730cc42293a34072e0164ed110bb8ac035dc7dca2e3ebb641bd4b37e00fdbbf09c951aa864b3d4888a6ed8c6243f7 languageName: node linkType: hard -"babel-plugin-transform-es2015-object-super@npm:^6.22.0": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-object-super@npm:6.24.1" +"chai-as-promised@npm:^7.1.1": + version: 7.1.2 + resolution: "chai-as-promised@npm:7.1.2" dependencies: - babel-helper-replace-supers: "npm:^6.24.1" - babel-runtime: "npm:^6.22.0" - checksum: 10c0/50f2a1e3f5dfa77febb2305db48e843c10a165d0ee23a679aca6d5ef2279789582c67a1ca5ed2b2a78af2558cc45a0f05270e1c8208c4e62b59cb8a20730bb16 + check-error: "npm:^1.0.2" + peerDependencies: + chai: ">= 2.1.2 < 6" + checksum: 10c0/ee20ed75296d8cbf828b2f3c9ad64627cee67b1a38b8e906ca59fe788fb6965ddb10f702ae66645ed88f15a905ade4f2d9f8540029e92e2d59b229c9f912273f languageName: node linkType: hard -"babel-plugin-transform-es2015-parameters@npm:^6.23.0": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-parameters@npm:6.24.1" +"chai@npm:^4.3.4": + version: 4.3.4 + resolution: "chai@npm:4.3.4" dependencies: - babel-helper-call-delegate: "npm:^6.24.1" - babel-helper-get-function-arity: "npm:^6.24.1" - babel-runtime: "npm:^6.22.0" - babel-template: "npm:^6.24.1" - babel-traverse: "npm:^6.24.1" - babel-types: "npm:^6.24.1" - checksum: 10c0/e40d6abba07a0c94ae19ccc9a6d6a3f8d828bbae9fdba30a63fd34f790c1742213a367db2610359da41c062f08d159aabc4b119cd62b0cadf30940335f4c8dd9 + assertion-error: "npm:^1.1.0" + check-error: "npm:^1.0.2" + deep-eql: "npm:^3.0.1" + get-func-name: "npm:^2.0.0" + pathval: "npm:^1.1.1" + type-detect: "npm:^4.0.5" + checksum: 10c0/e8be63a3ce412cc35f0209799c96b1f67397c4829489bd1604f9639f291b697f9a8c1ee129f5d502663332691950b278d2be7e8f19d753b86ea1876e99771a8e languageName: node linkType: hard -"babel-plugin-transform-es2015-shorthand-properties@npm:^6.22.0": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-shorthand-properties@npm:6.24.1" +"chalk@npm:4.1.2, chalk@npm:^4.0.0, chalk@npm:^4.1.0, chalk@npm:^4.1.2": + version: 4.1.2 + resolution: "chalk@npm:4.1.2" dependencies: - babel-runtime: "npm:^6.22.0" - babel-types: "npm:^6.24.1" - checksum: 10c0/fab41d02153dbe5077affe09dde6d20b1402e2cbc6fc0cce656e4846217cf15d4e02c1eeff2fc90ee64a4ff746d7fca78eff2d0c81420d623b4b6ffe5080db51 + ansi-styles: "npm:^4.1.0" + supports-color: "npm:^7.1.0" + checksum: 10c0/4a3fef5cc34975c898ffe77141450f679721df9dde00f6c304353fa9c8b571929123b26a0e4617bde5018977eb655b31970c297b91b63ee83bb82aeb04666880 languageName: node linkType: hard -"babel-plugin-transform-es2015-spread@npm:^6.22.0": - version: 6.22.0 - resolution: "babel-plugin-transform-es2015-spread@npm:6.22.0" +"chalk@npm:^2.0.0, chalk@npm:^2.4.2": + version: 2.4.2 + resolution: "chalk@npm:2.4.2" dependencies: - babel-runtime: "npm:^6.22.0" - checksum: 10c0/20542a3f592e7a4902bbc3cd72ca1c2d293696a9d27c2dc8acfcbcf597b3feff40141f4d68e73e050cb3a678cc06e72e9a4ee8a140260022ec04b58baf65e73f + ansi-styles: "npm:^3.2.1" + escape-string-regexp: "npm:^1.0.5" + supports-color: "npm:^5.3.0" + checksum: 10c0/e6543f02ec877732e3a2d1c3c3323ddb4d39fbab687c23f526e25bd4c6a9bf3b83a696e8c769d078e04e5754921648f7821b2a2acfd16c550435fd630026e073 languageName: node linkType: hard -"babel-plugin-transform-es2015-sticky-regex@npm:^6.22.0": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-sticky-regex@npm:6.24.1" - dependencies: - babel-helper-regex: "npm:^6.24.1" - babel-runtime: "npm:^6.22.0" - babel-types: "npm:^6.24.1" - checksum: 10c0/352c51d9cc1cdd23d9c04a8c0ee32a66d390bffd1f8205a86b031eff130861ca8c0b98d71d2128c6f6be2694451ab50d6f2e16707d3c37558f32854a8b46d397 +"charenc@npm:>= 0.0.1": + version: 0.0.2 + resolution: "charenc@npm:0.0.2" + checksum: 10c0/a45ec39363a16799d0f9365c8dd0c78e711415113c6f14787a22462ef451f5013efae8a28f1c058f81fc01f2a6a16955f7a5fd0cd56247ce94a45349c89877d8 languageName: node linkType: hard -"babel-plugin-transform-es2015-template-literals@npm:^6.22.0": - version: 6.22.0 - resolution: "babel-plugin-transform-es2015-template-literals@npm:6.22.0" - dependencies: - babel-runtime: "npm:^6.22.0" - checksum: 10c0/1e5cab288a27b28fb02c09c04fe381defd69ba06c02a11d2844d057d498bc2667a1716a79c3d8f0b954c30f3254675190fd0e135ea0fd62fe5947696cdf92960 +"check-error@npm:^1.0.2": + version: 1.0.2 + resolution: "check-error@npm:1.0.2" + checksum: 10c0/c58ac4d6a92203209a61d025568198c073f101691eb6247f999266e1d1e3ab3af2bbe0a41af5008c1f1b95446ec7831e6ba91f03816177f2da852f316ad7921d languageName: node linkType: hard -"babel-plugin-transform-es2015-typeof-symbol@npm:^6.23.0": - version: 6.23.0 - resolution: "babel-plugin-transform-es2015-typeof-symbol@npm:6.23.0" +"chokidar@npm:^3.5.2": + version: 3.5.3 + resolution: "chokidar@npm:3.5.3" dependencies: - babel-runtime: "npm:^6.22.0" - checksum: 10c0/5723667cf1feba1468d9dbf3216f9bc58f3d9c600f8c5626a65daef1c209ce36e7173873a4b6ff979b9e93e8cd741c30d521044d246ce183036afb0d9be77c0f + anymatch: "npm:~3.1.2" + braces: "npm:~3.0.2" + fsevents: "npm:~2.3.2" + glob-parent: "npm:~5.1.2" + is-binary-path: "npm:~2.1.0" + is-glob: "npm:~4.0.1" + normalize-path: "npm:~3.0.0" + readdirp: "npm:~3.6.0" + dependenciesMeta: + fsevents: + optional: true + checksum: 10c0/1076953093e0707c882a92c66c0f56ba6187831aa51bb4de878c1fec59ae611a3bf02898f190efec8e77a086b8df61c2b2a3ea324642a0558bdf8ee6c5dc9ca1 languageName: node linkType: hard -"babel-plugin-transform-es2015-unicode-regex@npm:^6.22.0": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-unicode-regex@npm:6.24.1" +"chokidar@npm:^4.0.0, chokidar@npm:^4.0.1": + version: 4.0.3 + resolution: "chokidar@npm:4.0.3" dependencies: - babel-helper-regex: "npm:^6.24.1" - babel-runtime: "npm:^6.22.0" - regexpu-core: "npm:^2.0.0" - checksum: 10c0/6bfe2d0521e8cb450ab92b58df380f94c2d39b425f8da28283fe7dd1132663c5d248f5b895341a0c56c5c4f242c0ca40219e9ab26f656c258747401e6696b5ce + readdirp: "npm:^4.0.1" + checksum: 10c0/a58b9df05bb452f7d105d9e7229ac82fa873741c0c40ddcc7bb82f8a909fbe3f7814c9ebe9bc9a2bef9b737c0ec6e2d699d179048ef06ad3ec46315df0ebe6ad languageName: node linkType: hard -"babel-plugin-transform-exponentiation-operator@npm:^6.22.0": - version: 6.24.1 - resolution: "babel-plugin-transform-exponentiation-operator@npm:6.24.1" - dependencies: - babel-helper-builder-binary-assignment-operator-visitor: "npm:^6.24.1" - babel-plugin-syntax-exponentiation-operator: "npm:^6.8.0" - babel-runtime: "npm:^6.22.0" - checksum: 10c0/e30e13e63fc578b4eaf667198fa46af904c678b6236c72260dc89bb55922c502390573af95e2a3878eaa7ce5c4de6693ae47809bc7536b684c5e2391e5db8b5d +"chownr@npm:^3.0.0": + version: 3.0.0 + resolution: "chownr@npm:3.0.0" + checksum: 10c0/43925b87700f7e3893296c8e9c56cc58f926411cce3a6e5898136daaf08f08b9a8eb76d37d3267e707d0dcc17aed2e2ebdf5848c0c3ce95cf910a919935c1b10 languageName: node linkType: hard -"babel-plugin-transform-regenerator@npm:^6.22.0": - version: 6.26.0 - resolution: "babel-plugin-transform-regenerator@npm:6.26.0" - dependencies: - regenerator-transform: "npm:^0.10.0" - checksum: 10c0/180460a380006f70b2ed76a714714a8f46ac64c28a31c403ff031233ddc89886b1de35b7c0e6401b97d3166c3bb3780a6578cbe9db1fdbcd9d410e8e5cc9bc57 +"ci-info@npm:^2.0.0": + version: 2.0.0 + resolution: "ci-info@npm:2.0.0" + checksum: 10c0/8c5fa3830a2bcee2b53c2e5018226f0141db9ec9f7b1e27a5c57db5512332cde8a0beb769bcbaf0d8775a78afbf2bb841928feca4ea6219638a5b088f9884b46 languageName: node linkType: hard -"babel-plugin-transform-strict-mode@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-plugin-transform-strict-mode@npm:6.24.1" +"cipher-base@npm:^1.0.0, cipher-base@npm:^1.0.1, cipher-base@npm:^1.0.3": + version: 1.0.4 + resolution: "cipher-base@npm:1.0.4" dependencies: - babel-runtime: "npm:^6.22.0" - babel-types: "npm:^6.24.1" - checksum: 10c0/736b2b5b4816a11cdf6c02304d133386714d1e586091f95359e0127605bfa8d47aea3e325d936346541b7e836eb7dd0c208833a5ab868ab85caece03d30518b9 + inherits: "npm:^2.0.1" + safe-buffer: "npm:^5.0.1" + checksum: 10c0/d8d005f8b64d8a77b3d3ce531301ae7b45902c9cab4ec8b66bdbd2bf2a1d9fceb9a2133c293eb3c060b2d964da0f14c47fb740366081338aa3795dd1faa8984b languageName: node linkType: hard -"babel-preset-env@npm:^1.7.0": - version: 1.7.0 - resolution: "babel-preset-env@npm:1.7.0" - dependencies: - babel-plugin-check-es2015-constants: "npm:^6.22.0" - babel-plugin-syntax-trailing-function-commas: "npm:^6.22.0" - babel-plugin-transform-async-to-generator: "npm:^6.22.0" - babel-plugin-transform-es2015-arrow-functions: "npm:^6.22.0" - babel-plugin-transform-es2015-block-scoped-functions: "npm:^6.22.0" - babel-plugin-transform-es2015-block-scoping: "npm:^6.23.0" - babel-plugin-transform-es2015-classes: "npm:^6.23.0" - babel-plugin-transform-es2015-computed-properties: "npm:^6.22.0" - babel-plugin-transform-es2015-destructuring: "npm:^6.23.0" - babel-plugin-transform-es2015-duplicate-keys: "npm:^6.22.0" - babel-plugin-transform-es2015-for-of: "npm:^6.23.0" - babel-plugin-transform-es2015-function-name: "npm:^6.22.0" - babel-plugin-transform-es2015-literals: "npm:^6.22.0" - babel-plugin-transform-es2015-modules-amd: "npm:^6.22.0" - babel-plugin-transform-es2015-modules-commonjs: "npm:^6.23.0" - babel-plugin-transform-es2015-modules-systemjs: "npm:^6.23.0" - babel-plugin-transform-es2015-modules-umd: "npm:^6.23.0" - babel-plugin-transform-es2015-object-super: "npm:^6.22.0" - babel-plugin-transform-es2015-parameters: "npm:^6.23.0" - babel-plugin-transform-es2015-shorthand-properties: "npm:^6.22.0" - babel-plugin-transform-es2015-spread: "npm:^6.22.0" - babel-plugin-transform-es2015-sticky-regex: "npm:^6.22.0" - babel-plugin-transform-es2015-template-literals: "npm:^6.22.0" - babel-plugin-transform-es2015-typeof-symbol: "npm:^6.23.0" - babel-plugin-transform-es2015-unicode-regex: "npm:^6.22.0" - babel-plugin-transform-exponentiation-operator: "npm:^6.22.0" - babel-plugin-transform-regenerator: "npm:^6.22.0" - browserslist: "npm:^3.2.6" - invariant: "npm:^2.2.2" - semver: "npm:^5.3.0" - checksum: 10c0/38b40b3b92dc3fa27afbdf1fee35a89c66c082009be3036ef20cb4dae472b7c498c20f56a1697ffcff00e42bfdedfbd9a71a6d3d5a829d60bb50f063faeb3157 - languageName: node - linkType: hard - -"babel-register@npm:^6.26.0": - version: 6.26.0 - resolution: "babel-register@npm:6.26.0" - dependencies: - babel-core: "npm:^6.26.0" - babel-runtime: "npm:^6.26.0" - core-js: "npm:^2.5.0" - home-or-tmp: "npm:^2.0.0" - lodash: "npm:^4.17.4" - mkdirp: "npm:^0.5.1" - source-map-support: "npm:^0.4.15" - checksum: 10c0/4ffbc1bfa60a817fb306c98d1a6d10852b0130a614dae3a91e45f391dbebdc95f428d95b489943d85724e046527d2aac3bafb74d3c24f62143492b5f606e2e04 - languageName: node - linkType: hard - -"babel-runtime@npm:^6.18.0, babel-runtime@npm:^6.22.0, babel-runtime@npm:^6.26.0": - version: 6.26.0 - resolution: "babel-runtime@npm:6.26.0" - dependencies: - core-js: "npm:^2.4.0" - regenerator-runtime: "npm:^0.11.0" - checksum: 10c0/caa752004936b1463765ed3199c52f6a55d0613b9bed108743d6f13ca532b821d4ea9decc4be1b583193164462b1e3e7eefdfa36b15c72e7daac58dd72c1772f - languageName: node - linkType: hard - -"babel-template@npm:^6.24.1, babel-template@npm:^6.26.0": - version: 6.26.0 - resolution: "babel-template@npm:6.26.0" - dependencies: - babel-runtime: "npm:^6.26.0" - babel-traverse: "npm:^6.26.0" - babel-types: "npm:^6.26.0" - babylon: "npm:^6.18.0" - lodash: "npm:^4.17.4" - checksum: 10c0/67bc875f19d289dabb1830a1cde93d7f1e187e4599dac9b1d16392fd47f1d12b53fea902dacf7be360acd09807d440faafe0f7907758c13275b1a14d100b68e4 - languageName: node - linkType: hard - -"babel-traverse@npm:^6.24.1, babel-traverse@npm:^6.26.0": - version: 6.26.0 - resolution: "babel-traverse@npm:6.26.0" - dependencies: - babel-code-frame: "npm:^6.26.0" - babel-messages: "npm:^6.23.0" - babel-runtime: "npm:^6.26.0" - babel-types: "npm:^6.26.0" - babylon: "npm:^6.18.0" - debug: "npm:^2.6.8" - globals: "npm:^9.18.0" - invariant: "npm:^2.2.2" - lodash: "npm:^4.17.4" - checksum: 10c0/dca71b23d07e3c00833c3222d7998202e687105f461048107afeb2b4a7aa2507efab1bd5a6e3e724724ebb9b1e0b14f0113621e1d8c25b4ffdb829392b54b8de - languageName: node - linkType: hard - -"babel-types@npm:^6.19.0, babel-types@npm:^6.24.1, babel-types@npm:^6.26.0": - version: 6.26.0 - resolution: "babel-types@npm:6.26.0" - dependencies: - babel-runtime: "npm:^6.26.0" - esutils: "npm:^2.0.2" - lodash: "npm:^4.17.4" - to-fast-properties: "npm:^1.0.3" - checksum: 10c0/cabe371de1b32c4bbb1fd4ed0fe8a8726d42e5ad7d5cefb83cdae6de0f0a152dce591e4026719743fdf3aa45f84fea2c8851fb822fbe29b0c78a1f0094b67418 +"clean-stack@npm:^2.0.0": + version: 2.2.0 + resolution: "clean-stack@npm:2.2.0" + checksum: 10c0/1f90262d5f6230a17e27d0c190b09d47ebe7efdd76a03b5a1127863f7b3c9aec4c3e6c8bb3a7bbf81d553d56a1fd35728f5a8ef4c63f867ac8d690109742a8c1 languageName: node linkType: hard -"babelify@npm:^7.3.0": - version: 7.3.0 - resolution: "babelify@npm:7.3.0" - dependencies: - babel-core: "npm:^6.0.14" - object-assign: "npm:^4.0.0" - checksum: 10c0/1464c4cdd127ba9ae3c5ce69fa52af73d6027d8b65126059f10f068d260c5b60dbcd83fd737c9f954998e00bbc55421c09acf3fdb4f03e682bb167a32e93bbd4 - languageName: node - linkType: hard - -"babylon@npm:^6.18.0": - version: 6.18.0 - resolution: "babylon@npm:6.18.0" - bin: - babylon: ./bin/babylon.js - checksum: 10c0/9b1bf946e16782deadb1f5414c1269efa6044eb1e97a3de2051f09a3f2a54e97be3542d4242b28d23de0ef67816f519d38ce1ec3ddb7be306131c39a60e5a667 +"cli-boxes@npm:^2.2.1": + version: 2.2.1 + resolution: "cli-boxes@npm:2.2.1" + checksum: 10c0/6111352edbb2f62dbc7bfd58f2d534de507afed7f189f13fa894ce5a48badd94b2aa502fda28f1d7dd5f1eb456e7d4033d09a76660013ef50c7f66e7a034f050 languageName: node linkType: hard -"backoff@npm:^2.5.0": - version: 2.5.0 - resolution: "backoff@npm:2.5.0" +"cli-table3@npm:^0.6.0": + version: 0.6.0 + resolution: "cli-table3@npm:0.6.0" dependencies: - precond: "npm:0.2" - checksum: 10c0/57afcd07c08e9174d78f79643ebca1e8da752143ef6675e6b4a0b08ec6b497db3317089350c02fb747ae54c53f485c4d8b0742130b78028bb8a8cd96dd69ce0f - languageName: node - linkType: hard - -"balanced-match@npm:^1.0.0": - version: 1.0.2 - resolution: "balanced-match@npm:1.0.2" - checksum: 10c0/9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee - languageName: node - linkType: hard - -"balanced-match@npm:^4.0.2": - version: 4.0.4 - resolution: "balanced-match@npm:4.0.4" - checksum: 10c0/07e86102a3eb2ee2a6a1a89164f29d0dbaebd28f2ca3f5ca786f36b8b23d9e417eb3be45a4acf754f837be5ac0a2317de90d3fcb7f4f4dc95720a1f36b26a17b + colors: "npm:^1.1.2" + object-assign: "npm:^4.1.0" + string-width: "npm:^4.2.0" + dependenciesMeta: + colors: + optional: true + checksum: 10c0/3805702bb9a0d54ed8a5385237088b489109744b37654fd2fe9ca9df0369dc1603feef28f610c5f5fee8ed4350c38ddcfb1dfc7f700616e668f5487529551249 languageName: node linkType: hard -"base-x@npm:^3.0.2": - version: 3.0.9 - resolution: "base-x@npm:3.0.9" +"cli-table3@npm:^0.6.2, cli-table3@npm:^0.6.3": + version: 0.6.5 + resolution: "cli-table3@npm:0.6.5" dependencies: - safe-buffer: "npm:^5.0.1" - checksum: 10c0/e6bbeae30b24f748b546005affb710c5fbc8b11a83f6cd0ca999bd1ab7ad3a22e42888addc40cd145adc4edfe62fcfab4ebc91da22e4259aae441f95a77aee1a + "@colors/colors": "npm:1.5.0" + string-width: "npm:^4.2.0" + dependenciesMeta: + "@colors/colors": + optional: true + checksum: 10c0/d7cc9ed12212ae68241cc7a3133c52b844113b17856e11f4f81308acc3febcea7cc9fd298e70933e294dd642866b29fd5d113c2c098948701d0c35f09455de78 languageName: node linkType: hard -"base-x@npm:^3.0.8": - version: 3.0.8 - resolution: "base-x@npm:3.0.8" +"cliui@npm:^8.0.1": + version: 8.0.1 + resolution: "cliui@npm:8.0.1" dependencies: - safe-buffer: "npm:^5.0.1" - checksum: 10c0/6336c3aec4098fed49982ea170c221b4379cc399ec482a76208598aaab08a1ac68ba9b128b45ab1cfccbb43875f6cfd89fe6bbc45d564cd637e78db372c02de6 + string-width: "npm:^4.2.0" + strip-ansi: "npm:^6.0.1" + wrap-ansi: "npm:^7.0.0" + checksum: 10c0/4bda0f09c340cbb6dfdc1ed508b3ca080f12992c18d68c6be4d9cf51756033d5266e61ec57529e610dacbf4da1c634423b0c1b11037709cc6b09045cbd815df5 languageName: node linkType: hard -"base64-js@npm:^1.3.1": - version: 1.5.1 - resolution: "base64-js@npm:1.5.1" - checksum: 10c0/f23823513b63173a001030fae4f2dabe283b99a9d324ade3ad3d148e218134676f1ee8568c877cd79ec1c53158dcf2d2ba527a97c606618928ba99dd930102bf +"color-convert@npm:^1.9.0": + version: 1.9.3 + resolution: "color-convert@npm:1.9.3" + dependencies: + color-name: "npm:1.1.3" + checksum: 10c0/5ad3c534949a8c68fca8fbc6f09068f435f0ad290ab8b2f76841b9e6af7e0bb57b98cb05b0e19fe33f5d91e5a8611ad457e5f69e0a484caad1f7487fd0e8253c languageName: node linkType: hard -"base@npm:^0.11.1": - version: 0.11.2 - resolution: "base@npm:0.11.2" +"color-convert@npm:^2.0.1": + version: 2.0.1 + resolution: "color-convert@npm:2.0.1" dependencies: - cache-base: "npm:^1.0.1" - class-utils: "npm:^0.3.5" - component-emitter: "npm:^1.2.1" - define-property: "npm:^1.0.0" - isobject: "npm:^3.0.1" - mixin-deep: "npm:^1.2.0" - pascalcase: "npm:^0.1.1" - checksum: 10c0/30a2c0675eb52136b05ef496feb41574d9f0bb2d6d677761da579c00a841523fccf07f1dbabec2337b5f5750f428683b8ca60d89e56a1052c4ae1c0cd05de64d + color-name: "npm:~1.1.4" + checksum: 10c0/37e1150172f2e311fe1b2df62c6293a342ee7380da7b9cfdba67ea539909afbd74da27033208d01d6d5cfc65ee7868a22e18d7e7648e004425441c0f8a15a7d7 languageName: node linkType: hard -"bcrypt-pbkdf@npm:^1.0.0": - version: 1.0.2 - resolution: "bcrypt-pbkdf@npm:1.0.2" - dependencies: - tweetnacl: "npm:^0.14.3" - checksum: 10c0/ddfe85230b32df25aeebfdccfbc61d3bc493ace49c884c9c68575de1f5dcf733a5d7de9def3b0f318b786616b8d85bad50a28b1da1750c43e0012c93badcc148 +"color-name@npm:1.1.3": + version: 1.1.3 + resolution: "color-name@npm:1.1.3" + checksum: 10c0/566a3d42cca25b9b3cd5528cd7754b8e89c0eb646b7f214e8e2eaddb69994ac5f0557d9c175eb5d8f0ad73531140d9c47525085ee752a91a2ab15ab459caf6d6 languageName: node linkType: hard -"bech32@npm:1.1.4": +"color-name@npm:~1.1.4": version: 1.1.4 - resolution: "bech32@npm:1.1.4" - checksum: 10c0/5f62ca47b8df99ace9c0e0d8deb36a919d91bf40066700aaa9920a45f86bb10eb56d537d559416fd8703aa0fb60dddb642e58f049701e7291df678b2033e5ee5 + resolution: "color-name@npm:1.1.4" + checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95 languageName: node linkType: hard -"bignumber.js@npm:^9.0.0": - version: 9.1.0 - resolution: "bignumber.js@npm:9.1.0" - checksum: 10c0/82b7314c9b1480e0471c21ac154342b910bd00807050e4ae248e291168eb23140456191c3f9b522da822c87a7730e8e18524db4db836d4455d821222c0acdfac +"colors@npm:^1.1.2": + version: 1.4.0 + resolution: "colors@npm:1.4.0" + checksum: 10c0/9af357c019da3c5a098a301cf64e3799d27549d8f185d86f79af23069e4f4303110d115da98483519331f6fb71c8568d5688fa1c6523600044fd4a54e97c4efb languageName: node linkType: hard -"bignumber.js@npm:^9.0.1": - version: 9.0.2 - resolution: "bignumber.js@npm:9.0.2" - checksum: 10c0/b5c598ede49c3e391e53de6f992ee53960c45c96bb26e3933bd252890e77e3c703b88897a2148703f90f693d538396f8bed7c118a84a32fd54e24932bd16c04f +"combined-stream@npm:^1.0.8": + version: 1.0.8 + resolution: "combined-stream@npm:1.0.8" + dependencies: + delayed-stream: "npm:~1.0.0" + checksum: 10c0/0dbb829577e1b1e839fa82b40c07ffaf7de8a09b935cadd355a73652ae70a88b4320db322f6634a4ad93424292fa80973ac6480986247f1734a1137debf271d5 languageName: node linkType: hard -"binary-extensions@npm:^2.0.0": - version: 2.2.0 - resolution: "binary-extensions@npm:2.2.0" - checksum: 10c0/d73d8b897238a2d3ffa5f59c0241870043aa7471335e89ea5e1ff48edb7c2d0bb471517a3e4c5c3f4c043615caa2717b5f80a5e61e07503d51dc85cb848e665d +"command-exists@npm:^1.2.8": + version: 1.2.9 + resolution: "command-exists@npm:1.2.9" + checksum: 10c0/75040240062de46cd6cd43e6b3032a8b0494525c89d3962e280dde665103f8cc304a8b313a5aa541b91da2f5a9af75c5959dc3a77893a2726407a5e9a0234c16 languageName: node linkType: hard -"bip39@npm:2.5.0": - version: 2.5.0 - resolution: "bip39@npm:2.5.0" +"command-line-args@npm:^5.1.1": + version: 5.2.1 + resolution: "command-line-args@npm:5.2.1" dependencies: - create-hash: "npm:^1.1.0" - pbkdf2: "npm:^3.0.9" - randombytes: "npm:^2.0.1" - safe-buffer: "npm:^5.0.1" - unorm: "npm:^1.3.3" - checksum: 10c0/127da2987e7753551419a4be0a968ecca2f1514e871b5902e9bdf769b85a4484200546e51de5ca39a2fdf848dbfb7e2bdcce7f3deb9e0430187334db9d00334d + array-back: "npm:^3.1.0" + find-replace: "npm:^3.0.0" + lodash.camelcase: "npm:^4.3.0" + typical: "npm:^4.0.0" + checksum: 10c0/a4f6a23a1e420441bd1e44dee24efd12d2e49af7efe6e21eb32fca4e843ca3d5501ddebad86a4e9d99aa626dd6dcb64c04a43695388be54e3a803dbc326cc89f languageName: node linkType: hard -"blakejs@npm:^1.1.0": - version: 1.2.1 - resolution: "blakejs@npm:1.2.1" - checksum: 10c0/c284557ce55b9c70203f59d381f1b85372ef08ee616a90162174d1291a45d3e5e809fdf9edab6e998740012538515152471dc4f1f9dbfa974ba2b9c1f7b9aad7 +"command-line-usage@npm:^6.1.0": + version: 6.1.1 + resolution: "command-line-usage@npm:6.1.1" + dependencies: + array-back: "npm:^4.0.1" + chalk: "npm:^2.4.2" + table-layout: "npm:^1.0.1" + typical: "npm:^5.2.0" + checksum: 10c0/2597ee2a529020c86e2a3ef4288ffd1a9ccf05dbe4fafd4d33a75c36241054e551132a358a3355544df09b6855dbc7aca05efd9b0aba5b25b36d3225bb303c02 languageName: node linkType: hard -"bluebird@npm:^3.5.0, bluebird@npm:^3.5.2": - version: 3.7.2 - resolution: "bluebird@npm:3.7.2" - checksum: 10c0/680de03adc54ff925eaa6c7bb9a47a0690e8b5de60f4792604aae8ed618c65e6b63a7893b57ca924beaf53eee69c5af4f8314148c08124c550fe1df1add897d2 +"commander@npm:^10.0.0": + version: 10.0.1 + resolution: "commander@npm:10.0.1" + checksum: 10c0/53f33d8927758a911094adadda4b2cbac111a5b377d8706700587650fd8f45b0bbe336de4b5c3fe47fd61f420a3d9bd452b6e0e6e5600a7e74d7bf0174f6efe3 languageName: node linkType: hard -"bn.js@npm:4.11.6": - version: 4.11.6 - resolution: "bn.js@npm:4.11.6" - checksum: 10c0/e6ee7d3f597f60722cc3361071e23ccf71d3387e166de02381f180f22d2fa79f5dbbdf9e4909e81faaf5da01c16ec6857ddff02678339ce085e2058fd0e405db +"commander@npm:^8.1.0": + version: 8.3.0 + resolution: "commander@npm:8.3.0" + checksum: 10c0/8b043bb8322ea1c39664a1598a95e0495bfe4ca2fad0d84a92d7d1d8d213e2a155b441d2470c8e08de7c4a28cf2bc6e169211c49e1b21d9f7edc6ae4d9356060 languageName: node linkType: hard -"bn.js@npm:^4.0.0, bn.js@npm:^4.1.0, bn.js@npm:^4.11.0, bn.js@npm:^4.11.1, bn.js@npm:^4.11.6, bn.js@npm:^4.11.8, bn.js@npm:^4.11.9": - version: 4.12.0 - resolution: "bn.js@npm:4.12.0" - checksum: 10c0/9736aaa317421b6b3ed038ff3d4491935a01419ac2d83ddcfebc5717385295fcfcf0c57311d90fe49926d0abbd7a9dbefdd8861e6129939177f7e67ebc645b21 +"commander@npm:^9.4.0": + version: 9.5.0 + resolution: "commander@npm:9.5.0" + checksum: 10c0/5f7784fbda2aaec39e89eb46f06a999e00224b3763dc65976e05929ec486e174fe9aac2655f03ba6a5e83875bd173be5283dc19309b7c65954701c02025b3c1d languageName: node linkType: hard -"bn.js@npm:^5.0.0, bn.js@npm:^5.1.1, bn.js@npm:^5.2.0, bn.js@npm:^5.2.1": - version: 5.2.1 - resolution: "bn.js@npm:5.2.1" - checksum: 10c0/bed3d8bd34ec89dbcf9f20f88bd7d4a49c160fda3b561c7bb227501f974d3e435a48fb9b61bc3de304acab9215a3bda0803f7017ffb4d0016a0c3a740a283caa +"comment-parser@npm:^1.4.1": + version: 1.4.8 + resolution: "comment-parser@npm:1.4.8" + checksum: 10c0/7638c29abefdd705917ee73a1a28e0b5851f59b73ed3ebb3369583c74e87d1b4bb2ceae1c94e699e7bf00f06ad679d5a32adc2a42c656965912c9ac85fa17e90 languageName: node linkType: hard -"bn.js@npm:^5.1.2": - version: 5.2.0 - resolution: "bn.js@npm:5.2.0" - checksum: 10c0/67e17b1934d9c7a73aed9b89222dc8c1c8e3aff46cca6609b8c2ab04fa22c6b8db42c7774b039d09fa63136d8866b777ab88af0d64d8ea3839a94e69193a6b13 +"compare-versions@npm:^6.0.0": + version: 6.1.1 + resolution: "compare-versions@npm:6.1.1" + checksum: 10c0/415205c7627f9e4f358f571266422980c9fe2d99086be0c9a48008ef7c771f32b0fbe8e97a441ffedc3910872f917a0675fe0fe3c3b6d331cda6d8690be06338 languageName: node linkType: hard -"body-parser@npm:1.20.0, body-parser@npm:^1.16.0": - version: 1.20.0 - resolution: "body-parser@npm:1.20.0" - dependencies: - bytes: "npm:3.1.2" - content-type: "npm:~1.0.4" - debug: "npm:2.6.9" - depd: "npm:2.0.0" - destroy: "npm:1.2.0" - http-errors: "npm:2.0.0" - iconv-lite: "npm:0.4.24" - on-finished: "npm:2.4.1" - qs: "npm:6.10.3" - raw-body: "npm:2.5.1" - type-is: "npm:~1.6.18" - unpipe: "npm:1.0.0" - checksum: 10c0/36aa63aa7862ccbb32ea92fc3e6e1dea25b8c2fda03762bc26d0f82f61272635c532b2d77ef43d312de779fac83f24061a375d047be7f2bbf3ece66dc6b2c460 +"concat-map@npm:0.0.1": + version: 0.0.1 + resolution: "concat-map@npm:0.0.1" + checksum: 10c0/c996b1cfdf95b6c90fee4dae37e332c8b6eb7d106430c17d538034c0ad9a1630cb194d2ab37293b1bdd4d779494beee7786d586a50bd9376fd6f7bcc2bd4c98f languageName: node linkType: hard -"boxen@npm:^5.1.2": - version: 5.1.2 - resolution: "boxen@npm:5.1.2" +"config-chain@npm:^1.1.11": + version: 1.1.13 + resolution: "config-chain@npm:1.1.13" dependencies: - ansi-align: "npm:^3.0.0" - camelcase: "npm:^6.2.0" - chalk: "npm:^4.1.0" - cli-boxes: "npm:^2.2.1" - string-width: "npm:^4.2.2" - type-fest: "npm:^0.20.2" - widest-line: "npm:^3.1.0" - wrap-ansi: "npm:^7.0.0" - checksum: 10c0/71f31c2eb3dcacd5fce524ae509e0cc90421752e0bfbd0281fd3352871d106c462a0f810c85f2fdb02f3a9fab2d7a84e9718b4999384d651b76104ebe5d2c024 + ini: "npm:^1.3.4" + proto-list: "npm:~1.2.1" + checksum: 10c0/39d1df18739d7088736cc75695e98d7087aea43646351b028dfabd5508d79cf6ef4c5bcd90471f52cd87ae470d1c5490c0a8c1a292fbe6ee9ff688061ea0963e languageName: node linkType: hard -"brace-expansion@npm:^1.1.7": - version: 1.1.11 - resolution: "brace-expansion@npm:1.1.11" - dependencies: - balanced-match: "npm:^1.0.0" - concat-map: "npm:0.0.1" - checksum: 10c0/695a56cd058096a7cb71fb09d9d6a7070113c7be516699ed361317aca2ec169f618e28b8af352e02ab4233fb54eb0168460a40dc320bab0034b36ab59aaad668 +"cookie@npm:^0.4.1": + version: 0.4.1 + resolution: "cookie@npm:0.4.1" + checksum: 10c0/4d7bc798df3d0f34035977949cd6b7d05bbab47d7dcb868667f460b578a550cd20dec923832b8a3a107ef35aba091a3975e14f79efacf6e39282dc0fed6db4a1 languageName: node linkType: hard -"brace-expansion@npm:^2.0.2": - version: 2.1.2 - resolution: "brace-expansion@npm:2.1.2" +"cosmiconfig@npm:^8.0.0": + version: 8.3.6 + resolution: "cosmiconfig@npm:8.3.6" dependencies: - balanced-match: "npm:^1.0.0" - checksum: 10c0/5442ecab84045d21826268bc56c81a6ef4215327ee1f5ee153f67928e93f7a915d130ecec9966623143277fa3cce036ebb50020024bcc4d78853cdd6af9a19f8 + import-fresh: "npm:^3.3.0" + js-yaml: "npm:^4.1.0" + parse-json: "npm:^5.2.0" + path-type: "npm:^4.0.0" + peerDependencies: + typescript: ">=4.9.5" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/0382a9ed13208f8bfc22ca2f62b364855207dffdb73dc26e150ade78c3093f1cf56172df2dd460c8caf2afa91c0ed4ec8a88c62f8f9cd1cf423d26506aa8797a languageName: node linkType: hard -"brace-expansion@npm:^5.0.5": - version: 5.0.5 - resolution: "brace-expansion@npm:5.0.5" +"create-hash@npm:^1.1.0, create-hash@npm:^1.1.2, create-hash@npm:^1.2.0": + version: 1.2.0 + resolution: "create-hash@npm:1.2.0" dependencies: - balanced-match: "npm:^4.0.2" - checksum: 10c0/4d238e14ed4f5cc9c07285550a41cef23121ca08ba99fa9eb5b55b580dcb6bf868b8210aa10526bdc9f8dc97f33ca2a7259039c4cc131a93042beddb424c48e3 + cipher-base: "npm:^1.0.1" + inherits: "npm:^2.0.1" + md5.js: "npm:^1.3.4" + ripemd160: "npm:^2.0.1" + sha.js: "npm:^2.4.0" + checksum: 10c0/d402e60e65e70e5083cb57af96d89567954d0669e90550d7cec58b56d49c4b193d35c43cec8338bc72358198b8cbf2f0cac14775b651e99238e1cf411490f915 languageName: node linkType: hard -"braces@npm:^2.3.1": - version: 2.3.2 - resolution: "braces@npm:2.3.2" +"create-hmac@npm:^1.1.4, create-hmac@npm:^1.1.7": + version: 1.1.7 + resolution: "create-hmac@npm:1.1.7" dependencies: - arr-flatten: "npm:^1.1.0" - array-unique: "npm:^0.3.2" - extend-shallow: "npm:^2.0.1" - fill-range: "npm:^4.0.0" - isobject: "npm:^3.0.1" - repeat-element: "npm:^1.1.2" - snapdragon: "npm:^0.8.1" - snapdragon-node: "npm:^2.0.1" - split-string: "npm:^3.0.2" - to-regex: "npm:^3.0.1" - checksum: 10c0/72b27ea3ea2718f061c29e70fd6e17606e37c65f5801abddcf0b0052db1de7d60f3bf92cfc220ab57b44bd0083a5f69f9d03b3461d2816cfe9f9398207acc728 + cipher-base: "npm:^1.0.3" + create-hash: "npm:^1.1.0" + inherits: "npm:^2.0.1" + ripemd160: "npm:^2.0.0" + safe-buffer: "npm:^5.0.1" + sha.js: "npm:^2.4.8" + checksum: 10c0/24332bab51011652a9a0a6d160eed1e8caa091b802335324ae056b0dcb5acbc9fcf173cf10d128eba8548c3ce98dfa4eadaa01bd02f44a34414baee26b651835 languageName: node linkType: hard -"braces@npm:^3.0.1, braces@npm:~3.0.2": - version: 3.0.2 - resolution: "braces@npm:3.0.2" +"create-require@npm:^1.1.0": + version: 1.1.1 + resolution: "create-require@npm:1.1.1" + checksum: 10c0/157cbc59b2430ae9a90034a5f3a1b398b6738bf510f713edc4d4e45e169bc514d3d99dd34d8d01ca7ae7830b5b8b537e46ae8f3c8f932371b0875c0151d7ec91 + languageName: node + linkType: hard + +"cross-spawn@npm:^7.0.6": + version: 7.0.6 + resolution: "cross-spawn@npm:7.0.6" dependencies: - fill-range: "npm:^7.0.1" - checksum: 10c0/321b4d675791479293264019156ca322163f02dc06e3c4cab33bb15cd43d80b51efef69b0930cfde3acd63d126ebca24cd0544fa6f261e093a0fb41ab9dda381 + path-key: "npm:^3.1.0" + shebang-command: "npm:^2.0.0" + which: "npm:^2.0.1" + checksum: 10c0/053ea8b2135caff68a9e81470e845613e374e7309a47731e81639de3eaeb90c3d01af0e0b44d2ab9d50b43467223b88567dfeb3262db942dc063b9976718ffc1 languageName: node linkType: hard -"brorand@npm:^1.0.1, brorand@npm:^1.1.0": - version: 1.1.0 - resolution: "brorand@npm:1.1.0" - checksum: 10c0/6f366d7c4990f82c366e3878492ba9a372a73163c09871e80d82fb4ae0d23f9f8924cb8a662330308206e6b3b76ba1d528b4601c9ef73c2166b440b2ea3b7571 +"crypt@npm:>= 0.0.1": + version: 0.0.2 + resolution: "crypt@npm:0.0.2" + checksum: 10c0/adbf263441dd801665d5425f044647533f39f4612544071b1471962209d235042fb703c27eea2795c7c53e1dfc242405173003f83cf4f4761a633d11f9653f18 languageName: node linkType: hard -"brotli-wasm@npm:^2.0.1": - version: 2.0.1 - resolution: "brotli-wasm@npm:2.0.1" - checksum: 10c0/d7a4135f4b45474422cc01f2b817f2075efbbfe7239bda973387f62415fa0102c6a6bbdfef744f7583b5113e2b1a25ee8c638f0fa2fe41042fb4b1737daa9df9 +"debug@npm:4, debug@npm:^4.1.1, debug@npm:^4.3.1": + version: 4.3.2 + resolution: "debug@npm:4.3.2" + dependencies: + ms: "npm:2.1.2" + peerDependenciesMeta: + supports-color: + optional: true + checksum: 10c0/3cc408070bcee066ee9b2a4f3a9c40f53728919ec7c7ff568f7c3a75b0723cb5a8407191a63495be4e10669e99b0ff7f26ec70e10b025da1898cdce4876d96ca languageName: node linkType: hard -"browser-stdout@npm:^1.3.1": - version: 1.3.1 - resolution: "browser-stdout@npm:1.3.1" - checksum: 10c0/c40e482fd82be872b6ea7b9f7591beafbf6f5ba522fe3dade98ba1573a1c29a11101564993e4eb44e5488be8f44510af072df9a9637c739217eb155ceb639205 +"debug@npm:^4.3.2": + version: 4.3.4 + resolution: "debug@npm:4.3.4" + dependencies: + ms: "npm:2.1.2" + peerDependenciesMeta: + supports-color: + optional: true + checksum: 10c0/cedbec45298dd5c501d01b92b119cd3faebe5438c3917ff11ae1bff86a6c722930ac9c8659792824013168ba6db7c4668225d845c633fbdafbbf902a6389f736 languageName: node linkType: hard -"browserify-aes@npm:^1.0.0, browserify-aes@npm:^1.0.4, browserify-aes@npm:^1.2.0": - version: 1.2.0 - resolution: "browserify-aes@npm:1.2.0" +"debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.4.1, debug@npm:^4.4.3": + version: 4.4.3 + resolution: "debug@npm:4.4.3" dependencies: - buffer-xor: "npm:^1.0.3" - cipher-base: "npm:^1.0.0" - create-hash: "npm:^1.1.0" - evp_bytestokey: "npm:^1.0.3" - inherits: "npm:^2.0.1" - safe-buffer: "npm:^5.0.1" - checksum: 10c0/967f2ae60d610b7b252a4cbb55a7a3331c78293c94b4dd9c264d384ca93354c089b3af9c0dd023534efdc74ffbc82510f7ad4399cf82bc37bc07052eea485f18 + ms: "npm:^2.1.3" + peerDependenciesMeta: + supports-color: + optional: true + checksum: 10c0/d79136ec6c83ecbefd0f6a5593da6a9c91ec4d7ddc4b54c883d6e71ec9accb5f67a1a5e96d00a328196b5b5c86d365e98d8a3a70856aaf16b4e7b1985e67f5a6 languageName: node linkType: hard -"browserify-cipher@npm:^1.0.0": - version: 1.0.1 - resolution: "browserify-cipher@npm:1.0.1" - dependencies: - browserify-aes: "npm:^1.0.4" - browserify-des: "npm:^1.0.0" - evp_bytestokey: "npm:^1.0.0" - checksum: 10c0/aa256dcb42bc53a67168bbc94ab85d243b0a3b56109dee3b51230b7d010d9b78985ffc1fb36e145c6e4db151f888076c1cfc207baf1525d3e375cbe8187fe27d +"decamelize@npm:^4.0.0": + version: 4.0.0 + resolution: "decamelize@npm:4.0.0" + checksum: 10c0/e06da03fc05333e8cd2778c1487da67ffbea5b84e03ca80449519b8fa61f888714bbc6f459ea963d5641b4aa98832130eb5cd193d90ae9f0a27eee14be8e278d languageName: node linkType: hard -"browserify-des@npm:^1.0.0": - version: 1.0.2 - resolution: "browserify-des@npm:1.0.2" +"decompress-response@npm:^6.0.0": + version: 6.0.0 + resolution: "decompress-response@npm:6.0.0" dependencies: - cipher-base: "npm:^1.0.1" - des.js: "npm:^1.0.0" - inherits: "npm:^2.0.1" - safe-buffer: "npm:^5.1.2" - checksum: 10c0/943eb5d4045eff80a6cde5be4e5fbb1f2d5002126b5a4789c3c1aae3cdddb1eb92b00fb92277f512288e5c6af330730b1dbabcf7ce0923e749e151fcee5a074d + mimic-response: "npm:^3.1.0" + checksum: 10c0/bd89d23141b96d80577e70c54fb226b2f40e74a6817652b80a116d7befb8758261ad073a8895648a29cc0a5947021ab66705cb542fa9c143c82022b27c5b175e languageName: node linkType: hard -"browserify-rsa@npm:^4.0.0, browserify-rsa@npm:^4.0.1": - version: 4.1.0 - resolution: "browserify-rsa@npm:4.1.0" +"deep-eql@npm:^3.0.1": + version: 3.0.1 + resolution: "deep-eql@npm:3.0.1" dependencies: - bn.js: "npm:^5.0.0" - randombytes: "npm:^2.0.1" - checksum: 10c0/fb2b5a8279d8a567a28d8ee03fb62e448428a906bab5c3dc9e9c3253ace551b5ea271db15e566ac78f1b1d71b243559031446604168b9235c351a32cae99d02a + type-detect: "npm:^4.0.0" + checksum: 10c0/80b33c1c7713b3d5db89e6b5e9b22050f39c8a88e12a015616da8391e013988790d045a5c612b0c6dc43cc4bec51eadbe0fcf6075cc9717f8f56efdb305b6e6f languageName: node linkType: hard -"browserify-sign@npm:^4.0.0": - version: 4.2.1 - resolution: "browserify-sign@npm:4.2.1" +"deep-eql@npm:^4.0.1": + version: 4.1.4 + resolution: "deep-eql@npm:4.1.4" dependencies: - bn.js: "npm:^5.1.1" - browserify-rsa: "npm:^4.0.1" - create-hash: "npm:^1.2.0" - create-hmac: "npm:^1.1.7" - elliptic: "npm:^6.5.3" - inherits: "npm:^2.0.4" - parse-asn1: "npm:^5.1.5" - readable-stream: "npm:^3.6.0" - safe-buffer: "npm:^5.2.0" - checksum: 10c0/8f00a370e3e97060977dc58e51251d3ca398ee73523994a44430321e8de2c7d85395362d59014b2b07efe4190f369baee2ff28eb8f405ff4660b776651cf052d + type-detect: "npm:^4.0.0" + checksum: 10c0/264e0613493b43552fc908f4ff87b8b445c0e6e075656649600e1b8a17a57ee03e960156fce7177646e4d2ddaf8e5ee616d76bd79929ff593e5c79e4e5e6c517 languageName: node linkType: hard -"browserslist@npm:^3.2.6": - version: 3.2.8 - resolution: "browserslist@npm:3.2.8" - dependencies: - caniuse-lite: "npm:^1.0.30000844" - electron-to-chromium: "npm:^1.3.47" - bin: - browserslist: ./cli.js - checksum: 10c0/da44ceb7fc4a48b50ce54d0683bb82becc35bf8fea58831f4294f8f8c1357b8fd6dbf553a208ac5998513c722af49fc564f54192068797a13dae90bd9093a199 +"deep-extend@npm:^0.6.0, deep-extend@npm:~0.6.0": + version: 0.6.0 + resolution: "deep-extend@npm:0.6.0" + checksum: 10c0/1c6b0abcdb901e13a44c7d699116d3d4279fdb261983122a3783e7273844d5f2537dc2e1c454a23fcf645917f93fbf8d07101c1d03c015a87faa662755212566 languageName: node linkType: hard -"bs58@npm:^4.0.0": - version: 4.0.1 - resolution: "bs58@npm:4.0.1" - dependencies: - base-x: "npm:^3.0.2" - checksum: 10c0/613a1b1441e754279a0e3f44d1faeb8c8e838feef81e550efe174ff021dd2e08a4c9ae5805b52dfdde79f97b5c0918c78dd24a0eb726c4a94365f0984a0ffc65 +"deep-is@npm:^0.1.3": + version: 0.1.4 + resolution: "deep-is@npm:0.1.4" + checksum: 10c0/7f0ee496e0dff14a573dc6127f14c95061b448b87b995fc96c017ce0a1e66af1675e73f1d6064407975bc4ea6ab679497a29fff7b5b9c4e99cb10797c1ad0b4c languageName: node linkType: hard -"bs58check@npm:^2.1.2": - version: 2.1.2 - resolution: "bs58check@npm:2.1.2" - dependencies: - bs58: "npm:^4.0.0" - create-hash: "npm:^1.1.0" - safe-buffer: "npm:^5.1.2" - checksum: 10c0/5d33f319f0d7abbe1db786f13f4256c62a076bc8d184965444cb62ca4206b2c92bee58c93bce57150ffbbbe00c48838ac02e6f384e0da8215cac219c0556baa9 +"deepmerge@npm:^4.2.2": + version: 4.2.2 + resolution: "deepmerge@npm:4.2.2" + checksum: 10c0/d6136eee869057fea7a829aa2d10073ed49db5216e42a77cc737dd385334aab9b68dae22020a00c24c073d5f79cbbdd3f11b8d4fc87700d112ddaa0e1f968ef2 languageName: node linkType: hard -"buffer-from@npm:^1.0.0": - version: 1.1.2 - resolution: "buffer-from@npm:1.1.2" - checksum: 10c0/124fff9d66d691a86d3b062eff4663fe437a9d9ee4b47b1b9e97f5a5d14f6d5399345db80f796827be7c95e70a8e765dd404b7c3ff3b3324f98e9b0c8826cc34 +"defer-to-connect@npm:^2.0.1": + version: 2.0.1 + resolution: "defer-to-connect@npm:2.0.1" + checksum: 10c0/625ce28e1b5ad10cf77057b9a6a727bf84780c17660f6644dab61dd34c23de3001f03cedc401f7d30a4ed9965c2e8a7336e220a329146f2cf85d4eddea429782 languageName: node linkType: hard -"buffer-to-arraybuffer@npm:^0.0.5": - version: 0.0.5 - resolution: "buffer-to-arraybuffer@npm:0.0.5" - checksum: 10c0/0eea361112a67725e098796b931d931a279b8925cae906f07ed876fab4131e3a83073933a4a33b79d96251722a61c1b875b0ef1e04190734921b9e808a73978c +"define-lazy-prop@npm:^2.0.0": + version: 2.0.0 + resolution: "define-lazy-prop@npm:2.0.0" + checksum: 10c0/db6c63864a9d3b7dc9def55d52764968a5af296de87c1b2cc71d8be8142e445208071953649e0386a8cc37cfcf9a2067a47207f1eb9ff250c2a269658fdae422 languageName: node linkType: hard -"buffer-xor@npm:^1.0.3": - version: 1.0.3 - resolution: "buffer-xor@npm:1.0.3" - checksum: 10c0/fd269d0e0bf71ecac3146187cfc79edc9dbb054e2ee69b4d97dfb857c6d997c33de391696d04bdd669272751fa48e7872a22f3a6c7b07d6c0bc31dbe02a4075c +"delayed-stream@npm:~1.0.0": + version: 1.0.0 + resolution: "delayed-stream@npm:1.0.0" + checksum: 10c0/d758899da03392e6712f042bec80aa293bbe9e9ff1b2634baae6a360113e708b91326594c8a486d475c69d6259afb7efacdc3537bfcda1c6c648e390ce601b19 languageName: node linkType: hard -"buffer-xor@npm:^2.0.1": - version: 2.0.2 - resolution: "buffer-xor@npm:2.0.2" - dependencies: - safe-buffer: "npm:^5.1.1" - checksum: 10c0/84c39f316c3f7d194b6313fdd047ddae02619dcb7eccfc9675731ac6fe9c01b42d94f8b8d3f04271803618c7db2eebdca82c1de5c1fc37210c1c112998b09671 +"depd@npm:~1.1.2": + version: 1.1.2 + resolution: "depd@npm:1.1.2" + checksum: 10c0/acb24aaf936ef9a227b6be6d495f0d2eb20108a9a6ad40585c5bda1a897031512fef6484e4fdbb80bd249fdaa82841fa1039f416ece03188e677ba11bcfda249 languageName: node linkType: hard -"buffer@npm:^5.0.5, buffer@npm:^5.2.1, buffer@npm:^5.5.0, buffer@npm:^5.6.0": - version: 5.7.1 - resolution: "buffer@npm:5.7.1" - dependencies: - base64-js: "npm:^1.3.1" - ieee754: "npm:^1.1.13" - checksum: 10c0/27cac81cff434ed2876058d72e7c4789d11ff1120ef32c9de48f59eab58179b66710c488987d295ae89a228f835fc66d088652dffeb8e3ba8659f80eb091d55e +"diff@npm:^4.0.1": + version: 4.0.2 + resolution: "diff@npm:4.0.2" + checksum: 10c0/81b91f9d39c4eaca068eb0c1eb0e4afbdc5bb2941d197f513dd596b820b956fef43485876226d65d497bebc15666aa2aa82c679e84f65d5f2bfbf14ee46e32c1 languageName: node linkType: hard -"bufferutil@npm:^4.0.1": - version: 4.0.4 - resolution: "bufferutil@npm:4.0.4" - dependencies: - node-gyp: "npm:latest" - node-gyp-build: "npm:^4.2.0" - checksum: 10c0/43aa9fe45eb3ad730dbfa60fb4094f5fe9f4877527ee7b682900403edfdd1e262e1ac366c2773aed5595d6ac05a15eaae416905d385cec117c07cfe33c562cb1 +"diff@npm:^7.0.0": + version: 7.0.0 + resolution: "diff@npm:7.0.0" + checksum: 10c0/251fd15f85ffdf814cfc35a728d526b8d2ad3de338dcbd011ac6e57c461417090766b28995f8ff733135b5fbc3699c392db1d5e27711ac4e00244768cd1d577b languageName: node linkType: hard -"busboy@npm:^1.6.0": - version: 1.6.0 - resolution: "busboy@npm:1.6.0" +"dunder-proto@npm:^1.0.1": + version: 1.0.1 + resolution: "dunder-proto@npm:1.0.1" dependencies: - streamsearch: "npm:^1.1.0" - checksum: 10c0/fa7e836a2b82699b6e074393428b91ae579d4f9e21f5ac468e1b459a244341d722d2d22d10920cdd849743dbece6dca11d72de939fb75a7448825cf2babfba1f + call-bind-apply-helpers: "npm:^1.0.1" + es-errors: "npm:^1.3.0" + gopd: "npm:^1.2.0" + checksum: 10c0/199f2a0c1c16593ca0a145dbf76a962f8033ce3129f01284d48c45ed4e14fea9bbacd7b3610b6cdc33486cef20385ac054948fefc6272fcce645c09468f93031 languageName: node linkType: hard -"bytes@npm:3.1.0": - version: 3.1.0 - resolution: "bytes@npm:3.1.0" - checksum: 10c0/7034f475b006b9a8a37c7ecaa0947d0be181feb6d3d5231984e4c14e01c587a47e0fe85f66c630689fa6a046cfa498b6891f5af8022357e52db09365f1dfb625 +"eastasianwidth@npm:^0.2.0": + version: 0.2.0 + resolution: "eastasianwidth@npm:0.2.0" + checksum: 10c0/26f364ebcdb6395f95124fda411f63137a4bfb5d3a06453f7f23dfe52502905bd84e0488172e0f9ec295fdc45f05c23d5d91baf16bd26f0fe9acd777a188dc39 languageName: node linkType: hard -"bytes@npm:3.1.2": - version: 3.1.2 - resolution: "bytes@npm:3.1.2" - checksum: 10c0/76d1c43cbd602794ad8ad2ae94095cddeb1de78c5dddaa7005c51af10b0176c69971a6d88e805a90c2b6550d76636e43c40d8427a808b8645ede885de4a0358e +"elliptic@npm:6.5.4, elliptic@npm:^6.5.4": + version: 6.5.4 + resolution: "elliptic@npm:6.5.4" + dependencies: + bn.js: "npm:^4.11.9" + brorand: "npm:^1.1.0" + hash.js: "npm:^1.0.0" + hmac-drbg: "npm:^1.0.1" + inherits: "npm:^2.0.4" + minimalistic-assert: "npm:^1.0.1" + minimalistic-crypto-utils: "npm:^1.0.1" + checksum: 10c0/5f361270292c3b27cf0843e84526d11dec31652f03c2763c6c2b8178548175ff5eba95341dd62baff92b2265d1af076526915d8af6cc9cb7559c44a62f8ca6e2 languageName: node linkType: hard -"bytewise-core@npm:^1.2.2": - version: 1.2.3 - resolution: "bytewise-core@npm:1.2.3" +"elliptic@npm:6.6.1": + version: 6.6.1 + resolution: "elliptic@npm:6.6.1" dependencies: - typewise-core: "npm:^1.2" - checksum: 10c0/210239f3048de9463b4ab02968bd0ef7b3c9b330c0329f9df1851fee0819e19fbb0eca8cc235947112dcce942ed58541283ddaefe29515c93a2b7e0820be3f2d + bn.js: "npm:^4.11.9" + brorand: "npm:^1.1.0" + hash.js: "npm:^1.0.0" + hmac-drbg: "npm:^1.0.1" + inherits: "npm:^2.0.4" + minimalistic-assert: "npm:^1.0.1" + minimalistic-crypto-utils: "npm:^1.0.1" + checksum: 10c0/8b24ef782eec8b472053793ea1e91ae6bee41afffdfcb78a81c0a53b191e715cbe1292aa07165958a9bbe675bd0955142560b1a007ffce7d6c765bcaf951a867 languageName: node linkType: hard -"bytewise@npm:~1.1.0": - version: 1.1.0 - resolution: "bytewise@npm:1.1.0" - dependencies: - bytewise-core: "npm:^1.2.2" - typewise: "npm:^1.0.3" - checksum: 10c0/bcf994a8b635390dce43b22e97201cc0e3df0089ada4e77cc0bb48ce241efd0c27ca24a9400828cdd288a69a961da0b60c05bf7381b6cb529f048ab22092cc6d +"emoji-regex@npm:^8.0.0": + version: 8.0.0 + resolution: "emoji-regex@npm:8.0.0" + checksum: 10c0/b6053ad39951c4cf338f9092d7bfba448cdfd46fe6a2a034700b149ac9ffbc137e361cbd3c442297f86bed2e5f7576c1b54cc0a6bf8ef5106cc62f496af35010 languageName: node linkType: hard -"cacache@npm:^20.0.1": - version: 20.0.4 - resolution: "cacache@npm:20.0.4" - dependencies: - "@npmcli/fs": "npm:^5.0.0" - fs-minipass: "npm:^3.0.0" - glob: "npm:^13.0.0" - lru-cache: "npm:^11.1.0" - minipass: "npm:^7.0.3" - minipass-collect: "npm:^2.0.1" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - p-map: "npm:^7.0.2" - ssri: "npm:^13.0.0" - checksum: 10c0/539bf4020e44ba9ca5afc2ec435623ed7e0dd80c020097677e6b4a0545df5cc9d20b473212d01209c8b4aea43c0d095af0bb6da97bcb991642ea6fac0d7c462b +"emoji-regex@npm:^9.2.2": + version: 9.2.2 + resolution: "emoji-regex@npm:9.2.2" + checksum: 10c0/af014e759a72064cf66e6e694a7fc6b0ed3d8db680427b021a89727689671cefe9d04151b2cad51dbaf85d5ba790d061cd167f1cf32eb7b281f6368b3c181639 languageName: node linkType: hard -"cache-base@npm:^1.0.1": - version: 1.0.1 - resolution: "cache-base@npm:1.0.1" - dependencies: - collection-visit: "npm:^1.0.0" - component-emitter: "npm:^1.2.1" - get-value: "npm:^2.0.6" - has-value: "npm:^1.0.0" - isobject: "npm:^3.0.1" - set-value: "npm:^2.0.0" - to-object-path: "npm:^0.3.0" - union-value: "npm:^1.0.0" - unset-value: "npm:^1.0.0" - checksum: 10c0/a7142e25c73f767fa520957dcd179b900b86eac63b8cfeaa3b2a35e18c9ca5968aa4e2d2bed7a3e7efd10f13be404344cfab3a4156217e71f9bdb95940bb9c8c +"encode-utf8@npm:^1.0.2": + version: 1.0.3 + resolution: "encode-utf8@npm:1.0.3" + checksum: 10c0/6b3458b73e868113d31099d7508514a5c627d8e16d1e0542d1b4e3652299b8f1f590c468e2b9dcdf1b4021ee961f31839d0be9d70a7f2a8a043c63b63c9b3a88 languageName: node linkType: hard -"cacheable-request@npm:^6.0.0": - version: 6.1.0 - resolution: "cacheable-request@npm:6.1.0" +"enquirer@npm:^2.3.0, enquirer@npm:^2.3.6": + version: 2.3.6 + resolution: "enquirer@npm:2.3.6" dependencies: - clone-response: "npm:^1.0.2" - get-stream: "npm:^5.1.0" - http-cache-semantics: "npm:^4.0.0" - keyv: "npm:^3.0.0" - lowercase-keys: "npm:^2.0.0" - normalize-url: "npm:^4.1.0" - responselike: "npm:^1.0.2" - checksum: 10c0/e92f2b2078c014ba097647ab4ff6a6149dc2974a65670ee97ec593ec9f4148ecc988e86b9fcd8ebf7fe255774a53d5dc3db6b01065d44f09a7452c7a7d8e4844 + ansi-colors: "npm:^4.1.1" + checksum: 10c0/8e070e052c2c64326a2803db9084d21c8aaa8c688327f133bf65c4a712586beb126fd98c8a01cfb0433e82a4bd3b6262705c55a63e0f7fb91d06b9cedbde9a11 languageName: node linkType: hard -"cachedown@npm:1.0.0": - version: 1.0.0 - resolution: "cachedown@npm:1.0.0" - dependencies: - abstract-leveldown: "npm:^2.4.1" - lru-cache: "npm:^3.2.0" - checksum: 10c0/7cd84ce0d7e14b75c2a333cbc18a7a417527d3b10f1e13a860c09c5d3006ec3755def9920f4d0e82ee200c505caebac4946c9e1f8786bc203f9bfe4217b5e7f0 +"env-paths@npm:^2.2.0": + version: 2.2.1 + resolution: "env-paths@npm:2.2.1" + checksum: 10c0/285325677bf00e30845e330eec32894f5105529db97496ee3f598478e50f008c5352a41a30e5e72ec9de8a542b5a570b85699cd63bd2bc646dbcb9f311d83bc4 languageName: node linkType: hard -"call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2": - version: 1.0.2 - resolution: "call-bind-apply-helpers@npm:1.0.2" +"error-ex@npm:^1.3.1": + version: 1.3.2 + resolution: "error-ex@npm:1.3.2" dependencies: - es-errors: "npm:^1.3.0" - function-bind: "npm:^1.1.2" - checksum: 10c0/47bd9901d57b857590431243fea704ff18078b16890a6b3e021e12d279bbf211d039155e27d7566b374d49ee1f8189344bac9833dec7a20cdec370506361c938 + is-arrayish: "npm:^0.2.1" + checksum: 10c0/ba827f89369b4c93382cfca5a264d059dfefdaa56ecc5e338ffa58a6471f5ed93b71a20add1d52290a4873d92381174382658c885ac1a2305f7baca363ce9cce languageName: node linkType: hard -"call-bind@npm:^1.0.0, call-bind@npm:^1.0.2, call-bind@npm:~1.0.2": - version: 1.0.2 - resolution: "call-bind@npm:1.0.2" - dependencies: - function-bind: "npm:^1.1.1" - get-intrinsic: "npm:^1.0.2" - checksum: 10c0/74ba3f31e715456e22e451d8d098779b861eba3c7cac0d9b510049aced70d75c231ba05071f97e1812c98e34e2bee734c0c6126653e0088c2d9819ca047f4073 +"es-define-property@npm:^1.0.1": + version: 1.0.1 + resolution: "es-define-property@npm:1.0.1" + checksum: 10c0/3f54eb49c16c18707949ff25a1456728c883e81259f045003499efba399c08bad00deebf65cccde8c0e07908c1a225c9d472b7107e558f2a48e28d530e34527c languageName: node linkType: hard -"caller-callsite@npm:^2.0.0": - version: 2.0.0 - resolution: "caller-callsite@npm:2.0.0" - dependencies: - callsites: "npm:^2.0.0" - checksum: 10c0/a00ca91280e10ee2321de21dda6c168e427df7a63aeaca027ea45e3e466ac5e1a5054199f6547ba1d5a513d3b6b5933457266daaa47f8857fb532a343ee6b5e1 +"es-errors@npm:^1.3.0": + version: 1.3.0 + resolution: "es-errors@npm:1.3.0" + checksum: 10c0/0a61325670072f98d8ae3b914edab3559b6caa980f08054a3b872052640d91da01d38df55df797fcc916389d77fc92b8d5906cf028f4db46d7e3003abecbca85 languageName: node linkType: hard -"caller-path@npm:^2.0.0": - version: 2.0.0 - resolution: "caller-path@npm:2.0.0" +"es-object-atoms@npm:^1.0.0, es-object-atoms@npm:^1.1.1": + version: 1.1.2 + resolution: "es-object-atoms@npm:1.1.2" dependencies: - caller-callsite: "npm:^2.0.0" - checksum: 10c0/029b5b2c557d831216305c3218e9ff30fa668be31d58dd08088f74c8eabc8362c303e0908b3a93abb25ba10e3a5bfc9cff5eb7fab6ab9cf820e3b160ccb67581 + es-errors: "npm:^1.3.0" + checksum: 10c0/1772861f094f739d6f41b579cfb9a18579daffeb434552a370a5fbef50a32d22227e27b63fdbb757b7ddd429d1b42fe52ccae7966d9302a2ec221b6f1b41bbc4 languageName: node linkType: hard -"callsites@npm:^2.0.0": - version: 2.0.0 - resolution: "callsites@npm:2.0.0" - checksum: 10c0/13bff4fee946e6020b37e76284e95e24aa239c9e34ac4f3451e4c5330fca6f2f962e1d1ab69e4da7940e1fce135107a2b2b98c01d62ea33144350fc89dc5494e +"es-set-tostringtag@npm:^2.1.0": + version: 2.1.0 + resolution: "es-set-tostringtag@npm:2.1.0" + dependencies: + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.6" + has-tostringtag: "npm:^1.0.2" + hasown: "npm:^2.0.2" + checksum: 10c0/ef2ca9ce49afe3931cb32e35da4dcb6d86ab02592cfc2ce3e49ced199d9d0bb5085fc7e73e06312213765f5efa47cc1df553a6a5154584b21448e9fb8355b1af languageName: node linkType: hard -"callsites@npm:^3.0.0": - version: 3.1.0 - resolution: "callsites@npm:3.1.0" - checksum: 10c0/fff92277400eb06c3079f9e74f3af120db9f8ea03bad0e84d9aede54bbe2d44a56cccb5f6cf12211f93f52306df87077ecec5b712794c5a9b5dac6d615a3f301 +"escalade@npm:^3.1.1": + version: 3.1.1 + resolution: "escalade@npm:3.1.1" + checksum: 10c0/afd02e6ca91ffa813e1108b5e7756566173d6bc0d1eb951cb44d6b21702ec17c1cf116cfe75d4a2b02e05acb0b808a7a9387d0d1ca5cf9c04ad03a8445c3e46d languageName: node linkType: hard -"camelcase@npm:^3.0.0": - version: 3.0.0 - resolution: "camelcase@npm:3.0.0" - checksum: 10c0/98871bb40b936430beca49490d325759f8d8ade32bea538ee63c20b17b326abb6bbd3e1d84daf63d9332b2fc7637f28696bf76da59180b1247051b955cb1da12 +"escape-string-regexp@npm:^1.0.5": + version: 1.0.5 + resolution: "escape-string-regexp@npm:1.0.5" + checksum: 10c0/a968ad453dd0c2724e14a4f20e177aaf32bb384ab41b674a8454afe9a41c5e6fe8903323e0a1052f56289d04bd600f81278edf140b0fcc02f5cac98d0f5b5371 languageName: node linkType: hard -"camelcase@npm:^6.0.0, camelcase@npm:^6.2.0": - version: 6.3.0 - resolution: "camelcase@npm:6.3.0" - checksum: 10c0/0d701658219bd3116d12da3eab31acddb3f9440790c0792e0d398f0a520a6a4058018e546862b6fba89d7ae990efaeb97da71e1913e9ebf5a8b5621a3d55c710 +"escape-string-regexp@npm:^4.0.0": + version: 4.0.0 + resolution: "escape-string-regexp@npm:4.0.0" + checksum: 10c0/9497d4dd307d845bd7f75180d8188bb17ea8c151c1edbf6b6717c100e104d629dc2dfb687686181b0f4b7d732c7dfdc4d5e7a8ff72de1b0ca283a75bbb3a9cd9 languageName: node linkType: hard -"caniuse-lite@npm:^1.0.30000844": - version: 1.0.30001264 - resolution: "caniuse-lite@npm:1.0.30001264" - checksum: 10c0/54e97b692cf1299d0a572f687e743e1260292f2350ba76ab193158272952e8c47030535ab5126618aba0fc52952ac3e94efbd8db2b4597e03ed52dad0f04d3b0 +"eslint-import-context@npm:^0.1.8, eslint-import-context@npm:^0.1.9": + version: 0.1.9 + resolution: "eslint-import-context@npm:0.1.9" + dependencies: + get-tsconfig: "npm:^4.10.1" + stable-hash-x: "npm:^0.2.0" + peerDependencies: + unrs-resolver: ^1.0.0 + peerDependenciesMeta: + unrs-resolver: + optional: true + checksum: 10c0/07851103443b70af681c5988e2702e681ff9b956e055e11d4bd9b2322847fa0d9e8da50c18fc7cb1165106b043f34fbd0384d7011c239465c4645c52132e56f3 languageName: node linkType: hard -"caseless@npm:~0.12.0": - version: 0.12.0 - resolution: "caseless@npm:0.12.0" - checksum: 10c0/ccf64bcb6c0232cdc5b7bd91ddd06e23a4b541f138336d4725233ac538041fb2f29c2e86c3c4a7a61ef990b665348db23a047060b9414c3a6603e9fa61ad4626 +"eslint-import-resolver-typescript@npm:^4.4.5": + version: 4.4.5 + resolution: "eslint-import-resolver-typescript@npm:4.4.5" + dependencies: + debug: "npm:^4.4.1" + eslint-import-context: "npm:^0.1.8" + get-tsconfig: "npm:^4.10.1" + is-bun-module: "npm:^2.0.0" + stable-hash-x: "npm:^0.2.0" + tinyglobby: "npm:^0.2.14" + unrs-resolver: "npm:^1.7.11" + peerDependencies: + eslint: "*" + eslint-plugin-import: "*" + eslint-plugin-import-x: "*" + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true + checksum: 10c0/15fa1c47dfc508deaef638d8f9b65eedfd4722c23c1b4e51391082daf4f23a75fc5e42ebcbc5ebcae8a3977f9aa204dd2574528ab0c27b678e582122f3c8cc02 languageName: node linkType: hard -"cbor@npm:^5.0.2": - version: 5.2.0 - resolution: "cbor@npm:5.2.0" +"eslint-plugin-import-x@npm:^4.17.1": + version: 4.17.1 + resolution: "eslint-plugin-import-x@npm:4.17.1" dependencies: - bignumber.js: "npm:^9.0.1" - nofilter: "npm:^1.0.4" - checksum: 10c0/d39e14a05930648c6446b107aee3653e1b1ce8195dd121cb65790d9091202d8d98af0e4c17787f38bbc33fadc969ca99c94b40c144b84ce1e406a7f411c3ccf4 + "@typescript-eslint/types": "npm:^8.56.0" + comment-parser: "npm:^1.4.1" + debug: "npm:^4.4.1" + eslint-import-context: "npm:^0.1.9" + is-glob: "npm:^4.0.3" + minimatch: "npm:^9.0.3 || ^10.1.2" + semver: "npm:^7.7.2" + stable-hash-x: "npm:^0.2.0" + unrs-resolver: "npm:^1.9.2" + peerDependencies: + "@typescript-eslint/utils": ^8.56.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + eslint-import-resolver-node: "*" + peerDependenciesMeta: + "@typescript-eslint/utils": + optional: true + eslint-import-resolver-node: + optional: true + checksum: 10c0/4ea2ace22c3d805f2253063912211c438055f112ca9a2124df262311744975fc96443e4526fd80eef0acec7845a48fb6d1da444a4c4b0ff9786927fe2755f2a7 languageName: node linkType: hard -"cbor@npm:^8.0.0": - version: 8.1.0 - resolution: "cbor@npm:8.1.0" - dependencies: - nofilter: "npm:^3.1.0" - checksum: 10c0/a836e2e7ea0efb1b9c4e5a4be906c57113d730cc42293a34072e0164ed110bb8ac035dc7dca2e3ebb641bd4b37e00fdbbf09c951aa864b3d4888a6ed8c6243f7 +"eslint-plugin-no-only-tests@npm:^3.4.0": + version: 3.4.0 + resolution: "eslint-plugin-no-only-tests@npm:3.4.0" + checksum: 10c0/7c2163ab71cce74bb276025463910ea760888290cc9a3fb3e8ed4058055fd69cc7c145beca2f809232488b62c331e17a7b9271a025ef462e87d706298fb6f87a languageName: node linkType: hard -"chai@npm:^4.3.4": - version: 4.3.4 - resolution: "chai@npm:4.3.4" - dependencies: - assertion-error: "npm:^1.1.0" - check-error: "npm:^1.0.2" - deep-eql: "npm:^3.0.1" - get-func-name: "npm:^2.0.0" - pathval: "npm:^1.1.1" - type-detect: "npm:^4.0.5" - checksum: 10c0/e8be63a3ce412cc35f0209799c96b1f67397c4829489bd1604f9639f291b697f9a8c1ee129f5d502663332691950b278d2be7e8f19d753b86ea1876e99771a8e - languageName: node - linkType: hard - -"chalk@npm:4.1.2, chalk@npm:^4.0.0, chalk@npm:^4.1.0, chalk@npm:^4.1.2": - version: 4.1.2 - resolution: "chalk@npm:4.1.2" +"eslint-scope@npm:^9.1.2": + version: 9.1.2 + resolution: "eslint-scope@npm:9.1.2" dependencies: - ansi-styles: "npm:^4.1.0" - supports-color: "npm:^7.1.0" - checksum: 10c0/4a3fef5cc34975c898ffe77141450f679721df9dde00f6c304353fa9c8b571929123b26a0e4617bde5018977eb655b31970c297b91b63ee83bb82aeb04666880 + "@types/esrecurse": "npm:^4.3.1" + "@types/estree": "npm:^1.0.8" + esrecurse: "npm:^4.3.0" + estraverse: "npm:^5.2.0" + checksum: 10c0/9fb8bca5a73e5741efb6cec84467027b6cb6f4203ff9b43a938e272c5cd30800bde46a5c20dfd1609f840225f0b62b7673be391b20acadf8658ca9fa4729b3dd languageName: node linkType: hard -"chalk@npm:^1.1.3": - version: 1.1.3 - resolution: "chalk@npm:1.1.3" - dependencies: - ansi-styles: "npm:^2.2.1" - escape-string-regexp: "npm:^1.0.2" - has-ansi: "npm:^2.0.0" - strip-ansi: "npm:^3.0.0" - supports-color: "npm:^2.0.0" - checksum: 10c0/28c3e399ec286bb3a7111fd4225ebedb0d7b813aef38a37bca7c498d032459c265ef43404201d5fbb8d888d29090899c95335b4c0cda13e8b126ff15c541cef8 +"eslint-visitor-keys@npm:^3.4.3": + version: 3.4.3 + resolution: "eslint-visitor-keys@npm:3.4.3" + checksum: 10c0/92708e882c0a5ffd88c23c0b404ac1628cf20104a108c745f240a13c332a11aac54f49a22d5762efbffc18ecbc9a580d1b7ad034bf5f3cc3307e5cbff2ec9820 languageName: node linkType: hard -"chalk@npm:^2.0.0, chalk@npm:^2.1.0, chalk@npm:^2.4.1, chalk@npm:^2.4.2": - version: 2.4.2 - resolution: "chalk@npm:2.4.2" - dependencies: - ansi-styles: "npm:^3.2.1" - escape-string-regexp: "npm:^1.0.5" - supports-color: "npm:^5.3.0" - checksum: 10c0/e6543f02ec877732e3a2d1c3c3323ddb4d39fbab687c23f526e25bd4c6a9bf3b83a696e8c769d078e04e5754921648f7821b2a2acfd16c550435fd630026e073 +"eslint-visitor-keys@npm:^4.2.1": + version: 4.2.1 + resolution: "eslint-visitor-keys@npm:4.2.1" + checksum: 10c0/fcd43999199d6740db26c58dbe0c2594623e31ca307e616ac05153c9272f12f1364f5a0b1917a8e962268fdecc6f3622c1c2908b4fcc2e047a106fe6de69dc43 languageName: node linkType: hard -"chardet@npm:^0.7.0": - version: 0.7.0 - resolution: "chardet@npm:0.7.0" - checksum: 10c0/96e4731b9ec8050cbb56ab684e8c48d6c33f7826b755802d14e3ebfdc51c57afeece3ea39bc6b09acc359e4363525388b915e16640c1378053820f5e70d0f27d +"eslint-visitor-keys@npm:^5.0.0, eslint-visitor-keys@npm:^5.0.1": + version: 5.0.1 + resolution: "eslint-visitor-keys@npm:5.0.1" + checksum: 10c0/16190bdf2cbae40a1109384c94450c526a79b0b9c3cb21e544256ed85ac48a4b84db66b74a6561d20fe6ab77447f150d711c2ad5ad74df4fcc133736bce99678 + languageName: node + linkType: hard + +"eslint@npm:^10.10.0": + version: 10.10.0 + resolution: "eslint@npm:10.10.0" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.8.0" + "@eslint-community/regexpp": "npm:^4.12.2" + "@eslint/config-array": "npm:^0.23.5" + "@eslint/config-helpers": "npm:^0.7.0" + "@eslint/core": "npm:^1.2.1" + "@eslint/plugin-kit": "npm:^0.7.3" + "@humanfs/node": "npm:^0.16.6" + "@humanwhocodes/module-importer": "npm:^1.0.1" + "@humanwhocodes/retry": "npm:^0.4.2" + "@types/estree": "npm:^1.0.6" + ajv: "npm:^6.14.0" + cross-spawn: "npm:^7.0.6" + debug: "npm:^4.3.2" + escape-string-regexp: "npm:^4.0.0" + eslint-scope: "npm:^9.1.2" + eslint-visitor-keys: "npm:^5.0.1" + espree: "npm:^11.2.0" + esquery: "npm:^1.7.0" + esutils: "npm:^2.0.2" + fast-deep-equal: "npm:^3.1.3" + file-entry-cache: "npm:11.1.5 || >11.1.6 <12" + find-up: "npm:^5.0.0" + glob-parent: "npm:^6.0.2" + ignore: "npm:^5.2.0" + imurmurhash: "npm:^0.1.4" + is-glob: "npm:^4.0.0" + json-stable-stringify-without-jsonify: "npm:^1.0.1" + minimatch: "npm:^10.2.5" + natural-compare: "npm:^1.4.0" + optionator: "npm:^0.9.3" + peerDependencies: + jiti: "*" + peerDependenciesMeta: + jiti: + optional: true + bin: + eslint: bin/eslint.js + checksum: 10c0/ba583145305f088585f91c5dab6825492ec657614558e4610cffc94174cf800f456e39ec3cafd3eed73e04bd9a05794067ae33b553f1323e3e7c1157242409d2 languageName: node linkType: hard -"charenc@npm:>= 0.0.1": - version: 0.0.2 - resolution: "charenc@npm:0.0.2" - checksum: 10c0/a45ec39363a16799d0f9365c8dd0c78e711415113c6f14787a22462ef451f5013efae8a28f1c058f81fc01f2a6a16955f7a5fd0cd56247ce94a45349c89877d8 +"espree@npm:^10.4.0": + version: 10.4.0 + resolution: "espree@npm:10.4.0" + dependencies: + acorn: "npm:^8.15.0" + acorn-jsx: "npm:^5.3.2" + eslint-visitor-keys: "npm:^4.2.1" + checksum: 10c0/c63fe06131c26c8157b4083313cb02a9a54720a08e21543300e55288c40e06c3fc284bdecf108d3a1372c5934a0a88644c98714f38b6ae8ed272b40d9ea08d6b languageName: node linkType: hard -"check-error@npm:^1.0.2": - version: 1.0.2 - resolution: "check-error@npm:1.0.2" - checksum: 10c0/c58ac4d6a92203209a61d025568198c073f101691eb6247f999266e1d1e3ab3af2bbe0a41af5008c1f1b95446ec7831e6ba91f03816177f2da852f316ad7921d +"espree@npm:^11.2.0": + version: 11.2.0 + resolution: "espree@npm:11.2.0" + dependencies: + acorn: "npm:^8.16.0" + acorn-jsx: "npm:^5.3.2" + eslint-visitor-keys: "npm:^5.0.1" + checksum: 10c0/cf87e18ffd9dc113eb8d16588e7757701bc10c9934a71cce8b89c2611d51672681a918307bd6b19ac3ccd0e7ba1cbccc2f815b36b52fa7e73097b251014c3d81 languageName: node linkType: hard -"checkpoint-store@npm:^1.1.0": - version: 1.1.0 - resolution: "checkpoint-store@npm:1.1.0" +"esquery@npm:^1.7.0": + version: 1.7.0 + resolution: "esquery@npm:1.7.0" dependencies: - functional-red-black-tree: "npm:^1.0.1" - checksum: 10c0/257dea033983adbbfb50c54db0cb8045450aa00f260c95e75cad62574b467f5b1060b1e35d5d1c296c6923026827d8dc0e5cd450feddd74b15d8b6580075cd23 + estraverse: "npm:^5.1.0" + checksum: 10c0/77d5173db450b66f3bc685d11af4c90cffeedb340f34a39af96d43509a335ce39c894fd79233df32d38f5e4e219fa0f7076f6ec90bae8320170ba082c0db4793 languageName: node linkType: hard -"chokidar@npm:^3.5.2": - version: 3.5.3 - resolution: "chokidar@npm:3.5.3" +"esrecurse@npm:^4.3.0": + version: 4.3.0 + resolution: "esrecurse@npm:4.3.0" dependencies: - anymatch: "npm:~3.1.2" - braces: "npm:~3.0.2" - fsevents: "npm:~2.3.2" - glob-parent: "npm:~5.1.2" - is-binary-path: "npm:~2.1.0" - is-glob: "npm:~4.0.1" - normalize-path: "npm:~3.0.0" - readdirp: "npm:~3.6.0" - dependenciesMeta: - fsevents: - optional: true - checksum: 10c0/1076953093e0707c882a92c66c0f56ba6187831aa51bb4de878c1fec59ae611a3bf02898f190efec8e77a086b8df61c2b2a3ea324642a0558bdf8ee6c5dc9ca1 + estraverse: "npm:^5.2.0" + checksum: 10c0/81a37116d1408ded88ada45b9fb16dbd26fba3aadc369ce50fcaf82a0bac12772ebd7b24cd7b91fc66786bf2c1ac7b5f196bc990a473efff972f5cb338877cf5 languageName: node linkType: hard -"chokidar@npm:^4.0.0, chokidar@npm:^4.0.1": - version: 4.0.3 - resolution: "chokidar@npm:4.0.3" - dependencies: - readdirp: "npm:^4.0.1" - checksum: 10c0/a58b9df05bb452f7d105d9e7229ac82fa873741c0c40ddcc7bb82f8a909fbe3f7814c9ebe9bc9a2bef9b737c0ec6e2d699d179048ef06ad3ec46315df0ebe6ad +"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0": + version: 5.2.0 + resolution: "estraverse@npm:5.2.0" + checksum: 10c0/76a07411841ddf30a6a75afc93e8c00bbfe255a62dee7e1dc90b06ce0d7b939a00cf816ae94566ab5bc1cfde773a49387a35650287840b842143fff46f8f9ae3 languageName: node linkType: hard -"chownr@npm:^1.1.4": - version: 1.1.4 - resolution: "chownr@npm:1.1.4" - checksum: 10c0/ed57952a84cc0c802af900cf7136de643d3aba2eecb59d29344bc2f3f9bf703a301b9d84cdc71f82c3ffc9ccde831b0d92f5b45f91727d6c9da62f23aef9d9db +"estraverse@npm:^5.3.0": + version: 5.3.0 + resolution: "estraverse@npm:5.3.0" + checksum: 10c0/1ff9447b96263dec95d6d67431c5e0771eb9776427421260a3e2f0fdd5d6bd4f8e37a7338f5ad2880c9f143450c9b1e4fc2069060724570a49cf9cf0312bd107 languageName: node linkType: hard -"chownr@npm:^3.0.0": - version: 3.0.0 - resolution: "chownr@npm:3.0.0" - checksum: 10c0/43925b87700f7e3893296c8e9c56cc58f926411cce3a6e5898136daaf08f08b9a8eb76d37d3267e707d0dcc17aed2e2ebdf5848c0c3ce95cf910a919935c1b10 +"esutils@npm:^2.0.2": + version: 2.0.3 + resolution: "esutils@npm:2.0.3" + checksum: 10c0/9a2fe69a41bfdade834ba7c42de4723c97ec776e40656919c62cbd13607c45e127a003f05f724a1ea55e5029a4cf2de444b13009f2af71271e42d93a637137c7 languageName: node linkType: hard -"ci-info@npm:^2.0.0": - version: 2.0.0 - resolution: "ci-info@npm:2.0.0" - checksum: 10c0/8c5fa3830a2bcee2b53c2e5018226f0141db9ec9f7b1e27a5c57db5512332cde8a0beb769bcbaf0d8775a78afbf2bb841928feca4ea6219638a5b088f9884b46 +"ethereum-cryptography@npm:^0.1.3": + version: 0.1.3 + resolution: "ethereum-cryptography@npm:0.1.3" + dependencies: + "@types/pbkdf2": "npm:^3.0.0" + "@types/secp256k1": "npm:^4.0.1" + blakejs: "npm:^1.1.0" + browserify-aes: "npm:^1.2.0" + bs58check: "npm:^2.1.2" + create-hash: "npm:^1.2.0" + create-hmac: "npm:^1.1.7" + hash.js: "npm:^1.1.7" + keccak: "npm:^3.0.0" + pbkdf2: "npm:^3.0.17" + randombytes: "npm:^2.1.0" + safe-buffer: "npm:^5.1.2" + scrypt-js: "npm:^3.0.0" + secp256k1: "npm:^4.0.1" + setimmediate: "npm:^1.0.5" + checksum: 10c0/aa36e11fca9d67d67c96e02a98b33bae2e1add20bd11af43feb7f28cdafe0cd3bdbae3bfecc7f2d9ec8f504b10a1c8f7590f5f7fe236560fd8083dd321ad7144 languageName: node linkType: hard -"cids@npm:^0.7.1": - version: 0.7.5 - resolution: "cids@npm:0.7.5" +"ethereum-cryptography@npm:^1.0.3": + version: 1.0.3 + resolution: "ethereum-cryptography@npm:1.0.3" dependencies: - buffer: "npm:^5.5.0" - class-is: "npm:^1.1.0" - multibase: "npm:~0.6.0" - multicodec: "npm:^1.0.0" - multihashes: "npm:~0.4.15" - checksum: 10c0/8fc7a14a2c2b302e3e76051fa7936150b24c0da681438ed036390c8fbcb78df5af20a3f73a35b7fc93305c633e595691399abf44a1c33fe4834544f2737d99ae + "@noble/hashes": "npm:1.0.0" + "@noble/secp256k1": "npm:1.5.5" + "@scure/bip32": "npm:1.0.1" + "@scure/bip39": "npm:1.0.0" + checksum: 10c0/b235a99180d4155984f8ea96b3abd8dfa6ba7a8b20d916ee33c7aeedba008a76921101542721fe705765fadc8bbfa1c12a50160fda86b7cc0a5fd3f03c8e00c1 languageName: node linkType: hard -"cipher-base@npm:^1.0.0, cipher-base@npm:^1.0.1, cipher-base@npm:^1.0.3": - version: 1.0.4 - resolution: "cipher-base@npm:1.0.4" +"ethereum-cryptography@npm:^2.1.3, ethereum-cryptography@npm:^2.2.1": + version: 2.2.1 + resolution: "ethereum-cryptography@npm:2.2.1" dependencies: - inherits: "npm:^2.0.1" - safe-buffer: "npm:^5.0.1" - checksum: 10c0/d8d005f8b64d8a77b3d3ce531301ae7b45902c9cab4ec8b66bdbd2bf2a1d9fceb9a2133c293eb3c060b2d964da0f14c47fb740366081338aa3795dd1faa8984b + "@noble/curves": "npm:1.4.2" + "@noble/hashes": "npm:1.4.0" + "@scure/bip32": "npm:1.4.0" + "@scure/bip39": "npm:1.3.0" + checksum: 10c0/c6c7626d393980577b57f709878b2eb91f270fe56116044b1d7afb70d5c519cddc0c072e8c05e4a335e05342eb64d9c3ab39d52f78bb75f76ad70817da9645ef languageName: node linkType: hard -"class-is@npm:^1.1.0": - version: 1.1.0 - resolution: "class-is@npm:1.1.0" - checksum: 10c0/07241182c379a630c1841e99cd2301f0492d8f973f111f13b4487231f7cc28a1f1166670ce2dfcab91449155e6e107379eb9d15ba140e749a11d4fcba3883f52 +"ethereumjs-util@npm:^7.0.3": + version: 7.1.4 + resolution: "ethereumjs-util@npm:7.1.4" + dependencies: + "@types/bn.js": "npm:^5.1.0" + bn.js: "npm:^5.1.2" + create-hash: "npm:^1.1.2" + ethereum-cryptography: "npm:^0.1.3" + rlp: "npm:^2.2.4" + checksum: 10c0/33907f4010f5f91cec75e4bfa941b7c9f1d8290e7e1e24637b205d0560ae16d0f817b6b3b0b0e4e39e8ba65e631b7e265cae3bcaf6b616c9588b689daea1d030 languageName: node linkType: hard -"class-utils@npm:^0.3.5": - version: 0.3.6 - resolution: "class-utils@npm:0.3.6" +"ethereumjs-util@npm:^7.1.4, ethereumjs-util@npm:^7.1.5": + version: 7.1.5 + resolution: "ethereumjs-util@npm:7.1.5" dependencies: - arr-union: "npm:^3.1.0" - define-property: "npm:^0.2.5" - isobject: "npm:^3.0.0" - static-extend: "npm:^0.1.1" - checksum: 10c0/d44f4afc7a3e48dba4c2d3fada5f781a1adeeff371b875c3b578bc33815c6c29d5d06483c2abfd43a32d35b104b27b67bfa39c2e8a422fa858068bd756cfbd42 + "@types/bn.js": "npm:^5.1.0" + bn.js: "npm:^5.1.2" + create-hash: "npm:^1.1.2" + ethereum-cryptography: "npm:^0.1.3" + rlp: "npm:^2.2.4" + checksum: 10c0/8b9487f35ecaa078bf9af6858eba6855fc61c73cc2b90c8c37486fcf94faf4fc1c5cda9758e6769f9ef2658daedaf2c18b366312ac461f8c8a122b392e3041eb languageName: node linkType: hard -"clean-stack@npm:^2.0.0": - version: 2.2.0 - resolution: "clean-stack@npm:2.2.0" - checksum: 10c0/1f90262d5f6230a17e27d0c190b09d47ebe7efdd76a03b5a1127863f7b3c9aec4c3e6c8bb3a7bbf81d553d56a1fd35728f5a8ef4c63f867ac8d690109742a8c1 +"ethers@npm:^5.7.0, ethers@npm:^5.7.2": + version: 5.8.0 + resolution: "ethers@npm:5.8.0" + dependencies: + "@ethersproject/abi": "npm:5.8.0" + "@ethersproject/abstract-provider": "npm:5.8.0" + "@ethersproject/abstract-signer": "npm:5.8.0" + "@ethersproject/address": "npm:5.8.0" + "@ethersproject/base64": "npm:5.8.0" + "@ethersproject/basex": "npm:5.8.0" + "@ethersproject/bignumber": "npm:5.8.0" + "@ethersproject/bytes": "npm:5.8.0" + "@ethersproject/constants": "npm:5.8.0" + "@ethersproject/contracts": "npm:5.8.0" + "@ethersproject/hash": "npm:5.8.0" + "@ethersproject/hdnode": "npm:5.8.0" + "@ethersproject/json-wallets": "npm:5.8.0" + "@ethersproject/keccak256": "npm:5.8.0" + "@ethersproject/logger": "npm:5.8.0" + "@ethersproject/networks": "npm:5.8.0" + "@ethersproject/pbkdf2": "npm:5.8.0" + "@ethersproject/properties": "npm:5.8.0" + "@ethersproject/providers": "npm:5.8.0" + "@ethersproject/random": "npm:5.8.0" + "@ethersproject/rlp": "npm:5.8.0" + "@ethersproject/sha2": "npm:5.8.0" + "@ethersproject/signing-key": "npm:5.8.0" + "@ethersproject/solidity": "npm:5.8.0" + "@ethersproject/strings": "npm:5.8.0" + "@ethersproject/transactions": "npm:5.8.0" + "@ethersproject/units": "npm:5.8.0" + "@ethersproject/wallet": "npm:5.8.0" + "@ethersproject/web": "npm:5.8.0" + "@ethersproject/wordlists": "npm:5.8.0" + checksum: 10c0/8f187bb6af3736fbafcb613d8fb5be31fe7667a1bae480dd0a4c31b597ed47e0693d552adcababcb05111da39a059fac22e44840ce1671b1cc972de22d6d85d9 + languageName: node + linkType: hard + +"ethers@npm:^6.17.0, ethers@npm:^6.8.1": + version: 6.17.0 + resolution: "ethers@npm:6.17.0" + dependencies: + "@adraffy/ens-normalize": "npm:1.11.1" + "@noble/curves": "npm:1.2.0" + "@noble/hashes": "npm:1.3.2" + "@types/node": "npm:22.7.5" + aes-js: "npm:4.0.0-beta.5" + tslib: "npm:2.7.0" + ws: "npm:8.21.0" + checksum: 10c0/0a75f3b4cedaaddb95ba31fecdfca04202735564e66512f202069dd1a11946e01c310a158e3a1299b994274e9d9fe11db10c6f7997222a28d79dfecb8f1fd162 languageName: node linkType: hard -"cli-boxes@npm:^2.2.1": - version: 2.2.1 - resolution: "cli-boxes@npm:2.2.1" - checksum: 10c0/6111352edbb2f62dbc7bfd58f2d534de507afed7f189f13fa894ce5a48badd94b2aa502fda28f1d7dd5f1eb456e7d4033d09a76660013ef50c7f66e7a034f050 +"ethers@npm:~5.7.0": + version: 5.7.2 + resolution: "ethers@npm:5.7.2" + dependencies: + "@ethersproject/abi": "npm:5.7.0" + "@ethersproject/abstract-provider": "npm:5.7.0" + "@ethersproject/abstract-signer": "npm:5.7.0" + "@ethersproject/address": "npm:5.7.0" + "@ethersproject/base64": "npm:5.7.0" + "@ethersproject/basex": "npm:5.7.0" + "@ethersproject/bignumber": "npm:5.7.0" + "@ethersproject/bytes": "npm:5.7.0" + "@ethersproject/constants": "npm:5.7.0" + "@ethersproject/contracts": "npm:5.7.0" + "@ethersproject/hash": "npm:5.7.0" + "@ethersproject/hdnode": "npm:5.7.0" + "@ethersproject/json-wallets": "npm:5.7.0" + "@ethersproject/keccak256": "npm:5.7.0" + "@ethersproject/logger": "npm:5.7.0" + "@ethersproject/networks": "npm:5.7.1" + "@ethersproject/pbkdf2": "npm:5.7.0" + "@ethersproject/properties": "npm:5.7.0" + "@ethersproject/providers": "npm:5.7.2" + "@ethersproject/random": "npm:5.7.0" + "@ethersproject/rlp": "npm:5.7.0" + "@ethersproject/sha2": "npm:5.7.0" + "@ethersproject/signing-key": "npm:5.7.0" + "@ethersproject/solidity": "npm:5.7.0" + "@ethersproject/strings": "npm:5.7.0" + "@ethersproject/transactions": "npm:5.7.0" + "@ethersproject/units": "npm:5.7.0" + "@ethersproject/wallet": "npm:5.7.0" + "@ethersproject/web": "npm:5.7.1" + "@ethersproject/wordlists": "npm:5.7.0" + checksum: 10c0/90629a4cdb88cde7a7694f5610a83eb00d7fbbaea687446b15631397988f591c554dd68dfa752ddf00aabefd6285e5b298be44187e960f5e4962684e10b39962 languageName: node linkType: hard -"cli-cursor@npm:^2.1.0": - version: 2.1.0 - resolution: "cli-cursor@npm:2.1.0" - dependencies: - restore-cursor: "npm:^2.0.0" - checksum: 10c0/09ee6d8b5b818d840bf80ec9561eaf696672197d3a02a7daee2def96d5f52ce6e0bbe7afca754ccf14f04830b5a1b4556273e983507d5029f95bba3016618eda +"eventemitter3@npm:5.0.1": + version: 5.0.1 + resolution: "eventemitter3@npm:5.0.1" + checksum: 10c0/4ba5c00c506e6c786b4d6262cfbce90ddc14c10d4667e5c83ae993c9de88aa856033994dd2b35b83e8dc1170e224e66a319fa80adc4c32adcd2379bbc75da814 languageName: node linkType: hard -"cli-table3@npm:^0.6.0": - version: 0.6.0 - resolution: "cli-table3@npm:0.6.0" +"evp_bytestokey@npm:^1.0.3": + version: 1.0.3 + resolution: "evp_bytestokey@npm:1.0.3" dependencies: - colors: "npm:^1.1.2" - object-assign: "npm:^4.1.0" - string-width: "npm:^4.2.0" - dependenciesMeta: - colors: - optional: true - checksum: 10c0/3805702bb9a0d54ed8a5385237088b489109744b37654fd2fe9ca9df0369dc1603feef28f610c5f5fee8ed4350c38ddcfb1dfc7f700616e668f5487529551249 + md5.js: "npm:^1.3.4" + node-gyp: "npm:latest" + safe-buffer: "npm:^5.1.1" + checksum: 10c0/77fbe2d94a902a80e9b8f5a73dcd695d9c14899c5e82967a61b1fc6cbbb28c46552d9b127cff47c45fcf684748bdbcfa0a50410349109de87ceb4b199ef6ee99 languageName: node linkType: hard -"cli-table3@npm:^0.6.3": - version: 0.6.5 - resolution: "cli-table3@npm:0.6.5" - dependencies: - "@colors/colors": "npm:1.5.0" - string-width: "npm:^4.2.0" - dependenciesMeta: - "@colors/colors": - optional: true - checksum: 10c0/d7cc9ed12212ae68241cc7a3133c52b844113b17856e11f4f81308acc3febcea7cc9fd298e70933e294dd642866b29fd5d113c2c098948701d0c35f09455de78 +"exponential-backoff@npm:^3.1.1": + version: 3.1.3 + resolution: "exponential-backoff@npm:3.1.3" + checksum: 10c0/77e3ae682b7b1f4972f563c6dbcd2b0d54ac679e62d5d32f3e5085feba20483cf28bd505543f520e287a56d4d55a28d7874299941faf637e779a1aa5994d1267 languageName: node linkType: hard -"cli-width@npm:^2.0.0": - version: 2.2.1 - resolution: "cli-width@npm:2.2.1" - checksum: 10c0/e3a6d422d657ca111c630f69ee0f1a499e8f114eea158ccb2cdbedd19711edffa217093bbd43dafb34b68d1b1a3b5334126e51d059b9ec1d19afa53b42b3ef86 +"fast-base64-decode@npm:^1.0.0": + version: 1.0.0 + resolution: "fast-base64-decode@npm:1.0.0" + checksum: 10c0/6d8feab513222a463d1cb58d24e04d2e04b0791ac6559861f99543daaa590e2636d040d611b40a50799bfb5c5304265d05e3658b5adf6b841a50ef6bf833d821 languageName: node linkType: hard -"cliui@npm:^3.2.0": - version: 3.2.0 - resolution: "cliui@npm:3.2.0" - dependencies: - string-width: "npm:^1.0.1" - strip-ansi: "npm:^3.0.1" - wrap-ansi: "npm:^2.0.0" - checksum: 10c0/07b121fac7fd33ff8dbf3523f0d3dca0329d4e457e57dee54502aa5f27a33cbd9e66aa3e248f0260d8a1431b65b2bad8f510cd97fb8ab6a8e0506310a92e18d5 +"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": + version: 3.1.3 + resolution: "fast-deep-equal@npm:3.1.3" + checksum: 10c0/40dedc862eb8992c54579c66d914635afbec43350afbbe991235fdcb4e3a8d5af1b23ae7e79bef7d4882d0ecee06c3197488026998fb19f72dc95acff1d1b1d0 languageName: node linkType: hard -"cliui@npm:^8.0.1": - version: 8.0.1 - resolution: "cliui@npm:8.0.1" - dependencies: - string-width: "npm:^4.2.0" - strip-ansi: "npm:^6.0.1" - wrap-ansi: "npm:^7.0.0" - checksum: 10c0/4bda0f09c340cbb6dfdc1ed508b3ca080f12992c18d68c6be4d9cf51756033d5266e61ec57529e610dacbf4da1c634423b0c1b11037709cc6b09045cbd815df5 +"fast-diff@npm:^1.2.0": + version: 1.3.0 + resolution: "fast-diff@npm:1.3.0" + checksum: 10c0/5c19af237edb5d5effda008c891a18a585f74bf12953be57923f17a3a4d0979565fc64dbc73b9e20926b9d895f5b690c618cbb969af0cf022e3222471220ad29 languageName: node linkType: hard -"clone-response@npm:^1.0.2": - version: 1.0.3 - resolution: "clone-response@npm:1.0.3" - dependencies: - mimic-response: "npm:^1.0.0" - checksum: 10c0/06a2b611824efb128810708baee3bd169ec9a1bf5976a5258cd7eb3f7db25f00166c6eee5961f075c7e38e194f373d4fdf86b8166ad5b9c7e82bbd2e333a6087 +"fast-json-stable-stringify@npm:^2.0.0": + version: 2.1.0 + resolution: "fast-json-stable-stringify@npm:2.1.0" + checksum: 10c0/7f081eb0b8a64e0057b3bb03f974b3ef00135fbf36c1c710895cd9300f13c94ba809bb3a81cf4e1b03f6e5285610a61abbd7602d0652de423144dfee5a389c9b languageName: node linkType: hard -"clone@npm:2.1.2, clone@npm:^2.0.0": - version: 2.1.2 - resolution: "clone@npm:2.1.2" - checksum: 10c0/ed0601cd0b1606bc7d82ee7175b97e68d1dd9b91fd1250a3617b38d34a095f8ee0431d40a1a611122dcccb4f93295b4fdb94942aa763392b5fe44effa50c2d5e +"fast-levenshtein@npm:^2.0.6": + version: 2.0.6 + resolution: "fast-levenshtein@npm:2.0.6" + checksum: 10c0/111972b37338bcb88f7d9e2c5907862c280ebf4234433b95bc611e518d192ccb2d38119c4ac86e26b668d75f7f3894f4ff5c4982899afced7ca78633b08287c4 languageName: node linkType: hard -"code-point-at@npm:^1.0.0": - version: 1.1.0 - resolution: "code-point-at@npm:1.1.0" - checksum: 10c0/33f6b234084e46e6e369b6f0b07949392651b4dde70fc6a592a8d3dafa08d5bb32e3981a02f31f6fc323a26bc03a4c063a9d56834848695bda7611c2417ea2e6 +"fast-uri@npm:^3.0.1": + version: 3.1.7 + resolution: "fast-uri@npm:3.1.7" + checksum: 10c0/ca2baa4bde48fc7322bdc692c6636975943ebe4f6dd97e07d70b14e0ab85af2ff30de90f550f5ec2956684fe208e150d85d6cb5f3c74438c8ac1bf86bd435c13 languageName: node linkType: hard -"collection-visit@npm:^1.0.0": - version: 1.0.0 - resolution: "collection-visit@npm:1.0.0" - dependencies: - map-visit: "npm:^1.0.0" - object-visit: "npm:^1.0.0" - checksum: 10c0/add72a8d1c37cb90e53b1aaa2c31bf1989bfb733f0b02ce82c9fa6828c7a14358dba2e4f8e698c02f69e424aeccae1ffb39acdeaf872ade2f41369e84a2fcf8a +"fdir@npm:^6.5.0": + version: 6.5.0 + resolution: "fdir@npm:6.5.0" + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + checksum: 10c0/e345083c4306b3aed6cb8ec551e26c36bab5c511e99ea4576a16750ddc8d3240e63826cc624f5ae17ad4dc82e68a253213b60d556c11bfad064b7607847ed07f languageName: node linkType: hard -"color-convert@npm:^1.9.0": - version: 1.9.3 - resolution: "color-convert@npm:1.9.3" +"file-entry-cache@npm:11.1.5 || >11.1.6 <12": + version: 11.1.5 + resolution: "file-entry-cache@npm:11.1.5" dependencies: - color-name: "npm:1.1.3" - checksum: 10c0/5ad3c534949a8c68fca8fbc6f09068f435f0ad290ab8b2f76841b9e6af7e0bb57b98cb05b0e19fe33f5d91e5a8611ad457e5f69e0a484caad1f7487fd0e8253c + flat-cache: "npm:^6.1.23" + checksum: 10c0/d05eca8794b27824d79a0f1a0bc76b81ca7232b6c9634bc086f365a6d9ddac749c4826b2b2d36bb7ef9ed84fdf0097f34979527daeb9255b4f17673a4ae50fc5 languageName: node linkType: hard -"color-convert@npm:^2.0.1": - version: 2.0.1 - resolution: "color-convert@npm:2.0.1" +"fill-range@npm:^7.0.1": + version: 7.0.1 + resolution: "fill-range@npm:7.0.1" dependencies: - color-name: "npm:~1.1.4" - checksum: 10c0/37e1150172f2e311fe1b2df62c6293a342ee7380da7b9cfdba67ea539909afbd74da27033208d01d6d5cfc65ee7868a22e18d7e7648e004425441c0f8a15a7d7 - languageName: node - linkType: hard - -"color-name@npm:1.1.3": - version: 1.1.3 - resolution: "color-name@npm:1.1.3" - checksum: 10c0/566a3d42cca25b9b3cd5528cd7754b8e89c0eb646b7f214e8e2eaddb69994ac5f0557d9c175eb5d8f0ad73531140d9c47525085ee752a91a2ab15ab459caf6d6 - languageName: node - linkType: hard - -"color-name@npm:~1.1.4": - version: 1.1.4 - resolution: "color-name@npm:1.1.4" - checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95 + to-regex-range: "npm:^5.0.1" + checksum: 10c0/7cdad7d426ffbaadf45aeb5d15ec675bbd77f7597ad5399e3d2766987ed20bda24d5fac64b3ee79d93276f5865608bb22344a26b9b1ae6c4d00bd94bf611623f languageName: node linkType: hard -"colors@npm:^1.1.2": - version: 1.4.0 - resolution: "colors@npm:1.4.0" - checksum: 10c0/9af357c019da3c5a098a301cf64e3799d27549d8f185d86f79af23069e4f4303110d115da98483519331f6fb71c8568d5688fa1c6523600044fd4a54e97c4efb +"find-replace@npm:^3.0.0": + version: 3.0.0 + resolution: "find-replace@npm:3.0.0" + dependencies: + array-back: "npm:^3.0.1" + checksum: 10c0/fcd1bf7960388c8193c2861bcdc760c18ac14edb4bde062a961915d9a25727b2e8aabf0229e90cc09c753fd557e5a3e5ae61e49cadbe727be89a9e8e49ce7668 languageName: node linkType: hard -"combined-stream@npm:^1.0.6, combined-stream@npm:^1.0.8, combined-stream@npm:~1.0.6": - version: 1.0.8 - resolution: "combined-stream@npm:1.0.8" +"find-up@npm:^5.0.0": + version: 5.0.0 + resolution: "find-up@npm:5.0.0" dependencies: - delayed-stream: "npm:~1.0.0" - checksum: 10c0/0dbb829577e1b1e839fa82b40c07ffaf7de8a09b935cadd355a73652ae70a88b4320db322f6634a4ad93424292fa80973ac6480986247f1734a1137debf271d5 + locate-path: "npm:^6.0.0" + path-exists: "npm:^4.0.0" + checksum: 10c0/062c5a83a9c02f53cdd6d175a37ecf8f87ea5bbff1fdfb828f04bfa021441bc7583e8ebc0872a4c1baab96221fb8a8a275a19809fb93fbc40bd69ec35634069a languageName: node linkType: hard -"command-exists@npm:^1.2.8": - version: 1.2.9 - resolution: "command-exists@npm:1.2.9" - checksum: 10c0/75040240062de46cd6cd43e6b3032a8b0494525c89d3962e280dde665103f8cc304a8b313a5aa541b91da2f5a9af75c5959dc3a77893a2726407a5e9a0234c16 +"flat-cache@npm:^6.1.23": + version: 6.1.23 + resolution: "flat-cache@npm:6.1.23" + dependencies: + cacheable: "npm:^2.5.0" + flatted: "npm:^3.4.2" + hookified: "npm:^1.15.0" + checksum: 10c0/c757c24f51334e1917958cd9d62d4ed3d520a3815d5a1ec50d993ac3a93fa81b6de7e28264231914bb0d990babd426e4d713d3e2f3d782dae65c42a2ded1e651 languageName: node linkType: hard -"command-line-args@npm:^4.0.7": - version: 4.0.7 - resolution: "command-line-args@npm:4.0.7" - dependencies: - array-back: "npm:^2.0.0" - find-replace: "npm:^1.0.3" - typical: "npm:^2.6.1" +"flat@npm:^5.0.2": + version: 5.0.2 + resolution: "flat@npm:5.0.2" bin: - command-line-args: bin/cli.js - checksum: 10c0/ff1b1f5ca8b4f2c396ae9fcaf187824c5f0129e6ca85e082b3d6c3c54e388b5086a36a98d7eef28bc4358b10d639a732871df6e5a09122d7f911f2240c1e5f0b + flat: cli.js + checksum: 10c0/f178b13482f0cd80c7fede05f4d10585b1f2fdebf26e12edc138e32d3150c6ea6482b7f12813a1091143bad52bb6d3596bca51a162257a21163c0ff438baa5fe languageName: node linkType: hard -"command-line-args@npm:^5.1.1": - version: 5.2.1 - resolution: "command-line-args@npm:5.2.1" - dependencies: - array-back: "npm:^3.1.0" - find-replace: "npm:^3.0.0" - lodash.camelcase: "npm:^4.3.0" - typical: "npm:^4.0.0" - checksum: 10c0/a4f6a23a1e420441bd1e44dee24efd12d2e49af7efe6e21eb32fca4e843ca3d5501ddebad86a4e9d99aa626dd6dcb64c04a43695388be54e3a803dbc326cc89f +"flatted@npm:^3.4.2": + version: 3.4.4 + resolution: "flatted@npm:3.4.4" + checksum: 10c0/a3a52a88ea5a4c333e5a1f097dcd87a037fa31c236a77cf46222c2aa4036ef895ab9bc76138a66d9dc22bdb3652128f9598cd26e7439561bf19f67276e2bc37e languageName: node linkType: hard -"command-line-usage@npm:^6.1.0": - version: 6.1.1 - resolution: "command-line-usage@npm:6.1.1" +"fmix@npm:^0.1.0": + version: 0.1.0 + resolution: "fmix@npm:0.1.0" dependencies: - array-back: "npm:^4.0.1" - chalk: "npm:^2.4.2" - table-layout: "npm:^1.0.1" - typical: "npm:^5.2.0" - checksum: 10c0/2597ee2a529020c86e2a3ef4288ffd1a9ccf05dbe4fafd4d33a75c36241054e551132a358a3355544df09b6855dbc7aca05efd9b0aba5b25b36d3225bb303c02 - languageName: node - linkType: hard - -"commander@npm:2.18.0": - version: 2.18.0 - resolution: "commander@npm:2.18.0" - checksum: 10c0/34fe2c3bf52c697ba79e690f26c38163d3c68bbb60cdcc9376c3f686e12276f158113a8d15e569f9b7ea974b52963bd2fdcbdd98d659caccca14d9495ba01a6a + imul: "npm:^1.0.0" + checksum: 10c0/af9e54eacc00b46e1c4a77229840e37252fff7634f81026591da9d24438ca15a1afa2786f579eb7865489ded21b76af7327d111b90b944e7409cd60f4d4f2ded languageName: node linkType: hard -"commander@npm:3.0.2": - version: 3.0.2 - resolution: "commander@npm:3.0.2" - checksum: 10c0/8a279b4bacde68f03664086260ccb623122d2bdae6f380a41c9e06b646e830372c30a4b88261238550e0ad69d53f7af8883cb705d8237fdd22947e84913b149c +"follow-redirects@npm:^1.12.1": + version: 1.14.9 + resolution: "follow-redirects@npm:1.14.9" + peerDependenciesMeta: + debug: + optional: true + checksum: 10c0/08c465c17cbf3011ad16516609ee476abffa8fd1ff78c2082f1ff43614cb06586a0ccc8e99e5ebe13da06d064367cb269789e3ca0e93e2ad5b24fdc30b4294b6 languageName: node linkType: hard -"commander@npm:^8.1.0": - version: 8.3.0 - resolution: "commander@npm:8.3.0" - checksum: 10c0/8b043bb8322ea1c39664a1598a95e0495bfe4ca2fad0d84a92d7d1d8d213e2a155b441d2470c8e08de7c4a28cf2bc6e169211c49e1b21d9f7edc6ae4d9356060 +"follow-redirects@npm:^1.16.0": + version: 1.16.0 + resolution: "follow-redirects@npm:1.16.0" + peerDependenciesMeta: + debug: + optional: true + checksum: 10c0/a1e2900163e6f1b4d1ed5c221b607f41decbab65534c63fe7e287e40a5d552a6496e7d9d7d976fa4ba77b4c51c11e5e9f683f10b43011ea11e442ff128d0e181 languageName: node linkType: hard -"compare-versions@npm:^5.0.0": - version: 5.0.1 - resolution: "compare-versions@npm:5.0.1" - checksum: 10c0/11210f69725021bc80371f1cbcbb4353ba975cd503ffceb876f8bc043026ad1075bcc6eb7285ba862cadd000fc11d1f40c4d2477c87ceda03b8ab10d67a98eca +"foreground-child@npm:^3.1.0": + version: 3.3.1 + resolution: "foreground-child@npm:3.3.1" + dependencies: + cross-spawn: "npm:^7.0.6" + signal-exit: "npm:^4.0.1" + checksum: 10c0/8986e4af2430896e65bc2788d6679067294d6aee9545daefc84923a0a4b399ad9c7a3ea7bd8c0b2b80fdf4a92de4c69df3f628233ff3224260e9c1541a9e9ed3 languageName: node linkType: hard -"component-emitter@npm:^1.2.1": - version: 1.3.0 - resolution: "component-emitter@npm:1.3.0" - checksum: 10c0/68774a0a3754fb6c0ba53c2e88886dfbd0c773931066abb1d7fd1b0c893b2a838d8f088ab4dca1f18cc1a4fc2e6932019eba3ded2d931b5ba2241ce40e93a24f +"form-data-encoder@npm:^2.1.2": + version: 2.1.4 + resolution: "form-data-encoder@npm:2.1.4" + checksum: 10c0/4c06ae2b79ad693a59938dc49ebd020ecb58e4584860a90a230f80a68b026483b022ba5e4143cff06ae5ac8fd446a0b500fabc87bbac3d1f62f2757f8dabcaf7 languageName: node linkType: hard -"concat-map@npm:0.0.1": - version: 0.0.1 - resolution: "concat-map@npm:0.0.1" - checksum: 10c0/c996b1cfdf95b6c90fee4dae37e332c8b6eb7d106430c17d538034c0ad9a1630cb194d2ab37293b1bdd4d779494beee7786d586a50bd9376fd6f7bcc2bd4c98f +"form-data@npm:^4.0.0": + version: 4.0.0 + resolution: "form-data@npm:4.0.0" + dependencies: + asynckit: "npm:^0.4.0" + combined-stream: "npm:^1.0.8" + mime-types: "npm:^2.1.12" + checksum: 10c0/cb6f3ac49180be03ff07ba3ff125f9eba2ff0b277fb33c7fc47569fc5e616882c5b1c69b9904c4c4187e97dd0419dd03b134174756f296dec62041e6527e2c6e languageName: node linkType: hard -"concat-stream@npm:^1.5.1": - version: 1.6.2 - resolution: "concat-stream@npm:1.6.2" +"form-data@npm:^4.0.6": + version: 4.0.6 + resolution: "form-data@npm:4.0.6" dependencies: - buffer-from: "npm:^1.0.0" - inherits: "npm:^2.0.3" - readable-stream: "npm:^2.2.2" - typedarray: "npm:^0.0.6" - checksum: 10c0/2e9864e18282946dabbccb212c5c7cec0702745e3671679eb8291812ca7fd12023f7d8cb36493942a62f770ac96a7f90009dc5c82ad69893438371720fa92617 + asynckit: "npm:^0.4.0" + combined-stream: "npm:^1.0.8" + es-set-tostringtag: "npm:^2.1.0" + hasown: "npm:^2.0.4" + mime-types: "npm:^2.1.35" + checksum: 10c0/43947a77bf0ff45c6ceed789778982d47a3f3e720a74b71721174ebf3310a5f1a8be1d6b38a3ee3688e8a18a2c4273073ec0844cd37efda3eaf46d41c9c318ff languageName: node linkType: hard -"confusing-browser-globals@npm:^1.0.10": - version: 1.0.10 - resolution: "confusing-browser-globals@npm:1.0.10" - checksum: 10c0/539532caf30cb2f16dd587617e1677a0c184e31aa7b17113e46ba6e94b4c943d25b191e054a266843a76f39ebca87276ad3283729bf4b3a8828679851f3b463f +"fp-ts@npm:1.19.3": + version: 1.19.3 + resolution: "fp-ts@npm:1.19.3" + checksum: 10c0/a016cfc98ad5e61564ab2d53a5379bbb8254642b66df13ced47e8c1d8d507abf4588d8bb43530198dfe1907211d8bae8f112cab52ba0ac6ab055da9168a6e260 languageName: node linkType: hard -"content-disposition@npm:0.5.4": - version: 0.5.4 - resolution: "content-disposition@npm:0.5.4" - dependencies: - safe-buffer: "npm:5.2.1" - checksum: 10c0/bac0316ebfeacb8f381b38285dc691c9939bf0a78b0b7c2d5758acadad242d04783cee5337ba7d12a565a19075af1b3c11c728e1e4946de73c6ff7ce45f3f1bb +"fp-ts@npm:^1.0.0": + version: 1.19.5 + resolution: "fp-ts@npm:1.19.5" + checksum: 10c0/2a330fa1779561307740c26a7255fdffeb1ca2d0c7448d4dc094b477b772b0c8f7da1dfc88569b6f13f6958169b63b5df7361e514535b46b2e215bbf03a3722d languageName: node linkType: hard -"content-hash@npm:^2.5.2": - version: 2.5.2 - resolution: "content-hash@npm:2.5.2" +"fs-extra@npm:^10.0.0, fs-extra@npm:^10.1.0": + version: 10.1.0 + resolution: "fs-extra@npm:10.1.0" dependencies: - cids: "npm:^0.7.1" - multicodec: "npm:^0.5.5" - multihashes: "npm:^0.4.15" - checksum: 10c0/107463b574365cf0dc07711bb6fdc2b613ef631fee2245bb77f507057e91d52e8e28faf2f4c092bfff918eb7ae8eb226b75cae4320721138126ec9925a500228 - languageName: node - linkType: hard - -"content-type@npm:~1.0.4": - version: 1.0.4 - resolution: "content-type@npm:1.0.4" - checksum: 10c0/19e08f406f9ae3f80fb4607c75fbde1f22546647877e8047c9fa0b1c61e38f3ede853f51e915c95fd499c2e1c7478cb23c35cfb804d0e8e0495e8db88cfaed75 + graceful-fs: "npm:^4.2.0" + jsonfile: "npm:^6.0.1" + universalify: "npm:^2.0.0" + checksum: 10c0/5f579466e7109719d162a9249abbeffe7f426eb133ea486e020b89bc6d67a741134076bf439983f2eb79276ceaf6bd7b7c1e43c3fd67fe889863e69072fb0a5e languageName: node linkType: hard -"convert-source-map@npm:^1.5.1": - version: 1.8.0 - resolution: "convert-source-map@npm:1.8.0" +"fs-extra@npm:^11.2.0": + version: 11.3.4 + resolution: "fs-extra@npm:11.3.4" dependencies: - safe-buffer: "npm:~5.1.1" - checksum: 10c0/da4649990b633c070c0dab1680b89a67b9315dd2b1168d143536f667214c97e4eb4a49e5b7ff912f0196fe303e31fc16a529457436d25b2b5a89613eaf4f27fa + graceful-fs: "npm:^4.2.0" + jsonfile: "npm:^6.0.1" + universalify: "npm:^2.0.0" + checksum: 10c0/e08276f767a62496ae97d711aaa692c6a478177f24a85979b6a2881c9db9c68b8c2ad5da0bcf92c0b2a474cea6e935ec245656441527958fd8372cb647087df0 languageName: node linkType: hard -"cookie-signature@npm:1.0.6": - version: 1.0.6 - resolution: "cookie-signature@npm:1.0.6" - checksum: 10c0/b36fd0d4e3fef8456915fcf7742e58fbfcc12a17a018e0eb9501c9d5ef6893b596466f03b0564b81af29ff2538fd0aa4b9d54fe5ccbfb4c90ea50ad29fe2d221 +"fs-extra@npm:^7.0.0, fs-extra@npm:^7.0.1": + version: 7.0.1 + resolution: "fs-extra@npm:7.0.1" + dependencies: + graceful-fs: "npm:^4.1.2" + jsonfile: "npm:^4.0.0" + universalify: "npm:^0.1.0" + checksum: 10c0/1943bb2150007e3739921b8d13d4109abdc3cc481e53b97b7ea7f77eda1c3c642e27ae49eac3af074e3496ea02fde30f411ef410c760c70a38b92e656e5da784 languageName: node linkType: hard -"cookie@npm:0.5.0": - version: 0.5.0 - resolution: "cookie@npm:0.5.0" - checksum: 10c0/c01ca3ef8d7b8187bae434434582288681273b5a9ed27521d4d7f9f7928fe0c920df0decd9f9d3bbd2d14ac432b8c8cf42b98b3bdd5bfe0e6edddeebebe8b61d +"fs-extra@npm:^9.1.0": + version: 9.1.0 + resolution: "fs-extra@npm:9.1.0" + dependencies: + at-least-node: "npm:^1.0.0" + graceful-fs: "npm:^4.2.0" + jsonfile: "npm:^6.0.1" + universalify: "npm:^2.0.0" + checksum: 10c0/9b808bd884beff5cb940773018179a6b94a966381d005479f00adda6b44e5e3d4abf765135773d849cc27efe68c349e4a7b86acd7d3306d5932c14f3a4b17a92 languageName: node linkType: hard -"cookie@npm:^0.4.1": - version: 0.4.1 - resolution: "cookie@npm:0.4.1" - checksum: 10c0/4d7bc798df3d0f34035977949cd6b7d05bbab47d7dcb868667f460b578a550cd20dec923832b8a3a107ef35aba091a3975e14f79efacf6e39282dc0fed6db4a1 +"fs-minipass@npm:^3.0.0": + version: 3.0.3 + resolution: "fs-minipass@npm:3.0.3" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10c0/63e80da2ff9b621e2cb1596abcb9207f1cf82b968b116ccd7b959e3323144cce7fb141462200971c38bbf2ecca51695069db45265705bed09a7cd93ae5b89f94 languageName: node linkType: hard -"cookiejar@npm:^2.1.1": - version: 2.1.4 - resolution: "cookiejar@npm:2.1.4" - checksum: 10c0/2dae55611c6e1678f34d93984cbd4bda58f4fe3e5247cc4993f4a305cd19c913bbaf325086ed952e892108115073a747596453d3dc1c34947f47f731818b8ad1 +"fs.realpath@npm:^1.0.0": + version: 1.0.0 + resolution: "fs.realpath@npm:1.0.0" + checksum: 10c0/444cf1291d997165dfd4c0d58b69f0e4782bfd9149fd72faa4fe299e68e0e93d6db941660b37dd29153bf7186672ececa3b50b7e7249477b03fdf850f287c948 languageName: node linkType: hard -"copy-descriptor@npm:^0.1.0": - version: 0.1.1 - resolution: "copy-descriptor@npm:0.1.1" - checksum: 10c0/161f6760b7348c941007a83df180588fe2f1283e0867cc027182734e0f26134e6cc02de09aa24a95dc267b2e2025b55659eef76c8019df27bc2d883033690181 +"fsevents@npm:~2.3.2": + version: 2.3.2 + resolution: "fsevents@npm:2.3.2" + dependencies: + node-gyp: "npm:latest" + checksum: 10c0/be78a3efa3e181cda3cf7a4637cb527bcebb0bd0ea0440105a3bb45b86f9245b307dc10a2507e8f4498a7d4ec349d1910f4d73e4d4495b16103106e07eee735b + conditions: os=darwin languageName: node linkType: hard -"core-js-pure@npm:^3.0.1, core-js-pure@npm:^3.16.0": - version: 3.18.1 - resolution: "core-js-pure@npm:3.18.1" - checksum: 10c0/25509f7b3e33b99033d720636ffe63cf397fcc6715e8781add8a665dd5802a11d7f343147237670050197981cedee1343c6ba509671f2d29beb363de43e8b287 +"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin": + version: 2.3.2 + resolution: "fsevents@patch:fsevents@npm%3A2.3.2#optional!builtin::version=2.3.2&hash=df0bf1" + dependencies: + node-gyp: "npm:latest" + conditions: os=darwin languageName: node linkType: hard -"core-js@npm:^2.4.0, core-js@npm:^2.5.0": - version: 2.6.12 - resolution: "core-js@npm:2.6.12" - checksum: 10c0/00128efe427789120a06b819adc94cc72b96955acb331cb71d09287baf9bd37bebd191d91f1ee4939c893a050307ead4faea08876f09115112612b6a05684b63 +"function-bind@npm:^1.1.2": + version: 1.1.2 + resolution: "function-bind@npm:1.1.2" + checksum: 10c0/d8680ee1e5fcd4c197e4ac33b2b4dce03c71f4d91717292785703db200f5c21f977c568d28061226f9b5900cbcd2c84463646134fd5337e7925e0942bc3f46d5 languageName: node linkType: hard -"core-util-is@npm:1.0.2": - version: 1.0.2 - resolution: "core-util-is@npm:1.0.2" - checksum: 10c0/980a37a93956d0de8a828ce508f9b9e3317039d68922ca79995421944146700e4aaf490a6dbfebcb1c5292a7184600c7710b957d724be1e37b8254c6bc0fe246 +"generator-function@npm:^2.0.0": + version: 2.0.1 + resolution: "generator-function@npm:2.0.1" + checksum: 10c0/8a9f59df0f01cfefafdb3b451b80555e5cf6d76487095db91ac461a0e682e4ff7a9dbce15f4ecec191e53586d59eece01949e05a4b4492879600bbbe8e28d6b8 languageName: node linkType: hard -"core-util-is@npm:~1.0.0": - version: 1.0.3 - resolution: "core-util-is@npm:1.0.3" - checksum: 10c0/90a0e40abbddfd7618f8ccd63a74d88deea94e77d0e8dbbea059fa7ebebb8fbb4e2909667fe26f3a467073de1a542ebe6ae4c73a73745ac5833786759cd906c9 +"get-caller-file@npm:^2.0.5": + version: 2.0.5 + resolution: "get-caller-file@npm:2.0.5" + checksum: 10c0/c6c7b60271931fa752aeb92f2b47e355eac1af3a2673f47c9589e8f8a41adc74d45551c1bc57b5e66a80609f10ffb72b6f575e4370d61cc3f7f3aaff01757cde languageName: node linkType: hard -"cors@npm:^2.8.1": - version: 2.8.5 - resolution: "cors@npm:2.8.5" - dependencies: - object-assign: "npm:^4" - vary: "npm:^1" - checksum: 10c0/373702b7999409922da80de4a61938aabba6929aea5b6fd9096fefb9e8342f626c0ebd7507b0e8b0b311380744cc985f27edebc0a26e0ddb784b54e1085de761 +"get-func-name@npm:^2.0.0": + version: 2.0.2 + resolution: "get-func-name@npm:2.0.2" + checksum: 10c0/89830fd07623fa73429a711b9daecdb304386d237c71268007f788f113505ef1d4cc2d0b9680e072c5082490aec9df5d7758bf5ac6f1c37062855e8e3dc0b9df languageName: node linkType: hard -"cosmiconfig@npm:^5.0.7": - version: 5.2.1 - resolution: "cosmiconfig@npm:5.2.1" +"get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.3.0": + version: 1.3.1 + resolution: "get-intrinsic@npm:1.3.1" dependencies: - import-fresh: "npm:^2.0.0" - is-directory: "npm:^0.3.1" - js-yaml: "npm:^3.13.1" - parse-json: "npm:^4.0.0" - checksum: 10c0/ae9ba309cdbb42d0c9d63dad5c1dfa1c56bb8f818cb8633eea14fd2dbdc9f33393b77658ba96fdabda497bc943afed8c3371d1222afe613c518ba676fa624645 - languageName: node - linkType: hard - -"create-ecdh@npm:^4.0.0": - version: 4.0.4 - resolution: "create-ecdh@npm:4.0.4" - dependencies: - bn.js: "npm:^4.1.0" - elliptic: "npm:^6.5.3" - checksum: 10c0/77b11a51360fec9c3bce7a76288fc0deba4b9c838d5fb354b3e40c59194d23d66efe6355fd4b81df7580da0661e1334a235a2a5c040b7569ba97db428d466e7f - languageName: node - linkType: hard - -"create-hash@npm:^1.1.0, create-hash@npm:^1.1.2, create-hash@npm:^1.2.0": - version: 1.2.0 - resolution: "create-hash@npm:1.2.0" - dependencies: - cipher-base: "npm:^1.0.1" - inherits: "npm:^2.0.1" - md5.js: "npm:^1.3.4" - ripemd160: "npm:^2.0.1" - sha.js: "npm:^2.4.0" - checksum: 10c0/d402e60e65e70e5083cb57af96d89567954d0669e90550d7cec58b56d49c4b193d35c43cec8338bc72358198b8cbf2f0cac14775b651e99238e1cf411490f915 + async-function: "npm:^1.0.0" + async-generator-function: "npm:^1.0.0" + call-bind-apply-helpers: "npm:^1.0.2" + es-define-property: "npm:^1.0.1" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.1.1" + function-bind: "npm:^1.1.2" + generator-function: "npm:^2.0.0" + get-proto: "npm:^1.0.1" + gopd: "npm:^1.2.0" + has-symbols: "npm:^1.1.0" + hasown: "npm:^2.0.2" + math-intrinsics: "npm:^1.1.0" + checksum: 10c0/9f4ab0cf7efe0fd2c8185f52e6f637e708f3a112610c88869f8f041bb9ecc2ce44bf285dfdbdc6f4f7c277a5b88d8e94a432374d97cca22f3de7fc63795deb5d languageName: node linkType: hard -"create-hmac@npm:^1.1.0, create-hmac@npm:^1.1.4, create-hmac@npm:^1.1.7": - version: 1.1.7 - resolution: "create-hmac@npm:1.1.7" +"get-proto@npm:^1.0.1": + version: 1.0.1 + resolution: "get-proto@npm:1.0.1" dependencies: - cipher-base: "npm:^1.0.3" - create-hash: "npm:^1.1.0" - inherits: "npm:^2.0.1" - ripemd160: "npm:^2.0.0" - safe-buffer: "npm:^5.0.1" - sha.js: "npm:^2.4.8" - checksum: 10c0/24332bab51011652a9a0a6d160eed1e8caa091b802335324ae056b0dcb5acbc9fcf173cf10d128eba8548c3ce98dfa4eadaa01bd02f44a34414baee26b651835 + dunder-proto: "npm:^1.0.1" + es-object-atoms: "npm:^1.0.0" + checksum: 10c0/9224acb44603c5526955e83510b9da41baf6ae73f7398875fba50edc5e944223a89c4a72b070fcd78beb5f7bdda58ecb6294adc28f7acfc0da05f76a2399643c languageName: node linkType: hard -"create-require@npm:^1.1.0": - version: 1.1.1 - resolution: "create-require@npm:1.1.1" - checksum: 10c0/157cbc59b2430ae9a90034a5f3a1b398b6738bf510f713edc4d4e45e169bc514d3d99dd34d8d01ca7ae7830b5b8b537e46ae8f3c8f932371b0875c0151d7ec91 +"get-stream@npm:^6.0.1": + version: 6.0.1 + resolution: "get-stream@npm:6.0.1" + checksum: 10c0/49825d57d3fd6964228e6200a58169464b8e8970489b3acdc24906c782fb7f01f9f56f8e6653c4a50713771d6658f7cfe051e5eb8c12e334138c9c918b296341 languageName: node linkType: hard -"cross-fetch@npm:^2.1.0, cross-fetch@npm:^2.1.1": - version: 2.2.6 - resolution: "cross-fetch@npm:2.2.6" +"get-tsconfig@npm:^4.10.1": + version: 4.14.3 + resolution: "get-tsconfig@npm:4.14.3" dependencies: - node-fetch: "npm:^2.6.7" - whatwg-fetch: "npm:^2.0.4" - checksum: 10c0/073d160a4d5d7ce7f88b01a18f425e31f60da4563e41f1c4f130c52c302f1f202f1a1999f39bb86daa39ca077b80b4985259c19f13fcfafdde3968d49ae94da5 + resolve-pkg-maps: "npm:^1.0.0" + checksum: 10c0/22119bb5b7e37b922a973bfb50deac89ca845cef50a24cd27b6c628f314e91a2bccceb186e0b5183e231ad6480d7173738912975332caf60678af39b7236eeac languageName: node linkType: hard -"cross-spawn@npm:^6.0.5": - version: 6.0.5 - resolution: "cross-spawn@npm:6.0.5" +"glob-parent@npm:^6.0.2": + version: 6.0.2 + resolution: "glob-parent@npm:6.0.2" dependencies: - nice-try: "npm:^1.0.4" - path-key: "npm:^2.0.1" - semver: "npm:^5.5.0" - shebang-command: "npm:^1.2.0" - which: "npm:^1.2.9" - checksum: 10c0/e05544722e9d7189b4292c66e42b7abeb21db0d07c91b785f4ae5fefceb1f89e626da2703744657b287e86dcd4af57b54567cef75159957ff7a8a761d9055012 + is-glob: "npm:^4.0.3" + checksum: 10c0/317034d88654730230b3f43bb7ad4f7c90257a426e872ea0bf157473ac61c99bf5d205fad8f0185f989be8d2fa6d3c7dce1645d99d545b6ea9089c39f838e7f8 languageName: node linkType: hard -"cross-spawn@npm:^7.0.2": - version: 7.0.3 - resolution: "cross-spawn@npm:7.0.3" +"glob-parent@npm:~5.1.2": + version: 5.1.2 + resolution: "glob-parent@npm:5.1.2" dependencies: - path-key: "npm:^3.1.0" - shebang-command: "npm:^2.0.0" - which: "npm:^2.0.1" - checksum: 10c0/5738c312387081c98d69c98e105b6327b069197f864a60593245d64c8089c8a0a744e16349281210d56835bb9274130d825a78b2ad6853ca13cfbeffc0c31750 + is-glob: "npm:^4.0.1" + checksum: 10c0/cab87638e2112bee3f839ef5f6e0765057163d39c66be8ec1602f3823da4692297ad4e972de876ea17c44d652978638d2fd583c6713d0eb6591706825020c9ee languageName: node linkType: hard -"cross-spawn@npm:^7.0.6": - version: 7.0.6 - resolution: "cross-spawn@npm:7.0.6" +"glob@npm:7.1.7": + version: 7.1.7 + resolution: "glob@npm:7.1.7" dependencies: - path-key: "npm:^3.1.0" - shebang-command: "npm:^2.0.0" - which: "npm:^2.0.1" - checksum: 10c0/053ea8b2135caff68a9e81470e845613e374e7309a47731e81639de3eaeb90c3d01af0e0b44d2ab9d50b43467223b88567dfeb3262db942dc063b9976718ffc1 - languageName: node - linkType: hard - -"crypt@npm:>= 0.0.1": - version: 0.0.2 - resolution: "crypt@npm:0.0.2" - checksum: 10c0/adbf263441dd801665d5425f044647533f39f4612544071b1471962209d235042fb703c27eea2795c7c53e1dfc242405173003f83cf4f4761a633d11f9653f18 + fs.realpath: "npm:^1.0.0" + inflight: "npm:^1.0.4" + inherits: "npm:2" + minimatch: "npm:^3.0.4" + once: "npm:^1.3.0" + path-is-absolute: "npm:^1.0.0" + checksum: 10c0/173245e6f9ccf904309eb7ef4a44a11f3bf68e9e341dff5a28b5db0dd7123b7506daf41497f3437a0710f57198187b758c2351eeaabce4d16935e956920da6a4 languageName: node linkType: hard -"crypto-browserify@npm:3.12.0": - version: 3.12.0 - resolution: "crypto-browserify@npm:3.12.0" +"glob@npm:^10.3.10, glob@npm:^10.4.5": + version: 10.5.0 + resolution: "glob@npm:10.5.0" dependencies: - browserify-cipher: "npm:^1.0.0" - browserify-sign: "npm:^4.0.0" - create-ecdh: "npm:^4.0.0" - create-hash: "npm:^1.1.0" - create-hmac: "npm:^1.1.0" - diffie-hellman: "npm:^5.0.0" - inherits: "npm:^2.0.1" - pbkdf2: "npm:^3.0.3" - public-encrypt: "npm:^4.0.0" - randombytes: "npm:^2.0.0" - randomfill: "npm:^1.0.3" - checksum: 10c0/0c20198886576050a6aa5ba6ae42f2b82778bfba1753d80c5e7a090836890dc372bdc780986b2568b4fb8ed2a91c958e61db1f0b6b1cc96af4bd03ffc298ba92 + foreground-child: "npm:^3.1.0" + jackspeak: "npm:^3.1.2" + minimatch: "npm:^9.0.4" + minipass: "npm:^7.1.2" + package-json-from-dist: "npm:^1.0.0" + path-scurry: "npm:^1.11.1" + bin: + glob: dist/esm/bin.mjs + checksum: 10c0/100705eddbde6323e7b35e1d1ac28bcb58322095bd8e63a7d0bef1a2cdafe0d0f7922a981b2b48369a4f8c1b077be5c171804534c3509dfe950dde15fbe6d828 languageName: node linkType: hard -"d@npm:1, d@npm:^1.0.1": - version: 1.0.1 - resolution: "d@npm:1.0.1" +"glob@npm:^13.0.0, glob@npm:^13.0.6": + version: 13.0.6 + resolution: "glob@npm:13.0.6" dependencies: - es5-ext: "npm:^0.10.50" - type: "npm:^1.0.1" - checksum: 10c0/1fedcb3b956a461f64d86b94b347441beff5cef8910b6ac4ec509a2c67eeaa7093660a98b26601ac91f91260238add73bdf25867a9c0cb783774642bc4c1523f - languageName: node - linkType: hard - -"damerau-levenshtein@npm:^1.0.6": - version: 1.0.7 - resolution: "damerau-levenshtein@npm:1.0.7" - checksum: 10c0/05083ca068c3d126191a7bd9392e313117010166540bb3018b40e63cd24c376fe323161c46b1a1dd73e482f323416eaee4430352c69207d6a968b33f4af66217 + minimatch: "npm:^10.2.2" + minipass: "npm:^7.1.3" + path-scurry: "npm:^2.0.2" + checksum: 10c0/269c236f11a9b50357fe7a8c6aadac667e01deb5242b19c84975628f05f4438d8ee1354bb62c5d6c10f37fd59911b54d7799730633a2786660d8c69f1d18120a languageName: node linkType: hard -"dashdash@npm:^1.12.0": - version: 1.14.1 - resolution: "dashdash@npm:1.14.1" - dependencies: - assert-plus: "npm:^1.0.0" - checksum: 10c0/64589a15c5bd01fa41ff7007e0f2c6552c5ef2028075daa16b188a3721f4ba001841bf306dfc2eee6e2e6e7f76b38f5f17fb21fa847504192290ffa9e150118a +"globals@npm:^17.12.0": + version: 17.12.0 + resolution: "globals@npm:17.12.0" + checksum: 10c0/8325cf8818c848871d17c32974c2c74e9c5f09c1b0e04421886f64f21e77c3e95f3ba25586743895a73acd860ada151132481d87d44a1f12993ae7758a694d03 languageName: node linkType: hard -"debug@npm:2.6.9, debug@npm:^2.2.0, debug@npm:^2.3.3, debug@npm:^2.6.8, debug@npm:^2.6.9": - version: 2.6.9 - resolution: "debug@npm:2.6.9" - dependencies: - ms: "npm:2.0.0" - checksum: 10c0/121908fb839f7801180b69a7e218a40b5a0b718813b886b7d6bdb82001b931c938e2941d1e4450f33a1b1df1da653f5f7a0440c197f29fbf8a6e9d45ff6ef589 +"gopd@npm:^1.2.0": + version: 1.2.0 + resolution: "gopd@npm:1.2.0" + checksum: 10c0/50fff1e04ba2b7737c097358534eacadad1e68d24cccee3272e04e007bed008e68d2614f3987788428fd192a5ae3889d08fb2331417e4fc4a9ab366b2043cead languageName: node linkType: hard -"debug@npm:3.2.6": - version: 3.2.6 - resolution: "debug@npm:3.2.6" +"got@npm:^12.1.0": + version: 12.6.1 + resolution: "got@npm:12.6.1" dependencies: - ms: "npm:^2.1.1" - checksum: 10c0/406ae034424c5570c83bb7f7baf6a2321ace5b94d6f0032ec796c686e277a55bbb575712bb9e6f204e044b1a8c31981ba97fab725a09fcdc7f85cd89daf4de30 + "@sindresorhus/is": "npm:^5.2.0" + "@szmarczak/http-timer": "npm:^5.0.1" + cacheable-lookup: "npm:^7.0.0" + cacheable-request: "npm:^10.2.8" + decompress-response: "npm:^6.0.0" + form-data-encoder: "npm:^2.1.2" + get-stream: "npm:^6.0.1" + http2-wrapper: "npm:^2.1.10" + lowercase-keys: "npm:^3.0.0" + p-cancelable: "npm:^3.0.0" + responselike: "npm:^3.0.0" + checksum: 10c0/2fe97fcbd7a9ffc7c2d0ecf59aca0a0562e73a7749cadada9770eeb18efbdca3086262625fb65590594edc220a1eca58fab0d26b0c93c2f9a008234da71ca66b languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.0.1, debug@npm:^4.1.1, debug@npm:^4.3.1": - version: 4.3.2 - resolution: "debug@npm:4.3.2" - dependencies: - ms: "npm:2.1.2" - peerDependenciesMeta: - supports-color: - optional: true - checksum: 10c0/3cc408070bcee066ee9b2a4f3a9c40f53728919ec7c7ff568f7c3a75b0723cb5a8407191a63495be4e10669e99b0ff7f26ec70e10b025da1898cdce4876d96ca +"graceful-fs@npm:4.2.10, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4": + version: 4.2.10 + resolution: "graceful-fs@npm:4.2.10" + checksum: 10c0/4223a833e38e1d0d2aea630c2433cfb94ddc07dfc11d511dbd6be1d16688c5be848acc31f9a5d0d0ddbfb56d2ee5a6ae0278aceeb0ca6a13f27e06b9956fb952 languageName: node linkType: hard -"debug@npm:^3.1.0, debug@npm:^3.2.7": - version: 3.2.7 - resolution: "debug@npm:3.2.7" - dependencies: - ms: "npm:^2.1.1" - checksum: 10c0/37d96ae42cbc71c14844d2ae3ba55adf462ec89fd3a999459dec3833944cd999af6007ff29c780f1c61153bcaaf2c842d1e4ce1ec621e4fc4923244942e4a02a +"graceful-fs@npm:^4.2.6": + version: 4.2.11 + resolution: "graceful-fs@npm:4.2.11" + checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 languageName: node linkType: hard -"debug@npm:^4.3.2": - version: 4.3.4 - resolution: "debug@npm:4.3.4" +"handlebars@npm:^4.7.7": + version: 4.7.7 + resolution: "handlebars@npm:4.7.7" dependencies: - ms: "npm:2.1.2" - peerDependenciesMeta: - supports-color: + minimist: "npm:^1.2.5" + neo-async: "npm:^2.6.0" + source-map: "npm:^0.6.1" + uglify-js: "npm:^3.1.4" + wordwrap: "npm:^1.0.0" + dependenciesMeta: + uglify-js: optional: true - checksum: 10c0/cedbec45298dd5c501d01b92b119cd3faebe5438c3917ff11ae1bff86a6c722930ac9c8659792824013168ba6db7c4668225d845c633fbdafbbf902a6389f736 + bin: + handlebars: bin/handlebars + checksum: 10c0/4c0913fc0018a2a2e358ee94e4fe83f071762b8bec51a473d187e6642e94e569843adcf550ffe329554c63ad450c062f3a05447bd2e3fff5ebfe698e214225c6 languageName: node linkType: hard -"debug@npm:^4.3.4, debug@npm:^4.3.5": - version: 4.4.3 - resolution: "debug@npm:4.4.3" +"hardhat-contract-sizer@npm:^2.5.1": + version: 2.5.1 + resolution: "hardhat-contract-sizer@npm:2.5.1" dependencies: - ms: "npm:^2.1.3" - peerDependenciesMeta: - supports-color: - optional: true - checksum: 10c0/d79136ec6c83ecbefd0f6a5593da6a9c91ec4d7ddc4b54c883d6e71ec9accb5f67a1a5e96d00a328196b5b5c86d365e98d8a3a70856aaf16b4e7b1985e67f5a6 - languageName: node - linkType: hard - -"decamelize@npm:^1.1.1": - version: 1.2.0 - resolution: "decamelize@npm:1.2.0" - checksum: 10c0/85c39fe8fbf0482d4a1e224ef0119db5c1897f8503bcef8b826adff7a1b11414972f6fef2d7dec2ee0b4be3863cf64ac1439137ae9e6af23a3d8dcbe26a5b4b2 - languageName: node - linkType: hard - -"decamelize@npm:^4.0.0": - version: 4.0.0 - resolution: "decamelize@npm:4.0.0" - checksum: 10c0/e06da03fc05333e8cd2778c1487da67ffbea5b84e03ca80449519b8fa61f888714bbc6f459ea963d5641b4aa98832130eb5cd193d90ae9f0a27eee14be8e278d + chalk: "npm:^4.0.0" + cli-table3: "npm:^0.6.0" + peerDependencies: + hardhat: ^2.0.0 + checksum: 10c0/0bb1ff3496f96fcdc8a658db7b811be1155e70c9d31cc1d7afdd02b42b73e85182d7c5342a77f563696b73c22892094f9d10bc9158fbb8336195e0ddcf35fc79 languageName: node linkType: hard -"decode-uri-component@npm:^0.2.0": - version: 0.2.2 - resolution: "decode-uri-component@npm:0.2.2" - checksum: 10c0/1f4fa54eb740414a816b3f6c24818fbfcabd74ac478391e9f4e2282c994127db02010ce804f3d08e38255493cfe68608b3f5c8e09fd6efc4ae46c807691f7a31 +"hardhat-dependency-compiler@npm:^1.1.2": + version: 1.1.2 + resolution: "hardhat-dependency-compiler@npm:1.1.2" + peerDependencies: + hardhat: ^2.0.0 + checksum: 10c0/e300a8fcd1e520990c2798501e8aaa6ba8cf019e55ed393b6bc5466d68d4b89b9bfd1baaf493e990815dc3875e8808949df0bef95e46b9168c6788bf93c26461 languageName: node linkType: hard -"decompress-response@npm:^3.2.0, decompress-response@npm:^3.3.0": - version: 3.3.0 - resolution: "decompress-response@npm:3.3.0" +"hardhat-deploy@npm:^0.11.43": + version: 0.11.45 + resolution: "hardhat-deploy@npm:0.11.45" dependencies: - mimic-response: "npm:^1.0.0" - checksum: 10c0/5ffaf1d744277fd51c68c94ddc3081cd011b10b7de06637cccc6ecba137d45304a09ba1a776dee1c47fccc60b4a056c4bc74468eeea798ff1f1fca0024b45c9d + "@ethersproject/abi": "npm:^5.7.0" + "@ethersproject/abstract-signer": "npm:^5.7.0" + "@ethersproject/address": "npm:^5.7.0" + "@ethersproject/bignumber": "npm:^5.7.0" + "@ethersproject/bytes": "npm:^5.7.0" + "@ethersproject/constants": "npm:^5.7.0" + "@ethersproject/contracts": "npm:^5.7.0" + "@ethersproject/providers": "npm:^5.7.2" + "@ethersproject/solidity": "npm:^5.7.0" + "@ethersproject/transactions": "npm:^5.7.0" + "@ethersproject/wallet": "npm:^5.7.0" + "@types/qs": "npm:^6.9.7" + axios: "npm:^0.21.1" + chalk: "npm:^4.1.2" + chokidar: "npm:^3.5.2" + debug: "npm:^4.3.2" + enquirer: "npm:^2.3.6" + ethers: "npm:^5.7.0" + form-data: "npm:^4.0.0" + fs-extra: "npm:^10.0.0" + match-all: "npm:^1.2.6" + murmur-128: "npm:^0.2.1" + qs: "npm:^6.9.4" + zksync-web3: "npm:^0.14.3" + checksum: 10c0/6171ffccd46bb21954ebf2303a00d35d3793ad7216adaaf2d6e1836ec9387583a34e1640ff93e0d2d89e61cd3b06454f40cb11573463d86900eb24a940ce3682 languageName: node linkType: hard -"deep-eql@npm:^3.0.1": - version: 3.0.1 - resolution: "deep-eql@npm:3.0.1" +"hardhat-deploy@npm:^1.0.4": + version: 1.0.4 + resolution: "hardhat-deploy@npm:1.0.4" dependencies: - type-detect: "npm:^4.0.0" - checksum: 10c0/80b33c1c7713b3d5db89e6b5e9b22050f39c8a88e12a015616da8391e013988790d045a5c612b0c6dc43cc4bec51eadbe0fcf6075cc9717f8f56efdb305b6e6f + "@ethersproject/abi": "npm:^5.7.0" + "@ethersproject/abstract-signer": "npm:^5.7.0" + "@ethersproject/address": "npm:^5.7.0" + "@ethersproject/bignumber": "npm:^5.7.0" + "@ethersproject/bytes": "npm:^5.7.0" + "@ethersproject/constants": "npm:^5.7.0" + "@ethersproject/contracts": "npm:^5.7.0" + "@ethersproject/providers": "npm:^5.7.2" + "@ethersproject/solidity": "npm:^5.7.0" + "@ethersproject/transactions": "npm:^5.7.0" + "@ethersproject/wallet": "npm:^5.7.0" + axios: "npm:^0.21.1" + chalk: "npm:^4.1.2" + chokidar: "npm:^3.5.2" + debug: "npm:^4.3.2" + enquirer: "npm:^2.3.6" + ethers: "npm:^5.7.0" + form-data: "npm:^4.0.0" + fs-extra: "npm:^10.0.0" + match-all: "npm:^1.2.6" + murmur-128: "npm:^0.2.1" + neoqs: "npm:^6.13.0" + zksync-ethers: "npm:^5.0.0" + checksum: 10c0/21365c79ab169bf53ac8f10967de6ef2e962e8c9bdcba0a54f5424a1a953c6d2c1836136553d27b3b2db86aa708a9e7edde44abba768c40203ef5bc847c6a815 languageName: node linkType: hard -"deep-equal@npm:~1.1.1": - version: 1.1.1 - resolution: "deep-equal@npm:1.1.1" +"hardhat-gas-reporter@npm:^2.3.0": + version: 2.3.0 + resolution: "hardhat-gas-reporter@npm:2.3.0" dependencies: - is-arguments: "npm:^1.0.4" - is-date-object: "npm:^1.0.1" - is-regex: "npm:^1.0.4" - object-is: "npm:^1.0.1" - object-keys: "npm:^1.1.1" - regexp.prototype.flags: "npm:^1.2.0" - checksum: 10c0/473d5dd1d707afd5ad3068864765590591b049d0e0d9a01931599dbbd820e35f09d0a42faa6e4644deb7cf6b7dc90f7bfdf5559f42279d67f714209b62036212 - languageName: node - linkType: hard - -"deep-extend@npm:~0.6.0": - version: 0.6.0 - resolution: "deep-extend@npm:0.6.0" - checksum: 10c0/1c6b0abcdb901e13a44c7d699116d3d4279fdb261983122a3783e7273844d5f2537dc2e1c454a23fcf645917f93fbf8d07101c1d03c015a87faa662755212566 + "@ethersproject/abi": "npm:^5.7.0" + "@ethersproject/bytes": "npm:^5.7.0" + "@ethersproject/units": "npm:^5.7.0" + "@solidity-parser/parser": "npm:^0.20.1" + axios: "npm:^1.6.7" + brotli-wasm: "npm:^2.0.1" + chalk: "npm:4.1.2" + cli-table3: "npm:^0.6.3" + ethereum-cryptography: "npm:^2.1.3" + glob: "npm:^10.3.10" + jsonschema: "npm:^1.4.1" + lodash: "npm:^4.17.21" + markdown-table: "npm:2.0.0" + sha1: "npm:^1.1.1" + viem: "npm:^2.27.0" + peerDependencies: + hardhat: ^2.16.0 + checksum: 10c0/200ff3fb318de657e72e660526f41c692c4bb3a1b1a43414bd29c1737cf71d514258546bb7722abfad3c296a38e0c0d6e7239410beff4d26d6b529e0d6f94d62 languageName: node linkType: hard -"deep-is@npm:^0.1.3, deep-is@npm:~0.1.3": - version: 0.1.4 - resolution: "deep-is@npm:0.1.4" - checksum: 10c0/7f0ee496e0dff14a573dc6127f14c95061b448b87b995fc96c017ce0a1e66af1675e73f1d6064407975bc4ea6ab679497a29fff7b5b9c4e99cb10797c1ad0b4c - languageName: node - linkType: hard - -"deepmerge@npm:^4.2.2": - version: 4.2.2 - resolution: "deepmerge@npm:4.2.2" - checksum: 10c0/d6136eee869057fea7a829aa2d10073ed49db5216e42a77cc737dd385334aab9b68dae22020a00c24c073d5f79cbbdd3f11b8d4fc87700d112ddaa0e1f968ef2 - languageName: node - linkType: hard - -"defer-to-connect@npm:^1.0.1": - version: 1.1.3 - resolution: "defer-to-connect@npm:1.1.3" - checksum: 10c0/9feb161bd7d21836fdff31eba79c2b11b7aaf844be58faf727121f8b0d9c2e82b494560df0903f41b52dd75027dc7c9455c11b3739f3202b28ca92b56c8f960e - languageName: node - linkType: hard - -"deferred-leveldown@npm:~1.2.1": - version: 1.2.2 - resolution: "deferred-leveldown@npm:1.2.2" - dependencies: - abstract-leveldown: "npm:~2.6.0" - checksum: 10c0/5b0c2c1c8c13b71237a90a30ed6f60afcebeea18c99f3269d75ada92403e8089f42f2c1b891f8a5b96da1216806c28a4ea65d634ea86cf98368d46b27d9002d2 - languageName: node - linkType: hard - -"deferred-leveldown@npm:~4.0.0": - version: 4.0.2 - resolution: "deferred-leveldown@npm:4.0.2" - dependencies: - abstract-leveldown: "npm:~5.0.0" - inherits: "npm:^2.0.3" - checksum: 10c0/316156e2475b64fc286c35c1f9fae2f278889b098e840cb948a6da4946b87220fb8f448879f2318e8806e34c6f510e1320f0bd6d143c5a79f4b85be28ef77e46 - languageName: node - linkType: hard - -"define-properties@npm:^1.1.3": - version: 1.1.3 - resolution: "define-properties@npm:1.1.3" - dependencies: - object-keys: "npm:^1.0.12" - checksum: 10c0/a2fa03d97ee44bb7c679bac7c3b3e63431a2efd83c12c0d61c7f5adf4fa1cf0a669c77afd274babbc5400926bdc2befb25679e4bf687140b078c0fe14f782e4f - languageName: node - linkType: hard - -"define-property@npm:^0.2.5": - version: 0.2.5 - resolution: "define-property@npm:0.2.5" - dependencies: - is-descriptor: "npm:^0.1.0" - checksum: 10c0/9986915c0893818dedc9ca23eaf41370667762fd83ad8aa4bf026a28563120dbaacebdfbfbf2b18d3b929026b9c6ee972df1dbf22de8fafb5fe6ef18361e4750 - languageName: node - linkType: hard - -"define-property@npm:^1.0.0": - version: 1.0.0 - resolution: "define-property@npm:1.0.0" - dependencies: - is-descriptor: "npm:^1.0.0" - checksum: 10c0/d7cf09db10d55df305f541694ed51dafc776ad9bb8a24428899c9f2d36b11ab38dce5527a81458d1b5e7c389f8cbe803b4abad6e91a0037a329d153b84fc975e - languageName: node - linkType: hard - -"define-property@npm:^2.0.2": - version: 2.0.2 - resolution: "define-property@npm:2.0.2" - dependencies: - is-descriptor: "npm:^1.0.2" - isobject: "npm:^3.0.1" - checksum: 10c0/f91a08ad008fa764172a2c072adc7312f10217ade89ddaea23018321c6d71b2b68b8c229141ed2064179404e345c537f1a2457c379824813695b51a6ad3e4969 - languageName: node - linkType: hard - -"defined@npm:~1.0.0": - version: 1.0.0 - resolution: "defined@npm:1.0.0" - checksum: 10c0/2b9929414857729a97cfcc77987e65005e03b3fd92747e1d6a743b054c1387b62e669dc453b53e3a8105f1398df6aad54c07eed984871c93be8c7f4560a1828b - languageName: node - linkType: hard - -"delayed-stream@npm:~1.0.0": - version: 1.0.0 - resolution: "delayed-stream@npm:1.0.0" - checksum: 10c0/d758899da03392e6712f042bec80aa293bbe9e9ff1b2634baae6a360113e708b91326594c8a486d475c69d6259afb7efacdc3537bfcda1c6c648e390ce601b19 - languageName: node - linkType: hard - -"depd@npm:2.0.0": - version: 2.0.0 - resolution: "depd@npm:2.0.0" - checksum: 10c0/58bd06ec20e19529b06f7ad07ddab60e504d9e0faca4bd23079fac2d279c3594334d736508dc350e06e510aba5e22e4594483b3a6562ce7c17dd797f4cc4ad2c - languageName: node - linkType: hard - -"depd@npm:~1.1.2": - version: 1.1.2 - resolution: "depd@npm:1.1.2" - checksum: 10c0/acb24aaf936ef9a227b6be6d495f0d2eb20108a9a6ad40585c5bda1a897031512fef6484e4fdbb80bd249fdaa82841fa1039f416ece03188e677ba11bcfda249 - languageName: node - linkType: hard - -"des.js@npm:^1.0.0": - version: 1.0.1 - resolution: "des.js@npm:1.0.1" - dependencies: - inherits: "npm:^2.0.1" - minimalistic-assert: "npm:^1.0.0" - checksum: 10c0/69bf742d1c381e01d75151bdcaac71a18d251d7debfc9b6ae5ee4b4edaf39691ae203c5ec9173ba89aedb3ddc622cdff4fca065448c6c2afb1140d9fb826339d - languageName: node - linkType: hard - -"destroy@npm:1.2.0": - version: 1.2.0 - resolution: "destroy@npm:1.2.0" - checksum: 10c0/bd7633942f57418f5a3b80d5cb53898127bcf53e24cdf5d5f4396be471417671f0fee48a4ebe9a1e9defbde2a31280011af58a57e090ff822f589b443ed4e643 - languageName: node - linkType: hard - -"detect-indent@npm:^4.0.0": - version: 4.0.0 - resolution: "detect-indent@npm:4.0.0" - dependencies: - repeating: "npm:^2.0.0" - checksum: 10c0/066a0d13eadebb1e7d2ba395fdf9f3956f31f8383a6db263320108c283e2230250a102f4871f54926cc8a77c6323ac7103f30550a4ac3d6518aa1b934c041295 - languageName: node - linkType: hard - -"diff@npm:^4.0.1": - version: 4.0.2 - resolution: "diff@npm:4.0.2" - checksum: 10c0/81b91f9d39c4eaca068eb0c1eb0e4afbdc5bb2941d197f513dd596b820b956fef43485876226d65d497bebc15666aa2aa82c679e84f65d5f2bfbf14ee46e32c1 - languageName: node - linkType: hard - -"diff@npm:^7.0.0": - version: 7.0.0 - resolution: "diff@npm:7.0.0" - checksum: 10c0/251fd15f85ffdf814cfc35a728d526b8d2ad3de338dcbd011ac6e57c461417090766b28995f8ff733135b5fbc3699c392db1d5e27711ac4e00244768cd1d577b - languageName: node - linkType: hard - -"diffie-hellman@npm:^5.0.0": - version: 5.0.3 - resolution: "diffie-hellman@npm:5.0.3" - dependencies: - bn.js: "npm:^4.1.0" - miller-rabin: "npm:^4.0.0" - randombytes: "npm:^2.0.0" - checksum: 10c0/ce53ccafa9ca544b7fc29b08a626e23a9b6562efc2a98559a0c97b4718937cebaa9b5d7d0a05032cc9c1435e9b3c1532b9e9bf2e0ede868525922807ad6e1ecf - languageName: node - linkType: hard - -"dir-glob@npm:^3.0.1": - version: 3.0.1 - resolution: "dir-glob@npm:3.0.1" - dependencies: - path-type: "npm:^4.0.0" - checksum: 10c0/dcac00920a4d503e38bb64001acb19df4efc14536ada475725e12f52c16777afdee4db827f55f13a908ee7efc0cb282e2e3dbaeeb98c0993dd93d1802d3bf00c - languageName: node - linkType: hard - -"doctrine@npm:^2.1.0": - version: 2.1.0 - resolution: "doctrine@npm:2.1.0" - dependencies: - esutils: "npm:^2.0.2" - checksum: 10c0/b6416aaff1f380bf56c3b552f31fdf7a69b45689368deca72d28636f41c16bb28ec3ebc40ace97db4c1afc0ceeb8120e8492fe0046841c94c2933b2e30a7d5ac - languageName: node - linkType: hard - -"doctrine@npm:^3.0.0": - version: 3.0.0 - resolution: "doctrine@npm:3.0.0" - dependencies: - esutils: "npm:^2.0.2" - checksum: 10c0/c96bdccabe9d62ab6fea9399fdff04a66e6563c1d6fb3a3a063e8d53c3bb136ba63e84250bbf63d00086a769ad53aef92d2bd483f03f837fc97b71cbee6b2520 - languageName: node - linkType: hard - -"dom-walk@npm:^0.1.0": - version: 0.1.2 - resolution: "dom-walk@npm:0.1.2" - checksum: 10c0/4d2ad9062a9423d890f8577aa202b597a6b85f9489bdde656b9443901b8b322b289655c3affefc58ec2e41931e0828dfee0a1d2db6829a607d76def5901fc5a9 - languageName: node - linkType: hard - -"dotignore@npm:~0.1.2": - version: 0.1.2 - resolution: "dotignore@npm:0.1.2" - dependencies: - minimatch: "npm:^3.0.4" - bin: - ignored: bin/ignored - checksum: 10c0/71f25a507cbe88a7dbf07d5108bb0924af39c71a3c5fd83045fc42d5dc1605a23113ba29999b94d964555e6e6be2980caa8da3711cfa31a6b6d88c184b1ab181 - languageName: node - linkType: hard - -"dunder-proto@npm:^1.0.1": - version: 1.0.1 - resolution: "dunder-proto@npm:1.0.1" - dependencies: - call-bind-apply-helpers: "npm:^1.0.1" - es-errors: "npm:^1.3.0" - gopd: "npm:^1.2.0" - checksum: 10c0/199f2a0c1c16593ca0a145dbf76a962f8033ce3129f01284d48c45ed4e14fea9bbacd7b3610b6cdc33486cef20385ac054948fefc6272fcce645c09468f93031 - languageName: node - linkType: hard - -"duplexer3@npm:^0.1.4": - version: 0.1.5 - resolution: "duplexer3@npm:0.1.5" - checksum: 10c0/02195030d61c4d6a2a34eca71639f2ea5e05cb963490e5bd9527623c2ac7f50c33842a34d14777ea9cbfd9bc2be5a84065560b897d9fabb99346058a5b86ca98 - languageName: node - linkType: hard - -"eastasianwidth@npm:^0.2.0": - version: 0.2.0 - resolution: "eastasianwidth@npm:0.2.0" - checksum: 10c0/26f364ebcdb6395f95124fda411f63137a4bfb5d3a06453f7f23dfe52502905bd84e0488172e0f9ec295fdc45f05c23d5d91baf16bd26f0fe9acd777a188dc39 - languageName: node - linkType: hard - -"ecc-jsbn@npm:~0.1.1": - version: 0.1.2 - resolution: "ecc-jsbn@npm:0.1.2" - dependencies: - jsbn: "npm:~0.1.0" - safer-buffer: "npm:^2.1.0" - checksum: 10c0/6cf168bae1e2dad2e46561d9af9cbabfbf5ff592176ad4e9f0f41eaaf5fe5e10bb58147fe0a804de62b1ee9dad42c28810c88d652b21b6013c47ba8efa274ca1 - languageName: node - linkType: hard - -"ee-first@npm:1.1.1": - version: 1.1.1 - resolution: "ee-first@npm:1.1.1" - checksum: 10c0/b5bb125ee93161bc16bfe6e56c6b04de5ad2aa44234d8f644813cc95d861a6910903132b05093706de2b706599367c4130eb6d170f6b46895686b95f87d017b7 - languageName: node - linkType: hard - -"electron-to-chromium@npm:^1.3.47": - version: 1.3.859 - resolution: "electron-to-chromium@npm:1.3.859" - checksum: 10c0/c81c754f75ccb55a9ba0829fc79b97fc92c4a275e8e767a06c1cb281b4824a1c42321e5035d1c9efe54b6adb40ccefebe773f544dc0a7133c25407aa0d7697bf - languageName: node - linkType: hard - -"elliptic@npm:6.5.4, elliptic@npm:^6.4.0, elliptic@npm:^6.5.2, elliptic@npm:^6.5.3, elliptic@npm:^6.5.4": - version: 6.5.4 - resolution: "elliptic@npm:6.5.4" - dependencies: - bn.js: "npm:^4.11.9" - brorand: "npm:^1.1.0" - hash.js: "npm:^1.0.0" - hmac-drbg: "npm:^1.0.1" - inherits: "npm:^2.0.4" - minimalistic-assert: "npm:^1.0.1" - minimalistic-crypto-utils: "npm:^1.0.1" - checksum: 10c0/5f361270292c3b27cf0843e84526d11dec31652f03c2763c6c2b8178548175ff5eba95341dd62baff92b2265d1af076526915d8af6cc9cb7559c44a62f8ca6e2 - languageName: node - linkType: hard - -"emoji-regex@npm:^7.0.1": - version: 7.0.3 - resolution: "emoji-regex@npm:7.0.3" - checksum: 10c0/a8917d695c3a3384e4b7230a6a06fd2de6b3db3709116792e8b7b36ddbb3db4deb28ad3e983e70d4f2a1f9063b5dab9025e4e26e9ca08278da4fbb73e213743f - languageName: node - linkType: hard - -"emoji-regex@npm:^8.0.0": - version: 8.0.0 - resolution: "emoji-regex@npm:8.0.0" - checksum: 10c0/b6053ad39951c4cf338f9092d7bfba448cdfd46fe6a2a034700b149ac9ffbc137e361cbd3c442297f86bed2e5f7576c1b54cc0a6bf8ef5106cc62f496af35010 - languageName: node - linkType: hard - -"emoji-regex@npm:^9.0.0, emoji-regex@npm:^9.2.2": - version: 9.2.2 - resolution: "emoji-regex@npm:9.2.2" - checksum: 10c0/af014e759a72064cf66e6e694a7fc6b0ed3d8db680427b021a89727689671cefe9d04151b2cad51dbaf85d5ba790d061cd167f1cf32eb7b281f6368b3c181639 - languageName: node - linkType: hard - -"encode-utf8@npm:^1.0.2": - version: 1.0.3 - resolution: "encode-utf8@npm:1.0.3" - checksum: 10c0/6b3458b73e868113d31099d7508514a5c627d8e16d1e0542d1b4e3652299b8f1f590c468e2b9dcdf1b4021ee961f31839d0be9d70a7f2a8a043c63b63c9b3a88 - languageName: node - linkType: hard - -"encodeurl@npm:~1.0.2": - version: 1.0.2 - resolution: "encodeurl@npm:1.0.2" - checksum: 10c0/f6c2387379a9e7c1156c1c3d4f9cb7bb11cf16dd4c1682e1f6746512564b053df5781029b6061296832b59fb22f459dbe250386d217c2f6e203601abb2ee0bec - languageName: node - linkType: hard - -"encoding-down@npm:5.0.4, encoding-down@npm:~5.0.0": - version: 5.0.4 - resolution: "encoding-down@npm:5.0.4" - dependencies: - abstract-leveldown: "npm:^5.0.0" - inherits: "npm:^2.0.3" - level-codec: "npm:^9.0.0" - level-errors: "npm:^2.0.0" - xtend: "npm:^4.0.1" - checksum: 10c0/7b2c27cae01672ca587795b4ef300e32a78fd0494462b34342683ae1abc86a3412d56d00a7339c0003c771a0bb3e197326bb353692558097c793833355962f71 - languageName: node - linkType: hard - -"encoding@npm:^0.1.11": - version: 0.1.13 - resolution: "encoding@npm:0.1.13" - dependencies: - iconv-lite: "npm:^0.6.2" - checksum: 10c0/36d938712ff00fe1f4bac88b43bcffb5930c1efa57bbcdca9d67e1d9d6c57cfb1200fb01efe0f3109b2ce99b231f90779532814a81370a1bd3274a0f58585039 - languageName: node - linkType: hard - -"end-of-stream@npm:^1.1.0": - version: 1.4.4 - resolution: "end-of-stream@npm:1.4.4" - dependencies: - once: "npm:^1.4.0" - checksum: 10c0/870b423afb2d54bb8d243c63e07c170409d41e20b47eeef0727547aea5740bd6717aca45597a9f2745525667a6b804c1e7bede41f856818faee5806dd9ff3975 - languageName: node - linkType: hard - -"enquirer@npm:^2.3.0, enquirer@npm:^2.3.5, enquirer@npm:^2.3.6": - version: 2.3.6 - resolution: "enquirer@npm:2.3.6" - dependencies: - ansi-colors: "npm:^4.1.1" - checksum: 10c0/8e070e052c2c64326a2803db9084d21c8aaa8c688327f133bf65c4a712586beb126fd98c8a01cfb0433e82a4bd3b6262705c55a63e0f7fb91d06b9cedbde9a11 - languageName: node - linkType: hard - -"env-paths@npm:^2.2.0": - version: 2.2.1 - resolution: "env-paths@npm:2.2.1" - checksum: 10c0/285325677bf00e30845e330eec32894f5105529db97496ee3f598478e50f008c5352a41a30e5e72ec9de8a542b5a570b85699cd63bd2bc646dbcb9f311d83bc4 - languageName: node - linkType: hard - -"errno@npm:~0.1.1": - version: 0.1.8 - resolution: "errno@npm:0.1.8" - dependencies: - prr: "npm:~1.0.1" - bin: - errno: cli.js - checksum: 10c0/83758951967ec57bf00b5f5b7dc797e6d65a6171e57ea57adcf1bd1a0b477fd9b5b35fae5be1ff18f4090ed156bce1db749fe7e317aac19d485a5d150f6a4936 - languageName: node - linkType: hard - -"error-ex@npm:^1.2.0, error-ex@npm:^1.3.1": - version: 1.3.2 - resolution: "error-ex@npm:1.3.2" - dependencies: - is-arrayish: "npm:^0.2.1" - checksum: 10c0/ba827f89369b4c93382cfca5a264d059dfefdaa56ecc5e338ffa58a6471f5ed93b71a20add1d52290a4873d92381174382658c885ac1a2305f7baca363ce9cce - languageName: node - linkType: hard - -"es-abstract@npm:^1.19.0, es-abstract@npm:^1.19.1": - version: 1.19.1 - resolution: "es-abstract@npm:1.19.1" - dependencies: - call-bind: "npm:^1.0.2" - es-to-primitive: "npm:^1.2.1" - function-bind: "npm:^1.1.1" - get-intrinsic: "npm:^1.1.1" - get-symbol-description: "npm:^1.0.0" - has: "npm:^1.0.3" - has-symbols: "npm:^1.0.2" - internal-slot: "npm:^1.0.3" - is-callable: "npm:^1.2.4" - is-negative-zero: "npm:^2.0.1" - is-regex: "npm:^1.1.4" - is-shared-array-buffer: "npm:^1.0.1" - is-string: "npm:^1.0.7" - is-weakref: "npm:^1.0.1" - object-inspect: "npm:^1.11.0" - object-keys: "npm:^1.1.1" - object.assign: "npm:^4.1.2" - string.prototype.trimend: "npm:^1.0.4" - string.prototype.trimstart: "npm:^1.0.4" - unbox-primitive: "npm:^1.0.1" - checksum: 10c0/24ed66dfa682f1bbcfa70cd95581c29a6ba88baf579619bff5690ac383b8612f3f5fcebf30dec8df634d507b633ef1ed9f09b010b07e17e3975d4ce674e3059c - languageName: node - linkType: hard - -"es-define-property@npm:^1.0.1": - version: 1.0.1 - resolution: "es-define-property@npm:1.0.1" - checksum: 10c0/3f54eb49c16c18707949ff25a1456728c883e81259f045003499efba399c08bad00deebf65cccde8c0e07908c1a225c9d472b7107e558f2a48e28d530e34527c - languageName: node - linkType: hard - -"es-errors@npm:^1.3.0": - version: 1.3.0 - resolution: "es-errors@npm:1.3.0" - checksum: 10c0/0a61325670072f98d8ae3b914edab3559b6caa980f08054a3b872052640d91da01d38df55df797fcc916389d77fc92b8d5906cf028f4db46d7e3003abecbca85 - languageName: node - linkType: hard - -"es-object-atoms@npm:^1.0.0, es-object-atoms@npm:^1.1.1": - version: 1.1.2 - resolution: "es-object-atoms@npm:1.1.2" - dependencies: - es-errors: "npm:^1.3.0" - checksum: 10c0/1772861f094f739d6f41b579cfb9a18579daffeb434552a370a5fbef50a32d22227e27b63fdbb757b7ddd429d1b42fe52ccae7966d9302a2ec221b6f1b41bbc4 - languageName: node - linkType: hard - -"es-set-tostringtag@npm:^2.1.0": - version: 2.1.0 - resolution: "es-set-tostringtag@npm:2.1.0" - dependencies: - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.6" - has-tostringtag: "npm:^1.0.2" - hasown: "npm:^2.0.2" - checksum: 10c0/ef2ca9ce49afe3931cb32e35da4dcb6d86ab02592cfc2ce3e49ced199d9d0bb5085fc7e73e06312213765f5efa47cc1df553a6a5154584b21448e9fb8355b1af - languageName: node - linkType: hard - -"es-to-primitive@npm:^1.2.1": - version: 1.2.1 - resolution: "es-to-primitive@npm:1.2.1" - dependencies: - is-callable: "npm:^1.1.4" - is-date-object: "npm:^1.0.1" - is-symbol: "npm:^1.0.2" - checksum: 10c0/0886572b8dc075cb10e50c0af62a03d03a68e1e69c388bd4f10c0649ee41b1fbb24840a1b7e590b393011b5cdbe0144b776da316762653685432df37d6de60f1 - languageName: node - linkType: hard - -"es5-ext@npm:^0.10.35, es5-ext@npm:^0.10.50": - version: 0.10.62 - resolution: "es5-ext@npm:0.10.62" - dependencies: - es6-iterator: "npm:^2.0.3" - es6-symbol: "npm:^3.1.3" - next-tick: "npm:^1.1.0" - checksum: 10c0/72dfbec5e4bce24754be9f2c2a1c67c01de3fe000103c115f52891f6a51f44a59674c40a1f6bd2390fcd43987746dccb76efafea91c7bb6295bdca8d63ba3db4 - languageName: node - linkType: hard - -"es6-iterator@npm:^2.0.3": - version: 2.0.3 - resolution: "es6-iterator@npm:2.0.3" - dependencies: - d: "npm:1" - es5-ext: "npm:^0.10.35" - es6-symbol: "npm:^3.1.1" - checksum: 10c0/91f20b799dba28fb05bf623c31857fc1524a0f1c444903beccaf8929ad196c8c9ded233e5ac7214fc63a92b3f25b64b7f2737fcca8b1f92d2d96cf3ac902f5d8 - languageName: node - linkType: hard - -"es6-symbol@npm:^3.1.1, es6-symbol@npm:^3.1.3": - version: 3.1.3 - resolution: "es6-symbol@npm:3.1.3" - dependencies: - d: "npm:^1.0.1" - ext: "npm:^1.1.2" - checksum: 10c0/22982f815f00df553a89f4fb74c5048fed85df598482b4bd38dbd173174247949c72982a7d7132a58b147525398400e5f182db59b0916cb49f1e245fb0e22233 - languageName: node - linkType: hard - -"escalade@npm:^3.1.1": - version: 3.1.1 - resolution: "escalade@npm:3.1.1" - checksum: 10c0/afd02e6ca91ffa813e1108b5e7756566173d6bc0d1eb951cb44d6b21702ec17c1cf116cfe75d4a2b02e05acb0b808a7a9387d0d1ca5cf9c04ad03a8445c3e46d - languageName: node - linkType: hard - -"escape-html@npm:~1.0.3": - version: 1.0.3 - resolution: "escape-html@npm:1.0.3" - checksum: 10c0/524c739d776b36c3d29fa08a22e03e8824e3b2fd57500e5e44ecf3cc4707c34c60f9ca0781c0e33d191f2991161504c295e98f68c78fe7baa6e57081ec6ac0a3 - languageName: node - linkType: hard - -"escape-string-regexp@npm:^1.0.2, escape-string-regexp@npm:^1.0.5": - version: 1.0.5 - resolution: "escape-string-regexp@npm:1.0.5" - checksum: 10c0/a968ad453dd0c2724e14a4f20e177aaf32bb384ab41b674a8454afe9a41c5e6fe8903323e0a1052f56289d04bd600f81278edf140b0fcc02f5cac98d0f5b5371 - languageName: node - linkType: hard - -"escape-string-regexp@npm:^4.0.0": - version: 4.0.0 - resolution: "escape-string-regexp@npm:4.0.0" - checksum: 10c0/9497d4dd307d845bd7f75180d8188bb17ea8c151c1edbf6b6717c100e104d629dc2dfb687686181b0f4b7d732c7dfdc4d5e7a8ff72de1b0ca283a75bbb3a9cd9 - languageName: node - linkType: hard - -"eslint-config-airbnb-base@npm:^14.2.1": - version: 14.2.1 - resolution: "eslint-config-airbnb-base@npm:14.2.1" - dependencies: - confusing-browser-globals: "npm:^1.0.10" - object.assign: "npm:^4.1.2" - object.entries: "npm:^1.1.2" - peerDependencies: - eslint: ^5.16.0 || ^6.8.0 || ^7.2.0 - eslint-plugin-import: ^2.22.1 - checksum: 10c0/960654ae93f085800850ba5d54d745e576fb1c9e1fe46d0a64086586a1a6a78753ce6990b46c5543c35ba00ba4aee9018e4d3d3307dba8a0bf864a6ac803de16 - languageName: node - linkType: hard - -"eslint-config-airbnb-typescript@npm:^14.0.0": - version: 14.0.0 - resolution: "eslint-config-airbnb-typescript@npm:14.0.0" - peerDependencies: - "@typescript-eslint/eslint-plugin": ^4.29.3 - "@typescript-eslint/parser": ^4.29.3 - checksum: 10c0/0dba5e65a6920519b7f76dd123ad927ef5f34522e414ee8123a425da3a9b63d6ab1afa6d559a5ecfb0b1140c4a7aeefd6638b59e1254ac8ae0772d0607aa532c - languageName: node - linkType: hard - -"eslint-config-airbnb@npm:^18.2.1": - version: 18.2.1 - resolution: "eslint-config-airbnb@npm:18.2.1" - dependencies: - eslint-config-airbnb-base: "npm:^14.2.1" - object.assign: "npm:^4.1.2" - object.entries: "npm:^1.1.2" - peerDependencies: - eslint: ^5.16.0 || ^6.8.0 || ^7.2.0 - eslint-plugin-import: ^2.22.1 - eslint-plugin-jsx-a11y: ^6.4.1 - eslint-plugin-react: ^7.21.5 - eslint-plugin-react-hooks: ^4 || ^3 || ^2.3.0 || ^1.7.0 - checksum: 10c0/236ce3faf1c43079b441c8c5fe530d42f000d5abd9f5e55f0b7e559fcbe60f01b908a18977b0df6fdb9acd14961422fbf5e8c0734ffa380dea0dcd5dce78b8d2 - languageName: node - linkType: hard - -"eslint-config-prettier@npm:^8.3.0": - version: 8.3.0 - resolution: "eslint-config-prettier@npm:8.3.0" - peerDependencies: - eslint: ">=7.0.0" - bin: - eslint-config-prettier: bin/cli.js - checksum: 10c0/0d6bd272a05045f2815f0aba4592633a7226713d716d1a4c21126bbdbde27c98e7a6e2a8227e03fae343b40caf8c06a87e7ce87e69851279cf10334b6f36f7bc - languageName: node - linkType: hard - -"eslint-import-resolver-node@npm:^0.3.6": - version: 0.3.6 - resolution: "eslint-import-resolver-node@npm:0.3.6" - dependencies: - debug: "npm:^3.2.7" - resolve: "npm:^1.20.0" - checksum: 10c0/20e06f3fa27b49de7159c8db54b4d7f82c156498e0050c491fcf7395922f927765b8296bf857c3b487da361bd65c1dcc68203832ef8e9179b461aa4192406535 - languageName: node - linkType: hard - -"eslint-module-utils@npm:^2.6.2": - version: 2.6.2 - resolution: "eslint-module-utils@npm:2.6.2" - dependencies: - debug: "npm:^3.2.7" - pkg-dir: "npm:^2.0.0" - checksum: 10c0/808c817c6394a507f23ad75c96d4033ba0ab91c9feb8dc07d6b8b673d19f5c9994453266780a9606a18989d9d628b6426dd1a77ef93f3a7deb63c9a97f2e7bc1 - languageName: node - linkType: hard - -"eslint-plugin-import@npm:^2.23.4": - version: 2.24.2 - resolution: "eslint-plugin-import@npm:2.24.2" - dependencies: - array-includes: "npm:^3.1.3" - array.prototype.flat: "npm:^1.2.4" - debug: "npm:^2.6.9" - doctrine: "npm:^2.1.0" - eslint-import-resolver-node: "npm:^0.3.6" - eslint-module-utils: "npm:^2.6.2" - find-up: "npm:^2.0.0" - has: "npm:^1.0.3" - is-core-module: "npm:^2.6.0" - minimatch: "npm:^3.0.4" - object.values: "npm:^1.1.4" - pkg-up: "npm:^2.0.0" - read-pkg-up: "npm:^3.0.0" - resolve: "npm:^1.20.0" - tsconfig-paths: "npm:^3.11.0" - peerDependencies: - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 - checksum: 10c0/ba13337759b0d97566eb0363a704e40c856e86ec4e7d3dbd9dd5e50d7d9cab606162907272b443cdf9da4289efd1cfdc73218eb166f11a8604cf491529d08906 - languageName: node - linkType: hard - -"eslint-plugin-jsx-a11y@npm:^6.4.1": - version: 6.4.1 - resolution: "eslint-plugin-jsx-a11y@npm:6.4.1" - dependencies: - "@babel/runtime": "npm:^7.11.2" - aria-query: "npm:^4.2.2" - array-includes: "npm:^3.1.1" - ast-types-flow: "npm:^0.0.7" - axe-core: "npm:^4.0.2" - axobject-query: "npm:^2.2.0" - damerau-levenshtein: "npm:^1.0.6" - emoji-regex: "npm:^9.0.0" - has: "npm:^1.0.3" - jsx-ast-utils: "npm:^3.1.0" - language-tags: "npm:^1.0.5" - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 - checksum: 10c0/04aa10e995bb37fffba1b28d83202f520df21f895dfcd3a01cf156bd1a47cdf06bb5d19b32bb8f5b610ec162f2bff10c694e8082b80b565783feea49591b446b - languageName: node - linkType: hard - -"eslint-plugin-no-only-tests@npm:^2.6.0": - version: 2.6.0 - resolution: "eslint-plugin-no-only-tests@npm:2.6.0" - checksum: 10c0/23e0a65f7483fac71073535a12567dab1a32fa2fb1e993cac60bbb93409f669ee98a2a296c3a4f862aefa76850a1576c17511cb21e6e2470a58a8c6f9b6f3043 - languageName: node - linkType: hard - -"eslint-plugin-prettier@npm:^4.0.0": - version: 4.0.0 - resolution: "eslint-plugin-prettier@npm:4.0.0" - dependencies: - prettier-linter-helpers: "npm:^1.0.0" - peerDependencies: - eslint: ">=7.28.0" - prettier: ">=2.0.0" - peerDependenciesMeta: - eslint-config-prettier: - optional: true - checksum: 10c0/90248c927ed3b6702d329ad42577880c968064792292fa7b580143c79e44fecfc68c3553cc34471baa8bc2b3ece50686f7b7b2243e0684f9cdd1b4f42316e576 - languageName: node - linkType: hard - -"eslint-plugin-react-hooks@npm:^4.2.0": - version: 4.2.0 - resolution: "eslint-plugin-react-hooks@npm:4.2.0" - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - checksum: 10c0/981f6fc09a2cad298574eeab265e9c7de672dc975f7c249ef8079bdcf491241ecce02a45897c0e561a277d63762c80c7319a182492a544a9c61e9c25569e9f51 - languageName: node - linkType: hard - -"eslint-plugin-react@npm:^7.25.2": - version: 7.26.1 - resolution: "eslint-plugin-react@npm:7.26.1" - dependencies: - array-includes: "npm:^3.1.3" - array.prototype.flatmap: "npm:^1.2.4" - doctrine: "npm:^2.1.0" - estraverse: "npm:^5.2.0" - jsx-ast-utils: "npm:^2.4.1 || ^3.0.0" - minimatch: "npm:^3.0.4" - object.entries: "npm:^1.1.4" - object.fromentries: "npm:^2.0.4" - object.hasown: "npm:^1.0.0" - object.values: "npm:^1.1.4" - prop-types: "npm:^15.7.2" - resolve: "npm:^2.0.0-next.3" - semver: "npm:^6.3.0" - string.prototype.matchall: "npm:^4.0.5" - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 - checksum: 10c0/a14a98135d4f7926787c30461f396dc6a7912f2551142be7b675229c7abe032b183d1d4bbdcbb92ed2c0f7cf5595c9ab87d2fe64b4c5e4aa5d7a6fe3d85c0886 - languageName: node - linkType: hard - -"eslint-scope@npm:^4.0.3": - version: 4.0.3 - resolution: "eslint-scope@npm:4.0.3" - dependencies: - esrecurse: "npm:^4.1.0" - estraverse: "npm:^4.1.1" - checksum: 10c0/a2a3fe5845938ce7cfd2e658c309a9bb27a7f9ce94f0cc447ed5f9fa95b16451556d7e1db4c8e5d2aaa02d02850f5346d23091bbe94f7097412ce846504b4dcc - languageName: node - linkType: hard - -"eslint-scope@npm:^5.1.1": - version: 5.1.1 - resolution: "eslint-scope@npm:5.1.1" - dependencies: - esrecurse: "npm:^4.3.0" - estraverse: "npm:^4.1.1" - checksum: 10c0/d30ef9dc1c1cbdece34db1539a4933fe3f9b14e1ffb27ecc85987902ee663ad7c9473bbd49a9a03195a373741e62e2f807c4938992e019b511993d163450e70a - languageName: node - linkType: hard - -"eslint-utils@npm:^1.3.1": - version: 1.4.3 - resolution: "eslint-utils@npm:1.4.3" - dependencies: - eslint-visitor-keys: "npm:^1.1.0" - checksum: 10c0/ba19a817177d5fc54ae89cd80ecc8bc24eefd640bd8b0db204f29dc79cf9621bb42d68bf31eae6c89ca1f52d748b6583214f57288f9a78d2bd368a2340abe41c - languageName: node - linkType: hard - -"eslint-utils@npm:^2.1.0": - version: 2.1.0 - resolution: "eslint-utils@npm:2.1.0" - dependencies: - eslint-visitor-keys: "npm:^1.1.0" - checksum: 10c0/69521c5d6569384b24093125d037ba238d3d6e54367f7143af9928f5286369e912c26cad5016d730c0ffb9797ac9e83831059d7f1d863f7dc84330eb02414611 - languageName: node - linkType: hard - -"eslint-utils@npm:^3.0.0": - version: 3.0.0 - resolution: "eslint-utils@npm:3.0.0" - dependencies: - eslint-visitor-keys: "npm:^2.0.0" - peerDependencies: - eslint: ">=5" - checksum: 10c0/45aa2b63667a8d9b474c98c28af908d0a592bed1a4568f3145cd49fb5d9510f545327ec95561625290313fe126e6d7bdfe3fdbdb6f432689fab6b9497d3bfb52 - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^1.0.0, eslint-visitor-keys@npm:^1.1.0, eslint-visitor-keys@npm:^1.3.0": - version: 1.3.0 - resolution: "eslint-visitor-keys@npm:1.3.0" - checksum: 10c0/10c91fdbbe36810dd4308e57f9a8bc7177188b2a70247e54e3af1fa05ebc66414ae6fd4ce3c6c6821591f43a556e9037bc6b071122e099b5f8b7d2f76df553e3 - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^2.0.0": - version: 2.1.0 - resolution: "eslint-visitor-keys@npm:2.1.0" - checksum: 10c0/9f0e3a2db751d84067d15977ac4b4472efd6b303e369e6ff241a99feac04da758f46d5add022c33d06b53596038dbae4b4aceb27c7e68b8dfc1055b35e495787 - languageName: node - linkType: hard - -"eslint@npm:^5.6.0": - version: 5.16.0 - resolution: "eslint@npm:5.16.0" - dependencies: - "@babel/code-frame": "npm:^7.0.0" - ajv: "npm:^6.9.1" - chalk: "npm:^2.1.0" - cross-spawn: "npm:^6.0.5" - debug: "npm:^4.0.1" - doctrine: "npm:^3.0.0" - eslint-scope: "npm:^4.0.3" - eslint-utils: "npm:^1.3.1" - eslint-visitor-keys: "npm:^1.0.0" - espree: "npm:^5.0.1" - esquery: "npm:^1.0.1" - esutils: "npm:^2.0.2" - file-entry-cache: "npm:^5.0.1" - functional-red-black-tree: "npm:^1.0.1" - glob: "npm:^7.1.2" - globals: "npm:^11.7.0" - ignore: "npm:^4.0.6" - import-fresh: "npm:^3.0.0" - imurmurhash: "npm:^0.1.4" - inquirer: "npm:^6.2.2" - js-yaml: "npm:^3.13.0" - json-stable-stringify-without-jsonify: "npm:^1.0.1" - levn: "npm:^0.3.0" - lodash: "npm:^4.17.11" - minimatch: "npm:^3.0.4" - mkdirp: "npm:^0.5.1" - natural-compare: "npm:^1.4.0" - optionator: "npm:^0.8.2" - path-is-inside: "npm:^1.0.2" - progress: "npm:^2.0.0" - regexpp: "npm:^2.0.1" - semver: "npm:^5.5.1" - strip-ansi: "npm:^4.0.0" - strip-json-comments: "npm:^2.0.1" - table: "npm:^5.2.3" - text-table: "npm:^0.2.0" - bin: - eslint: ./bin/eslint.js - checksum: 10c0/b80161becd85523ffabb185f1604844fb2fd4d58970dc1d49f47f1fa838ef894e89a221b743016e7b7a50c5d6203dfb2452155ff5e1b4d1e8c17e677260c43d8 - languageName: node - linkType: hard - -"eslint@npm:^7.32.0": - version: 7.32.0 - resolution: "eslint@npm:7.32.0" - dependencies: - "@babel/code-frame": "npm:7.12.11" - "@eslint/eslintrc": "npm:^0.4.3" - "@humanwhocodes/config-array": "npm:^0.5.0" - ajv: "npm:^6.10.0" - chalk: "npm:^4.0.0" - cross-spawn: "npm:^7.0.2" - debug: "npm:^4.0.1" - doctrine: "npm:^3.0.0" - enquirer: "npm:^2.3.5" - escape-string-regexp: "npm:^4.0.0" - eslint-scope: "npm:^5.1.1" - eslint-utils: "npm:^2.1.0" - eslint-visitor-keys: "npm:^2.0.0" - espree: "npm:^7.3.1" - esquery: "npm:^1.4.0" - esutils: "npm:^2.0.2" - fast-deep-equal: "npm:^3.1.3" - file-entry-cache: "npm:^6.0.1" - functional-red-black-tree: "npm:^1.0.1" - glob-parent: "npm:^5.1.2" - globals: "npm:^13.6.0" - ignore: "npm:^4.0.6" - import-fresh: "npm:^3.0.0" - imurmurhash: "npm:^0.1.4" - is-glob: "npm:^4.0.0" - js-yaml: "npm:^3.13.1" - json-stable-stringify-without-jsonify: "npm:^1.0.1" - levn: "npm:^0.4.1" - lodash.merge: "npm:^4.6.2" - minimatch: "npm:^3.0.4" - natural-compare: "npm:^1.4.0" - optionator: "npm:^0.9.1" - progress: "npm:^2.0.0" - regexpp: "npm:^3.1.0" - semver: "npm:^7.2.1" - strip-ansi: "npm:^6.0.0" - strip-json-comments: "npm:^3.1.0" - table: "npm:^6.0.9" - text-table: "npm:^0.2.0" - v8-compile-cache: "npm:^2.0.3" - bin: - eslint: bin/eslint.js - checksum: 10c0/84409f7767556179cb11529f1215f335c7dfccf90419df6147f949f14c347a960c7b569e80ed84011a0b6d10da1ef5046edbbb9b11c3e59aa6696d5217092e93 - languageName: node - linkType: hard - -"espree@npm:^5.0.1": - version: 5.0.1 - resolution: "espree@npm:5.0.1" - dependencies: - acorn: "npm:^6.0.7" - acorn-jsx: "npm:^5.0.0" - eslint-visitor-keys: "npm:^1.0.0" - checksum: 10c0/738d028bd1ccf0fa872bfd8b427bfc4a985624a5a240997ee2e7ea3f281f47c6ac71356e2f563d4807908f3c53a3370e75d3f81eddde55efd10e6ab0821ce968 - languageName: node - linkType: hard - -"espree@npm:^7.3.0, espree@npm:^7.3.1": - version: 7.3.1 - resolution: "espree@npm:7.3.1" - dependencies: - acorn: "npm:^7.4.0" - acorn-jsx: "npm:^5.3.1" - eslint-visitor-keys: "npm:^1.3.0" - checksum: 10c0/f4e81b903f03eaf0e6925cea20571632da427deb6e14ca37e481f72c11f36d7bb4945fe8a2ff15ab22d078d3cd93ee65355fa94de9c27485c356481775f25d85 - languageName: node - linkType: hard - -"esprima@npm:^4.0.0": - version: 4.0.1 - resolution: "esprima@npm:4.0.1" - bin: - esparse: ./bin/esparse.js - esvalidate: ./bin/esvalidate.js - checksum: 10c0/ad4bab9ead0808cf56501750fd9d3fb276f6b105f987707d059005d57e182d18a7c9ec7f3a01794ebddcca676773e42ca48a32d67a250c9d35e009ca613caba3 - languageName: node - linkType: hard - -"esquery@npm:^1.0.1, esquery@npm:^1.4.0": - version: 1.4.0 - resolution: "esquery@npm:1.4.0" - dependencies: - estraverse: "npm:^5.1.0" - checksum: 10c0/b9b18178d33c4335210c76e062de979dc38ee6b49deea12bff1b2315e6cfcca1fd7f8bc49f899720ad8ff25967ac95b5b182e81a8b7b59ff09dbd0d978c32f64 - languageName: node - linkType: hard - -"esrecurse@npm:^4.1.0, esrecurse@npm:^4.3.0": - version: 4.3.0 - resolution: "esrecurse@npm:4.3.0" - dependencies: - estraverse: "npm:^5.2.0" - checksum: 10c0/81a37116d1408ded88ada45b9fb16dbd26fba3aadc369ce50fcaf82a0bac12772ebd7b24cd7b91fc66786bf2c1ac7b5f196bc990a473efff972f5cb338877cf5 - languageName: node - linkType: hard - -"estraverse@npm:^4.1.1": - version: 4.3.0 - resolution: "estraverse@npm:4.3.0" - checksum: 10c0/9cb46463ef8a8a4905d3708a652d60122a0c20bb58dec7e0e12ab0e7235123d74214fc0141d743c381813e1b992767e2708194f6f6e0f9fd00c1b4e0887b8b6d - languageName: node - linkType: hard - -"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0": - version: 5.2.0 - resolution: "estraverse@npm:5.2.0" - checksum: 10c0/76a07411841ddf30a6a75afc93e8c00bbfe255a62dee7e1dc90b06ce0d7b939a00cf816ae94566ab5bc1cfde773a49387a35650287840b842143fff46f8f9ae3 - languageName: node - linkType: hard - -"esutils@npm:^2.0.2": - version: 2.0.3 - resolution: "esutils@npm:2.0.3" - checksum: 10c0/9a2fe69a41bfdade834ba7c42de4723c97ec776e40656919c62cbd13607c45e127a003f05f724a1ea55e5029a4cf2de444b13009f2af71271e42d93a637137c7 - languageName: node - linkType: hard - -"etag@npm:~1.8.1": - version: 1.8.1 - resolution: "etag@npm:1.8.1" - checksum: 10c0/12be11ef62fb9817314d790089a0a49fae4e1b50594135dcb8076312b7d7e470884b5100d249b28c18581b7fd52f8b485689ffae22a11ed9ec17377a33a08f84 - languageName: node - linkType: hard - -"eth-block-tracker@npm:^3.0.0": - version: 3.0.1 - resolution: "eth-block-tracker@npm:3.0.1" - dependencies: - eth-query: "npm:^2.1.0" - ethereumjs-tx: "npm:^1.3.3" - ethereumjs-util: "npm:^5.1.3" - ethjs-util: "npm:^0.1.3" - json-rpc-engine: "npm:^3.6.0" - pify: "npm:^2.3.0" - tape: "npm:^4.6.3" - checksum: 10c0/3e872bf09c952b94ebb570217239feaa411f1255c4c927fc12b3646b2ef7d250012e6b98339ac15c74d1dcbd678263cd322cd965e75de11300647c2353cba769 - languageName: node - linkType: hard - -"eth-ens-namehash@npm:2.0.8, eth-ens-namehash@npm:^2.0.8": - version: 2.0.8 - resolution: "eth-ens-namehash@npm:2.0.8" - dependencies: - idna-uts46-hx: "npm:^2.3.1" - js-sha3: "npm:^0.5.7" - checksum: 10c0/b0b60e5bdc8b0fc5a5cdf6011d221f1fdae8a2ac80775fec3f2d61db62470e57a6fcd7455fc8b2af532c86e0946d6611077ae3e30c7afd331f686e3cd7cc0977 - languageName: node - linkType: hard - -"eth-json-rpc-infura@npm:^3.1.0": - version: 3.2.1 - resolution: "eth-json-rpc-infura@npm:3.2.1" - dependencies: - cross-fetch: "npm:^2.1.1" - eth-json-rpc-middleware: "npm:^1.5.0" - json-rpc-engine: "npm:^3.4.0" - json-rpc-error: "npm:^2.0.0" - checksum: 10c0/d805782f9d9ddc147dc9310dad06ddf473fba9e6194c21b7176eb15b8a9e5cdcd090accaddc1077e16538536146b6ed79e028be9c0aac012389fc42b7a9a63eb - languageName: node - linkType: hard - -"eth-json-rpc-middleware@npm:^1.5.0": - version: 1.6.0 - resolution: "eth-json-rpc-middleware@npm:1.6.0" - dependencies: - async: "npm:^2.5.0" - eth-query: "npm:^2.1.2" - eth-tx-summary: "npm:^3.1.2" - ethereumjs-block: "npm:^1.6.0" - ethereumjs-tx: "npm:^1.3.3" - ethereumjs-util: "npm:^5.1.2" - ethereumjs-vm: "npm:^2.1.0" - fetch-ponyfill: "npm:^4.0.0" - json-rpc-engine: "npm:^3.6.0" - json-rpc-error: "npm:^2.0.0" - json-stable-stringify: "npm:^1.0.1" - promise-to-callback: "npm:^1.0.0" - tape: "npm:^4.6.3" - checksum: 10c0/1ab123834dc32c866656d40eeb45acd96fc76352cf757f6daf0bac303f4d795444da1f4c6cbb6df4f899a4cc2a2ba5cfc36caa6d67225e990de7db054cae9ba5 - languageName: node - linkType: hard - -"eth-lib@npm:0.2.8": - version: 0.2.8 - resolution: "eth-lib@npm:0.2.8" - dependencies: - bn.js: "npm:^4.11.6" - elliptic: "npm:^6.4.0" - xhr-request-promise: "npm:^0.1.2" - checksum: 10c0/5c4fc31acc0f690f5dffcbaa6130faed55f1395dc1b367cb5899e69baa5b21296889d1c24523e05a97815222ded297381f1cbac96bb8cdeec2a85dbd6cb2fa20 - languageName: node - linkType: hard - -"eth-lib@npm:^0.1.26": - version: 0.1.29 - resolution: "eth-lib@npm:0.1.29" - dependencies: - bn.js: "npm:^4.11.6" - elliptic: "npm:^6.4.0" - nano-json-stream-parser: "npm:^0.1.2" - servify: "npm:^0.1.12" - ws: "npm:^3.0.0" - xhr-request-promise: "npm:^0.1.2" - checksum: 10c0/8759dffa412dce728620413d5a9d063b175c33bded2a5749f48b4433b1751fbb0cf03c7dbe7081e77eb805c613a5e1aea6a3b11669128202150622d6cb98c37d - languageName: node - linkType: hard - -"eth-query@npm:^2.0.2, eth-query@npm:^2.1.0, eth-query@npm:^2.1.2": - version: 2.1.2 - resolution: "eth-query@npm:2.1.2" - dependencies: - json-rpc-random-id: "npm:^1.0.0" - xtend: "npm:^4.0.1" - checksum: 10c0/ef28d14bfad14b8813c9ba8f9f0baf8778946a4797a222b8a039067222ac68aa3d9d53ed22a71c75b99240a693af1ed42508a99fd484cce2a7726822723346b7 - languageName: node - linkType: hard - -"eth-sig-util@npm:3.0.0": - version: 3.0.0 - resolution: "eth-sig-util@npm:3.0.0" - dependencies: - buffer: "npm:^5.2.1" - elliptic: "npm:^6.4.0" - ethereumjs-abi: "npm:0.6.5" - ethereumjs-util: "npm:^5.1.1" - tweetnacl: "npm:^1.0.0" - tweetnacl-util: "npm:^0.15.0" - checksum: 10c0/289e7bfc2f6fef314d6294aaca5551eb56195e39ffd7e99cc7f5fb382790885745f2a589712b4866aef66d8c51744898517e860a479c52baa591043477349a9e - languageName: node - linkType: hard - -"eth-sig-util@npm:^1.4.2": - version: 1.4.2 - resolution: "eth-sig-util@npm:1.4.2" - dependencies: - ethereumjs-abi: "git+https://github.com/ethereumjs/ethereumjs-abi.git" - ethereumjs-util: "npm:^5.1.1" - checksum: 10c0/63f88b8dda12eedfa83d47c43f52025dba724ca602385386f408fd41f40c077b06ada2d58c13d9844dae7340b7fee6a0281517b4e20e41d05bf68de2340fc314 - languageName: node - linkType: hard - -"eth-tx-summary@npm:^3.1.2": - version: 3.2.4 - resolution: "eth-tx-summary@npm:3.2.4" - dependencies: - async: "npm:^2.1.2" - clone: "npm:^2.0.0" - concat-stream: "npm:^1.5.1" - end-of-stream: "npm:^1.1.0" - eth-query: "npm:^2.0.2" - ethereumjs-block: "npm:^1.4.1" - ethereumjs-tx: "npm:^1.1.1" - ethereumjs-util: "npm:^5.0.1" - ethereumjs-vm: "npm:^2.6.0" - through2: "npm:^2.0.3" - checksum: 10c0/fb9ed94bc3af2e8b5a27814aa46f117fe2e19eb4f790c381155130b393b74956ea2e484eeb92d846a4426571b6d61dd57a05f31939ec5741506e2518e4bfe2ec - languageName: node - linkType: hard - -"ethashjs@npm:~0.0.7": - version: 0.0.8 - resolution: "ethashjs@npm:0.0.8" - dependencies: - async: "npm:^2.1.2" - buffer-xor: "npm:^2.0.1" - ethereumjs-util: "npm:^7.0.2" - miller-rabin: "npm:^4.0.0" - checksum: 10c0/0ccd932652ebe08d0d678305f1bc36805689f5a08daea713625f4a52396aa0a7bb96984f119c80335415ab7bf77f125b70480ec2ecc314fad4f65ffcc3ac19d9 - languageName: node - linkType: hard - -"ethereum-bloom-filters@npm:^1.0.6": - version: 1.0.10 - resolution: "ethereum-bloom-filters@npm:1.0.10" - dependencies: - js-sha3: "npm:^0.8.0" - checksum: 10c0/ae70b0b0b6d83beece65638a634818f0bd1d00d7a4447e17b83797f4d8db4c49491b57119c5ed081c008fb766bb8f230f3603187fd6649d58a8cf3b9aa91549c - languageName: node - linkType: hard - -"ethereum-common@npm:0.2.0": - version: 0.2.0 - resolution: "ethereum-common@npm:0.2.0" - checksum: 10c0/3fbb7440b1c7ed75d074c5559dfba80426dec0bf5c1bbe4d8d6c8872b5c505bfe0535ef082e408497f3488c2cc7088509cbeb70c2962e2d3ab5d9020ac666a61 - languageName: node - linkType: hard - -"ethereum-common@npm:^0.0.18": - version: 0.0.18 - resolution: "ethereum-common@npm:0.0.18" - checksum: 10c0/3eb2d58489c2e47bba077dea01cc0886df3a6cd931631539d36e0b656776d8afe5a0bcb8842bf7714f2ef639d0fb8643e0ad85b9a49a1f2b0fc1fe66819824d8 - languageName: node - linkType: hard - -"ethereum-cryptography@npm:^0.1.3": - version: 0.1.3 - resolution: "ethereum-cryptography@npm:0.1.3" - dependencies: - "@types/pbkdf2": "npm:^3.0.0" - "@types/secp256k1": "npm:^4.0.1" - blakejs: "npm:^1.1.0" - browserify-aes: "npm:^1.2.0" - bs58check: "npm:^2.1.2" - create-hash: "npm:^1.2.0" - create-hmac: "npm:^1.1.7" - hash.js: "npm:^1.1.7" - keccak: "npm:^3.0.0" - pbkdf2: "npm:^3.0.17" - randombytes: "npm:^2.1.0" - safe-buffer: "npm:^5.1.2" - scrypt-js: "npm:^3.0.0" - secp256k1: "npm:^4.0.1" - setimmediate: "npm:^1.0.5" - checksum: 10c0/aa36e11fca9d67d67c96e02a98b33bae2e1add20bd11af43feb7f28cdafe0cd3bdbae3bfecc7f2d9ec8f504b10a1c8f7590f5f7fe236560fd8083dd321ad7144 - languageName: node - linkType: hard - -"ethereum-cryptography@npm:^1.0.3": - version: 1.0.3 - resolution: "ethereum-cryptography@npm:1.0.3" - dependencies: - "@noble/hashes": "npm:1.0.0" - "@noble/secp256k1": "npm:1.5.5" - "@scure/bip32": "npm:1.0.1" - "@scure/bip39": "npm:1.0.0" - checksum: 10c0/b235a99180d4155984f8ea96b3abd8dfa6ba7a8b20d916ee33c7aeedba008a76921101542721fe705765fadc8bbfa1c12a50160fda86b7cc0a5fd3f03c8e00c1 - languageName: node - linkType: hard - -"ethereum-cryptography@npm:^2.1.3, ethereum-cryptography@npm:^2.2.1": - version: 2.2.1 - resolution: "ethereum-cryptography@npm:2.2.1" - dependencies: - "@noble/curves": "npm:1.4.2" - "@noble/hashes": "npm:1.4.0" - "@scure/bip32": "npm:1.4.0" - "@scure/bip39": "npm:1.3.0" - checksum: 10c0/c6c7626d393980577b57f709878b2eb91f270fe56116044b1d7afb70d5c519cddc0c072e8c05e4a335e05342eb64d9c3ab39d52f78bb75f76ad70817da9645ef - languageName: node - linkType: hard - -"ethereum-waffle@npm:^3.4.0": - version: 3.4.0 - resolution: "ethereum-waffle@npm:3.4.0" - dependencies: - "@ethereum-waffle/chai": "npm:^3.4.0" - "@ethereum-waffle/compiler": "npm:^3.4.0" - "@ethereum-waffle/mock-contract": "npm:^3.3.0" - "@ethereum-waffle/provider": "npm:^3.4.0" - ethers: "npm:^5.0.1" - bin: - waffle: bin/waffle - checksum: 10c0/55caced63f38c0568b20175c4d86da3a906c8c5bb75f3d35d118ce712c6a2423b3442dd7b6659bf9fbb9541e7b458bdd940382f72fbb2a58e5d773303d877dae - languageName: node - linkType: hard - -"ethereumjs-abi@npm:0.6.8": - version: 0.6.8 - resolution: "ethereumjs-abi@npm:0.6.8" - dependencies: - bn.js: "npm:^4.11.8" - ethereumjs-util: "npm:^6.0.0" - checksum: 10c0/a7ff1917625e3c812cb3bca6c1231fc0ece282cc7d202d60545a9c31cd379fd751bfed5ff78dae4279cb1ba4d0e8967f9fdd4f135a334a38dbf04e7afd0c4bcf - languageName: node - linkType: hard - -"ethereumjs-account@npm:3.0.0, ethereumjs-account@npm:^3.0.0": - version: 3.0.0 - resolution: "ethereumjs-account@npm:3.0.0" - dependencies: - ethereumjs-util: "npm:^6.0.0" - rlp: "npm:^2.2.1" - safe-buffer: "npm:^5.1.1" - checksum: 10c0/d84566eb6a876300b718fb7fe4d66e60dd40792ea48902b469e4917e7b5ea394f725c12543d162f68a4f9145aa3f04e9fdda649268bbcdf25310a09389033b8d - languageName: node - linkType: hard - -"ethereumjs-account@npm:^2.0.3": - version: 2.0.5 - resolution: "ethereumjs-account@npm:2.0.5" - dependencies: - ethereumjs-util: "npm:^5.0.0" - rlp: "npm:^2.0.0" - safe-buffer: "npm:^5.1.1" - checksum: 10c0/ba435280565220e4b431aaaa5474dff30f1fa652ccdbcfc5e4ff7f1d36aa1380272185625403134ab6cc4c1d5340f6b0a6f8e00aecd40c85e22b4dcb06145993 - languageName: node - linkType: hard - -"ethereumjs-block@npm:2.2.2, ethereumjs-block@npm:^2.2.2, ethereumjs-block@npm:~2.2.0, ethereumjs-block@npm:~2.2.2": - version: 2.2.2 - resolution: "ethereumjs-block@npm:2.2.2" - dependencies: - async: "npm:^2.0.1" - ethereumjs-common: "npm:^1.5.0" - ethereumjs-tx: "npm:^2.1.1" - ethereumjs-util: "npm:^5.0.0" - merkle-patricia-tree: "npm:^2.1.2" - checksum: 10c0/6fba40c9f08b937f850799b3b93fff61dcab0da8fbc4b472c2501442ece6e2b2361eef83ded95d7c7c3c151194f7f53c8e58a2a9d4c5d4cd3c7daafb3f45077f - languageName: node - linkType: hard - -"ethereumjs-block@npm:^1.2.2, ethereumjs-block@npm:^1.4.1, ethereumjs-block@npm:^1.6.0": - version: 1.7.1 - resolution: "ethereumjs-block@npm:1.7.1" - dependencies: - async: "npm:^2.0.1" - ethereum-common: "npm:0.2.0" - ethereumjs-tx: "npm:^1.2.2" - ethereumjs-util: "npm:^5.0.0" - merkle-patricia-tree: "npm:^2.1.2" - checksum: 10c0/d902aac5d1246595849821ea34b7184d7cb6673ec4aa1b92257d4aebdf99bdcd17d1ef2c5f8d2193c155dd152cb6a3b2ec89976c7348a0c3f908186b7689676c - languageName: node - linkType: hard - -"ethereumjs-blockchain@npm:^4.0.3": - version: 4.0.4 - resolution: "ethereumjs-blockchain@npm:4.0.4" - dependencies: - async: "npm:^2.6.1" - ethashjs: "npm:~0.0.7" - ethereumjs-block: "npm:~2.2.2" - ethereumjs-common: "npm:^1.5.0" - ethereumjs-util: "npm:^6.1.0" - flow-stoplight: "npm:^1.0.0" - level-mem: "npm:^3.0.1" - lru-cache: "npm:^5.1.1" - rlp: "npm:^2.2.2" - semaphore: "npm:^1.1.0" - checksum: 10c0/c5675adb566c85e986b46cfd3f81b31b5aa21d4139634eb64717cbcce692e2dbe4bf58ad62a9bcc3a2f3452f51f70579b56c520b0f4b856d28f89b3f1da5148d - languageName: node - linkType: hard - -"ethereumjs-common@npm:1.5.0": - version: 1.5.0 - resolution: "ethereumjs-common@npm:1.5.0" - checksum: 10c0/4ac872aa446d533d7c0c74763a6a24bb31209d79180cd91fd1cc768f101d9f2515e86e4a267dfa913675949acae2a2afed0f182f88bcbe7d4aff9ce100e981a6 - languageName: node - linkType: hard - -"ethereumjs-common@npm:^1.1.0, ethereumjs-common@npm:^1.3.2, ethereumjs-common@npm:^1.5.0": - version: 1.5.2 - resolution: "ethereumjs-common@npm:1.5.2" - checksum: 10c0/9b0802e830c6a07c835322ac6a2519840741740bf0831c5d1626714255a24133d8df021332ed22aa75d13eacfc5efdd51ee6032bfc8d8e3088e6ca3a5335ca69 - languageName: node - linkType: hard - -"ethereumjs-tx@npm:2.1.2, ethereumjs-tx@npm:^2.1.1, ethereumjs-tx@npm:^2.1.2": - version: 2.1.2 - resolution: "ethereumjs-tx@npm:2.1.2" - dependencies: - ethereumjs-common: "npm:^1.5.0" - ethereumjs-util: "npm:^6.0.0" - checksum: 10c0/286ea734a32ce376d947953f7838cfd509b55ded75a1c86a049775cf77bd02b45fde81e00e48b844f1b2eb59486c5087877b579f879b172cbb8a477d5f74c135 - languageName: node - linkType: hard - -"ethereumjs-tx@npm:^1.1.1, ethereumjs-tx@npm:^1.2.0, ethereumjs-tx@npm:^1.2.2, ethereumjs-tx@npm:^1.3.3": - version: 1.3.7 - resolution: "ethereumjs-tx@npm:1.3.7" - dependencies: - ethereum-common: "npm:^0.0.18" - ethereumjs-util: "npm:^5.0.0" - checksum: 10c0/0e97caba2c09ed77987f890ab56e65df158b8404265ad8c945024f58794f35072737b9188478fc7b9b8ddc0f53ad9e01f1d49f32da4686efde4f750c4a5c8984 - languageName: node - linkType: hard - -"ethereumjs-util@npm:6.2.1, ethereumjs-util@npm:^6.0.0, ethereumjs-util@npm:^6.1.0, ethereumjs-util@npm:^6.2.0": - version: 6.2.1 - resolution: "ethereumjs-util@npm:6.2.1" - dependencies: - "@types/bn.js": "npm:^4.11.3" - bn.js: "npm:^4.11.0" - create-hash: "npm:^1.1.2" - elliptic: "npm:^6.5.2" - ethereum-cryptography: "npm:^0.1.3" - ethjs-util: "npm:0.1.6" - rlp: "npm:^2.2.3" - checksum: 10c0/64aa7e6d591a0b890eb147c5d81f80a6456e87b3056e6bbafb54dff63f6ae9e646406763e8bd546c3b0b0162d027aecb3844873e894681826b03e0298f57e7a4 - languageName: node - linkType: hard - -"ethereumjs-util@npm:^5.0.0, ethereumjs-util@npm:^5.0.1, ethereumjs-util@npm:^5.1.1, ethereumjs-util@npm:^5.1.2, ethereumjs-util@npm:^5.1.3, ethereumjs-util@npm:^5.1.5, ethereumjs-util@npm:^5.2.0": - version: 5.2.1 - resolution: "ethereumjs-util@npm:5.2.1" - dependencies: - bn.js: "npm:^4.11.0" - create-hash: "npm:^1.1.2" - elliptic: "npm:^6.5.2" - ethereum-cryptography: "npm:^0.1.3" - ethjs-util: "npm:^0.1.3" - rlp: "npm:^2.0.0" - safe-buffer: "npm:^5.1.1" - checksum: 10c0/ed788c9d5e9672dedd5434c134ede7a69790b8c652f38558884b35975526ffa2eee9461f4f438943cfcc4d515cf80cd650ca0fb540f348623f3572720f85a366 - languageName: node - linkType: hard - -"ethereumjs-util@npm:^7.0.2, ethereumjs-util@npm:^7.1.0": - version: 7.1.2 - resolution: "ethereumjs-util@npm:7.1.2" - dependencies: - "@types/bn.js": "npm:^5.1.0" - bn.js: "npm:^5.1.2" - create-hash: "npm:^1.1.2" - ethereum-cryptography: "npm:^0.1.3" - ethjs-util: "npm:0.1.6" - rlp: "npm:^2.2.4" - checksum: 10c0/3745ba3f0a91bdf6d2bc6e3464edf911e2d903c86da7ea126d0f58a0449078a7edce5e712deab2a0934795b2a4118f32fa605c5619e301a770b3ac38b0e6cb5b - languageName: node - linkType: hard - -"ethereumjs-util@npm:^7.0.3": - version: 7.1.4 - resolution: "ethereumjs-util@npm:7.1.4" - dependencies: - "@types/bn.js": "npm:^5.1.0" - bn.js: "npm:^5.1.2" - create-hash: "npm:^1.1.2" - ethereum-cryptography: "npm:^0.1.3" - rlp: "npm:^2.2.4" - checksum: 10c0/33907f4010f5f91cec75e4bfa941b7c9f1d8290e7e1e24637b205d0560ae16d0f817b6b3b0b0e4e39e8ba65e631b7e265cae3bcaf6b616c9588b689daea1d030 - languageName: node - linkType: hard - -"ethereumjs-vm@npm:4.2.0": - version: 4.2.0 - resolution: "ethereumjs-vm@npm:4.2.0" - dependencies: - async: "npm:^2.1.2" - async-eventemitter: "npm:^0.2.2" - core-js-pure: "npm:^3.0.1" - ethereumjs-account: "npm:^3.0.0" - ethereumjs-block: "npm:^2.2.2" - ethereumjs-blockchain: "npm:^4.0.3" - ethereumjs-common: "npm:^1.5.0" - ethereumjs-tx: "npm:^2.1.2" - ethereumjs-util: "npm:^6.2.0" - fake-merkle-patricia-tree: "npm:^1.0.1" - functional-red-black-tree: "npm:^1.0.1" - merkle-patricia-tree: "npm:^2.3.2" - rustbn.js: "npm:~0.2.0" - safe-buffer: "npm:^5.1.1" - util.promisify: "npm:^1.0.0" - checksum: 10c0/e9cc47eba3fc26769b3a49aeb64a175953a58343522021b251ba736ff74d0df0a6f044e42e7ece26337cc10b74c5d9c3b09377be54a6b6fc25636db3ca9b19cc - languageName: node - linkType: hard - -"ethereumjs-vm@npm:^2.1.0, ethereumjs-vm@npm:^2.3.4, ethereumjs-vm@npm:^2.6.0": - version: 2.6.0 - resolution: "ethereumjs-vm@npm:2.6.0" - dependencies: - async: "npm:^2.1.2" - async-eventemitter: "npm:^0.2.2" - ethereumjs-account: "npm:^2.0.3" - ethereumjs-block: "npm:~2.2.0" - ethereumjs-common: "npm:^1.1.0" - ethereumjs-util: "npm:^6.0.0" - fake-merkle-patricia-tree: "npm:^1.0.1" - functional-red-black-tree: "npm:^1.0.1" - merkle-patricia-tree: "npm:^2.3.2" - rustbn.js: "npm:~0.2.0" - safe-buffer: "npm:^5.1.1" - checksum: 10c0/c33fe723bfb2d6a9f3ef0e6578b1c4ccbeaa762bb9cd7326dfebacecf83c27f3df393ce39ba0c8a0e6812e36556653c0231a497f9ab223bbff33fc2410f675a8 - languageName: node - linkType: hard - -"ethereumjs-wallet@npm:0.6.5": - version: 0.6.5 - resolution: "ethereumjs-wallet@npm:0.6.5" - dependencies: - aes-js: "npm:^3.1.1" - bs58check: "npm:^2.1.2" - ethereum-cryptography: "npm:^0.1.3" - ethereumjs-util: "npm:^6.0.0" - randombytes: "npm:^2.0.6" - safe-buffer: "npm:^5.1.2" - scryptsy: "npm:^1.2.1" - utf8: "npm:^3.0.0" - uuid: "npm:^3.3.2" - checksum: 10c0/471a4e804c928490236d00a7b88a54362e454155fde1eeea5a4f11e921994e2dc8ba752f29588eaf412410300f3ebb0b3b87d7c1ae5d81dadf487ad93a3c40eb - languageName: node - linkType: hard - -"ethers@npm:^5.0.1, ethers@npm:^5.0.2, ethers@npm:^5.4.7": - version: 5.4.7 - resolution: "ethers@npm:5.4.7" - dependencies: - "@ethersproject/abi": "npm:5.4.1" - "@ethersproject/abstract-provider": "npm:5.4.1" - "@ethersproject/abstract-signer": "npm:5.4.1" - "@ethersproject/address": "npm:5.4.0" - "@ethersproject/base64": "npm:5.4.0" - "@ethersproject/basex": "npm:5.4.0" - "@ethersproject/bignumber": "npm:5.4.2" - "@ethersproject/bytes": "npm:5.4.0" - "@ethersproject/constants": "npm:5.4.0" - "@ethersproject/contracts": "npm:5.4.1" - "@ethersproject/hash": "npm:5.4.0" - "@ethersproject/hdnode": "npm:5.4.0" - "@ethersproject/json-wallets": "npm:5.4.0" - "@ethersproject/keccak256": "npm:5.4.0" - "@ethersproject/logger": "npm:5.4.1" - "@ethersproject/networks": "npm:5.4.2" - "@ethersproject/pbkdf2": "npm:5.4.0" - "@ethersproject/properties": "npm:5.4.1" - "@ethersproject/providers": "npm:5.4.5" - "@ethersproject/random": "npm:5.4.0" - "@ethersproject/rlp": "npm:5.4.0" - "@ethersproject/sha2": "npm:5.4.0" - "@ethersproject/signing-key": "npm:5.4.0" - "@ethersproject/solidity": "npm:5.4.0" - "@ethersproject/strings": "npm:5.4.0" - "@ethersproject/transactions": "npm:5.4.0" - "@ethersproject/units": "npm:5.4.0" - "@ethersproject/wallet": "npm:5.4.0" - "@ethersproject/web": "npm:5.4.0" - "@ethersproject/wordlists": "npm:5.4.0" - checksum: 10c0/189de436ebf69d0ce206a82ae9784709281d25c5db963639568d487fd1cc1cc5c016f007077583d08bbedfdea6198490a4da9416a5d7c647591de5b19bb16f94 - languageName: node - linkType: hard - -"ethers@npm:^5.5.3": - version: 5.7.2 - resolution: "ethers@npm:5.7.2" - dependencies: - "@ethersproject/abi": "npm:5.7.0" - "@ethersproject/abstract-provider": "npm:5.7.0" - "@ethersproject/abstract-signer": "npm:5.7.0" - "@ethersproject/address": "npm:5.7.0" - "@ethersproject/base64": "npm:5.7.0" - "@ethersproject/basex": "npm:5.7.0" - "@ethersproject/bignumber": "npm:5.7.0" - "@ethersproject/bytes": "npm:5.7.0" - "@ethersproject/constants": "npm:5.7.0" - "@ethersproject/contracts": "npm:5.7.0" - "@ethersproject/hash": "npm:5.7.0" - "@ethersproject/hdnode": "npm:5.7.0" - "@ethersproject/json-wallets": "npm:5.7.0" - "@ethersproject/keccak256": "npm:5.7.0" - "@ethersproject/logger": "npm:5.7.0" - "@ethersproject/networks": "npm:5.7.1" - "@ethersproject/pbkdf2": "npm:5.7.0" - "@ethersproject/properties": "npm:5.7.0" - "@ethersproject/providers": "npm:5.7.2" - "@ethersproject/random": "npm:5.7.0" - "@ethersproject/rlp": "npm:5.7.0" - "@ethersproject/sha2": "npm:5.7.0" - "@ethersproject/signing-key": "npm:5.7.0" - "@ethersproject/solidity": "npm:5.7.0" - "@ethersproject/strings": "npm:5.7.0" - "@ethersproject/transactions": "npm:5.7.0" - "@ethersproject/units": "npm:5.7.0" - "@ethersproject/wallet": "npm:5.7.0" - "@ethersproject/web": "npm:5.7.1" - "@ethersproject/wordlists": "npm:5.7.0" - checksum: 10c0/90629a4cdb88cde7a7694f5610a83eb00d7fbbaea687446b15631397988f591c554dd68dfa752ddf00aabefd6285e5b298be44187e960f5e4962684e10b39962 - languageName: node - linkType: hard - -"ethjs-unit@npm:0.1.6": - version: 0.1.6 - resolution: "ethjs-unit@npm:0.1.6" - dependencies: - bn.js: "npm:4.11.6" - number-to-bn: "npm:1.7.0" - checksum: 10c0/0115ddeb4bc932026b9cd259f6eb020a45b38be62e3786526b70e4c5fb0254184bf6e8b7b3f0c8bb80d4d596a73893e386c02221faf203895db7cb9c29b37188 - languageName: node - linkType: hard - -"ethjs-util@npm:0.1.6, ethjs-util@npm:^0.1.3": - version: 0.1.6 - resolution: "ethjs-util@npm:0.1.6" - dependencies: - is-hex-prefixed: "npm:1.0.0" - strip-hex-prefix: "npm:1.0.0" - checksum: 10c0/9b4d6268705fd0620e73a56d2fa7b8a7c6b9770b2cf7f8ffe3a9c46b8bd1c5a08fff3d1181bb18cf85cf12b6fdbb6dca6d9aff6506005f3f565e742f026e6339 - languageName: node - linkType: hard - -"eventemitter3@npm:4.0.4": - version: 4.0.4 - resolution: "eventemitter3@npm:4.0.4" - checksum: 10c0/2a7e5c4f605e7d0ab96addcf0d98cddfadb242ea6e3504dc5c91b6b0aa411df086d8de8a8b75978d117573d106929c8d0cb94b089e7768dfb0de4e6bf07be73d - languageName: node - linkType: hard - -"eventemitter3@npm:5.0.1": - version: 5.0.1 - resolution: "eventemitter3@npm:5.0.1" - checksum: 10c0/4ba5c00c506e6c786b4d6262cfbce90ddc14c10d4667e5c83ae993c9de88aa856033994dd2b35b83e8dc1170e224e66a319fa80adc4c32adcd2379bbc75da814 - languageName: node - linkType: hard - -"events@npm:^3.0.0": - version: 3.3.0 - resolution: "events@npm:3.3.0" - checksum: 10c0/d6b6f2adbccbcda74ddbab52ed07db727ef52e31a61ed26db9feb7dc62af7fc8e060defa65e5f8af9449b86b52cc1a1f6a79f2eafcf4e62add2b7a1fa4a432f6 - languageName: node - linkType: hard - -"evp_bytestokey@npm:^1.0.0, evp_bytestokey@npm:^1.0.3": - version: 1.0.3 - resolution: "evp_bytestokey@npm:1.0.3" - dependencies: - md5.js: "npm:^1.3.4" - node-gyp: "npm:latest" - safe-buffer: "npm:^5.1.1" - checksum: 10c0/77fbe2d94a902a80e9b8f5a73dcd695d9c14899c5e82967a61b1fc6cbbb28c46552d9b127cff47c45fcf684748bdbcfa0a50410349109de87ceb4b199ef6ee99 - languageName: node - linkType: hard - -"expand-brackets@npm:^2.1.4": - version: 2.1.4 - resolution: "expand-brackets@npm:2.1.4" - dependencies: - debug: "npm:^2.3.3" - define-property: "npm:^0.2.5" - extend-shallow: "npm:^2.0.1" - posix-character-classes: "npm:^0.1.0" - regex-not: "npm:^1.0.0" - snapdragon: "npm:^0.8.1" - to-regex: "npm:^3.0.1" - checksum: 10c0/3e2fb95d2d7d7231486493fd65db913927b656b6fcdfcce41e139c0991a72204af619ad4acb1be75ed994ca49edb7995ef241dbf8cf44dc3c03d211328428a87 - languageName: node - linkType: hard - -"exponential-backoff@npm:^3.1.1": - version: 3.1.3 - resolution: "exponential-backoff@npm:3.1.3" - checksum: 10c0/77e3ae682b7b1f4972f563c6dbcd2b0d54ac679e62d5d32f3e5085feba20483cf28bd505543f520e287a56d4d55a28d7874299941faf637e779a1aa5994d1267 - languageName: node - linkType: hard - -"express@npm:^4.14.0": - version: 4.18.1 - resolution: "express@npm:4.18.1" - dependencies: - accepts: "npm:~1.3.8" - array-flatten: "npm:1.1.1" - body-parser: "npm:1.20.0" - content-disposition: "npm:0.5.4" - content-type: "npm:~1.0.4" - cookie: "npm:0.5.0" - cookie-signature: "npm:1.0.6" - debug: "npm:2.6.9" - depd: "npm:2.0.0" - encodeurl: "npm:~1.0.2" - escape-html: "npm:~1.0.3" - etag: "npm:~1.8.1" - finalhandler: "npm:1.2.0" - fresh: "npm:0.5.2" - http-errors: "npm:2.0.0" - merge-descriptors: "npm:1.0.1" - methods: "npm:~1.1.2" - on-finished: "npm:2.4.1" - parseurl: "npm:~1.3.3" - path-to-regexp: "npm:0.1.7" - proxy-addr: "npm:~2.0.7" - qs: "npm:6.10.3" - range-parser: "npm:~1.2.1" - safe-buffer: "npm:5.2.1" - send: "npm:0.18.0" - serve-static: "npm:1.15.0" - setprototypeof: "npm:1.2.0" - statuses: "npm:2.0.1" - type-is: "npm:~1.6.18" - utils-merge: "npm:1.0.1" - vary: "npm:~1.1.2" - checksum: 10c0/eeca44d91a73a8aa9101b36d1fb2dc7942d994a3ea471664daf35a42f2d498c3d43bb4e8541667d9b46d1773756d256bc5eed59632a1205773e40e468e60b6d3 - languageName: node - linkType: hard - -"ext@npm:^1.1.2": - version: 1.7.0 - resolution: "ext@npm:1.7.0" - dependencies: - type: "npm:^2.7.2" - checksum: 10c0/a8e5f34e12214e9eee3a4af3b5c9d05ba048f28996450975b369fc86e5d0ef13b6df0615f892f5396a9c65d616213c25ec5b0ad17ef42eac4a500512a19da6c7 - languageName: node - linkType: hard - -"extend-shallow@npm:^2.0.1": - version: 2.0.1 - resolution: "extend-shallow@npm:2.0.1" - dependencies: - is-extendable: "npm:^0.1.0" - checksum: 10c0/ee1cb0a18c9faddb42d791b2d64867bd6cfd0f3affb711782eb6e894dd193e2934a7f529426aac7c8ddb31ac5d38000a00aa2caf08aa3dfc3e1c8ff6ba340bd9 - languageName: node - linkType: hard - -"extend-shallow@npm:^3.0.0, extend-shallow@npm:^3.0.2": - version: 3.0.2 - resolution: "extend-shallow@npm:3.0.2" - dependencies: - assign-symbols: "npm:^1.0.0" - is-extendable: "npm:^1.0.1" - checksum: 10c0/f39581b8f98e3ad94995e33214fff725b0297cf09f2725b6f624551cfb71e0764accfd0af80becc0182af5014d2a57b31b85ec999f9eb8a6c45af81752feac9a - languageName: node - linkType: hard - -"extend@npm:~3.0.2": - version: 3.0.2 - resolution: "extend@npm:3.0.2" - checksum: 10c0/73bf6e27406e80aa3e85b0d1c4fd987261e628064e170ca781125c0b635a3dabad5e05adbf07595ea0cf1e6c5396cacb214af933da7cbaf24fe75ff14818e8f9 - languageName: node - linkType: hard - -"external-editor@npm:^3.0.3": - version: 3.1.0 - resolution: "external-editor@npm:3.1.0" - dependencies: - chardet: "npm:^0.7.0" - iconv-lite: "npm:^0.4.24" - tmp: "npm:^0.0.33" - checksum: 10c0/c98f1ba3efdfa3c561db4447ff366a6adb5c1e2581462522c56a18bf90dfe4da382f9cd1feee3e330108c3595a854b218272539f311ba1b3298f841eb0fbf339 - languageName: node - linkType: hard - -"extglob@npm:^2.0.4": - version: 2.0.4 - resolution: "extglob@npm:2.0.4" - dependencies: - array-unique: "npm:^0.3.2" - define-property: "npm:^1.0.0" - expand-brackets: "npm:^2.1.4" - extend-shallow: "npm:^2.0.1" - fragment-cache: "npm:^0.2.1" - regex-not: "npm:^1.0.0" - snapdragon: "npm:^0.8.1" - to-regex: "npm:^3.0.1" - checksum: 10c0/e1a891342e2010d046143016c6c03d58455c2c96c30bf5570ea07929984ee7d48fad86b363aee08f7a8a638f5c3a66906429b21ecb19bc8e90df56a001cd282c - languageName: node - linkType: hard - -"extsprintf@npm:1.3.0": - version: 1.3.0 - resolution: "extsprintf@npm:1.3.0" - checksum: 10c0/f75114a8388f0cbce68e277b6495dc3930db4dde1611072e4a140c24e204affd77320d004b947a132e9a3b97b8253017b2b62dce661975fb0adced707abf1ab5 - languageName: node - linkType: hard - -"extsprintf@npm:^1.2.0": - version: 1.4.1 - resolution: "extsprintf@npm:1.4.1" - checksum: 10c0/e10e2769985d0e9b6c7199b053a9957589d02e84de42832c295798cb422a025e6d4a92e0259c1fb4d07090f5bfde6b55fd9f880ac5855bd61d775f8ab75a7ab0 - languageName: node - linkType: hard - -"fake-merkle-patricia-tree@npm:^1.0.1": - version: 1.0.1 - resolution: "fake-merkle-patricia-tree@npm:1.0.1" - dependencies: - checkpoint-store: "npm:^1.1.0" - checksum: 10c0/7a476b3437e20d95d6483198c4f4bc697e6bd80b4b30127f2f0367dfc4d3fb04cbf21cee7803287df8393f1837ceaf61e5f9606ccb6d0fdf7fc2a42a6e6ee6d0 - languageName: node - linkType: hard - -"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": - version: 3.1.3 - resolution: "fast-deep-equal@npm:3.1.3" - checksum: 10c0/40dedc862eb8992c54579c66d914635afbec43350afbbe991235fdcb4e3a8d5af1b23ae7e79bef7d4882d0ecee06c3197488026998fb19f72dc95acff1d1b1d0 - languageName: node - linkType: hard - -"fast-diff@npm:^1.1.2": - version: 1.2.0 - resolution: "fast-diff@npm:1.2.0" - checksum: 10c0/2fbcb23957fb0bc920832a94ba627b860400f9cce45e1594e931dabf62e858369a58c6c2603e2ecc4f7679580f710b5b5b6e698a355a9a9bfcfd93c06c7c4350 - languageName: node - linkType: hard - -"fast-glob@npm:^3.1.1": - version: 3.2.7 - resolution: "fast-glob@npm:3.2.7" - dependencies: - "@nodelib/fs.stat": "npm:^2.0.2" - "@nodelib/fs.walk": "npm:^1.2.3" - glob-parent: "npm:^5.1.2" - merge2: "npm:^1.3.0" - micromatch: "npm:^4.0.4" - checksum: 10c0/cc820a9acbd99c51267d525ed3c0c368b57d273f8d34e2401eef824390ff38ff419af3c0308d4ec1aef3dae0e24d1ac1dfe3156e5c702d63416a4c877ab7e0c4 - languageName: node - linkType: hard - -"fast-json-stable-stringify@npm:^2.0.0": - version: 2.1.0 - resolution: "fast-json-stable-stringify@npm:2.1.0" - checksum: 10c0/7f081eb0b8a64e0057b3bb03f974b3ef00135fbf36c1c710895cd9300f13c94ba809bb3a81cf4e1b03f6e5285610a61abbd7602d0652de423144dfee5a389c9b - languageName: node - linkType: hard - -"fast-levenshtein@npm:^2.0.6, fast-levenshtein@npm:~2.0.6": - version: 2.0.6 - resolution: "fast-levenshtein@npm:2.0.6" - checksum: 10c0/111972b37338bcb88f7d9e2c5907862c280ebf4234433b95bc611e518d192ccb2d38119c4ac86e26b668d75f7f3894f4ff5c4982899afced7ca78633b08287c4 - languageName: node - linkType: hard - -"fastq@npm:^1.6.0": - version: 1.13.0 - resolution: "fastq@npm:1.13.0" - dependencies: - reusify: "npm:^1.0.4" - checksum: 10c0/76c7b5dafb93c7e74359a3e6de834ce7a7c2e3a3184050ed4cb652661de55cf8d4895178d8d3ccd23069395056c7bb15450660d38fb382ca88c142b22694d7c9 - languageName: node - linkType: hard - -"fdir@npm:^6.5.0": - version: 6.5.0 - resolution: "fdir@npm:6.5.0" - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - checksum: 10c0/e345083c4306b3aed6cb8ec551e26c36bab5c511e99ea4576a16750ddc8d3240e63826cc624f5ae17ad4dc82e68a253213b60d556c11bfad064b7607847ed07f - languageName: node - linkType: hard - -"fetch-ponyfill@npm:^4.0.0": - version: 4.1.0 - resolution: "fetch-ponyfill@npm:4.1.0" - dependencies: - node-fetch: "npm:~1.7.1" - checksum: 10c0/a0419b5b5adc380c6a48156a565513fa3d6c68af003751db3d4d0bdf114b5336206fd57f364a9588abcc2637297eb5968cd8ba09dff85aa15c1e1e91c52f6208 - languageName: node - linkType: hard - -"figures@npm:^2.0.0": - version: 2.0.0 - resolution: "figures@npm:2.0.0" - dependencies: - escape-string-regexp: "npm:^1.0.5" - checksum: 10c0/5dc5a75fec3e7e04ae65d6ce51d28b3e70d4656c51b06996b6fdb2cb5b542df512e3b3c04482f5193a964edddafa5521479ff948fa84e12ff556e53e094ab4ce - languageName: node - linkType: hard - -"file-entry-cache@npm:^5.0.1": - version: 5.0.1 - resolution: "file-entry-cache@npm:5.0.1" - dependencies: - flat-cache: "npm:^2.0.1" - checksum: 10c0/2480fb523a0342b8ede8b17717517f69ce6b775083d06e50e2e10ca45f16c94f1d4d95976ae627735716174033374a2d6717ba4b58569e1fea8564a1b1f2e4c1 - languageName: node - linkType: hard - -"file-entry-cache@npm:^6.0.1": - version: 6.0.1 - resolution: "file-entry-cache@npm:6.0.1" - dependencies: - flat-cache: "npm:^3.0.4" - checksum: 10c0/58473e8a82794d01b38e5e435f6feaf648e3f36fdb3a56e98f417f4efae71ad1c0d4ebd8a9a7c50c3ad085820a93fc7494ad721e0e4ebc1da3573f4e1c3c7cdd - languageName: node - linkType: hard - -"fill-range@npm:^4.0.0": - version: 4.0.0 - resolution: "fill-range@npm:4.0.0" - dependencies: - extend-shallow: "npm:^2.0.1" - is-number: "npm:^3.0.0" - repeat-string: "npm:^1.6.1" - to-regex-range: "npm:^2.1.0" - checksum: 10c0/ccd57b7c43d7e28a1f8a60adfa3c401629c08e2f121565eece95e2386ebc64dedc7128d8c3448342aabf19db0c55a34f425f148400c7a7be9a606ba48749e089 - languageName: node - linkType: hard - -"fill-range@npm:^7.0.1": - version: 7.0.1 - resolution: "fill-range@npm:7.0.1" - dependencies: - to-regex-range: "npm:^5.0.1" - checksum: 10c0/7cdad7d426ffbaadf45aeb5d15ec675bbd77f7597ad5399e3d2766987ed20bda24d5fac64b3ee79d93276f5865608bb22344a26b9b1ae6c4d00bd94bf611623f - languageName: node - linkType: hard - -"finalhandler@npm:1.2.0": - version: 1.2.0 - resolution: "finalhandler@npm:1.2.0" - dependencies: - debug: "npm:2.6.9" - encodeurl: "npm:~1.0.2" - escape-html: "npm:~1.0.3" - on-finished: "npm:2.4.1" - parseurl: "npm:~1.3.3" - statuses: "npm:2.0.1" - unpipe: "npm:~1.0.0" - checksum: 10c0/64b7e5ff2ad1fcb14931cd012651631b721ce657da24aedb5650ddde9378bf8e95daa451da43398123f5de161a81e79ff5affe4f9f2a6d2df4a813d6d3e254b7 - languageName: node - linkType: hard - -"find-replace@npm:^1.0.3": - version: 1.0.3 - resolution: "find-replace@npm:1.0.3" - dependencies: - array-back: "npm:^1.0.4" - test-value: "npm:^2.1.0" - checksum: 10c0/427dfe320a3d9d13973f59f4116bb8f451379e25bee5893b393c150863d67e57dedfb306a5956e78b2bfe25e7c5a2090d96cdcef952aa44f09c38539016309b7 - languageName: node - linkType: hard - -"find-replace@npm:^3.0.0": - version: 3.0.0 - resolution: "find-replace@npm:3.0.0" - dependencies: - array-back: "npm:^3.0.1" - checksum: 10c0/fcd1bf7960388c8193c2861bcdc760c18ac14edb4bde062a961915d9a25727b2e8aabf0229e90cc09c753fd557e5a3e5ae61e49cadbe727be89a9e8e49ce7668 - languageName: node - linkType: hard - -"find-up@npm:^1.0.0": - version: 1.1.2 - resolution: "find-up@npm:1.1.2" - dependencies: - path-exists: "npm:^2.0.0" - pinkie-promise: "npm:^2.0.0" - checksum: 10c0/51e35c62d9b7efe82d7d5cce966bfe10c2eaa78c769333f8114627e3a8a4a4f50747f5f50bff50b1094cbc6527776f0d3b9ff74d3561ef714a5290a17c80c2bc - languageName: node - linkType: hard - -"find-up@npm:^2.0.0, find-up@npm:^2.1.0": - version: 2.1.0 - resolution: "find-up@npm:2.1.0" - dependencies: - locate-path: "npm:^2.0.0" - checksum: 10c0/c080875c9fe28eb1962f35cbe83c683796a0321899f1eed31a37577800055539815de13d53495049697d3ba313013344f843bb9401dd337a1b832be5edfc6840 - languageName: node - linkType: hard - -"find-up@npm:^5.0.0": - version: 5.0.0 - resolution: "find-up@npm:5.0.0" - dependencies: - locate-path: "npm:^6.0.0" - path-exists: "npm:^4.0.0" - checksum: 10c0/062c5a83a9c02f53cdd6d175a37ecf8f87ea5bbff1fdfb828f04bfa021441bc7583e8ebc0872a4c1baab96221fb8a8a275a19809fb93fbc40bd69ec35634069a - languageName: node - linkType: hard - -"find-yarn-workspace-root@npm:^1.2.1": - version: 1.2.1 - resolution: "find-yarn-workspace-root@npm:1.2.1" - dependencies: - fs-extra: "npm:^4.0.3" - micromatch: "npm:^3.1.4" - checksum: 10c0/c406e4d30a87eccd85e2ca283be813426941d8e7933c389184a8587e75a00b9a1352a8111c81e1988d88ceeb88d1a3372d113846d386126e98b39094fddb752e - languageName: node - linkType: hard - -"find-yarn-workspace-root@npm:^2.0.0": - version: 2.0.0 - resolution: "find-yarn-workspace-root@npm:2.0.0" - dependencies: - micromatch: "npm:^4.0.2" - checksum: 10c0/b0d3843013fbdaf4e57140e0165889d09fa61745c9e85da2af86e54974f4cc9f1967e40f0d8fc36a79d53091f0829c651d06607d552582e53976f3cd8f4e5689 - languageName: node - linkType: hard - -"flat-cache@npm:^2.0.1": - version: 2.0.1 - resolution: "flat-cache@npm:2.0.1" - dependencies: - flatted: "npm:^2.0.0" - rimraf: "npm:2.6.3" - write: "npm:1.0.3" - checksum: 10c0/09e4d2300d05734eb2ac39ea0bb9cc6d64c0c856f6b77d2bdc7734490b4a8f860d721f59ffd5508f6938c577f8394fe7b5f6acf99a5ec4af6478d7c5c8390bcb - languageName: node - linkType: hard - -"flat-cache@npm:^3.0.4": - version: 3.0.4 - resolution: "flat-cache@npm:3.0.4" - dependencies: - flatted: "npm:^3.1.0" - rimraf: "npm:^3.0.2" - checksum: 10c0/f274dcbadb09ad8d7b6edf2ee9b034bc40bf0c12638f6c4084e9f1d39208cb104a5ebbb24b398880ef048200eaa116852f73d2d8b72e8c9627aba8c3e27ca057 - languageName: node - linkType: hard - -"flat@npm:^5.0.2": - version: 5.0.2 - resolution: "flat@npm:5.0.2" - bin: - flat: cli.js - checksum: 10c0/f178b13482f0cd80c7fede05f4d10585b1f2fdebf26e12edc138e32d3150c6ea6482b7f12813a1091143bad52bb6d3596bca51a162257a21163c0ff438baa5fe - languageName: node - linkType: hard - -"flatted@npm:^2.0.0": - version: 2.0.2 - resolution: "flatted@npm:2.0.2" - checksum: 10c0/1895ac3971c3a71b0384c6d8b8ef1f217dfe7e72bc7dabc51ef532772b761e626dd7cae53a729b9e65389409d7f03fd84f1900bde4f9e719ed04e57e8510e0d4 - languageName: node - linkType: hard - -"flatted@npm:^3.1.0": - version: 3.2.2 - resolution: "flatted@npm:3.2.2" - checksum: 10c0/6e21d30a691867893d145dc1c231345ea96ed18249c3a551138322be5c5425209606ae568536953177db0376e91f916947a4ae956be21a240ca9af603cf73cb5 - languageName: node - linkType: hard - -"flow-stoplight@npm:^1.0.0": - version: 1.0.0 - resolution: "flow-stoplight@npm:1.0.0" - checksum: 10c0/64ab2739079020d85afd099939e739cb7c80bb914d855267ddbaf14e4aafd3ed24da81ed531a4f048f60f314f8427a64c8bbf9369326bc8deb89fc702263c81f - languageName: node - linkType: hard - -"fmix@npm:^0.1.0": - version: 0.1.0 - resolution: "fmix@npm:0.1.0" - dependencies: - imul: "npm:^1.0.0" - checksum: 10c0/af9e54eacc00b46e1c4a77229840e37252fff7634f81026591da9d24438ca15a1afa2786f579eb7865489ded21b76af7327d111b90b944e7409cd60f4d4f2ded - languageName: node - linkType: hard - -"follow-redirects@npm:^1.12.1": - version: 1.14.9 - resolution: "follow-redirects@npm:1.14.9" - peerDependenciesMeta: - debug: - optional: true - checksum: 10c0/08c465c17cbf3011ad16516609ee476abffa8fd1ff78c2082f1ff43614cb06586a0ccc8e99e5ebe13da06d064367cb269789e3ca0e93e2ad5b24fdc30b4294b6 - languageName: node - linkType: hard - -"follow-redirects@npm:^1.14.0": - version: 1.15.2 - resolution: "follow-redirects@npm:1.15.2" - peerDependenciesMeta: - debug: - optional: true - checksum: 10c0/da5932b70e63944d38eecaa16954bac4347036f08303c913d166eda74809d8797d38386e3a0eb1d2fe37d2aaff2764cce8e9dbd99459d860cf2cdfa237923b5f - languageName: node - linkType: hard - -"follow-redirects@npm:^1.16.0": - version: 1.16.0 - resolution: "follow-redirects@npm:1.16.0" - peerDependenciesMeta: - debug: - optional: true - checksum: 10c0/a1e2900163e6f1b4d1ed5c221b607f41decbab65534c63fe7e287e40a5d552a6496e7d9d7d976fa4ba77b4c51c11e5e9f683f10b43011ea11e442ff128d0e181 - languageName: node - linkType: hard - -"for-each@npm:^0.3.3, for-each@npm:~0.3.3": - version: 0.3.3 - resolution: "for-each@npm:0.3.3" - dependencies: - is-callable: "npm:^1.1.3" - checksum: 10c0/22330d8a2db728dbf003ec9182c2d421fbcd2969b02b4f97ec288721cda63eb28f2c08585ddccd0f77cb2930af8d958005c9e72f47141dc51816127a118f39aa - languageName: node - linkType: hard - -"for-in@npm:^1.0.2": - version: 1.0.2 - resolution: "for-in@npm:1.0.2" - checksum: 10c0/42bb609d564b1dc340e1996868b67961257fd03a48d7fdafd4f5119530b87f962be6b4d5b7e3a3fc84c9854d149494b1d358e0b0ce9837e64c4c6603a49451d6 - languageName: node - linkType: hard - -"foreground-child@npm:^3.1.0": - version: 3.3.1 - resolution: "foreground-child@npm:3.3.1" - dependencies: - cross-spawn: "npm:^7.0.6" - signal-exit: "npm:^4.0.1" - checksum: 10c0/8986e4af2430896e65bc2788d6679067294d6aee9545daefc84923a0a4b399ad9c7a3ea7bd8c0b2b80fdf4a92de4c69df3f628233ff3224260e9c1541a9e9ed3 - languageName: node - linkType: hard - -"forever-agent@npm:~0.6.1": - version: 0.6.1 - resolution: "forever-agent@npm:0.6.1" - checksum: 10c0/364f7f5f7d93ab661455351ce116a67877b66f59aca199559a999bd39e3cfadbfbfacc10415a915255e2210b30c23febe9aec3ca16bf2d1ff11c935a1000e24c - languageName: node - linkType: hard - -"form-data@npm:^3.0.0": - version: 3.0.1 - resolution: "form-data@npm:3.0.1" - dependencies: - asynckit: "npm:^0.4.0" - combined-stream: "npm:^1.0.8" - mime-types: "npm:^2.1.12" - checksum: 10c0/1ccc3ae064a080a799923f754d49fcebdd90515a8924f0f54de557540b50e7f1fe48ba5f2bd0435a5664aa2d49729107e6aaf2155a9abf52339474c5638b4485 - languageName: node - linkType: hard - -"form-data@npm:^4.0.0": - version: 4.0.0 - resolution: "form-data@npm:4.0.0" - dependencies: - asynckit: "npm:^0.4.0" - combined-stream: "npm:^1.0.8" - mime-types: "npm:^2.1.12" - checksum: 10c0/cb6f3ac49180be03ff07ba3ff125f9eba2ff0b277fb33c7fc47569fc5e616882c5b1c69b9904c4c4187e97dd0419dd03b134174756f296dec62041e6527e2c6e - languageName: node - linkType: hard - -"form-data@npm:^4.0.5": - version: 4.0.6 - resolution: "form-data@npm:4.0.6" - dependencies: - asynckit: "npm:^0.4.0" - combined-stream: "npm:^1.0.8" - es-set-tostringtag: "npm:^2.1.0" - hasown: "npm:^2.0.4" - mime-types: "npm:^2.1.35" - checksum: 10c0/43947a77bf0ff45c6ceed789778982d47a3f3e720a74b71721174ebf3310a5f1a8be1d6b38a3ee3688e8a18a2c4273073ec0844cd37efda3eaf46d41c9c318ff - languageName: node - linkType: hard - -"form-data@npm:~2.3.2": - version: 2.3.3 - resolution: "form-data@npm:2.3.3" - dependencies: - asynckit: "npm:^0.4.0" - combined-stream: "npm:^1.0.6" - mime-types: "npm:^2.1.12" - checksum: 10c0/706ef1e5649286b6a61e5bb87993a9842807fd8f149cd2548ee807ea4fb882247bdf7f6e64ac4720029c0cd5c80343de0e22eee1dc9e9882e12db9cc7bc016a4 - languageName: node - linkType: hard - -"forwarded@npm:0.2.0": - version: 0.2.0 - resolution: "forwarded@npm:0.2.0" - checksum: 10c0/9b67c3fac86acdbc9ae47ba1ddd5f2f81526fa4c8226863ede5600a3f7c7416ef451f6f1e240a3cc32d0fd79fcfe6beb08fd0da454f360032bde70bf80afbb33 - languageName: node - linkType: hard - -"fp-ts@npm:1.19.3": - version: 1.19.3 - resolution: "fp-ts@npm:1.19.3" - checksum: 10c0/a016cfc98ad5e61564ab2d53a5379bbb8254642b66df13ced47e8c1d8d507abf4588d8bb43530198dfe1907211d8bae8f112cab52ba0ac6ab055da9168a6e260 - languageName: node - linkType: hard - -"fp-ts@npm:^1.0.0": - version: 1.19.5 - resolution: "fp-ts@npm:1.19.5" - checksum: 10c0/2a330fa1779561307740c26a7255fdffeb1ca2d0c7448d4dc094b477b772b0c8f7da1dfc88569b6f13f6958169b63b5df7361e514535b46b2e215bbf03a3722d - languageName: node - linkType: hard - -"fragment-cache@npm:^0.2.1": - version: 0.2.1 - resolution: "fragment-cache@npm:0.2.1" - dependencies: - map-cache: "npm:^0.2.2" - checksum: 10c0/5891d1c1d1d5e1a7fb3ccf28515c06731476fa88f7a50f4ede8a0d8d239a338448e7f7cc8b73db48da19c229fa30066104fe6489862065a4f1ed591c42fbeabf - languageName: node - linkType: hard - -"fresh@npm:0.5.2": - version: 0.5.2 - resolution: "fresh@npm:0.5.2" - checksum: 10c0/c6d27f3ed86cc5b601404822f31c900dd165ba63fff8152a3ef714e2012e7535027063bc67ded4cb5b3a49fa596495d46cacd9f47d6328459cf570f08b7d9e5a - languageName: node - linkType: hard - -"fs-extra@npm:^0.30.0": - version: 0.30.0 - resolution: "fs-extra@npm:0.30.0" - dependencies: - graceful-fs: "npm:^4.1.2" - jsonfile: "npm:^2.1.0" - klaw: "npm:^1.0.0" - path-is-absolute: "npm:^1.0.0" - rimraf: "npm:^2.2.8" - checksum: 10c0/24f3c966018c7bf436bf38ca3a126f1d95bf0f82598302195c4f0c8887767f045dae308f92c53a39cead74631dabbc30fcf1c71dbe96f1f0148f6de8edd114bc - languageName: node - linkType: hard - -"fs-extra@npm:^10.0.0": - version: 10.1.0 - resolution: "fs-extra@npm:10.1.0" - dependencies: - graceful-fs: "npm:^4.2.0" - jsonfile: "npm:^6.0.1" - universalify: "npm:^2.0.0" - checksum: 10c0/5f579466e7109719d162a9249abbeffe7f426eb133ea486e020b89bc6d67a741134076bf439983f2eb79276ceaf6bd7b7c1e43c3fd67fe889863e69072fb0a5e - languageName: node - linkType: hard - -"fs-extra@npm:^11.2.0": - version: 11.3.4 - resolution: "fs-extra@npm:11.3.4" - dependencies: - graceful-fs: "npm:^4.2.0" - jsonfile: "npm:^6.0.1" - universalify: "npm:^2.0.0" - checksum: 10c0/e08276f767a62496ae97d711aaa692c6a478177f24a85979b6a2881c9db9c68b8c2ad5da0bcf92c0b2a474cea6e935ec245656441527958fd8372cb647087df0 - languageName: node - linkType: hard - -"fs-extra@npm:^4.0.2, fs-extra@npm:^4.0.3": - version: 4.0.3 - resolution: "fs-extra@npm:4.0.3" - dependencies: - graceful-fs: "npm:^4.1.2" - jsonfile: "npm:^4.0.0" - universalify: "npm:^0.1.0" - checksum: 10c0/b34344de77adaccb294e6dc116e8b247ae0a4da45b79749814893549e6f15e3baace2998db06a966a9f8d5a39b6b2d8e51543bd0a565a8927c37d6373dfd20b9 - languageName: node - linkType: hard - -"fs-extra@npm:^7.0.0, fs-extra@npm:^7.0.1": - version: 7.0.1 - resolution: "fs-extra@npm:7.0.1" - dependencies: - graceful-fs: "npm:^4.1.2" - jsonfile: "npm:^4.0.0" - universalify: "npm:^0.1.0" - checksum: 10c0/1943bb2150007e3739921b8d13d4109abdc3cc481e53b97b7ea7f77eda1c3c642e27ae49eac3af074e3496ea02fde30f411ef410c760c70a38b92e656e5da784 - languageName: node - linkType: hard - -"fs-extra@npm:^9.0.1, fs-extra@npm:^9.1.0": - version: 9.1.0 - resolution: "fs-extra@npm:9.1.0" - dependencies: - at-least-node: "npm:^1.0.0" - graceful-fs: "npm:^4.2.0" - jsonfile: "npm:^6.0.1" - universalify: "npm:^2.0.0" - checksum: 10c0/9b808bd884beff5cb940773018179a6b94a966381d005479f00adda6b44e5e3d4abf765135773d849cc27efe68c349e4a7b86acd7d3306d5932c14f3a4b17a92 - languageName: node - linkType: hard - -"fs-minipass@npm:^1.2.7": - version: 1.2.7 - resolution: "fs-minipass@npm:1.2.7" - dependencies: - minipass: "npm:^2.6.0" - checksum: 10c0/c8259ce8caab360f16b8c3774fd09dd1d5240d6f3f78fd8efa0a215b5f40edfa90e7b5b5ddc2335a4c50885e29d5983f9fe6ac3ac19320e6917a21dbb9f05c64 - languageName: node - linkType: hard - -"fs-minipass@npm:^3.0.0": - version: 3.0.3 - resolution: "fs-minipass@npm:3.0.3" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10c0/63e80da2ff9b621e2cb1596abcb9207f1cf82b968b116ccd7b959e3323144cce7fb141462200971c38bbf2ecca51695069db45265705bed09a7cd93ae5b89f94 - languageName: node - linkType: hard - -"fs.realpath@npm:^1.0.0": - version: 1.0.0 - resolution: "fs.realpath@npm:1.0.0" - checksum: 10c0/444cf1291d997165dfd4c0d58b69f0e4782bfd9149fd72faa4fe299e68e0e93d6db941660b37dd29153bf7186672ececa3b50b7e7249477b03fdf850f287c948 - languageName: node - linkType: hard - -"fsevents@npm:~2.3.2": - version: 2.3.2 - resolution: "fsevents@npm:2.3.2" - dependencies: - node-gyp: "npm:latest" - checksum: 10c0/be78a3efa3e181cda3cf7a4637cb527bcebb0bd0ea0440105a3bb45b86f9245b307dc10a2507e8f4498a7d4ec349d1910f4d73e4d4495b16103106e07eee735b - conditions: os=darwin - languageName: node - linkType: hard - -"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin": - version: 2.3.2 - resolution: "fsevents@patch:fsevents@npm%3A2.3.2#optional!builtin::version=2.3.2&hash=df0bf1" - dependencies: - node-gyp: "npm:latest" - conditions: os=darwin - languageName: node - linkType: hard - -"function-bind@npm:^1.1.1": - version: 1.1.1 - resolution: "function-bind@npm:1.1.1" - checksum: 10c0/60b74b2407e1942e1ed7f8c284f8ef714d0689dcfce5319985a5b7da3fc727f40b4a59ec72dc55aa83365ad7b8fa4fac3a30d93c850a2b452f29ae03dbc10a1e - languageName: node - linkType: hard - -"function-bind@npm:^1.1.2": - version: 1.1.2 - resolution: "function-bind@npm:1.1.2" - checksum: 10c0/d8680ee1e5fcd4c197e4ac33b2b4dce03c71f4d91717292785703db200f5c21f977c568d28061226f9b5900cbcd2c84463646134fd5337e7925e0942bc3f46d5 - languageName: node - linkType: hard - -"functional-red-black-tree@npm:^1.0.1, functional-red-black-tree@npm:~1.0.1": - version: 1.0.1 - resolution: "functional-red-black-tree@npm:1.0.1" - checksum: 10c0/5959eed0375803d9924f47688479bb017e0c6816a0e5ac151e22ba6bfe1d12c41de2f339188885e0aa8eeea2072dad509d8e4448467e816bde0a2ca86a0670d3 - languageName: node - linkType: hard - -"ganache-core@npm:^2.13.2": - version: 2.13.2 - resolution: "ganache-core@npm:2.13.2" - dependencies: - abstract-leveldown: "npm:3.0.0" - async: "npm:2.6.2" - bip39: "npm:2.5.0" - cachedown: "npm:1.0.0" - clone: "npm:2.1.2" - debug: "npm:3.2.6" - encoding-down: "npm:5.0.4" - eth-sig-util: "npm:3.0.0" - ethereumjs-abi: "npm:0.6.8" - ethereumjs-account: "npm:3.0.0" - ethereumjs-block: "npm:2.2.2" - ethereumjs-common: "npm:1.5.0" - ethereumjs-tx: "npm:2.1.2" - ethereumjs-util: "npm:6.2.1" - ethereumjs-vm: "npm:4.2.0" - ethereumjs-wallet: "npm:0.6.5" - heap: "npm:0.2.6" - keccak: "npm:3.0.1" - level-sublevel: "npm:6.6.4" - levelup: "npm:3.1.1" - lodash: "npm:4.17.20" - lru-cache: "npm:5.1.1" - merkle-patricia-tree: "npm:3.0.0" - patch-package: "npm:6.2.2" - seedrandom: "npm:3.0.1" - source-map-support: "npm:0.5.12" - tmp: "npm:0.1.0" - web3: "npm:1.2.11" - web3-provider-engine: "npm:14.2.1" - websocket: "npm:1.0.32" - dependenciesMeta: - ethereumjs-wallet: - optional: true - web3: - optional: true - checksum: 10c0/cdae2cbfaa4b06148b4ab7095f707acb21235fed7717325da63279d83845dcee9086da165cd4af3eebebdb442a0ebf29f878d1b455277a84d8bcd98dcf309d1c - languageName: node - linkType: hard - -"generator-function@npm:^2.0.0": - version: 2.0.1 - resolution: "generator-function@npm:2.0.1" - checksum: 10c0/8a9f59df0f01cfefafdb3b451b80555e5cf6d76487095db91ac461a0e682e4ff7a9dbce15f4ecec191e53586d59eece01949e05a4b4492879600bbbe8e28d6b8 - languageName: node - linkType: hard - -"get-caller-file@npm:^1.0.1": - version: 1.0.3 - resolution: "get-caller-file@npm:1.0.3" - checksum: 10c0/763dcee2de8ff60ae7e13a4bad8306205a2fbe108e555686344ddd9ef211b8bebfe459d3a739669257014c59e7cc1e7a44003c21af805c1214673e6a45f06c51 - languageName: node - linkType: hard - -"get-caller-file@npm:^2.0.5": - version: 2.0.5 - resolution: "get-caller-file@npm:2.0.5" - checksum: 10c0/c6c7b60271931fa752aeb92f2b47e355eac1af3a2673f47c9589e8f8a41adc74d45551c1bc57b5e66a80609f10ffb72b6f575e4370d61cc3f7f3aaff01757cde - languageName: node - linkType: hard - -"get-func-name@npm:^2.0.0": - version: 2.0.2 - resolution: "get-func-name@npm:2.0.2" - checksum: 10c0/89830fd07623fa73429a711b9daecdb304386d237c71268007f788f113505ef1d4cc2d0b9680e072c5082490aec9df5d7758bf5ac6f1c37062855e8e3dc0b9df - languageName: node - linkType: hard - -"get-intrinsic@npm:^1.0.2": - version: 1.1.3 - resolution: "get-intrinsic@npm:1.1.3" - dependencies: - function-bind: "npm:^1.1.1" - has: "npm:^1.0.3" - has-symbols: "npm:^1.0.3" - checksum: 10c0/6f201d5f95ea0dd6c8d0dc2c265603aff0b9e15614cb70f8f4674bb3d2b2369d521efaa84d0b70451d2c00762ebd28402758bf46279c6f2a00d242ebac0d8442 - languageName: node - linkType: hard - -"get-intrinsic@npm:^1.1.0, get-intrinsic@npm:^1.1.1": - version: 1.1.1 - resolution: "get-intrinsic@npm:1.1.1" - dependencies: - function-bind: "npm:^1.1.1" - has: "npm:^1.0.3" - has-symbols: "npm:^1.0.1" - checksum: 10c0/c01055578e9b8da37a7779b18b732436c55d93e5ffa56b0fc4d3da8468ad89a25ce2343ba1945f20c0e78119bc7bb296fb59a0da521b6e43fd632de73376e040 - languageName: node - linkType: hard - -"get-intrinsic@npm:^1.2.6": - version: 1.3.1 - resolution: "get-intrinsic@npm:1.3.1" - dependencies: - async-function: "npm:^1.0.0" - async-generator-function: "npm:^1.0.0" - call-bind-apply-helpers: "npm:^1.0.2" - es-define-property: "npm:^1.0.1" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.1.1" - function-bind: "npm:^1.1.2" - generator-function: "npm:^2.0.0" - get-proto: "npm:^1.0.1" - gopd: "npm:^1.2.0" - has-symbols: "npm:^1.1.0" - hasown: "npm:^2.0.2" - math-intrinsics: "npm:^1.1.0" - checksum: 10c0/9f4ab0cf7efe0fd2c8185f52e6f637e708f3a112610c88869f8f041bb9ecc2ce44bf285dfdbdc6f4f7c277a5b88d8e94a432374d97cca22f3de7fc63795deb5d - languageName: node - linkType: hard - -"get-proto@npm:^1.0.1": - version: 1.0.1 - resolution: "get-proto@npm:1.0.1" - dependencies: - dunder-proto: "npm:^1.0.1" - es-object-atoms: "npm:^1.0.0" - checksum: 10c0/9224acb44603c5526955e83510b9da41baf6ae73f7398875fba50edc5e944223a89c4a72b070fcd78beb5f7bdda58ecb6294adc28f7acfc0da05f76a2399643c - languageName: node - linkType: hard - -"get-stream@npm:^3.0.0": - version: 3.0.0 - resolution: "get-stream@npm:3.0.0" - checksum: 10c0/003f5f3b8870da59c6aafdf6ed7e7b07b48c2f8629cd461bd3900726548b6b8cfa2e14d6b7814fbb08f07a42f4f738407fa70b989928b2783a76b278505bba22 - languageName: node - linkType: hard - -"get-stream@npm:^4.1.0": - version: 4.1.0 - resolution: "get-stream@npm:4.1.0" - dependencies: - pump: "npm:^3.0.0" - checksum: 10c0/294d876f667694a5ca23f0ca2156de67da950433b6fb53024833733975d32582896dbc7f257842d331809979efccf04d5e0b6b75ad4d45744c45f193fd497539 - languageName: node - linkType: hard - -"get-stream@npm:^5.1.0": - version: 5.2.0 - resolution: "get-stream@npm:5.2.0" - dependencies: - pump: "npm:^3.0.0" - checksum: 10c0/43797ffd815fbb26685bf188c8cfebecb8af87b3925091dd7b9a9c915993293d78e3c9e1bce125928ff92f2d0796f3889b92b5ec6d58d1041b574682132e0a80 - languageName: node - linkType: hard - -"get-symbol-description@npm:^1.0.0": - version: 1.0.0 - resolution: "get-symbol-description@npm:1.0.0" - dependencies: - call-bind: "npm:^1.0.2" - get-intrinsic: "npm:^1.1.1" - checksum: 10c0/23bc3b44c221cdf7669a88230c62f4b9e30393b61eb21ba4400cb3e346801bd8f95fe4330ee78dbae37aecd874646d53e3e76a17a654d0c84c77f6690526d6bb - languageName: node - linkType: hard - -"get-value@npm:^2.0.3, get-value@npm:^2.0.6": - version: 2.0.6 - resolution: "get-value@npm:2.0.6" - checksum: 10c0/f069c132791b357c8fc4adfe9e2929b0a2c6e95f98ca7bc6fcbc27f8a302e552f86b4ae61ec56d9e9ac2544b93b6a39743d479866a37b43fcc104088ba74f0d9 - languageName: node - linkType: hard - -"getpass@npm:^0.1.1": - version: 0.1.7 - resolution: "getpass@npm:0.1.7" - dependencies: - assert-plus: "npm:^1.0.0" - checksum: 10c0/c13f8530ecf16fc509f3fa5cd8dd2129ffa5d0c7ccdf5728b6022d52954c2d24be3706b4cdf15333eec52f1fbb43feb70a01dabc639d1d10071e371da8aaa52f - languageName: node - linkType: hard - -"glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": - version: 5.1.2 - resolution: "glob-parent@npm:5.1.2" - dependencies: - is-glob: "npm:^4.0.1" - checksum: 10c0/cab87638e2112bee3f839ef5f6e0765057163d39c66be8ec1602f3823da4692297ad4e972de876ea17c44d652978638d2fd583c6713d0eb6591706825020c9ee - languageName: node - linkType: hard - -"glob@npm:^10.3.10, glob@npm:^10.4.5": - version: 10.5.0 - resolution: "glob@npm:10.5.0" - dependencies: - foreground-child: "npm:^3.1.0" - jackspeak: "npm:^3.1.2" - minimatch: "npm:^9.0.4" - minipass: "npm:^7.1.2" - package-json-from-dist: "npm:^1.0.0" - path-scurry: "npm:^1.11.1" - bin: - glob: dist/esm/bin.mjs - checksum: 10c0/100705eddbde6323e7b35e1d1ac28bcb58322095bd8e63a7d0bef1a2cdafe0d0f7922a981b2b48369a4f8c1b077be5c171804534c3509dfe950dde15fbe6d828 - languageName: node - linkType: hard - -"glob@npm:^13.0.0": - version: 13.0.6 - resolution: "glob@npm:13.0.6" - dependencies: - minimatch: "npm:^10.2.2" - minipass: "npm:^7.1.3" - path-scurry: "npm:^2.0.2" - checksum: 10c0/269c236f11a9b50357fe7a8c6aadac667e01deb5242b19c84975628f05f4438d8ee1354bb62c5d6c10f37fd59911b54d7799730633a2786660d8c69f1d18120a - languageName: node - linkType: hard - -"glob@npm:^7.1.2, glob@npm:^7.1.6": - version: 7.2.0 - resolution: "glob@npm:7.2.0" - dependencies: - fs.realpath: "npm:^1.0.0" - inflight: "npm:^1.0.4" - inherits: "npm:2" - minimatch: "npm:^3.0.4" - once: "npm:^1.3.0" - path-is-absolute: "npm:^1.0.0" - checksum: 10c0/478b40e38be5a3d514e64950e1e07e0ac120585add6a37c98d0ed24d72d9127d734d2a125786073c8deb687096e84ae82b641c441a869ada3a9cc91b68978632 - languageName: node - linkType: hard - -"glob@npm:^7.1.3": - version: 7.2.3 - resolution: "glob@npm:7.2.3" - dependencies: - fs.realpath: "npm:^1.0.0" - inflight: "npm:^1.0.4" - inherits: "npm:2" - minimatch: "npm:^3.1.1" - once: "npm:^1.3.0" - path-is-absolute: "npm:^1.0.0" - checksum: 10c0/65676153e2b0c9095100fe7f25a778bf45608eeb32c6048cf307f579649bcc30353277b3b898a3792602c65764e5baa4f643714dfbdfd64ea271d210c7a425fe - languageName: node - linkType: hard - -"glob@npm:~7.1.7": - version: 7.1.7 - resolution: "glob@npm:7.1.7" - dependencies: - fs.realpath: "npm:^1.0.0" - inflight: "npm:^1.0.4" - inherits: "npm:2" - minimatch: "npm:^3.0.4" - once: "npm:^1.3.0" - path-is-absolute: "npm:^1.0.0" - checksum: 10c0/173245e6f9ccf904309eb7ef4a44a11f3bf68e9e341dff5a28b5db0dd7123b7506daf41497f3437a0710f57198187b758c2351eeaabce4d16935e956920da6a4 - languageName: node - linkType: hard - -"global@npm:~4.4.0": - version: 4.4.0 - resolution: "global@npm:4.4.0" - dependencies: - min-document: "npm:^2.19.0" - process: "npm:^0.11.10" - checksum: 10c0/4a467aec6602c00a7c5685f310574ab04e289ad7f894f0f01c9c5763562b82f4b92d1e381ce6c5bbb12173e2a9f759c1b63dda6370cfb199970267e14d90aa91 - languageName: node - linkType: hard - -"globals@npm:^11.7.0": - version: 11.12.0 - resolution: "globals@npm:11.12.0" - checksum: 10c0/758f9f258e7b19226bd8d4af5d3b0dcf7038780fb23d82e6f98932c44e239f884847f1766e8fa9cc5635ccb3204f7fa7314d4408dd4002a5e8ea827b4018f0a1 - languageName: node - linkType: hard - -"globals@npm:^13.6.0, globals@npm:^13.9.0": - version: 13.11.0 - resolution: "globals@npm:13.11.0" - dependencies: - type-fest: "npm:^0.20.2" - checksum: 10c0/35025ddb3587b467a30a5fc20e48fa3ccf703b469e32357594cc1f67417ee7b2cb8d60293cd55388a92ec16ea6e39b2e6e5c822d2e450866a2ac8a4566352375 - languageName: node - linkType: hard - -"globals@npm:^9.18.0": - version: 9.18.0 - resolution: "globals@npm:9.18.0" - checksum: 10c0/5ab74cb67cf060a9fceede4a0f2babc4c2c0b90dbb13847d2659defdf2121c60035ef23823c8417ce8c11bdaa7b412396077f2b3d2a7dedab490a881a0a96754 - languageName: node - linkType: hard - -"globby@npm:^11.0.3": - version: 11.0.4 - resolution: "globby@npm:11.0.4" - dependencies: - array-union: "npm:^2.1.0" - dir-glob: "npm:^3.0.1" - fast-glob: "npm:^3.1.1" - ignore: "npm:^5.1.4" - merge2: "npm:^1.3.0" - slash: "npm:^3.0.0" - checksum: 10c0/de5f828c834baf75e3bd3c629bb3a64d1dfa9965831d0b105b728f9184284c6ba2b0d42e24862b411abc18e6e0af12e60880b3a62e096752de3426f2839f9ef7 - languageName: node - linkType: hard - -"gopd@npm:^1.2.0": - version: 1.2.0 - resolution: "gopd@npm:1.2.0" - checksum: 10c0/50fff1e04ba2b7737c097358534eacadad1e68d24cccee3272e04e007bed008e68d2614f3987788428fd192a5ae3889d08fb2331417e4fc4a9ab366b2043cead - languageName: node - linkType: hard - -"got@npm:9.6.0": - version: 9.6.0 - resolution: "got@npm:9.6.0" - dependencies: - "@sindresorhus/is": "npm:^0.14.0" - "@szmarczak/http-timer": "npm:^1.1.2" - cacheable-request: "npm:^6.0.0" - decompress-response: "npm:^3.3.0" - duplexer3: "npm:^0.1.4" - get-stream: "npm:^4.1.0" - lowercase-keys: "npm:^1.0.1" - mimic-response: "npm:^1.0.1" - p-cancelable: "npm:^1.0.0" - to-readable-stream: "npm:^1.0.0" - url-parse-lax: "npm:^3.0.0" - checksum: 10c0/5cb3111e14b48bf4fb8b414627be481ebfb14151ec867e80a74b6d1472489965b9c4f4ac5cf4f3b1f9b90c60a2ce63584d9072b16efd9a3171553e00afc5abc8 - languageName: node - linkType: hard - -"got@npm:^7.1.0": - version: 7.1.0 - resolution: "got@npm:7.1.0" - dependencies: - decompress-response: "npm:^3.2.0" - duplexer3: "npm:^0.1.4" - get-stream: "npm:^3.0.0" - is-plain-obj: "npm:^1.1.0" - is-retry-allowed: "npm:^1.0.0" - is-stream: "npm:^1.0.0" - isurl: "npm:^1.0.0-alpha5" - lowercase-keys: "npm:^1.0.0" - p-cancelable: "npm:^0.3.0" - p-timeout: "npm:^1.1.1" - safe-buffer: "npm:^5.0.1" - timed-out: "npm:^4.0.0" - url-parse-lax: "npm:^1.0.0" - url-to-options: "npm:^1.0.1" - checksum: 10c0/e5faeeb3763cc0c249581407d5e99beb289cef0253ebe17c1e7c68fc10fe213b1fa10a3a9ca7b0a91bf3e1ee756daf451499bb583481f12131a4afb6a29394fd - languageName: node - linkType: hard - -"graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.9": - version: 4.2.8 - resolution: "graceful-fs@npm:4.2.8" - checksum: 10c0/68365485460f7d2e95c05c1b7aeee935349f3b7776488d5bd95a45d8a45bd4977442e88cbbdb4ea01bc72f49f01f75d83f049069774ac8cc4328af4bcff1c542 - languageName: node - linkType: hard - -"graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4": - version: 4.2.10 - resolution: "graceful-fs@npm:4.2.10" - checksum: 10c0/4223a833e38e1d0d2aea630c2433cfb94ddc07dfc11d511dbd6be1d16688c5be848acc31f9a5d0d0ddbfb56d2ee5a6ae0278aceeb0ca6a13f27e06b9956fb952 - languageName: node - linkType: hard - -"graceful-fs@npm:^4.2.6": - version: 4.2.11 - resolution: "graceful-fs@npm:4.2.11" - checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 - languageName: node - linkType: hard - -"handlebars@npm:^4.7.7": - version: 4.7.7 - resolution: "handlebars@npm:4.7.7" - dependencies: - minimist: "npm:^1.2.5" - neo-async: "npm:^2.6.0" - source-map: "npm:^0.6.1" - uglify-js: "npm:^3.1.4" - wordwrap: "npm:^1.0.0" - dependenciesMeta: - uglify-js: - optional: true - bin: - handlebars: bin/handlebars - checksum: 10c0/4c0913fc0018a2a2e358ee94e4fe83f071762b8bec51a473d187e6642e94e569843adcf550ffe329554c63ad450c062f3a05447bd2e3fff5ebfe698e214225c6 - languageName: node - linkType: hard - -"har-schema@npm:^2.0.0": - version: 2.0.0 - resolution: "har-schema@npm:2.0.0" - checksum: 10c0/3856cb76152658e0002b9c2b45b4360bb26b3e832c823caed8fcf39a01096030bf09fa5685c0f7b0f2cb3ecba6e9dce17edaf28b64a423d6201092e6be56e592 - languageName: node - linkType: hard - -"har-validator@npm:~5.1.3": - version: 5.1.5 - resolution: "har-validator@npm:5.1.5" - dependencies: - ajv: "npm:^6.12.3" - har-schema: "npm:^2.0.0" - checksum: 10c0/f1d606eb1021839e3a905be5ef7cca81c2256a6be0748efb8fefc14312214f9e6c15d7f2eaf37514104071207d84f627b68bb9f6178703da4e06fbd1a0649a5e - languageName: node - linkType: hard - -"hardhat-contract-sizer@npm:^2.5.1": - version: 2.5.1 - resolution: "hardhat-contract-sizer@npm:2.5.1" - dependencies: - chalk: "npm:^4.0.0" - cli-table3: "npm:^0.6.0" - peerDependencies: - hardhat: ^2.0.0 - checksum: 10c0/0bb1ff3496f96fcdc8a658db7b811be1155e70c9d31cc1d7afdd02b42b73e85182d7c5342a77f563696b73c22892094f9d10bc9158fbb8336195e0ddcf35fc79 - languageName: node - linkType: hard - -"hardhat-dependency-compiler@npm:^1.1.2": - version: 1.1.2 - resolution: "hardhat-dependency-compiler@npm:1.1.2" - peerDependencies: - hardhat: ^2.0.0 - checksum: 10c0/e300a8fcd1e520990c2798501e8aaa6ba8cf019e55ed393b6bc5466d68d4b89b9bfd1baaf493e990815dc3875e8808949df0bef95e46b9168c6788bf93c26461 - languageName: node - linkType: hard - -"hardhat-deploy@npm:^0.11.11": - version: 0.11.12 - resolution: "hardhat-deploy@npm:0.11.12" - dependencies: - "@types/qs": "npm:^6.9.7" - axios: "npm:^0.21.1" - chalk: "npm:^4.1.2" - chokidar: "npm:^3.5.2" - debug: "npm:^4.3.2" - enquirer: "npm:^2.3.6" - ethers: "npm:^5.5.3" - form-data: "npm:^4.0.0" - fs-extra: "npm:^10.0.0" - match-all: "npm:^1.2.6" - murmur-128: "npm:^0.2.1" - qs: "npm:^6.9.4" - zksync-web3: "npm:^0.7.8" - checksum: 10c0/32e3e1215e0fe68742acf626ddbba86732badf6c06183d7364249c3ae3064881bae23b023abf2c25602e9e907d72f48598ef58f0a78ebd93a3255ca2a905d9b2 - languageName: node - linkType: hard - -"hardhat-gas-reporter@npm:^2.3.0": - version: 2.3.0 - resolution: "hardhat-gas-reporter@npm:2.3.0" - dependencies: - "@ethersproject/abi": "npm:^5.7.0" - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/units": "npm:^5.7.0" - "@solidity-parser/parser": "npm:^0.20.1" - axios: "npm:^1.6.7" - brotli-wasm: "npm:^2.0.1" - chalk: "npm:4.1.2" - cli-table3: "npm:^0.6.3" - ethereum-cryptography: "npm:^2.1.3" - glob: "npm:^10.3.10" - jsonschema: "npm:^1.4.1" - lodash: "npm:^4.17.21" - markdown-table: "npm:2.0.0" - sha1: "npm:^1.1.1" - viem: "npm:^2.27.0" - peerDependencies: - hardhat: ^2.16.0 - checksum: 10c0/200ff3fb318de657e72e660526f41c692c4bb3a1b1a43414bd29c1737cf71d514258546bb7722abfad3c296a38e0c0d6e7239410beff4d26d6b529e0d6f94d62 - languageName: node - linkType: hard - -"hardhat@npm:2.29.0": - version: 2.29.0 - resolution: "hardhat@npm:2.29.0" - dependencies: - "@ethereumjs/util": "npm:^9.1.0" - "@ethersproject/abi": "npm:^5.1.2" - "@nomicfoundation/edr": "npm:0.12.0-next.23" - "@nomicfoundation/solidity-analyzer": "npm:^0.1.0" - "@sentry/node": "npm:^5.18.1" - adm-zip: "npm:^0.4.16" - aggregate-error: "npm:^3.0.0" - ansi-escapes: "npm:^4.3.0" - boxen: "npm:^5.1.2" - chokidar: "npm:^4.0.0" - ci-info: "npm:^2.0.0" - debug: "npm:^4.1.1" - enquirer: "npm:^2.3.0" - env-paths: "npm:^2.2.0" - ethereum-cryptography: "npm:^1.0.3" - find-up: "npm:^5.0.0" - fp-ts: "npm:1.19.3" - fs-extra: "npm:^7.0.1" - immutable: "npm:^4.0.0-rc.12" - io-ts: "npm:1.10.4" - json-stream-stringify: "npm:^3.1.4" - keccak: "npm:^3.0.2" - lodash: "npm:^4.17.11" - micro-eth-signer: "npm:^0.14.0" - mnemonist: "npm:^0.38.0" - mocha: "npm:^11.1.0" - p-map: "npm:^4.0.0" - picocolors: "npm:^1.1.0" - raw-body: "npm:^2.4.1" - resolve: "npm:1.17.0" - semver: "npm:^6.3.0" - solc: "npm:0.8.26" - source-map-support: "npm:^0.5.13" - stacktrace-parser: "npm:^0.1.10" - tinyglobby: "npm:^0.2.6" - tsort: "npm:0.0.1" - undici: "npm:^5.14.0" - uuid: "npm:^8.3.2" - ws: "npm:^7.4.6" - peerDependencies: - ts-node: "*" - typescript: "*" - peerDependenciesMeta: - ts-node: - optional: true - typescript: - optional: true - bin: - hardhat: internal/cli/bootstrap.js - checksum: 10c0/3cf2b446e64ca877bcf26e95259024bc872a9e44b63151c3bcfaf88b200672423d9c182ec0460d0944e506a3b096dd76bc4f1e6ade3ce908275f4e407b582f7f - languageName: node - linkType: hard - -"has-ansi@npm:^2.0.0": - version: 2.0.0 - resolution: "has-ansi@npm:2.0.0" - dependencies: - ansi-regex: "npm:^2.0.0" - checksum: 10c0/f54e4887b9f8f3c4bfefd649c48825b3c093987c92c27880ee9898539e6f01aed261e82e73153c3f920fde0db5bf6ebd58deb498ed1debabcb4bc40113ccdf05 - languageName: node - linkType: hard - -"has-bigints@npm:^1.0.1": - version: 1.0.1 - resolution: "has-bigints@npm:1.0.1" - checksum: 10c0/59dc0ceb28468fcad0d3fd20a5d679dd577bae177f5caaf0b1f742df42a30267271538ab282c1c7dce14fcb9ba53401055363edab51d28fbae85c17b30f98a31 - languageName: node - linkType: hard - -"has-flag@npm:^3.0.0": - version: 3.0.0 - resolution: "has-flag@npm:3.0.0" - checksum: 10c0/1c6c83b14b8b1b3c25b0727b8ba3e3b647f99e9e6e13eb7322107261de07a4c1be56fc0d45678fc376e09772a3a1642ccdaf8fc69bdf123b6c086598397ce473 - languageName: node - linkType: hard - -"has-flag@npm:^4.0.0": - version: 4.0.0 - resolution: "has-flag@npm:4.0.0" - checksum: 10c0/2e789c61b7888d66993e14e8331449e525ef42aac53c627cc53d1c3334e768bcb6abdc4f5f0de1478a25beec6f0bd62c7549058b7ac53e924040d4f301f02fd1 - languageName: node - linkType: hard - -"has-symbol-support-x@npm:^1.4.1": - version: 1.4.2 - resolution: "has-symbol-support-x@npm:1.4.2" - checksum: 10c0/993f0e1a7a2c8f41f356b20c33cda49bc2f5c4442f858b0fa58b4852f4ba50e7d7400a2734822c415975114e6f768bba9bb6063dd687026baaeeed6453d94a03 - languageName: node - linkType: hard - -"has-symbols@npm:^1.0.1, has-symbols@npm:^1.0.3": - version: 1.0.3 - resolution: "has-symbols@npm:1.0.3" - checksum: 10c0/e6922b4345a3f37069cdfe8600febbca791c94988c01af3394d86ca3360b4b93928bbf395859158f88099cb10b19d98e3bbab7c9ff2c1bd09cf665ee90afa2c3 - languageName: node - linkType: hard - -"has-symbols@npm:^1.0.2": - version: 1.0.2 - resolution: "has-symbols@npm:1.0.2" - checksum: 10c0/bfac913244c77e6cb4e3cb6d617a70419f5fa4e1959e828a789b958933ceb997706eafb9615f27089e8fa57449094a3c81695ed3ec0c3b2fa8be8d506640b0f7 - languageName: node - linkType: hard - -"has-symbols@npm:^1.1.0": - version: 1.1.0 - resolution: "has-symbols@npm:1.1.0" - checksum: 10c0/dde0a734b17ae51e84b10986e651c664379018d10b91b6b0e9b293eddb32f0f069688c841fb40f19e9611546130153e0a2a48fd7f512891fb000ddfa36f5a20e - languageName: node - linkType: hard - -"has-to-string-tag-x@npm:^1.2.0": - version: 1.4.1 - resolution: "has-to-string-tag-x@npm:1.4.1" - dependencies: - has-symbol-support-x: "npm:^1.4.1" - checksum: 10c0/e7197e830fe55afe596fc3fe4ab23fa455f69a1ba850b493e527c728d1e6d2ecc7197ab38b8bdc7ae8a7669e23c19a8b9f52f853a509639c70e0efbdc5d175e5 - languageName: node - linkType: hard - -"has-tostringtag@npm:^1.0.0": - version: 1.0.0 - resolution: "has-tostringtag@npm:1.0.0" - dependencies: - has-symbols: "npm:^1.0.2" - checksum: 10c0/1cdba76b7d13f65198a92b8ca1560ba40edfa09e85d182bf436d928f3588a9ebd260451d569f0ed1b849c4bf54f49c862aa0d0a77f9552b1855bb6deb526c011 - languageName: node - linkType: hard - -"has-tostringtag@npm:^1.0.2": - version: 1.0.2 - resolution: "has-tostringtag@npm:1.0.2" - dependencies: - has-symbols: "npm:^1.0.3" - checksum: 10c0/a8b166462192bafe3d9b6e420a1d581d93dd867adb61be223a17a8d6dad147aa77a8be32c961bb2f27b3ef893cae8d36f564ab651f5e9b7938ae86f74027c48c - languageName: node - linkType: hard - -"has-value@npm:^0.3.1": - version: 0.3.1 - resolution: "has-value@npm:0.3.1" - dependencies: - get-value: "npm:^2.0.3" - has-values: "npm:^0.1.4" - isobject: "npm:^2.0.0" - checksum: 10c0/7a7c2e9d07bc9742c81806150adb154d149bc6155267248c459cd1ce2a64b0759980d26213260e4b7599c8a3754551179f155ded88d0533a0d2bc7bc29028432 - languageName: node - linkType: hard - -"has-value@npm:^1.0.0": - version: 1.0.0 - resolution: "has-value@npm:1.0.0" - dependencies: - get-value: "npm:^2.0.6" - has-values: "npm:^1.0.0" - isobject: "npm:^3.0.0" - checksum: 10c0/17cdccaf50f8aac80a109dba2e2ee5e800aec9a9d382ef9deab66c56b34269e4c9ac720276d5ffa722764304a1180ae436df077da0dd05548cfae0209708ba4d - languageName: node - linkType: hard - -"has-values@npm:^0.1.4": - version: 0.1.4 - resolution: "has-values@npm:0.1.4" - checksum: 10c0/a8f00ad862c20289798c35243d5bd0b0a97dd44b668c2204afe082e0265f2d0bf3b89fc8cc0ef01a52b49f10aa35cf85c336ee3a5f1cac96ed490f5e901cdbf2 - languageName: node - linkType: hard - -"has-values@npm:^1.0.0": - version: 1.0.0 - resolution: "has-values@npm:1.0.0" - dependencies: - is-number: "npm:^3.0.0" - kind-of: "npm:^4.0.0" - checksum: 10c0/a6f2a1cc6b2e43eacc68e62e71ad6890def7f4b13d2ef06b4ad3ee156c23e470e6df144b9b467701908e17633411f1075fdff0cab45fb66c5e0584d89b25f35e - languageName: node - linkType: hard - -"has@npm:^1.0.3, has@npm:~1.0.3": - version: 1.0.3 - resolution: "has@npm:1.0.3" - dependencies: - function-bind: "npm:^1.1.1" - checksum: 10c0/e1da0d2bd109f116b632f27782cf23182b42f14972ca9540e4c5aa7e52647407a0a4a76937334fddcb56befe94a3494825ec22b19b51f5e5507c3153fd1a5e1b - languageName: node - linkType: hard - -"hash-base@npm:^3.0.0": - version: 3.1.0 - resolution: "hash-base@npm:3.1.0" - dependencies: - inherits: "npm:^2.0.4" - readable-stream: "npm:^3.6.0" - safe-buffer: "npm:^5.2.0" - checksum: 10c0/663eabcf4173326fbb65a1918a509045590a26cc7e0964b754eef248d281305c6ec9f6b31cb508d02ffca383ab50028180ce5aefe013e942b44a903ac8dc80d0 - languageName: node - linkType: hard - -"hash.js@npm:1.1.7, hash.js@npm:^1.0.0, hash.js@npm:^1.0.3, hash.js@npm:^1.1.7": - version: 1.1.7 - resolution: "hash.js@npm:1.1.7" - dependencies: - inherits: "npm:^2.0.3" - minimalistic-assert: "npm:^1.0.1" - checksum: 10c0/41ada59494eac5332cfc1ce6b7ebdd7b88a3864a6d6b08a3ea8ef261332ed60f37f10877e0c825aaa4bddebf164fbffa618286aeeec5296675e2671cbfa746c4 - languageName: node - linkType: hard - -"hasown@npm:^2.0.2, hasown@npm:^2.0.4": - version: 2.0.4 - resolution: "hasown@npm:2.0.4" - dependencies: - function-bind: "npm:^1.1.2" - checksum: 10c0/2d8de939e270b70618f8cebb69746620db10617dbb495bc66ddad326955ea24d3ca4af133aff3eb7c1853e0218f867bc2b050ec26fe02e3aea58f880ffc5e506 - languageName: node - linkType: hard - -"he@npm:^1.2.0": - version: 1.2.0 - resolution: "he@npm:1.2.0" - bin: - he: bin/he - checksum: 10c0/a27d478befe3c8192f006cdd0639a66798979dfa6e2125c6ac582a19a5ebfec62ad83e8382e6036170d873f46e4536a7e795bf8b95bf7c247f4cc0825ccc8c17 - languageName: node - linkType: hard - -"heap@npm:0.2.6": - version: 0.2.6 - resolution: "heap@npm:0.2.6" - checksum: 10c0/8c1b74c2c538478105a2bad1d7983393cc24ea3f9822c89d6b4e9d14536b3bc4885d187962512c03e8f98b6a313fa58a12cf551a130457e768bfa38045f6e31a - languageName: node - linkType: hard - -"hmac-drbg@npm:^1.0.1": - version: 1.0.1 - resolution: "hmac-drbg@npm:1.0.1" - dependencies: - hash.js: "npm:^1.0.3" - minimalistic-assert: "npm:^1.0.0" - minimalistic-crypto-utils: "npm:^1.0.1" - checksum: 10c0/f3d9ba31b40257a573f162176ac5930109816036c59a09f901eb2ffd7e5e705c6832bedfff507957125f2086a0ab8f853c0df225642a88bf1fcaea945f20600d - languageName: node - linkType: hard - -"home-or-tmp@npm:^2.0.0": - version: 2.0.0 - resolution: "home-or-tmp@npm:2.0.0" - dependencies: - os-homedir: "npm:^1.0.0" - os-tmpdir: "npm:^1.0.1" - checksum: 10c0/a0e0d26db09dc0b3245f52a9159d3e970e628ddc22d69842e8413ea42f81d5a29c3808f9b08ea4d48db084e4e693193cc238c114775aa92d753bf95a9daa10fb - languageName: node - linkType: hard - -"hosted-git-info@npm:^2.1.4, hosted-git-info@npm:^2.6.0": - version: 2.8.9 - resolution: "hosted-git-info@npm:2.8.9" - checksum: 10c0/317cbc6b1bbbe23c2a40ae23f3dafe9fa349ce42a89a36f930e3f9c0530c179a3882d2ef1e4141a4c3674d6faaea862138ec55b43ad6f75e387fda2483a13c70 - languageName: node - linkType: hard - -"http-cache-semantics@npm:^4.0.0": - version: 4.1.1 - resolution: "http-cache-semantics@npm:4.1.1" - checksum: 10c0/ce1319b8a382eb3cbb4a37c19f6bfe14e5bb5be3d09079e885e8c513ab2d3cd9214902f8a31c9dc4e37022633ceabfc2d697405deeaf1b8f3552bb4ed996fdfc - languageName: node - linkType: hard - -"http-cache-semantics@npm:^4.1.1": - version: 4.2.0 - resolution: "http-cache-semantics@npm:4.2.0" - checksum: 10c0/45b66a945cf13ec2d1f29432277201313babf4a01d9e52f44b31ca923434083afeca03f18417f599c9ab3d0e7b618ceb21257542338b57c54b710463b4a53e37 - languageName: node - linkType: hard - -"http-errors@npm:1.7.3": - version: 1.7.3 - resolution: "http-errors@npm:1.7.3" - dependencies: - depd: "npm:~1.1.2" - inherits: "npm:2.0.4" - setprototypeof: "npm:1.1.1" - statuses: "npm:>= 1.5.0 < 2" - toidentifier: "npm:1.0.0" - checksum: 10c0/5c3443c340d35b2f18ce908266c4ae93305b7d900bef765ac8dc56fa90125b9fe18a1ed9ebf6af23dc3ba7763731921a2682bf968e199eccf383eb8f508be6c2 - languageName: node - linkType: hard - -"http-errors@npm:2.0.0": - version: 2.0.0 - resolution: "http-errors@npm:2.0.0" - dependencies: - depd: "npm:2.0.0" - inherits: "npm:2.0.4" - setprototypeof: "npm:1.2.0" - statuses: "npm:2.0.1" - toidentifier: "npm:1.0.1" - checksum: 10c0/fc6f2715fe188d091274b5ffc8b3657bd85c63e969daa68ccb77afb05b071a4b62841acb7a21e417b5539014dff2ebf9550f0b14a9ff126f2734a7c1387f8e19 - languageName: node - linkType: hard - -"http-https@npm:^1.0.0": - version: 1.0.0 - resolution: "http-https@npm:1.0.0" - checksum: 10c0/ffdec0da28627110d1dd9fbe3f9d0b61b1876c3c856d460c532b69fc0536adba0e032cd7acafad82fcb970ae9c5b34ae8340ef17aa422124b56c27f4da8fc74a - languageName: node - linkType: hard - -"http-proxy-agent@npm:^7.0.0": - version: 7.0.2 - resolution: "http-proxy-agent@npm:7.0.2" - dependencies: - agent-base: "npm:^7.1.0" - debug: "npm:^4.3.4" - checksum: 10c0/4207b06a4580fb85dd6dff521f0abf6db517489e70863dca1a0291daa7f2d3d2d6015a57bd702af068ea5cf9f1f6ff72314f5f5b4228d299c0904135d2aef921 - languageName: node - linkType: hard - -"http-signature@npm:~1.2.0": - version: 1.2.0 - resolution: "http-signature@npm:1.2.0" - dependencies: - assert-plus: "npm:^1.0.0" - jsprim: "npm:^1.2.2" - sshpk: "npm:^1.7.0" - checksum: 10c0/582f7af7f354429e1fb19b3bbb9d35520843c69bb30a25b88ca3c5c2c10715f20ae7924e20cffbed220b1d3a726ef4fe8ccc48568d5744db87be9a79887d6733 - languageName: node - linkType: hard - -"https-proxy-agent@npm:^5.0.0": - version: 5.0.0 - resolution: "https-proxy-agent@npm:5.0.0" - dependencies: - agent-base: "npm:6" - debug: "npm:4" - checksum: 10c0/670c04f7f0effb5a449c094ea037cbcfb28a5ab93ed22e8c343095202cc7288027869a5a21caf4ee3b8ea06f9624ef1e1fc9044669c0fd92617654ff39f30806 - languageName: node - linkType: hard - -"https-proxy-agent@npm:^5.0.1": - version: 5.0.1 - resolution: "https-proxy-agent@npm:5.0.1" - dependencies: - agent-base: "npm:6" - debug: "npm:4" - checksum: 10c0/6dd639f03434003577c62b27cafdb864784ef19b2de430d8ae2a1d45e31c4fd60719e5637b44db1a88a046934307da7089e03d6089ec3ddacc1189d8de8897d1 - languageName: node - linkType: hard - -"https-proxy-agent@npm:^7.0.1": - version: 7.0.6 - resolution: "https-proxy-agent@npm:7.0.6" - dependencies: - agent-base: "npm:^7.1.2" - debug: "npm:4" - checksum: 10c0/f729219bc735edb621fa30e6e84e60ee5d00802b8247aac0d7b79b0bd6d4b3294737a337b93b86a0bd9e68099d031858a39260c976dc14cdbba238ba1f8779ac - languageName: node - linkType: hard - -"iconv-lite@npm:0.4.24, iconv-lite@npm:^0.4.24": - version: 0.4.24 - resolution: "iconv-lite@npm:0.4.24" - dependencies: - safer-buffer: "npm:>= 2.1.2 < 3" - checksum: 10c0/c6886a24cc00f2a059767440ec1bc00d334a89f250db8e0f7feb4961c8727118457e27c495ba94d082e51d3baca378726cd110aaf7ded8b9bbfd6a44760cf1d4 - languageName: node - linkType: hard - -"iconv-lite@npm:^0.6.2": - version: 0.6.3 - resolution: "iconv-lite@npm:0.6.3" - dependencies: - safer-buffer: "npm:>= 2.1.2 < 3.0.0" - checksum: 10c0/98102bc66b33fcf5ac044099d1257ba0b7ad5e3ccd3221f34dd508ab4070edff183276221684e1e0555b145fce0850c9f7d2b60a9fcac50fbb4ea0d6e845a3b1 - languageName: node - linkType: hard - -"iconv-lite@npm:^0.7.2": - version: 0.7.2 - resolution: "iconv-lite@npm:0.7.2" - dependencies: - safer-buffer: "npm:>= 2.1.2 < 3.0.0" - checksum: 10c0/3c228920f3bd307f56bf8363706a776f4a060eb042f131cd23855ceca962951b264d0997ab38a1ad340e1c5df8499ed26e1f4f0db6b2a2ad9befaff22f14b722 - languageName: node - linkType: hard - -"idna-uts46-hx@npm:^2.3.1": - version: 2.3.1 - resolution: "idna-uts46-hx@npm:2.3.1" - dependencies: - punycode: "npm:2.1.0" - checksum: 10c0/e38d4684ca64449560bda9efc84554c7802a0a732a73c9eb89b561d970c26e431b1975264860c98c921da2126726ebd8ae8752099e9ea55914d0b5abcc950121 - languageName: node - linkType: hard - -"ieee754@npm:^1.1.13": - version: 1.2.1 - resolution: "ieee754@npm:1.2.1" - checksum: 10c0/b0782ef5e0935b9f12883a2e2aa37baa75da6e66ce6515c168697b42160807d9330de9a32ec1ed73149aea02e0d822e572bca6f1e22bdcbd2149e13b050b17bb - languageName: node - linkType: hard - -"ignore@npm:^4.0.6": - version: 4.0.6 - resolution: "ignore@npm:4.0.6" - checksum: 10c0/836ee7dc7fd9436096e2dba429359dbb9fa0e33d309e2b2d81692f375f6ca82024fc00567f798613d50c6b989e9cd2ad2b065acf116325cde177f02c86b7d4e0 - languageName: node - linkType: hard - -"ignore@npm:^5.1.4, ignore@npm:^5.1.8": - version: 5.1.8 - resolution: "ignore@npm:5.1.8" - checksum: 10c0/3d09e733049c7bad1c0982be8fe3e767bd7b756dd0bfeceff11acda0b7b57634b5516acc3554d2d536e64b2701b3d08d0e5fa4dbf46389847dd3f8fa49d437bb - languageName: node - linkType: hard - -"immediate@npm:^3.2.3": - version: 3.3.0 - resolution: "immediate@npm:3.3.0" - checksum: 10c0/40eab095d5944ad79af054700beee97000271fde8743720932d8eb41ccbf2cb8c855ff95b128cf9a7fec523a4f11ee2e392b9f2fa6456b055b1160f1b4ad3e3b - languageName: node - linkType: hard - -"immediate@npm:~3.2.3": - version: 3.2.3 - resolution: "immediate@npm:3.2.3" - checksum: 10c0/e2affb7f1a1335a3d0404073bcec5e6b09cdd15f0a4ec82b9a0f0496add2e0b020843123c021238934c3eac8792f8d48f523c48e7c3c0cd45b540dc9d149adae - languageName: node - linkType: hard - -"immutable@npm:^4.0.0-rc.12": - version: 4.0.0-rc.15 - resolution: "immutable@npm:4.0.0-rc.15" - checksum: 10c0/122a69825e923a14346c8446f75165368c2cf53c021059a5eb8b55bf456e61d06d8295416a588c37ca4d32d365f3dfa309481caa4a41bd9aa0f804501b6587a9 - languageName: node - linkType: hard - -"import-fresh@npm:^2.0.0": - version: 2.0.0 - resolution: "import-fresh@npm:2.0.0" - dependencies: - caller-path: "npm:^2.0.0" - resolve-from: "npm:^3.0.0" - checksum: 10c0/116c55ee5215a7839062285b60df85dbedde084c02111dc58c1b9d03ff7876627059f4beb16cdc090a3db21fea9022003402aa782139dc8d6302589038030504 - languageName: node - linkType: hard - -"import-fresh@npm:^3.0.0, import-fresh@npm:^3.2.1": - version: 3.3.0 - resolution: "import-fresh@npm:3.3.0" - dependencies: - parent-module: "npm:^1.0.0" - resolve-from: "npm:^4.0.0" - checksum: 10c0/7f882953aa6b740d1f0e384d0547158bc86efbf2eea0f1483b8900a6f65c5a5123c2cf09b0d542cc419d0b98a759ecaeb394237e97ea427f2da221dc3cd80cc3 - languageName: node - linkType: hard - -"imul@npm:^1.0.0": - version: 1.0.1 - resolution: "imul@npm:1.0.1" - checksum: 10c0/d564c45a5017f01f965509ef409fad8175749bc96a52a95e1a09f05378d135fb37051cea7194d0eeca5147541d8e80d68853f5f681eef05f9f14f1d551edae2f - languageName: node - linkType: hard - -"imurmurhash@npm:^0.1.4": - version: 0.1.4 - resolution: "imurmurhash@npm:0.1.4" - checksum: 10c0/8b51313850dd33605c6c9d3fd9638b714f4c4c40250cff658209f30d40da60f78992fb2df5dabee4acf589a6a82bbc79ad5486550754bd9ec4e3fc0d4a57d6a6 - languageName: node - linkType: hard - -"indent-string@npm:^4.0.0": - version: 4.0.0 - resolution: "indent-string@npm:4.0.0" - checksum: 10c0/1e1904ddb0cb3d6cce7cd09e27a90184908b7a5d5c21b92e232c93579d314f0b83c246ffb035493d0504b1e9147ba2c9b21df0030f48673fba0496ecd698161f - languageName: node - linkType: hard - -"inflight@npm:^1.0.4": - version: 1.0.6 - resolution: "inflight@npm:1.0.6" - dependencies: - once: "npm:^1.3.0" - wrappy: "npm:1" - checksum: 10c0/7faca22584600a9dc5b9fca2cd5feb7135ac8c935449837b315676b4c90aa4f391ec4f42240178244b5a34e8bede1948627fda392ca3191522fc46b34e985ab2 - languageName: node - linkType: hard - -"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.1, inherits@npm:~2.0.3, inherits@npm:~2.0.4": - version: 2.0.4 - resolution: "inherits@npm:2.0.4" - checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 - languageName: node - linkType: hard - -"inquirer@npm:^6.2.2": - version: 6.5.2 - resolution: "inquirer@npm:6.5.2" - dependencies: - ansi-escapes: "npm:^3.2.0" - chalk: "npm:^2.4.2" - cli-cursor: "npm:^2.1.0" - cli-width: "npm:^2.0.0" - external-editor: "npm:^3.0.3" - figures: "npm:^2.0.0" - lodash: "npm:^4.17.12" - mute-stream: "npm:0.0.7" - run-async: "npm:^2.2.0" - rxjs: "npm:^6.4.0" - string-width: "npm:^2.1.0" - strip-ansi: "npm:^5.1.0" - through: "npm:^2.3.6" - checksum: 10c0/a5aa53a8f88405cf1cff63111493f87a5b3b5deb5ea4a0dbcd73ccc06a51a6bba0c3f1a0747f8880e9e3ec2437c69f90417be16368abf636b1d29eebe35db0ac - languageName: node - linkType: hard - -"internal-slot@npm:^1.0.3": - version: 1.0.3 - resolution: "internal-slot@npm:1.0.3" - dependencies: - get-intrinsic: "npm:^1.1.0" - has: "npm:^1.0.3" - side-channel: "npm:^1.0.4" - checksum: 10c0/bb41342a474c1b607458b0c716c742d779a6ed9dfaf7986e5d20d1e7f55b7f3676e4d9f416bc253af4fd78d367e1f83e586f74840302bcf2e60c424f9284dde5 - languageName: node - linkType: hard - -"invariant@npm:^2.2.2": - version: 2.2.4 - resolution: "invariant@npm:2.2.4" - dependencies: - loose-envify: "npm:^1.0.0" - checksum: 10c0/5af133a917c0bcf65e84e7f23e779e7abc1cd49cb7fdc62d00d1de74b0d8c1b5ee74ac7766099fb3be1b05b26dfc67bab76a17030d2fe7ea2eef867434362dfc - languageName: node - linkType: hard - -"invert-kv@npm:^1.0.0": - version: 1.0.0 - resolution: "invert-kv@npm:1.0.0" - checksum: 10c0/9ccef12ada8494c56175cc0380b4cea18b6c0a368436f324a30e43a332db90bdfb83cd3a7987b71df359cdf931ce45b7daf35b677da56658565d61068e4bc20b - languageName: node - linkType: hard - -"io-ts@npm:1.10.4": - version: 1.10.4 - resolution: "io-ts@npm:1.10.4" - dependencies: - fp-ts: "npm:^1.0.0" - checksum: 10c0/9370988a7e17fc23c194115808168ccd1ccf7b7ebe92c39c1cc2fd91c1dc641552a5428bb04fe28c01c826fa4f230e856eb4f7d27c774a1400af3fecf2936ab5 - languageName: node - linkType: hard - -"ip-address@npm:^10.0.1": - version: 10.1.0 - resolution: "ip-address@npm:10.1.0" - checksum: 10c0/0103516cfa93f6433b3bd7333fa876eb21263912329bfa47010af5e16934eeeff86f3d2ae700a3744a137839ddfad62b900c7a445607884a49b5d1e32a3d7566 - languageName: node - linkType: hard - -"ipaddr.js@npm:1.9.1": - version: 1.9.1 - resolution: "ipaddr.js@npm:1.9.1" - checksum: 10c0/0486e775047971d3fdb5fb4f063829bac45af299ae0b82dcf3afa2145338e08290563a2a70f34b732d795ecc8311902e541a8530eeb30d75860a78ff4e94ce2a - languageName: node - linkType: hard - -"is-accessor-descriptor@npm:^0.1.6": - version: 0.1.6 - resolution: "is-accessor-descriptor@npm:0.1.6" - dependencies: - kind-of: "npm:^3.0.2" - checksum: 10c0/f2c314b314ec6e8a6e559351bff3c7ee9aed7a5e9c6f61dd8cb9e1382c8bfe33dca3f0e0af13daf9ded9e6e66390ff23b4acfb615d7a249009a51506a7b0f151 - languageName: node - linkType: hard - -"is-accessor-descriptor@npm:^1.0.0": - version: 1.0.0 - resolution: "is-accessor-descriptor@npm:1.0.0" - dependencies: - kind-of: "npm:^6.0.0" - checksum: 10c0/d68edafd8ef133e9003837f3c80f4e5b82b12ab5456c772d1796857671ae83e3a426ed225a28a7e35bceabbce68c1f1ffdabf47e6d53f5a4d6c4558776ad3c20 - languageName: node - linkType: hard - -"is-arguments@npm:^1.0.4": - version: 1.1.1 - resolution: "is-arguments@npm:1.1.1" - dependencies: - call-bind: "npm:^1.0.2" - has-tostringtag: "npm:^1.0.0" - checksum: 10c0/5ff1f341ee4475350adfc14b2328b38962564b7c2076be2f5bac7bd9b61779efba99b9f844a7b82ba7654adccf8e8eb19d1bb0cc6d1c1a085e498f6793d4328f - languageName: node - linkType: hard - -"is-arrayish@npm:^0.2.1": - version: 0.2.1 - resolution: "is-arrayish@npm:0.2.1" - checksum: 10c0/e7fb686a739068bb70f860b39b67afc62acc62e36bb61c5f965768abce1873b379c563e61dd2adad96ebb7edf6651111b385e490cf508378959b0ed4cac4e729 - languageName: node - linkType: hard - -"is-bigint@npm:^1.0.1": - version: 1.0.4 - resolution: "is-bigint@npm:1.0.4" - dependencies: - has-bigints: "npm:^1.0.1" - checksum: 10c0/eb9c88e418a0d195ca545aff2b715c9903d9b0a5033bc5922fec600eb0c3d7b1ee7f882dbf2e0d5a6e694e42391be3683e4368737bd3c4a77f8ac293e7773696 - languageName: node - linkType: hard - -"is-binary-path@npm:~2.1.0": - version: 2.1.0 - resolution: "is-binary-path@npm:2.1.0" - dependencies: - binary-extensions: "npm:^2.0.0" - checksum: 10c0/a16eaee59ae2b315ba36fad5c5dcaf8e49c3e27318f8ab8fa3cdb8772bf559c8d1ba750a589c2ccb096113bb64497084361a25960899cb6172a6925ab6123d38 - languageName: node - linkType: hard - -"is-boolean-object@npm:^1.1.0": - version: 1.1.2 - resolution: "is-boolean-object@npm:1.1.2" - dependencies: - call-bind: "npm:^1.0.2" - has-tostringtag: "npm:^1.0.0" - checksum: 10c0/6090587f8a8a8534c0f816da868bc94f32810f08807aa72fa7e79f7e11c466d281486ffe7a788178809c2aa71fe3e700b167fe80dd96dad68026bfff8ebf39f7 - languageName: node - linkType: hard - -"is-buffer@npm:^1.1.5": - version: 1.1.6 - resolution: "is-buffer@npm:1.1.6" - checksum: 10c0/ae18aa0b6e113d6c490ad1db5e8df9bdb57758382b313f5a22c9c61084875c6396d50bbf49315f5b1926d142d74dfb8d31b40d993a383e0a158b15fea7a82234 - languageName: node - linkType: hard - -"is-callable@npm:^1.1.3, is-callable@npm:^1.1.4, is-callable@npm:^1.2.4": - version: 1.2.4 - resolution: "is-callable@npm:1.2.4" - checksum: 10c0/bda3c67128741129d61e1cb7ca89025ca56b39bf3564657989567c9f6d1e20d6f5579750d3c1fa8887903c6dc669fbc695e33a1363e7c5ec944077e39d24f73d - languageName: node - linkType: hard - -"is-ci@npm:^2.0.0": - version: 2.0.0 - resolution: "is-ci@npm:2.0.0" - dependencies: - ci-info: "npm:^2.0.0" - bin: - is-ci: bin.js - checksum: 10c0/17de4e2cd8f993c56c86472dd53dd9e2c7f126d0ee55afe610557046cdd64de0e8feadbad476edc9eeff63b060523b8673d9094ed2ab294b59efb5a66dd05a9a - languageName: node - linkType: hard - -"is-core-module@npm:^2.2.0, is-core-module@npm:^2.6.0": - version: 2.7.0 - resolution: "is-core-module@npm:2.7.0" - dependencies: - has: "npm:^1.0.3" - checksum: 10c0/525bbb1580637a7f85e0d1e5537fed8008242f90782cb962ec5385cb76b63a8e8cd27cde43c854adc1dd3a62e1a7788cc952be4a99a865b92bdaa377bf913fa5 - languageName: node - linkType: hard - -"is-data-descriptor@npm:^0.1.4": - version: 0.1.4 - resolution: "is-data-descriptor@npm:0.1.4" - dependencies: - kind-of: "npm:^3.0.2" - checksum: 10c0/32fda7e966b2c1f093230d5ef2aad1bb86e43e7280da50961e38ec31dbd8a50570a2911fd45277d321074a0762adc98e8462bb62820462594128857225e90d21 - languageName: node - linkType: hard - -"is-data-descriptor@npm:^1.0.0": - version: 1.0.0 - resolution: "is-data-descriptor@npm:1.0.0" - dependencies: - kind-of: "npm:^6.0.0" - checksum: 10c0/bed31385d7d1a0dbb2ab3077faf2188acf42609192dca4e320ed7b3dc14a9d70c00658956cdaa2c0402be136c6b56e183973ad81b730fd90ab427fb6fd3608be - languageName: node - linkType: hard - -"is-date-object@npm:^1.0.1": - version: 1.0.5 - resolution: "is-date-object@npm:1.0.5" - dependencies: - has-tostringtag: "npm:^1.0.0" - checksum: 10c0/eed21e5dcc619c48ccef804dfc83a739dbb2abee6ca202838ee1bd5f760fe8d8a93444f0d49012ad19bb7c006186e2884a1b92f6e1c056da7fd23d0a9ad5992e - languageName: node - linkType: hard - -"is-descriptor@npm:^0.1.0": - version: 0.1.6 - resolution: "is-descriptor@npm:0.1.6" - dependencies: - is-accessor-descriptor: "npm:^0.1.6" - is-data-descriptor: "npm:^0.1.4" - kind-of: "npm:^5.0.0" - checksum: 10c0/6b8f5617b764ef8c6be3d54830184357e6cdedd8e0eddf1b97d0658616ac170bfdbc7c1ad00e0aa9f5b767acdb9d6c63d4df936501784b34936bd0f9acf3b665 - languageName: node - linkType: hard - -"is-descriptor@npm:^1.0.0, is-descriptor@npm:^1.0.2": - version: 1.0.2 - resolution: "is-descriptor@npm:1.0.2" - dependencies: - is-accessor-descriptor: "npm:^1.0.0" - is-data-descriptor: "npm:^1.0.0" - kind-of: "npm:^6.0.2" - checksum: 10c0/a05169c7a87feb88fc155e3ada469090cfabb5a548a3f794358b511cc47a0871b8b95e7345be4925a22ef3df585c3923b31943b3ad6255ce563a9d97f2e221e0 - languageName: node - linkType: hard - -"is-directory@npm:^0.3.1": - version: 0.3.1 - resolution: "is-directory@npm:0.3.1" - checksum: 10c0/1c39c7d1753b04e9483b89fb88908b8137ab4743b6f481947e97ccf93ecb384a814c8d3f0b95b082b149c5aa19c3e9e4464e2791d95174bce95998c26bb1974b - languageName: node - linkType: hard - -"is-docker@npm:^2.0.0": - version: 2.2.1 - resolution: "is-docker@npm:2.2.1" - bin: - is-docker: cli.js - checksum: 10c0/e828365958d155f90c409cdbe958f64051d99e8aedc2c8c4cd7c89dcf35329daed42f7b99346f7828df013e27deb8f721cf9408ba878c76eb9e8290235fbcdcc - languageName: node - linkType: hard - -"is-extendable@npm:^0.1.0, is-extendable@npm:^0.1.1": - version: 0.1.1 - resolution: "is-extendable@npm:0.1.1" - checksum: 10c0/dd5ca3994a28e1740d1e25192e66eed128e0b2ff161a7ea348e87ae4f616554b486854de423877a2a2c171d5f7cd6e8093b91f54533bc88a59ee1c9838c43879 - languageName: node - linkType: hard - -"is-extendable@npm:^1.0.1": - version: 1.0.1 - resolution: "is-extendable@npm:1.0.1" - dependencies: - is-plain-object: "npm:^2.0.4" - checksum: 10c0/1d6678a5be1563db6ecb121331c819c38059703f0179f52aa80c242c223ee9c6b66470286636c0e63d7163e4d905c0a7d82a096e0b5eaeabb51b9f8d0af0d73f - languageName: node - linkType: hard - -"is-extglob@npm:^2.1.1": - version: 2.1.1 - resolution: "is-extglob@npm:2.1.1" - checksum: 10c0/5487da35691fbc339700bbb2730430b07777a3c21b9ebaecb3072512dfd7b4ba78ac2381a87e8d78d20ea08affb3f1971b4af629173a6bf435ff8a4c47747912 - languageName: node - linkType: hard - -"is-finite@npm:^1.0.0": - version: 1.1.0 - resolution: "is-finite@npm:1.1.0" - checksum: 10c0/ca6bc7a0321b339f098e657bd4cbf4bb2410f5a11f1b9adb1a1a9ab72288b64368e8251326cb1f74e985f2779299cec3e1f1e558b68ce7e1e2c9be17b7cfd626 - languageName: node - linkType: hard - -"is-fn@npm:^1.0.0": - version: 1.0.0 - resolution: "is-fn@npm:1.0.0" - checksum: 10c0/0b4a3a9f71717d0cde510594c1bc3df31156ea4ac90f1f8d144ce6f97b30ce1c0ce6a99e32c97b63855c738973ea684ebd39b6baade3724e88e5bae909af448e - languageName: node - linkType: hard - -"is-fullwidth-code-point@npm:^1.0.0": - version: 1.0.0 - resolution: "is-fullwidth-code-point@npm:1.0.0" - dependencies: - number-is-nan: "npm:^1.0.0" - checksum: 10c0/12acfcf16142f2d431bf6af25d68569d3198e81b9799b4ae41058247aafcc666b0127d64384ea28e67a746372611fcbe9b802f69175287aba466da3eddd5ba0f - languageName: node - linkType: hard - -"is-fullwidth-code-point@npm:^2.0.0": - version: 2.0.0 - resolution: "is-fullwidth-code-point@npm:2.0.0" - checksum: 10c0/e58f3e4a601fc0500d8b2677e26e9fe0cd450980e66adb29d85b6addf7969731e38f8e43ed2ec868a09c101a55ac3d8b78902209269f38c5286bc98f5bc1b4d9 - languageName: node - linkType: hard - -"is-fullwidth-code-point@npm:^3.0.0": - version: 3.0.0 - resolution: "is-fullwidth-code-point@npm:3.0.0" - checksum: 10c0/bb11d825e049f38e04c06373a8d72782eee0205bda9d908cc550ccb3c59b99d750ff9537982e01733c1c94a58e35400661f57042158ff5e8f3e90cf936daf0fc - languageName: node - linkType: hard - -"is-function@npm:^1.0.1": - version: 1.0.2 - resolution: "is-function@npm:1.0.2" - checksum: 10c0/c55289042a0e828a773f1245e2652e0c029efacc78ebe03e61787746fda74e2c41006cd908f20b53c36e45f9e75464475a4b2d68b17f4c7b9f8018bcaec42f9e - languageName: node - linkType: hard - -"is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:~4.0.1": - version: 4.0.3 - resolution: "is-glob@npm:4.0.3" - dependencies: - is-extglob: "npm:^2.1.1" - checksum: 10c0/17fb4014e22be3bbecea9b2e3a76e9e34ff645466be702f1693e8f1ee1adac84710d0be0bd9f967d6354036fd51ab7c2741d954d6e91dae6bb69714de92c197a - languageName: node - linkType: hard - -"is-hex-prefixed@npm:1.0.0": - version: 1.0.0 - resolution: "is-hex-prefixed@npm:1.0.0" - checksum: 10c0/767fa481020ae654ab085ca24c63c518705ff36fdfbfc732292dc69092c6f8fdc551f6ce8c5f6ae704b0a19294e6f62be1b4b9859f0e1ac76e3b1b0733599d94 - languageName: node - linkType: hard - -"is-negative-zero@npm:^2.0.1": - version: 2.0.1 - resolution: "is-negative-zero@npm:2.0.1" - checksum: 10c0/e1ddf48f9e61a4802ccaa2ea9678fa8861dad25d57dcfd03a481320eaac42a3e2e0e8cabc1c8662d05f0188620a92b05c7e4aed8c1ebf48da96ff7a1af8e0f78 - languageName: node - linkType: hard - -"is-number-object@npm:^1.0.4": - version: 1.0.6 - resolution: "is-number-object@npm:1.0.6" - dependencies: - has-tostringtag: "npm:^1.0.0" - checksum: 10c0/f3220cd4882ed6c18f08d5122d320b353bc3ceeab5d93dbefded56da70fb544eaa3f27323902dd64d76a84260504c9bf7f4743f2d1817c716658b972573ef6ff - languageName: node - linkType: hard - -"is-number@npm:^3.0.0": - version: 3.0.0 - resolution: "is-number@npm:3.0.0" - dependencies: - kind-of: "npm:^3.0.2" - checksum: 10c0/e639c54640b7f029623df24d3d103901e322c0c25ea5bde97cd723c2d0d4c05857a8364ab5c58d963089dbed6bf1d0ffe975cb6aef917e2ad0ccbca653d31b4f - languageName: node - linkType: hard - -"is-number@npm:^7.0.0": - version: 7.0.0 - resolution: "is-number@npm:7.0.0" - checksum: 10c0/b4686d0d3053146095ccd45346461bc8e53b80aeb7671cc52a4de02dbbf7dc0d1d2a986e2fe4ae206984b4d34ef37e8b795ebc4f4295c978373e6575e295d811 - languageName: node - linkType: hard - -"is-object@npm:^1.0.1": - version: 1.0.2 - resolution: "is-object@npm:1.0.2" - checksum: 10c0/9cfb80c3a850f453d4a77297e0556bc2040ac6bea5b6e418aee208654938b36bab768169bef3945ccfac7a9bb460edd8034e7c6d8973bcf147d7571e1b53e764 - languageName: node - linkType: hard - -"is-path-inside@npm:^3.0.3": - version: 3.0.3 - resolution: "is-path-inside@npm:3.0.3" - checksum: 10c0/cf7d4ac35fb96bab6a1d2c3598fe5ebb29aafb52c0aaa482b5a3ed9d8ba3edc11631e3ec2637660c44b3ce0e61a08d54946e8af30dec0b60a7c27296c68ffd05 - languageName: node - linkType: hard - -"is-plain-obj@npm:^1.1.0": - version: 1.1.0 - resolution: "is-plain-obj@npm:1.1.0" - checksum: 10c0/daaee1805add26f781b413fdf192fc91d52409583be30ace35c82607d440da63cc4cac0ac55136716688d6c0a2c6ef3edb2254fecbd1fe06056d6bd15975ee8c - languageName: node - linkType: hard - -"is-plain-obj@npm:^2.1.0": - version: 2.1.0 - resolution: "is-plain-obj@npm:2.1.0" - checksum: 10c0/e5c9814cdaa627a9ad0a0964ded0e0491bfd9ace405c49a5d63c88b30a162f1512c069d5b80997893c4d0181eadc3fed02b4ab4b81059aba5620bfcdfdeb9c53 - languageName: node - linkType: hard - -"is-plain-object@npm:^2.0.3, is-plain-object@npm:^2.0.4": - version: 2.0.4 - resolution: "is-plain-object@npm:2.0.4" - dependencies: - isobject: "npm:^3.0.1" - checksum: 10c0/f050fdd5203d9c81e8c4df1b3ff461c4bc64e8b5ca383bcdde46131361d0a678e80bcf00b5257646f6c636197629644d53bd8e2375aea633de09a82d57e942f4 - languageName: node - linkType: hard - -"is-regex@npm:^1.0.4, is-regex@npm:^1.1.4, is-regex@npm:~1.1.3": - version: 1.1.4 - resolution: "is-regex@npm:1.1.4" - dependencies: - call-bind: "npm:^1.0.2" - has-tostringtag: "npm:^1.0.0" - checksum: 10c0/bb72aae604a69eafd4a82a93002058c416ace8cde95873589a97fc5dac96a6c6c78a9977d487b7b95426a8f5073969124dd228f043f9f604f041f32fcc465fc1 - languageName: node - linkType: hard - -"is-retry-allowed@npm:^1.0.0": - version: 1.2.0 - resolution: "is-retry-allowed@npm:1.2.0" - checksum: 10c0/a80f14e1e11c27a58f268f2927b883b635703e23a853cb7b8436e3456bf2ea3efd5082a4e920093eec7bd372c1ce6ea7cea78a9376929c211039d0cc4a393a44 - languageName: node - linkType: hard - -"is-shared-array-buffer@npm:^1.0.1": - version: 1.0.1 - resolution: "is-shared-array-buffer@npm:1.0.1" - checksum: 10c0/d27ff8661f30b6e90258a94c05c739260fb92f6c15d297cbf93e1122c6e7cf26ba65e89a63d427d22712f598905ca9d65840c1335449825aca4828e0bb53aa04 - languageName: node - linkType: hard - -"is-stream@npm:^1.0.0, is-stream@npm:^1.0.1": - version: 1.1.0 - resolution: "is-stream@npm:1.1.0" - checksum: 10c0/b8ae7971e78d2e8488d15f804229c6eed7ed36a28f8807a1815938771f4adff0e705218b7dab968270433f67103e4fef98062a0beea55d64835f705ee72c7002 - languageName: node - linkType: hard - -"is-string@npm:^1.0.5, is-string@npm:^1.0.7": - version: 1.0.7 - resolution: "is-string@npm:1.0.7" - dependencies: - has-tostringtag: "npm:^1.0.0" - checksum: 10c0/905f805cbc6eedfa678aaa103ab7f626aac9ebbdc8737abb5243acaa61d9820f8edc5819106b8fcd1839e33db21de9f0116ae20de380c8382d16dc2a601921f6 - languageName: node - linkType: hard - -"is-symbol@npm:^1.0.2, is-symbol@npm:^1.0.3": - version: 1.0.4 - resolution: "is-symbol@npm:1.0.4" - dependencies: - has-symbols: "npm:^1.0.2" - checksum: 10c0/9381dd015f7c8906154dbcbf93fad769de16b4b961edc94f88d26eb8c555935caa23af88bda0c93a18e65560f6d7cca0fd5a3f8a8e1df6f1abbb9bead4502ef7 - languageName: node - linkType: hard - -"is-typedarray@npm:^1.0.0, is-typedarray@npm:~1.0.0": - version: 1.0.0 - resolution: "is-typedarray@npm:1.0.0" - checksum: 10c0/4c096275ba041a17a13cca33ac21c16bc4fd2d7d7eb94525e7cd2c2f2c1a3ab956e37622290642501ff4310601e413b675cf399ad6db49855527d2163b3eeeec - languageName: node - linkType: hard - -"is-unicode-supported@npm:^0.1.0": - version: 0.1.0 - resolution: "is-unicode-supported@npm:0.1.0" - checksum: 10c0/00cbe3455c3756be68d2542c416cab888aebd5012781d6819749fefb15162ff23e38501fe681b3d751c73e8ff561ac09a5293eba6f58fdf0178462ce6dcb3453 - languageName: node - linkType: hard - -"is-url@npm:^1.2.4": - version: 1.2.4 - resolution: "is-url@npm:1.2.4" - checksum: 10c0/0157a79874f8f95fdd63540e3f38c8583c2ef572661cd0693cda80ae3e42dfe8e9a4a972ec1b827f861d9a9acf75b37f7d58a37f94a8a053259642912c252bc3 - languageName: node - linkType: hard - -"is-utf8@npm:^0.2.0": - version: 0.2.1 - resolution: "is-utf8@npm:0.2.1" - checksum: 10c0/3ed45e5b4ddfa04ed7e32c63d29c61b980ecd6df74698f45978b8c17a54034943bcbffb6ae243202e799682a66f90fef526f465dd39438745e9fe70794c1ef09 - languageName: node - linkType: hard - -"is-weakref@npm:^1.0.1": - version: 1.0.1 - resolution: "is-weakref@npm:1.0.1" - dependencies: - call-bind: "npm:^1.0.0" - checksum: 10c0/c21f472d98b4867f448f182cd0354039c2d0bce0bba47d5dac7717d92dc1e25e0134139530b3e56fdb4596efd32697bed50fd3e9b0b285f510493c7a5a542779 - languageName: node - linkType: hard - -"is-windows@npm:^1.0.2": - version: 1.0.2 - resolution: "is-windows@npm:1.0.2" - checksum: 10c0/b32f418ab3385604a66f1b7a3ce39d25e8881dee0bd30816dc8344ef6ff9df473a732bcc1ec4e84fe99b2f229ae474f7133e8e93f9241686cfcf7eebe53ba7a5 - languageName: node - linkType: hard - -"is-wsl@npm:^2.1.1": - version: 2.2.0 - resolution: "is-wsl@npm:2.2.0" - dependencies: - is-docker: "npm:^2.0.0" - checksum: 10c0/a6fa2d370d21be487c0165c7a440d567274fbba1a817f2f0bfa41cc5e3af25041d84267baa22df66696956038a43973e72fca117918c91431920bdef490fa25e - languageName: node - linkType: hard - -"isarray@npm:0.0.1": - version: 0.0.1 - resolution: "isarray@npm:0.0.1" - checksum: 10c0/ed1e62da617f71fe348907c71743b5ed550448b455f8d269f89a7c7ddb8ae6e962de3dab6a74a237b06f5eb7f6ece7a45ada8ce96d87fe972926530f91ae3311 - languageName: node - linkType: hard - -"isarray@npm:1.0.0, isarray@npm:~1.0.0": - version: 1.0.0 - resolution: "isarray@npm:1.0.0" - checksum: 10c0/18b5be6669be53425f0b84098732670ed4e727e3af33bc7f948aac01782110eb9a18b3b329c5323bcdd3acdaae547ee077d3951317e7f133bff7105264b3003d - languageName: node - linkType: hard - -"isexe@npm:^2.0.0": - version: 2.0.0 - resolution: "isexe@npm:2.0.0" - checksum: 10c0/228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d - languageName: node - linkType: hard - -"isexe@npm:^4.0.0": - version: 4.0.0 - resolution: "isexe@npm:4.0.0" - checksum: 10c0/5884815115bceac452877659a9c7726382531592f43dc29e5d48b7c4100661aed54018cb90bd36cb2eaeba521092570769167acbb95c18d39afdccbcca06c5ce - languageName: node - linkType: hard - -"isobject@npm:^2.0.0": - version: 2.1.0 - resolution: "isobject@npm:2.1.0" - dependencies: - isarray: "npm:1.0.0" - checksum: 10c0/c4cafec73b3b2ee11be75dff8dafd283b5728235ac099b07d7873d5182553a707768e208327bbc12931b9422d8822280bf88d894a0024ff5857b3efefb480e7b - languageName: node - linkType: hard - -"isobject@npm:^3.0.0, isobject@npm:^3.0.1": - version: 3.0.1 - resolution: "isobject@npm:3.0.1" - checksum: 10c0/03344f5064a82f099a0cd1a8a407f4c0d20b7b8485e8e816c39f249e9416b06c322e8dec5b842b6bb8a06de0af9cb48e7bc1b5352f0fadc2f0abac033db3d4db - languageName: node - linkType: hard - -"isows@npm:1.0.7": - version: 1.0.7 - resolution: "isows@npm:1.0.7" - peerDependencies: - ws: "*" - checksum: 10c0/43c41fe89c7c07258d0be3825f87e12da8ac9023c5b5ae6741ec00b2b8169675c04331ea73ef8c172d37a6747066f4dc93947b17cd369f92828a3b3e741afbda - languageName: node - linkType: hard - -"isstream@npm:~0.1.2": - version: 0.1.2 - resolution: "isstream@npm:0.1.2" - checksum: 10c0/a6686a878735ca0a48e0d674dd6d8ad31aedfaf70f07920da16ceadc7577b46d67179a60b313f2e6860cb097a2c2eb3cbd0b89e921ae89199a59a17c3273d66f - languageName: node - linkType: hard - -"isurl@npm:^1.0.0-alpha5": - version: 1.0.0 - resolution: "isurl@npm:1.0.0" - dependencies: - has-to-string-tag-x: "npm:^1.2.0" - is-object: "npm:^1.0.1" - checksum: 10c0/137e377cd72fefdbc950a226a08e7b35d53672c3b7173b03e72194c3e78a03109aa44c15390b26445b90b7708acb89ca89ed3cd7cc55a6afc7c37cbc88fc581a - languageName: node - linkType: hard - -"jackspeak@npm:^3.1.2": - version: 3.4.3 - resolution: "jackspeak@npm:3.4.3" - dependencies: - "@isaacs/cliui": "npm:^8.0.2" - "@pkgjs/parseargs": "npm:^0.11.0" - dependenciesMeta: - "@pkgjs/parseargs": - optional: true - checksum: 10c0/6acc10d139eaefdbe04d2f679e6191b3abf073f111edf10b1de5302c97ec93fffeb2fdd8681ed17f16268aa9dd4f8c588ed9d1d3bffbbfa6e8bf897cbb3149b9 - languageName: node - linkType: hard - -"js-sha3@npm:0.5.7, js-sha3@npm:^0.5.7": - version: 0.5.7 - resolution: "js-sha3@npm:0.5.7" - checksum: 10c0/17b17d557f9d594ed36ba6c8cdc234bedd7b74ce4baf171e23a1f16b9a89b1527ae160e4eb1b836520acf5919b00732a22183fb00b7808702c36f646c1e9e973 - languageName: node - linkType: hard - -"js-sha3@npm:0.8.0, js-sha3@npm:^0.8.0": - version: 0.8.0 - resolution: "js-sha3@npm:0.8.0" - checksum: 10c0/43a21dc7967c871bd2c46cb1c2ae97441a97169f324e509f382d43330d8f75cf2c96dba7c806ab08a425765a9c847efdd4bffbac2d99c3a4f3de6c0218f40533 - languageName: node - linkType: hard - -"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": - version: 4.0.0 - resolution: "js-tokens@npm:4.0.0" - checksum: 10c0/e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed - languageName: node - linkType: hard - -"js-tokens@npm:^3.0.2": - version: 3.0.2 - resolution: "js-tokens@npm:3.0.2" - checksum: 10c0/e3c3ee4d12643d90197628eb022a2884a15f08ea7dcac1ce97fdeee43031fbfc7ede674f2cdbbb582dcd4c94388b22e52d56c6cbeb2ac7d1b57c2f33c405e2ba - languageName: node - linkType: hard - -"js-yaml@npm:^3.12.0, js-yaml@npm:^3.13.0, js-yaml@npm:^3.13.1, js-yaml@npm:^3.14.0": - version: 3.14.1 - resolution: "js-yaml@npm:3.14.1" - dependencies: - argparse: "npm:^1.0.7" - esprima: "npm:^4.0.0" - bin: - js-yaml: bin/js-yaml.js - checksum: 10c0/6746baaaeac312c4db8e75fa22331d9a04cccb7792d126ed8ce6a0bbcfef0cedaddd0c5098fade53db067c09fe00aa1c957674b4765610a8b06a5a189e46433b - languageName: node - linkType: hard - -"js-yaml@npm:^4.1.0": - version: 4.3.0 - resolution: "js-yaml@npm:4.3.0" - dependencies: - argparse: "npm:^2.0.1" - bin: - js-yaml: bin/js-yaml.js - checksum: 10c0/058b30473d6915ca5b4feb11e2f7d4d97242f98d00a798ed48dd90b46b7c640398afe9128c5db22c5300f8c6528fe2a174b9a93f351a70ebc28c6203938d8bff - languageName: node - linkType: hard - -"jsbn@npm:~0.1.0": - version: 0.1.1 - resolution: "jsbn@npm:0.1.1" - checksum: 10c0/e046e05c59ff880ee4ef68902dbdcb6d2f3c5d60c357d4d68647dc23add556c31c0e5f41bdb7e69e793dd63468bd9e085da3636341048ef577b18f5b713877c0 - languageName: node - linkType: hard - -"jsesc@npm:^1.3.0": - version: 1.3.0 - resolution: "jsesc@npm:1.3.0" - bin: - jsesc: bin/jsesc - checksum: 10c0/62420889dd46b4cdba4df20fe6ffdefa6eeab7532fb4079170ea1b53c45d5a6abcb485144905833e5a69cc1735db12319b1e0b0f9a556811ec926b57a22318a7 - languageName: node - linkType: hard - -"jsesc@npm:~0.5.0": - version: 0.5.0 - resolution: "jsesc@npm:0.5.0" - bin: - jsesc: bin/jsesc - checksum: 10c0/f93792440ae1d80f091b65f8ceddf8e55c4bb7f1a09dee5dcbdb0db5612c55c0f6045625aa6b7e8edb2e0a4feabd80ee48616dbe2d37055573a84db3d24f96d9 - languageName: node - linkType: hard - -"json-buffer@npm:3.0.0": - version: 3.0.0 - resolution: "json-buffer@npm:3.0.0" - checksum: 10c0/118c060d84430a8ad8376d0c60250830f350a6381bd56541a1ef257ce7ba82d109d1f71a4c4e92e0be0e7ab7da568fad8f7bf02905910a76e8e0aa338621b944 - languageName: node - linkType: hard - -"json-parse-better-errors@npm:^1.0.1": - version: 1.0.2 - resolution: "json-parse-better-errors@npm:1.0.2" - checksum: 10c0/2f1287a7c833e397c9ddd361a78638e828fc523038bb3441fd4fc144cfd2c6cd4963ffb9e207e648cf7b692600f1e1e524e965c32df5152120910e4903a47dcb - languageName: node - linkType: hard - -"json-rpc-engine@npm:^3.4.0, json-rpc-engine@npm:^3.6.0": - version: 3.8.0 - resolution: "json-rpc-engine@npm:3.8.0" - dependencies: - async: "npm:^2.0.1" - babel-preset-env: "npm:^1.7.0" - babelify: "npm:^7.3.0" - json-rpc-error: "npm:^2.0.0" - promise-to-callback: "npm:^1.0.0" - safe-event-emitter: "npm:^1.0.1" - checksum: 10c0/79c864d0224bfe743cdf3ccc2c24147ec802ebb362dc9c1f7a1043b24d13dcceb38ec11c344c57aece9f815675480943ef90d555dd2cf354cdfdb32769592c97 - languageName: node - linkType: hard - -"json-rpc-error@npm:^2.0.0": - version: 2.0.0 - resolution: "json-rpc-error@npm:2.0.0" - dependencies: - inherits: "npm:^2.0.1" - checksum: 10c0/0a28e31dacb97ecc3716daf3b1872516de1988fa0d007f8975e4160c2641dad25289f3522acca2c5eea42499b6e853b1569e69e54e7c3320505e3a92e82feddb - languageName: node - linkType: hard - -"json-rpc-random-id@npm:^1.0.0": - version: 1.0.1 - resolution: "json-rpc-random-id@npm:1.0.1" - checksum: 10c0/8d4594a3d4ef5f4754336e350291a6677fc6e0d8801ecbb2a1e92e50ca04a4b57e5eb97168a4b2a8e6888462133cbfee13ea90abc008fb2f7279392d83d3ee7a - languageName: node - linkType: hard - -"json-schema-traverse@npm:^0.4.1": - version: 0.4.1 - resolution: "json-schema-traverse@npm:0.4.1" - checksum: 10c0/108fa90d4cc6f08243aedc6da16c408daf81793bf903e9fd5ab21983cda433d5d2da49e40711da016289465ec2e62e0324dcdfbc06275a607fe3233fde4942ce - languageName: node - linkType: hard - -"json-schema-traverse@npm:^1.0.0": - version: 1.0.0 - resolution: "json-schema-traverse@npm:1.0.0" - checksum: 10c0/71e30015d7f3d6dc1c316d6298047c8ef98a06d31ad064919976583eb61e1018a60a0067338f0f79cabc00d84af3fcc489bd48ce8a46ea165d9541ba17fb30c6 - languageName: node - linkType: hard - -"json-schema@npm:0.4.0": - version: 0.4.0 - resolution: "json-schema@npm:0.4.0" - checksum: 10c0/d4a637ec1d83544857c1c163232f3da46912e971d5bf054ba44fdb88f07d8d359a462b4aec46f2745efbc57053365608d88bc1d7b1729f7b4fc3369765639ed3 - languageName: node - linkType: hard - -"json-stable-stringify-without-jsonify@npm:^1.0.1": - version: 1.0.1 - resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" - checksum: 10c0/cb168b61fd4de83e58d09aaa6425ef71001bae30d260e2c57e7d09a5fd82223e2f22a042dedaab8db23b7d9ae46854b08bb1f91675a8be11c5cffebef5fb66a5 - languageName: node - linkType: hard - -"json-stable-stringify@npm:^1.0.1": - version: 1.0.1 - resolution: "json-stable-stringify@npm:1.0.1" - dependencies: - jsonify: "npm:~0.0.0" - checksum: 10c0/3127db54f6507096645411ad9e15abd6091b8a94d675321d5c28ecefe3ddabd07a255d12f27e140dd8af3eb07198c81e4d9a29a14f1f9342546a3e94881bb4f6 - languageName: node - linkType: hard - -"json-stream-stringify@npm:^3.1.4": - version: 3.1.7 - resolution: "json-stream-stringify@npm:3.1.7" - checksum: 10c0/53d01e897e06b62e799b13eb6b2dc52e14fd77a99d2d079d2ae012acc3c9893062b563e5aa1782f3bbaf9bb0f1ef60b9de20e64b905170a1c47e81513bff1ac9 - languageName: node - linkType: hard - -"json-stringify-safe@npm:~5.0.1": - version: 5.0.1 - resolution: "json-stringify-safe@npm:5.0.1" - checksum: 10c0/7dbf35cd0411d1d648dceb6d59ce5857ec939e52e4afc37601aa3da611f0987d5cee5b38d58329ceddf3ed48bd7215229c8d52059ab01f2444a338bf24ed0f37 - languageName: node - linkType: hard - -"json5@npm:^0.5.1": - version: 0.5.1 - resolution: "json5@npm:0.5.1" - bin: - json5: lib/cli.js - checksum: 10c0/aca0ab7ccf1883d3fc2ecc16219bc389716a773f774552817deaadb549acc0bb502e317a81946fc0a48f9eb6e0822cf1dc5a097009203f2c94de84c8db02a1f3 - languageName: node - linkType: hard - -"json5@npm:^1.0.1": - version: 1.0.1 - resolution: "json5@npm:1.0.1" - dependencies: - minimist: "npm:^1.2.0" - bin: - json5: lib/cli.js - checksum: 10c0/7f75dd797151680a4e14c4224c1343b32a43272aa6e6333ddec2b0822df4ea116971689b251879a1248592da24f7929902c13f83d7390c3f3d44f18e8e9719f5 - languageName: node - linkType: hard - -"jsonfile@npm:^2.1.0": - version: 2.4.0 - resolution: "jsonfile@npm:2.4.0" - dependencies: - graceful-fs: "npm:^4.1.6" - dependenciesMeta: - graceful-fs: - optional: true - checksum: 10c0/02ad746d9490686519b3369bc9572694076eb982e1b4982c5ad9b91bc3c0ad30d10c866bb26b7a87f0c4025a80222cd2962cb57083b5a6a475a9031eab8c8962 - languageName: node - linkType: hard - -"jsonfile@npm:^4.0.0": - version: 4.0.0 - resolution: "jsonfile@npm:4.0.0" - dependencies: - graceful-fs: "npm:^4.1.6" - dependenciesMeta: - graceful-fs: - optional: true - checksum: 10c0/7dc94b628d57a66b71fb1b79510d460d662eb975b5f876d723f81549c2e9cd316d58a2ddf742b2b93a4fa6b17b2accaf1a738a0e2ea114bdfb13a32e5377e480 - languageName: node - linkType: hard - -"jsonfile@npm:^6.0.1": - version: 6.1.0 - resolution: "jsonfile@npm:6.1.0" - dependencies: - graceful-fs: "npm:^4.1.6" - universalify: "npm:^2.0.0" - dependenciesMeta: - graceful-fs: - optional: true - checksum: 10c0/4f95b5e8a5622b1e9e8f33c96b7ef3158122f595998114d1e7f03985649ea99cb3cd99ce1ed1831ae94c8c8543ab45ebd044207612f31a56fd08462140e46865 - languageName: node - linkType: hard - -"jsonify@npm:~0.0.0": - version: 0.0.0 - resolution: "jsonify@npm:0.0.0" - checksum: 10c0/acb05782ee86a842d098e086fe07fde89c3f3b4f6c18b563b7e24ddc1e323d5c3cce10a3ed947b3b080109ad787cd370b912ba58ecca22fdb7a97d9094f95614 - languageName: node - linkType: hard - -"jsonschema@npm:^1.4.1": - version: 1.5.0 - resolution: "jsonschema@npm:1.5.0" - checksum: 10c0/c24ddb8d741f02efc0da3ad9b597a275f6b595062903d3edbfaa535c3f9c4c98613df68da5cb6635ed9aeab30d658986fea61d7662fc5b2b92840d5a1e21235e - languageName: node - linkType: hard - -"jsprim@npm:^1.2.2": - version: 1.4.2 - resolution: "jsprim@npm:1.4.2" - dependencies: - assert-plus: "npm:1.0.0" - extsprintf: "npm:1.3.0" - json-schema: "npm:0.4.0" - verror: "npm:1.10.0" - checksum: 10c0/5e4bca99e90727c2040eb4c2190d0ef1fe51798ed5714e87b841d304526190d960f9772acc7108fa1416b61e1122bcd60e4460c91793dce0835df5852aab55af - languageName: node - linkType: hard - -"jsx-ast-utils@npm:^2.4.1 || ^3.0.0, jsx-ast-utils@npm:^3.1.0": - version: 3.2.1 - resolution: "jsx-ast-utils@npm:3.2.1" - dependencies: - array-includes: "npm:^3.1.3" - object.assign: "npm:^4.1.2" - checksum: 10c0/9259c93bf4f80a740efcade8e6087f28c839ebf75799c1a886e13f6b84b3b3360aee0576bccb32ce01cf838409cf7e1a8fa6f7bd4dfb301a006c42208243e5ac - languageName: node - linkType: hard - -"keccak@npm:3.0.1": - version: 3.0.1 - resolution: "keccak@npm:3.0.1" - dependencies: - node-addon-api: "npm:^2.0.0" - node-gyp: "npm:latest" - node-gyp-build: "npm:^4.2.0" - checksum: 10c0/dd274c2e177c12c9f5a05bd7460f04b49c03711770ecdb5f1a7fa56169994f9f0a7857c426cf65a2a4078908b12fe8bb6fdf1c28c9baab69835c5e678c10d7ab - languageName: node - linkType: hard - -"keccak@npm:^3.0.0": - version: 3.0.2 - resolution: "keccak@npm:3.0.2" - dependencies: - node-addon-api: "npm:^2.0.0" - node-gyp: "npm:latest" - node-gyp-build: "npm:^4.2.0" - readable-stream: "npm:^3.6.0" - checksum: 10c0/f1673e0f9bab4eb8a5bd232227916c592716d3b961e14e6ab3fabcf703c896c83fdbcd230f7b4a44f076d50fb0931ec1b093a98e4b0e74680b56be123a4a93f6 - languageName: node - linkType: hard - -"keccak@npm:^3.0.2": - version: 3.0.4 - resolution: "keccak@npm:3.0.4" - dependencies: - node-addon-api: "npm:^2.0.0" - node-gyp: "npm:latest" - node-gyp-build: "npm:^4.2.0" - readable-stream: "npm:^3.6.0" - checksum: 10c0/153525c1c1f770beadb8f8897dec2f1d2dcbee11d063fe5f61957a5b236bfd3d2a111ae2727e443aa6a848df5edb98b9ef237c78d56df49087b0ca8a232ca9cd - languageName: node - linkType: hard - -"keyv@npm:^3.0.0": - version: 3.1.0 - resolution: "keyv@npm:3.1.0" - dependencies: - json-buffer: "npm:3.0.0" - checksum: 10c0/6ad784361b4c0213333a8c5bc0bcc59cf46cb7cbbe21fb2f1539ffcc8fe18b8f1562ff913b40552278fdea5f152a15996dfa61ce24ce1a22222560c650be4a1b - languageName: node - linkType: hard - -"kind-of@npm:^3.0.2, kind-of@npm:^3.0.3, kind-of@npm:^3.2.0": - version: 3.2.2 - resolution: "kind-of@npm:3.2.2" - dependencies: - is-buffer: "npm:^1.1.5" - checksum: 10c0/7e34bc29d4b02c997f92f080de34ebb92033a96736bbb0bb2410e033a7e5ae6571f1fa37b2d7710018f95361473b816c604234197f4f203f9cf149d8ef1574d9 - languageName: node - linkType: hard - -"kind-of@npm:^4.0.0": - version: 4.0.0 - resolution: "kind-of@npm:4.0.0" - dependencies: - is-buffer: "npm:^1.1.5" - checksum: 10c0/d6c44c75ee36898142dfc7106afbd50593216c37f96acb81a7ab33ca1a6938ce97d5692b8fc8fccd035f83811a9d97749d68771116441a48eedd0b68e2973165 - languageName: node - linkType: hard - -"kind-of@npm:^5.0.0": - version: 5.1.0 - resolution: "kind-of@npm:5.1.0" - checksum: 10c0/fe85b7a2ed4b4d5a12e16e01d00d5c336e1760842fe0da38283605b9880c984288935e87b13138909e4d23d2d197a1d492f7393c6638d2c0fab8a900c4fb0392 - languageName: node - linkType: hard - -"kind-of@npm:^6.0.0, kind-of@npm:^6.0.2": - version: 6.0.3 - resolution: "kind-of@npm:6.0.3" - checksum: 10c0/61cdff9623dabf3568b6445e93e31376bee1cdb93f8ba7033d86022c2a9b1791a1d9510e026e6465ebd701a6dd2f7b0808483ad8838341ac52f003f512e0b4c4 - languageName: node - linkType: hard - -"klaw-sync@npm:^6.0.0": - version: 6.0.0 - resolution: "klaw-sync@npm:6.0.0" - dependencies: - graceful-fs: "npm:^4.1.11" - checksum: 10c0/00d8e4c48d0d699b743b3b028e807295ea0b225caf6179f51029e19783a93ad8bb9bccde617d169659fbe99559d73fb35f796214de031d0023c26b906cecd70a - languageName: node - linkType: hard - -"klaw@npm:^1.0.0": - version: 1.3.1 - resolution: "klaw@npm:1.3.1" - dependencies: - graceful-fs: "npm:^4.1.9" - dependenciesMeta: - graceful-fs: - optional: true - checksum: 10c0/da994768b02b3843cc994c99bad3cf1c8c67716beb4dd2834133c919e9e9ee788669fbe27d88ab0ad9a3991349c28280afccbde01c2318229b662dd7a05e4728 - languageName: node - linkType: hard - -"language-subtag-registry@npm:~0.3.2": - version: 0.3.21 - resolution: "language-subtag-registry@npm:0.3.21" - checksum: 10c0/349ff5b6fbba6dcf345e8edcdce3c7a47624fed4b8f72b9215686b8de7c65067a1c44a45bdbc88282bff5396be63333e3ec67a42ffaa22027ffe6b079d3500e4 - languageName: node - linkType: hard - -"language-tags@npm:^1.0.5": - version: 1.0.5 - resolution: "language-tags@npm:1.0.5" - dependencies: - language-subtag-registry: "npm:~0.3.2" - checksum: 10c0/04215e821af9a8f1bc6c99ab5aa0a316c3fe1912ca3337eb28596316064bddd8edd22f2883d866069ebdf01b2002e504a760a336b2c728b6d30514e86744f76c - languageName: node - linkType: hard - -"lcid@npm:^1.0.0": - version: 1.0.0 - resolution: "lcid@npm:1.0.0" - dependencies: - invert-kv: "npm:^1.0.0" - checksum: 10c0/87fb32196c3c80458778f34f71c042e114f3134a3c86c0d60ee9c94f0750e467d7ca0c005a5224ffd9d49a6e449b5e5c31e1544f1827765a0ba8747298f5980e - languageName: node - linkType: hard - -"level-codec@npm:^9.0.0": - version: 9.0.2 - resolution: "level-codec@npm:9.0.2" - dependencies: - buffer: "npm:^5.6.0" - checksum: 10c0/38a7eb8beed37969ad93160251d5be8e667d4ea0ee199d5e72e61739e552987a71acaa2daa1d2dbc7541f0cfb64e2bd8b50c3d8757cfa41468d8631aa45cc0eb - languageName: node - linkType: hard - -"level-codec@npm:~7.0.0": - version: 7.0.1 - resolution: "level-codec@npm:7.0.1" - checksum: 10c0/4def4978695b6b2be359c2bbad86a1331aaa7f754955efa15bff898608e545bb9b26ae70d81ce161e0095b14d287efaf96db202166b7673947d57bac6d9ff2af - languageName: node - linkType: hard - -"level-errors@npm:^1.0.3": - version: 1.1.2 - resolution: "level-errors@npm:1.1.2" - dependencies: - errno: "npm:~0.1.1" - checksum: 10c0/c9543fcd83668c6fb15b16930905d3e4f35ae6780562e326c0b7272269e53e8a354e4148fbc5b19d0ac063f398cb014112435b9bf2b7e89a45c33a11b696d411 - languageName: node - linkType: hard - -"level-errors@npm:^2.0.0, level-errors@npm:~2.0.0": - version: 2.0.1 - resolution: "level-errors@npm:2.0.1" - dependencies: - errno: "npm:~0.1.1" - checksum: 10c0/9e664afb98febe22e6ccde063be85e2b6e472414325bea87f0b2288bec589ef97658028f8654dc4716a06cda15c205e910b6cf5eb3906ed3ca06ea84d370002f - languageName: node - linkType: hard - -"level-errors@npm:~1.0.3": - version: 1.0.5 - resolution: "level-errors@npm:1.0.5" - dependencies: - errno: "npm:~0.1.1" - checksum: 10c0/6a95e320df12eb17a3c4f2c1135fe3c2502acc6ceeb8e19c8bf753077528841f648399187def49726c86c475950503f22d3d8e5c7c6a4918f4a13e6ce80bdd06 - languageName: node - linkType: hard - -"level-iterator-stream@npm:^2.0.3": - version: 2.0.3 - resolution: "level-iterator-stream@npm:2.0.3" - dependencies: - inherits: "npm:^2.0.1" - readable-stream: "npm:^2.0.5" - xtend: "npm:^4.0.0" - checksum: 10c0/ae8b1d06c39aecf4760b7a12f5f3e04f214835210d61c178b7d06a5509b162888436adc93c1616e1bbd7d7d017ee0cd18b7e8009c2b5d2f9c967d5b222f08e56 - languageName: node - linkType: hard - -"level-iterator-stream@npm:~1.3.0": - version: 1.3.1 - resolution: "level-iterator-stream@npm:1.3.1" - dependencies: - inherits: "npm:^2.0.1" - level-errors: "npm:^1.0.3" - readable-stream: "npm:^1.0.33" - xtend: "npm:^4.0.0" - checksum: 10c0/d122c954c0fcb0034f1c2bba06a5f6c14faf56b0ea3c9c1b641059a9cd9181e20066a99dfb8e1e0a048aa03205850ac344792f27596064d77355d8bcb01de7a3 - languageName: node - linkType: hard - -"level-iterator-stream@npm:~3.0.0": - version: 3.0.1 - resolution: "level-iterator-stream@npm:3.0.1" - dependencies: - inherits: "npm:^2.0.1" - readable-stream: "npm:^2.3.6" - xtend: "npm:^4.0.0" - checksum: 10c0/2ade0a78199e9c58cbbb1cca94dfd1864fc5d66bae8ec304e2f2e8fb32ec412cdf0ee4315644a03407f4980a41821d85f4dedd4747df3b76c43de50d2d846895 - languageName: node - linkType: hard - -"level-mem@npm:^3.0.1": - version: 3.0.1 - resolution: "level-mem@npm:3.0.1" - dependencies: - level-packager: "npm:~4.0.0" - memdown: "npm:~3.0.0" - checksum: 10c0/81a08a7de8aed3cf6b0719fd2851d0b14a6d1d7bfc286198d64c57844eba91ea48ee838a277bf489d155b8e7e7cb1d9ea2fb4e4c4d51f6329dfd5cd51bd3df12 - languageName: node - linkType: hard - -"level-packager@npm:~4.0.0": - version: 4.0.1 - resolution: "level-packager@npm:4.0.1" - dependencies: - encoding-down: "npm:~5.0.0" - levelup: "npm:^3.0.0" - checksum: 10c0/e490159bfa930d4e941e445c2276f10ce58f5f097dca38547498d48bef56b6b6b373128410331dcd68cb33e81efbdd912a70904f10ea4837fde613e0f7a48528 - languageName: node - linkType: hard - -"level-post@npm:^1.0.7": - version: 1.0.7 - resolution: "level-post@npm:1.0.7" - dependencies: - ltgt: "npm:^2.1.2" - checksum: 10c0/b458a294ed056b37ccfb8adee46325073d839b2e594b7647edc8fcefd241dc6f78e0260a4f06e3097e4d38b260fcf082681d40e7155111f99c4ed540a2451d70 - languageName: node - linkType: hard - -"level-sublevel@npm:6.6.4": - version: 6.6.4 - resolution: "level-sublevel@npm:6.6.4" - dependencies: - bytewise: "npm:~1.1.0" - level-codec: "npm:^9.0.0" - level-errors: "npm:^2.0.0" - level-iterator-stream: "npm:^2.0.3" - ltgt: "npm:~2.1.1" - pull-defer: "npm:^0.2.2" - pull-level: "npm:^2.0.3" - pull-stream: "npm:^3.6.8" - typewiselite: "npm:~1.0.0" - xtend: "npm:~4.0.0" - checksum: 10c0/4e380d3c696ac37fb7136d447ab9204e2288270897834000c71c7bf1f50cd85536b1cc718e7cd6d8b4b19f6934de5c840a93e888d95189ba54cd2e785efcaf4b - languageName: node - linkType: hard - -"level-ws@npm:0.0.0": - version: 0.0.0 - resolution: "level-ws@npm:0.0.0" - dependencies: - readable-stream: "npm:~1.0.15" - xtend: "npm:~2.1.1" - checksum: 10c0/1be0d332fef7d79eb61670d0dd61837a523bdb914ba757af3d7898a9f46d5e54634b3e631baa3b88a283f44abb976cca5077a6a5f1d9e3fe9f8a7d67397a2fa0 - languageName: node - linkType: hard - -"level-ws@npm:^1.0.0": - version: 1.0.0 - resolution: "level-ws@npm:1.0.0" - dependencies: - inherits: "npm:^2.0.3" - readable-stream: "npm:^2.2.8" - xtend: "npm:^4.0.1" - checksum: 10c0/c80fcce2f86658a750aeccd11eb2c720ac0f25c0d0bc19cf3b8f25108d7245bc151603463ad8229e2d7ea3245e9cd32b0938e24aa388006192e190f8a6978796 - languageName: node - linkType: hard - -"levelup@npm:3.1.1, levelup@npm:^3.0.0": - version: 3.1.1 - resolution: "levelup@npm:3.1.1" - dependencies: - deferred-leveldown: "npm:~4.0.0" - level-errors: "npm:~2.0.0" - level-iterator-stream: "npm:~3.0.0" - xtend: "npm:~4.0.0" - checksum: 10c0/81f0434d42432820fcc65f4438c500bee379109594ff13af0556355f5ab352ecd9d75faca7e73ccdbddf117e7ab9a40f3eeaf0dd2ae6457556dd3b36769c2297 - languageName: node - linkType: hard - -"levelup@npm:^1.2.1": - version: 1.3.9 - resolution: "levelup@npm:1.3.9" - dependencies: - deferred-leveldown: "npm:~1.2.1" - level-codec: "npm:~7.0.0" - level-errors: "npm:~1.0.3" - level-iterator-stream: "npm:~1.3.0" - prr: "npm:~1.0.1" - semver: "npm:~5.4.1" - xtend: "npm:~4.0.0" - checksum: 10c0/dabd8988a4735e9275c8828bb110e9bbd120cde8dfb9f969ed0d2cf0643d034e8e5abe4cc99467b713e1867f89c877ff6b52a27c475375deb4c1440c713ee9e8 - languageName: node - linkType: hard - -"levn@npm:^0.3.0, levn@npm:~0.3.0": - version: 0.3.0 - resolution: "levn@npm:0.3.0" - dependencies: - prelude-ls: "npm:~1.1.2" - type-check: "npm:~0.3.2" - checksum: 10c0/e440df9de4233da0b389cd55bd61f0f6aaff766400bebbccd1231b81801f6dbc1d816c676ebe8d70566394b749fa624b1ed1c68070e9c94999f0bdecc64cb676 - languageName: node - linkType: hard - -"levn@npm:^0.4.1": - version: 0.4.1 - resolution: "levn@npm:0.4.1" - dependencies: - prelude-ls: "npm:^1.2.1" - type-check: "npm:~0.4.0" - checksum: 10c0/effb03cad7c89dfa5bd4f6989364bfc79994c2042ec5966cb9b95990e2edee5cd8969ddf42616a0373ac49fac1403437deaf6e9050fbbaa3546093a59b9ac94e - languageName: node - linkType: hard - -"load-json-file@npm:^1.0.0": - version: 1.1.0 - resolution: "load-json-file@npm:1.1.0" - dependencies: - graceful-fs: "npm:^4.1.2" - parse-json: "npm:^2.2.0" - pify: "npm:^2.0.0" - pinkie-promise: "npm:^2.0.0" - strip-bom: "npm:^2.0.0" - checksum: 10c0/2a5344c2d88643735a938fdca8582c0504e1c290577faa74f56b9cc187fa443832709a15f36e5771f779ec0878215a03abc8faf97ec57bb86092ceb7e0caef22 - languageName: node - linkType: hard - -"load-json-file@npm:^4.0.0": - version: 4.0.0 - resolution: "load-json-file@npm:4.0.0" - dependencies: - graceful-fs: "npm:^4.1.2" - parse-json: "npm:^4.0.0" - pify: "npm:^3.0.0" - strip-bom: "npm:^3.0.0" - checksum: 10c0/6b48f6a0256bdfcc8970be2c57f68f10acb2ee7e63709b386b2febb6ad3c86198f840889cdbe71d28f741cbaa2f23a7771206b138cd1bdd159564511ca37c1d5 - languageName: node - linkType: hard - -"locate-path@npm:^2.0.0": - version: 2.0.0 - resolution: "locate-path@npm:2.0.0" - dependencies: - p-locate: "npm:^2.0.0" - path-exists: "npm:^3.0.0" - checksum: 10c0/24efa0e589be6aa3c469b502f795126b26ab97afa378846cb508174211515633b770aa0ba610cab113caedab8d2a4902b061a08aaed5297c12ab6f5be4df0133 - languageName: node - linkType: hard - -"locate-path@npm:^6.0.0": - version: 6.0.0 - resolution: "locate-path@npm:6.0.0" - dependencies: - p-locate: "npm:^5.0.0" - checksum: 10c0/d3972ab70dfe58ce620e64265f90162d247e87159b6126b01314dd67be43d50e96a50b517bce2d9452a79409c7614054c277b5232377de50416564a77ac7aad3 - languageName: node - linkType: hard - -"lodash.assign@npm:^4.0.3, lodash.assign@npm:^4.0.6": - version: 4.2.0 - resolution: "lodash.assign@npm:4.2.0" - checksum: 10c0/77e9a28edcb41655e5f5b4b07ec55a5f9bbd6f020f64474acd66c94ce256ed26451f59e5eb421fc4e5ea79d3939a2e2b3a6abeaa0da47bfd1ccd64dfb21f89a0 - languageName: node - linkType: hard - -"lodash.camelcase@npm:^4.3.0": - version: 4.3.0 - resolution: "lodash.camelcase@npm:4.3.0" - checksum: 10c0/fcba15d21a458076dd309fce6b1b4bf611d84a0ec252cb92447c948c533ac250b95d2e00955801ebc367e5af5ed288b996d75d37d2035260a937008e14eaf432 - languageName: node - linkType: hard - -"lodash.clonedeep@npm:^4.5.0": - version: 4.5.0 - resolution: "lodash.clonedeep@npm:4.5.0" - checksum: 10c0/2caf0e4808f319d761d2939ee0642fa6867a4bbf2cfce43276698828380756b99d4c4fa226d881655e6ac298dd453fe12a5ec8ba49861777759494c534936985 - languageName: node - linkType: hard - -"lodash.merge@npm:^4.6.2": - version: 4.6.2 - resolution: "lodash.merge@npm:4.6.2" - checksum: 10c0/402fa16a1edd7538de5b5903a90228aa48eb5533986ba7fa26606a49db2572bf414ff73a2c9f5d5fd36b31c46a5d5c7e1527749c07cbcf965ccff5fbdf32c506 - languageName: node - linkType: hard - -"lodash.truncate@npm:^4.4.2": - version: 4.4.2 - resolution: "lodash.truncate@npm:4.4.2" - checksum: 10c0/4e870d54e8a6c86c8687e057cec4069d2e941446ccab7f40b4d9555fa5872d917d0b6aa73bece7765500a3123f1723bcdba9ae881b679ef120bba9e1a0b0ed70 - languageName: node - linkType: hard - -"lodash@npm:4.17.20": - version: 4.17.20 - resolution: "lodash@npm:4.17.20" - checksum: 10c0/faec37cb9f161b766bdc078a1356a07b9eaaa867796dd2520a407fe0a6a6d7be031e8f228f0cf3d305095703ee40258616c870b8d17dcdcb16f745bf31e8c3c2 - languageName: node - linkType: hard - -"lodash@npm:^4.17.11, lodash@npm:^4.17.12, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.4": - version: 4.17.21 - resolution: "lodash@npm:4.17.21" - checksum: 10c0/d8cbea072bb08655bb4c989da418994b073a608dffa608b09ac04b43a791b12aeae7cd7ad919aa4c925f33b48490b5cfe6c1f71d827956071dae2e7bb3a6b74c - languageName: node - linkType: hard - -"lodash@npm:^4.17.21": - version: 4.18.1 - resolution: "lodash@npm:4.18.1" - checksum: 10c0/757228fc68805c59789e82185135cf85f05d0b2d3d54631d680ca79ec21944ec8314d4533639a14b8bcfbd97a517e78960933041a5af17ecb693ec6eecb99a27 - languageName: node - linkType: hard - -"log-symbols@npm:^4.1.0": - version: 4.1.0 - resolution: "log-symbols@npm:4.1.0" - dependencies: - chalk: "npm:^4.1.0" - is-unicode-supported: "npm:^0.1.0" - checksum: 10c0/67f445a9ffa76db1989d0fa98586e5bc2fd5247260dafb8ad93d9f0ccd5896d53fb830b0e54dade5ad838b9de2006c826831a3c528913093af20dff8bd24aca6 - languageName: node - linkType: hard - -"looper@npm:^2.0.0": - version: 2.0.0 - resolution: "looper@npm:2.0.0" - checksum: 10c0/0f271009248fb767f760ab53ff04f81eb58f87f1e47f7380cb2141ba39085b8587bdbb6f2cba3bfd049e61b6d5b6306704239869ebc3e22937e5fdc717742234 - languageName: node - linkType: hard - -"looper@npm:^3.0.0": - version: 3.0.0 - resolution: "looper@npm:3.0.0" - checksum: 10c0/aa9199913f50ce3def9d3cc7fd9da8db8be9c2ad553d94c6f4d592b5e6d84f4338a87d194861b23586a785e2e18b57c58f6896ccacab84a4590d641b25581180 - languageName: node - linkType: hard - -"loose-envify@npm:^1.0.0, loose-envify@npm:^1.4.0": - version: 1.4.0 - resolution: "loose-envify@npm:1.4.0" - dependencies: - js-tokens: "npm:^3.0.0 || ^4.0.0" - bin: - loose-envify: cli.js - checksum: 10c0/655d110220983c1a4b9c0c679a2e8016d4b67f6e9c7b5435ff5979ecdb20d0813f4dec0a08674fcbdd4846a3f07edbb50a36811fd37930b94aaa0d9daceb017e - languageName: node - linkType: hard - -"lowercase-keys@npm:^1.0.0, lowercase-keys@npm:^1.0.1": - version: 1.0.1 - resolution: "lowercase-keys@npm:1.0.1" - checksum: 10c0/56776a8e1ef1aca98ecf6c19b30352ae1cf257b65b8ac858b7d8a0e8b348774d12a9b41aa7f59bfea51bff44bc7a198ab63ba4406bfba60dba008799618bef66 - languageName: node - linkType: hard - -"lowercase-keys@npm:^2.0.0": - version: 2.0.0 - resolution: "lowercase-keys@npm:2.0.0" - checksum: 10c0/f82a2b3568910509da4b7906362efa40f5b54ea14c2584778ddb313226f9cbf21020a5db35f9b9a0e95847a9b781d548601f31793d736b22a2b8ae8eb9ab1082 - languageName: node - linkType: hard - -"lru-cache@npm:5.1.1, lru-cache@npm:^5.1.1": - version: 5.1.1 - resolution: "lru-cache@npm:5.1.1" - dependencies: - yallist: "npm:^3.0.2" - checksum: 10c0/89b2ef2ef45f543011e38737b8a8622a2f8998cddf0e5437174ef8f1f70a8b9d14a918ab3e232cb3ba343b7abddffa667f0b59075b2b80e6b4d63c3de6127482 - languageName: node - linkType: hard - -"lru-cache@npm:^10.2.0": - version: 10.4.3 - resolution: "lru-cache@npm:10.4.3" - checksum: 10c0/ebd04fbca961e6c1d6c0af3799adcc966a1babe798f685bb84e6599266599cd95d94630b10262f5424539bc4640107e8a33aa28585374abf561d30d16f4b39fb - languageName: node - linkType: hard - -"lru-cache@npm:^11.0.0, lru-cache@npm:^11.1.0, lru-cache@npm:^11.2.1": - version: 11.3.5 - resolution: "lru-cache@npm:11.3.5" - checksum: 10c0/5b54ef7b88afb4bd25b7a778f1b2b1cde32d9770913e530da34ab203cf0442413bcaa6e372800cbab9562557a4480e4d8bf32e3a368bb5a91b12218eca085c66 - languageName: node - linkType: hard - -"lru-cache@npm:^3.2.0": - version: 3.2.0 - resolution: "lru-cache@npm:3.2.0" - dependencies: - pseudomap: "npm:^1.0.1" - checksum: 10c0/a42c01f98622733164cbd88c5f18a167b6bd4d7acd90c05c98f86d87b499733529674c2f66bf036fc6d7a82041d1215fefbc876f0d902626940dcb758ea5b17c - languageName: node - linkType: hard - -"lru-cache@npm:^6.0.0": - version: 6.0.0 - resolution: "lru-cache@npm:6.0.0" - dependencies: - yallist: "npm:^4.0.0" - checksum: 10c0/cb53e582785c48187d7a188d3379c181b5ca2a9c78d2bce3e7dee36f32761d1c42983da3fe12b55cb74e1779fa94cdc2e5367c028a9b35317184ede0c07a30a9 - languageName: node - linkType: hard - -"lru_map@npm:^0.3.3": - version: 0.3.3 - resolution: "lru_map@npm:0.3.3" - checksum: 10c0/d861f14a142a4a74ebf8d3ad57f2e768a5b820db4100ae53eed1a64eb6350912332e6ebc87cb7415ad6d0cd8f3ce6d20beab9a5e6042ccb5996ea0067a220448 - languageName: node - linkType: hard - -"ltgt@npm:^2.1.2, ltgt@npm:~2.2.0": - version: 2.2.1 - resolution: "ltgt@npm:2.2.1" - checksum: 10c0/60fdad732c3aa6acf37e927a5ef58c0d1776192321d55faa1f8775c134c27fbf20ef8ec542fb7f7f33033f79c2a2df75cac39b43e274b32e9d95400154cd41f3 - languageName: node - linkType: hard - -"ltgt@npm:~2.1.1": - version: 2.1.3 - resolution: "ltgt@npm:2.1.3" - checksum: 10c0/d499a6b4050653107ec227f9ae8238eef6b95eee1a9852f122f5874935fa6552a408b407ef21794a44b1e1f08206a59bdcd7dca20db64aa93d9d8a320663af81 - languageName: node - linkType: hard - -"make-error@npm:^1.1.1": - version: 1.3.6 - resolution: "make-error@npm:1.3.6" - checksum: 10c0/171e458d86854c6b3fc46610cfacf0b45149ba043782558c6875d9f42f222124384ad0b468c92e996d815a8a2003817a710c0a160e49c1c394626f76fa45396f - languageName: node - linkType: hard - -"make-fetch-happen@npm:^15.0.0": - version: 15.0.5 - resolution: "make-fetch-happen@npm:15.0.5" - dependencies: - "@gar/promise-retry": "npm:^1.0.0" - "@npmcli/agent": "npm:^4.0.0" - "@npmcli/redact": "npm:^4.0.0" - cacache: "npm:^20.0.1" - http-cache-semantics: "npm:^4.1.1" - minipass: "npm:^7.0.2" - minipass-fetch: "npm:^5.0.0" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - negotiator: "npm:^1.0.0" - proc-log: "npm:^6.0.0" - ssri: "npm:^13.0.0" - checksum: 10c0/527580eb5e5476e6ad07a4e3bd017d13e935f4be815674b442081ae5a721c13d3af5715006619e6be79a85723067e047f83a0c9e699f41d8cec43609a8de4f7b - languageName: node - linkType: hard - -"map-cache@npm:^0.2.2": - version: 0.2.2 - resolution: "map-cache@npm:0.2.2" - checksum: 10c0/05e3eb005c1b80b9f949ca007687640e8c5d0fc88dc45c3c3ab4902a3bec79d66a58f3e3b04d6985d90cd267c629c7b46c977e9c34433e8c11ecfcbb9f0fa290 - languageName: node - linkType: hard - -"map-visit@npm:^1.0.0": - version: 1.0.0 - resolution: "map-visit@npm:1.0.0" - dependencies: - object-visit: "npm:^1.0.0" - checksum: 10c0/fb3475e5311939a6147e339999113db607adc11c7c3cd3103e5e9dbf502898416ecba6b1c7c649c6d4d12941de00cee58b939756bdf20a9efe7d4fa5a5738b73 - languageName: node - linkType: hard - -"markdown-table@npm:2.0.0": - version: 2.0.0 - resolution: "markdown-table@npm:2.0.0" - dependencies: - repeat-string: "npm:^1.0.0" - checksum: 10c0/f257e0781ea50eb946919df84bdee4ba61f983971b277a369ca7276f89740fd0e2749b9b187163a42df4c48682b71962d4007215ce3523480028f06c11ddc2e6 - languageName: node - linkType: hard - -"match-all@npm:^1.2.6": - version: 1.2.6 - resolution: "match-all@npm:1.2.6" - checksum: 10c0/4e0344bf3c39fdedf212bc0e61ce970a40f7f5c1cbbf34de0992a47515d999dab3aa8600a2a09487afb5f561e59d267f0b5dd7a74dfaec203cec77c1f8c52d5a - languageName: node - linkType: hard - -"math-intrinsics@npm:^1.1.0": - version: 1.1.0 - resolution: "math-intrinsics@npm:1.1.0" - checksum: 10c0/7579ff94e899e2f76ab64491d76cf606274c874d8f2af4a442c016bd85688927fcfca157ba6bf74b08e9439dc010b248ce05b96cc7c126a354c3bae7fcb48b7f - languageName: node - linkType: hard - -"md5.js@npm:^1.3.4": - version: 1.3.5 - resolution: "md5.js@npm:1.3.5" - dependencies: - hash-base: "npm:^3.0.0" - inherits: "npm:^2.0.1" - safe-buffer: "npm:^5.1.2" - checksum: 10c0/b7bd75077f419c8e013fc4d4dada48be71882e37d69a44af65a2f2804b91e253441eb43a0614423a1c91bb830b8140b0dc906bc797245e2e275759584f4efcc5 - languageName: node - linkType: hard - -"media-typer@npm:0.3.0": - version: 0.3.0 - resolution: "media-typer@npm:0.3.0" - checksum: 10c0/d160f31246907e79fed398470285f21bafb45a62869dc469b1c8877f3f064f5eabc4bcc122f9479b8b605bc5c76187d7871cf84c4ee3ecd3e487da1993279928 - languageName: node - linkType: hard - -"memdown@npm:^1.0.0": - version: 1.4.1 - resolution: "memdown@npm:1.4.1" - dependencies: - abstract-leveldown: "npm:~2.7.1" - functional-red-black-tree: "npm:^1.0.1" - immediate: "npm:^3.2.3" - inherits: "npm:~2.0.1" - ltgt: "npm:~2.2.0" - safe-buffer: "npm:~5.1.1" - checksum: 10c0/046e69fc5da9242ae281e901df75e22ba01b2c9de4f6bbc6c89ab3da1b5d8408fbe81e54f92b273b217678eed0363e7165746df4772258cb0e588884459ebac6 - languageName: node - linkType: hard - -"memdown@npm:~3.0.0": - version: 3.0.0 - resolution: "memdown@npm:3.0.0" - dependencies: - abstract-leveldown: "npm:~5.0.0" - functional-red-black-tree: "npm:~1.0.1" - immediate: "npm:~3.2.3" - inherits: "npm:~2.0.1" - ltgt: "npm:~2.2.0" - safe-buffer: "npm:~5.1.1" - checksum: 10c0/3216fa4bee7b95fa9b3c87d89a92c6c09fe73601263ce9f46a6068764788092dbad1f38fa604fd30e3f1c6e3dc990fc64293014e844838dbb97da5c298ec99b7 - languageName: node - linkType: hard - -"memorystream@npm:^0.3.1": - version: 0.3.1 - resolution: "memorystream@npm:0.3.1" - checksum: 10c0/4bd164657711d9747ff5edb0508b2944414da3464b7fe21ac5c67cf35bba975c4b446a0124bd0f9a8be54cfc18faf92e92bd77563a20328b1ccf2ff04e9f39b9 - languageName: node - linkType: hard - -"merge-descriptors@npm:1.0.1": - version: 1.0.1 - resolution: "merge-descriptors@npm:1.0.1" - checksum: 10c0/b67d07bd44cfc45cebdec349bb6e1f7b077ee2fd5beb15d1f7af073849208cb6f144fe403e29a36571baf3f4e86469ac39acf13c318381e958e186b2766f54ec - languageName: node - linkType: hard - -"merge2@npm:^1.3.0": - version: 1.4.1 - resolution: "merge2@npm:1.4.1" - checksum: 10c0/254a8a4605b58f450308fc474c82ac9a094848081bf4c06778200207820e5193726dc563a0d2c16468810516a5c97d9d3ea0ca6585d23c58ccfff2403e8dbbeb - languageName: node - linkType: hard - -"merkle-patricia-tree@npm:3.0.0": - version: 3.0.0 - resolution: "merkle-patricia-tree@npm:3.0.0" - dependencies: - async: "npm:^2.6.1" - ethereumjs-util: "npm:^5.2.0" - level-mem: "npm:^3.0.1" - level-ws: "npm:^1.0.0" - readable-stream: "npm:^3.0.6" - rlp: "npm:^2.0.0" - semaphore: "npm:>=1.0.1" - checksum: 10c0/3fb7d901c07828ed066a132710b10ce0a6d498130d4d08db7e3158c9d57f0e21cd3d3114bdc7e8e55215f6734faef6c19a28250593d4dc8c381c01888a865068 - languageName: node - linkType: hard - -"merkle-patricia-tree@npm:^2.1.2, merkle-patricia-tree@npm:^2.3.2": - version: 2.3.2 - resolution: "merkle-patricia-tree@npm:2.3.2" - dependencies: - async: "npm:^1.4.2" - ethereumjs-util: "npm:^5.0.0" - level-ws: "npm:0.0.0" - levelup: "npm:^1.2.1" - memdown: "npm:^1.0.0" - readable-stream: "npm:^2.0.0" - rlp: "npm:^2.0.0" - semaphore: "npm:>=1.0.1" - checksum: 10c0/38b33bcb788cf6bee37544a843e6582ab6d4b173d5b8277b35712f1121aab0ba7d548c782b197713386774250cec1a8dbf48c1948f28fafae182c80131904ca4 - languageName: node - linkType: hard - -"methods@npm:~1.1.2": - version: 1.1.2 - resolution: "methods@npm:1.1.2" - checksum: 10c0/bdf7cc72ff0a33e3eede03708c08983c4d7a173f91348b4b1e4f47d4cdbf734433ad971e7d1e8c77247d9e5cd8adb81ea4c67b0a2db526b758b2233d7814b8b2 - languageName: node - linkType: hard - -"micro-eth-signer@npm:^0.14.0": - version: 0.14.0 - resolution: "micro-eth-signer@npm:0.14.0" - dependencies: - "@noble/curves": "npm:~1.8.1" - "@noble/hashes": "npm:~1.7.1" - micro-packed: "npm:~0.7.2" - checksum: 10c0/62c90d54d2b97cb4eaf713c69bc4ceb5903012d0237c26f0966076cfb89c4527de68b395e1bc29e6f237152ce08f7b551fb57b332003518a1331c2c0890fb164 - languageName: node - linkType: hard - -"micro-packed@npm:~0.7.2": - version: 0.7.3 - resolution: "micro-packed@npm:0.7.3" - dependencies: - "@scure/base": "npm:~1.2.5" - checksum: 10c0/1fde48a96d8d5606d3298ff36717bf7483d6d59e2d96f50cb88727379127a4d52881f48e7e1ce0d4906b2711b1902fb04d2128576326ce4d07e171ac022a4c2d - languageName: node - linkType: hard - -"micromatch@npm:^3.1.4": - version: 3.1.10 - resolution: "micromatch@npm:3.1.10" - dependencies: - arr-diff: "npm:^4.0.0" - array-unique: "npm:^0.3.2" - braces: "npm:^2.3.1" - define-property: "npm:^2.0.2" - extend-shallow: "npm:^3.0.2" - extglob: "npm:^2.0.4" - fragment-cache: "npm:^0.2.1" - kind-of: "npm:^6.0.2" - nanomatch: "npm:^1.2.9" - object.pick: "npm:^1.3.0" - regex-not: "npm:^1.0.0" - snapdragon: "npm:^0.8.1" - to-regex: "npm:^3.0.2" - checksum: 10c0/531a32e7ac92bef60657820202be71b63d0f945c08a69cc4c239c0b19372b751483d464a850a2e3a5ff6cc9060641e43d44c303af104c1a27493d137d8af017f - languageName: node - linkType: hard - -"micromatch@npm:^4.0.2, micromatch@npm:^4.0.4": - version: 4.0.4 - resolution: "micromatch@npm:4.0.4" - dependencies: - braces: "npm:^3.0.1" - picomatch: "npm:^2.2.3" - checksum: 10c0/87bc95e3e52ebe413dbadd43c96e797c736bf238f154e3b546859493e83781b6f7fa4dfa54e423034fb9aeea65259ee6480551581271c348d8e19214910a5a64 - languageName: node - linkType: hard - -"miller-rabin@npm:^4.0.0": - version: 4.0.1 - resolution: "miller-rabin@npm:4.0.1" - dependencies: - bn.js: "npm:^4.0.0" - brorand: "npm:^1.0.1" - bin: - miller-rabin: bin/miller-rabin - checksum: 10c0/26b2b96f6e49dbcff7faebb78708ed2f5f9ae27ac8cbbf1d7c08f83cf39bed3d418c0c11034dce997da70d135cc0ff6f3a4c15dc452f8e114c11986388a64346 - languageName: node - linkType: hard - -"mime-db@npm:1.52.0": - version: 1.52.0 - resolution: "mime-db@npm:1.52.0" - checksum: 10c0/0557a01deebf45ac5f5777fe7740b2a5c309c6d62d40ceab4e23da9f821899ce7a900b7ac8157d4548ddbb7beffe9abc621250e6d182b0397ec7f10c7b91a5aa - languageName: node - linkType: hard - -"mime-types@npm:^2.1.12, mime-types@npm:^2.1.16, mime-types@npm:^2.1.35, mime-types@npm:~2.1.19, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": - version: 2.1.35 - resolution: "mime-types@npm:2.1.35" - dependencies: - mime-db: "npm:1.52.0" - checksum: 10c0/82fb07ec56d8ff1fc999a84f2f217aa46cb6ed1033fefaabd5785b9a974ed225c90dc72fff460259e66b95b73648596dbcc50d51ed69cdf464af2d237d3149b2 - languageName: node - linkType: hard - -"mime@npm:1.6.0": - version: 1.6.0 - resolution: "mime@npm:1.6.0" - bin: - mime: cli.js - checksum: 10c0/b92cd0adc44888c7135a185bfd0dddc42c32606401c72896a842ae15da71eb88858f17669af41e498b463cd7eb998f7b48939a25b08374c7924a9c8a6f8a81b0 - languageName: node - linkType: hard - -"mimic-fn@npm:^1.0.0": - version: 1.2.0 - resolution: "mimic-fn@npm:1.2.0" - checksum: 10c0/ad55214aec6094c0af4c0beec1a13787556f8116ed88807cf3f05828500f21f93a9482326bcd5a077ae91e3e8795b4e76b5b4c8bb12237ff0e4043a365516cba - languageName: node - linkType: hard - -"mimic-response@npm:^1.0.0, mimic-response@npm:^1.0.1": - version: 1.0.1 - resolution: "mimic-response@npm:1.0.1" - checksum: 10c0/c5381a5eae997f1c3b5e90ca7f209ed58c3615caeee850e85329c598f0c000ae7bec40196580eef1781c60c709f47258131dab237cad8786f8f56750594f27fa - languageName: node - linkType: hard - -"min-document@npm:^2.19.0": - version: 2.19.0 - resolution: "min-document@npm:2.19.0" - dependencies: - dom-walk: "npm:^0.1.0" - checksum: 10c0/783724da716fc73a51c171865d7b29bf2b855518573f82ef61c40d214f6898d7b91b5c5419e4d22693cdb78d4615873ebc3b37d7639d3dd00ca283e5a07c7af9 - languageName: node - linkType: hard - -"minimalistic-assert@npm:^1.0.0, minimalistic-assert@npm:^1.0.1": - version: 1.0.1 - resolution: "minimalistic-assert@npm:1.0.1" - checksum: 10c0/96730e5601cd31457f81a296f521eb56036e6f69133c0b18c13fe941109d53ad23a4204d946a0d638d7f3099482a0cec8c9bb6d642604612ce43ee536be3dddd - languageName: node - linkType: hard - -"minimalistic-crypto-utils@npm:^1.0.1": - version: 1.0.1 - resolution: "minimalistic-crypto-utils@npm:1.0.1" - checksum: 10c0/790ecec8c5c73973a4fbf2c663d911033e8494d5fb0960a4500634766ab05d6107d20af896ca2132e7031741f19888154d44b2408ada0852446705441383e9f8 - languageName: node - linkType: hard - -"minimatch@npm:^10.2.2": - version: 10.2.5 - resolution: "minimatch@npm:10.2.5" - dependencies: - brace-expansion: "npm:^5.0.5" - checksum: 10c0/6bb058bd6324104b9ec2f763476a35386d05079c1f5fe4fbf1f324a25237cd4534d6813ecd71f48208f4e635c1221899bef94c3c89f7df55698fe373aaae20fd - languageName: node - linkType: hard - -"minimatch@npm:^3.0.4, minimatch@npm:^3.1.1": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" - dependencies: - brace-expansion: "npm:^1.1.7" - checksum: 10c0/0262810a8fc2e72cca45d6fd86bd349eee435eb95ac6aa45c9ea2180e7ee875ef44c32b55b5973ceabe95ea12682f6e3725cbb63d7a2d1da3ae1163c8b210311 - languageName: node - linkType: hard - -"minimatch@npm:^9.0.4, minimatch@npm:^9.0.5": - version: 9.0.9 - resolution: "minimatch@npm:9.0.9" - dependencies: - brace-expansion: "npm:^2.0.2" - checksum: 10c0/0b6a58530dbb00361745aa6c8cffaba4c90f551afe7c734830bd95fd88ebf469dd7355a027824ea1d09e37181cfeb0a797fb17df60c15ac174303ac110eb7e86 - languageName: node - linkType: hard - -"minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6, minimist@npm:~1.2.5": - version: 1.2.6 - resolution: "minimist@npm:1.2.6" - checksum: 10c0/d0b566204044481c4401abbd24cc75814e753b37268e7fe7ccc78612bf3e37bf1e45a6c43fb0b119445ea1c413c000bde013f320b7211974f2f49bcbec1d0dbf - languageName: node - linkType: hard - -"minipass-collect@npm:^2.0.1": - version: 2.0.1 - resolution: "minipass-collect@npm:2.0.1" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10c0/5167e73f62bb74cc5019594709c77e6a742051a647fe9499abf03c71dca75515b7959d67a764bdc4f8b361cf897fbf25e2d9869ee039203ed45240f48b9aa06e - languageName: node - linkType: hard - -"minipass-fetch@npm:^5.0.0": - version: 5.0.2 - resolution: "minipass-fetch@npm:5.0.2" - dependencies: - iconv-lite: "npm:^0.7.2" - minipass: "npm:^7.0.3" - minipass-sized: "npm:^2.0.0" - minizlib: "npm:^3.0.1" - dependenciesMeta: - iconv-lite: - optional: true - checksum: 10c0/ce4ab9f21cfabaead2097d95dd33f485af8072fbc6b19611bce694965393453a1639d641c2bcf1c48f2ea7d41ea7fab8278373f1d0bee4e63b0a5b2cdd0ef649 - languageName: node - linkType: hard - -"minipass-flush@npm:^1.0.5": - version: 1.0.7 - resolution: "minipass-flush@npm:1.0.7" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10c0/960915c02aa0991662c37c404517dd93708d17f96533b2ca8c1e776d158715d8107c5ced425ffc61674c167d93607f07f48a83c139ce1057f8781e5dfb4b90c2 - languageName: node - linkType: hard - -"minipass-pipeline@npm:^1.2.4": - version: 1.2.4 - resolution: "minipass-pipeline@npm:1.2.4" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10c0/cbda57cea20b140b797505dc2cac71581a70b3247b84480c1fed5ca5ba46c25ecc25f68bfc9e6dcb1a6e9017dab5c7ada5eab73ad4f0a49d84e35093e0c643f2 - languageName: node - linkType: hard - -"minipass-sized@npm:^2.0.0": - version: 2.0.0 - resolution: "minipass-sized@npm:2.0.0" - dependencies: - minipass: "npm:^7.1.2" - checksum: 10c0/f9201696a6f6d68610d04c9c83e3d2e5cb9c026aae1c8cbf7e17f386105cb79c1bb088dbc21bf0b1eb4f3fb5df384fd1e7aa3bf1f33868c416ae8c8a92679db8 - languageName: node - linkType: hard - -"minipass@npm:^2.6.0, minipass@npm:^2.9.0": - version: 2.9.0 - resolution: "minipass@npm:2.9.0" - dependencies: - safe-buffer: "npm:^5.1.2" - yallist: "npm:^3.0.0" - checksum: 10c0/307d8765ac3db9fcd6b486367e6f6c3e460f3a3e198d95d6c0005a2d95804c40c72959261cdebde3c8237cda0b03d4c01975e4581fe11abcf201f5005caafd2a - languageName: node - linkType: hard - -"minipass@npm:^3.0.0": - version: 3.3.6 - resolution: "minipass@npm:3.3.6" - dependencies: - yallist: "npm:^4.0.0" - checksum: 10c0/a114746943afa1dbbca8249e706d1d38b85ed1298b530f5808ce51f8e9e941962e2a5ad2e00eae7dd21d8a4aae6586a66d4216d1a259385e9d0358f0c1eba16c - languageName: node - linkType: hard - -"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2, minipass@npm:^7.1.3": - version: 7.1.3 - resolution: "minipass@npm:7.1.3" - checksum: 10c0/539da88daca16533211ea5a9ee98dc62ff5742f531f54640dd34429e621955e91cc280a91a776026264b7f9f6735947629f920944e9c1558369e8bf22eb33fbb - languageName: node - linkType: hard - -"minizlib@npm:^1.3.3": - version: 1.3.3 - resolution: "minizlib@npm:1.3.3" - dependencies: - minipass: "npm:^2.9.0" - checksum: 10c0/79798032bbaa6594fa517e5b7ff9977951984fc9548a421b28d3fb0add8ed7e98a33e41e262af53b944f9d860c1e00fc778b477ef692e7b38b1ba12b390ffb17 - languageName: node - linkType: hard - -"minizlib@npm:^3.0.1, minizlib@npm:^3.1.0": - version: 3.1.0 - resolution: "minizlib@npm:3.1.0" - dependencies: - minipass: "npm:^7.1.2" - checksum: 10c0/5aad75ab0090b8266069c9aabe582c021ae53eb33c6c691054a13a45db3b4f91a7fb1bd79151e6b4e9e9a86727b522527c0a06ec7d45206b745d54cd3097bcec - languageName: node - linkType: hard - -"mixin-deep@npm:^1.2.0": - version: 1.3.2 - resolution: "mixin-deep@npm:1.3.2" - dependencies: - for-in: "npm:^1.0.2" - is-extendable: "npm:^1.0.1" - checksum: 10c0/cb39ffb73c377222391af788b4c83d1a6cecb2d9fceb7015384f8deb46e151a9b030c21ef59a79cb524d4557e3f74c7248ab948a62a6e7e296b42644863d183b - languageName: node - linkType: hard - -"mkdirp-promise@npm:^5.0.1": - version: 5.0.1 - resolution: "mkdirp-promise@npm:5.0.1" - dependencies: - mkdirp: "npm:*" - checksum: 10c0/c99007908866d65ebaa1fd7f0b0d090e577ac92f6cc5cb98b91a68a461fd9b973412447fb00be3bb2346f5535126667f1e27964abf390f2c1cd077e4fdb59e08 - languageName: node - linkType: hard - -"mkdirp@npm:*, mkdirp@npm:^1.0.4": - version: 1.0.4 - resolution: "mkdirp@npm:1.0.4" - bin: - mkdirp: bin/cmd.js - checksum: 10c0/46ea0f3ffa8bc6a5bc0c7081ffc3907777f0ed6516888d40a518c5111f8366d97d2678911ad1a6882bf592fa9de6c784fea32e1687bb94e1f4944170af48a5cf - languageName: node - linkType: hard - -"mkdirp@npm:^0.5.1": - version: 0.5.5 - resolution: "mkdirp@npm:0.5.5" - dependencies: - minimist: "npm:^1.2.5" - bin: - mkdirp: bin/cmd.js - checksum: 10c0/4469faeeba703bc46b7cdbe3097d6373747a581eb8b556ce41c8fd25a826eb3254466c6522ba823c2edb0b6f0da7beb91cf71f040bc4e361534a3e67f0994bd0 - languageName: node - linkType: hard - -"mkdirp@npm:^0.5.5": - version: 0.5.6 - resolution: "mkdirp@npm:0.5.6" - dependencies: - minimist: "npm:^1.2.6" - bin: - mkdirp: bin/cmd.js - checksum: 10c0/e2e2be789218807b58abced04e7b49851d9e46e88a2f9539242cc8a92c9b5c3a0b9bab360bd3014e02a140fc4fbc58e31176c408b493f8a2a6f4986bd7527b01 - languageName: node - linkType: hard - -"mnemonist@npm:^0.38.0": - version: 0.38.4 - resolution: "mnemonist@npm:0.38.4" - dependencies: - obliterator: "npm:^1.6.1" - checksum: 10c0/ca241e8c682f60ff4a68c15f6a20c07a5db1041359458fa4fbbb96775f8c2052b24af7c1cd79cd2184add9aba76a7677c8b0e31a03f2377402c2afd28e036e9f - languageName: node - linkType: hard - -"mocha@npm:^11.1.0": - version: 11.7.6 - resolution: "mocha@npm:11.7.6" - dependencies: - browser-stdout: "npm:^1.3.1" - chokidar: "npm:^4.0.1" - debug: "npm:^4.3.5" - diff: "npm:^7.0.0" - escape-string-regexp: "npm:^4.0.0" - find-up: "npm:^5.0.0" - glob: "npm:^10.4.5" - he: "npm:^1.2.0" - is-path-inside: "npm:^3.0.3" - js-yaml: "npm:^4.1.0" - log-symbols: "npm:^4.1.0" - minimatch: "npm:^9.0.5" - ms: "npm:^2.1.3" - picocolors: "npm:^1.1.1" - serialize-javascript: "npm:^6.0.2" - strip-json-comments: "npm:^3.1.1" - supports-color: "npm:^8.1.1" - workerpool: "npm:^9.2.0" - yargs: "npm:^17.7.2" - yargs-parser: "npm:^21.1.1" - yargs-unparser: "npm:^2.0.0" - bin: - _mocha: bin/_mocha - mocha: bin/mocha.js - checksum: 10c0/95b3eeb52eaf253167d335d1c1a46659f6f282dc112a74fd0ac46380637ae3ee52894319e00a46412a1e5a6e3056128153dc87c1fe36565c748b9fbe8d705ad0 - languageName: node - linkType: hard - -"mock-fs@npm:^4.1.0": - version: 4.14.0 - resolution: "mock-fs@npm:4.14.0" - checksum: 10c0/a23bc2ce74f2a01d02053fb20aecc2ea359e62580cd15b5e1029b55929802e2770bbd683ccdc5c1eabb5cecbf452196bb81a0ef61c4629dc819023e10d8303c6 - languageName: node - linkType: hard - -"ms@npm:2.0.0": - version: 2.0.0 - resolution: "ms@npm:2.0.0" - checksum: 10c0/f8fda810b39fd7255bbdc451c46286e549794fcc700dc9cd1d25658bbc4dc2563a5de6fe7c60f798a16a60c6ceb53f033cb353f493f0cf63e5199b702943159d - languageName: node - linkType: hard - -"ms@npm:2.1.2": - version: 2.1.2 - resolution: "ms@npm:2.1.2" - checksum: 10c0/a437714e2f90dbf881b5191d35a6db792efbca5badf112f87b9e1c712aace4b4b9b742dd6537f3edf90fd6f684de897cec230abde57e87883766712ddda297cc - languageName: node - linkType: hard - -"ms@npm:2.1.3, ms@npm:^2.1.1, ms@npm:^2.1.3": - version: 2.1.3 - resolution: "ms@npm:2.1.3" - checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 - languageName: node - linkType: hard - -"multibase@npm:^0.7.0": - version: 0.7.0 - resolution: "multibase@npm:0.7.0" - dependencies: - base-x: "npm:^3.0.8" - buffer: "npm:^5.5.0" - checksum: 10c0/59f0ccda12b33d358d91c13b99f565a58b06629dd558d8e07ee919bb7c7ba90c823f72b84c011b7e9abe50e55d72e75c7289e9c6d630babf2b757cdf138ad01a - languageName: node - linkType: hard - -"multibase@npm:~0.6.0": - version: 0.6.1 - resolution: "multibase@npm:0.6.1" - dependencies: - base-x: "npm:^3.0.8" - buffer: "npm:^5.5.0" - checksum: 10c0/305b6b77da15735d0c3104751b1d7af637812efeb78ebc7f77df385bed401217a2bbc4b6f113518a5c4b89df85e28e8f8186b31ad4cda913c8da09d46b489083 - languageName: node - linkType: hard - -"multicodec@npm:^0.5.5": - version: 0.5.7 - resolution: "multicodec@npm:0.5.7" - dependencies: - varint: "npm:^5.0.0" - checksum: 10c0/449afa52a3e4cc3fdd164e9035d6e876c72365fec5cae212af56c9564345172b284272396adf8197ad5476941c76852021b505fd1190e2471628f1cf1b5f2e68 - languageName: node - linkType: hard - -"multicodec@npm:^1.0.0": - version: 1.0.4 - resolution: "multicodec@npm:1.0.4" - dependencies: - buffer: "npm:^5.6.0" - varint: "npm:^5.0.0" - checksum: 10c0/b64516ec9cbea770748aa502fe3f69e1199c220954766bf271ed2fcbcc8916d844bd82f590285490486bf533ea437a9ac402a8dcd18124954c536e6568d948cf - languageName: node - linkType: hard - -"multihashes@npm:^0.4.15, multihashes@npm:~0.4.15": - version: 0.4.21 - resolution: "multihashes@npm:0.4.21" - dependencies: - buffer: "npm:^5.5.0" - multibase: "npm:^0.7.0" - varint: "npm:^5.0.0" - checksum: 10c0/7138eed5566775ff4966ffe55201e3bdd64c949256c71f3d290dc4f41a75d27d4a81755b58048ecfd8a252cfd3f7181976973ea6245d09a7ea992afc8dc77d9d - languageName: node - linkType: hard - -"murmur-128@npm:^0.2.1": - version: 0.2.1 - resolution: "murmur-128@npm:0.2.1" - dependencies: - encode-utf8: "npm:^1.0.2" - fmix: "npm:^0.1.0" - imul: "npm:^1.0.0" - checksum: 10c0/1ae871af53693a9159794b92ace63c1b5c1cc137d235cc954a56af00e48856625131605517e1ee00f60295d0223a13091b88d33a55686011774a63db3b94ecd5 - languageName: node - linkType: hard - -"mute-stream@npm:0.0.7": - version: 0.0.7 - resolution: "mute-stream@npm:0.0.7" - checksum: 10c0/c687cfe99289166fe17dcbd0cf49612c5d267410a7819b654a82df45016967d7b2b0b18b35410edef86de6bb089a00413557dc0182c5e78a4af50ba5d61edb42 - languageName: node - linkType: hard - -"nano-json-stream-parser@npm:^0.1.2": - version: 0.1.2 - resolution: "nano-json-stream-parser@npm:0.1.2" - checksum: 10c0/c42df4cf2922a0b9771a6927df85bb10de01009ea0ea3d354eb3cd7f59d50cbe1350ebdfc78c0fb3dcb71adcdea2c4e3452e0210db8875b0d03f61210151a9a7 - languageName: node - linkType: hard - -"nanomatch@npm:^1.2.9": - version: 1.2.13 - resolution: "nanomatch@npm:1.2.13" - dependencies: - arr-diff: "npm:^4.0.0" - array-unique: "npm:^0.3.2" - define-property: "npm:^2.0.2" - extend-shallow: "npm:^3.0.2" - fragment-cache: "npm:^0.2.1" - is-windows: "npm:^1.0.2" - kind-of: "npm:^6.0.2" - object.pick: "npm:^1.3.0" - regex-not: "npm:^1.0.0" - snapdragon: "npm:^0.8.1" - to-regex: "npm:^3.0.1" - checksum: 10c0/0f5cefa755ca2e20c86332821995effb24acb79551ddaf51c1b9112628cad234a0d8fd9ac6aa56ad1f8bfad6ff6ae86e851acb960943249d9fa44b091479953a - languageName: node - linkType: hard - -"natural-compare@npm:^1.4.0": - version: 1.4.0 - resolution: "natural-compare@npm:1.4.0" - checksum: 10c0/f5f9a7974bfb28a91afafa254b197f0f22c684d4a1731763dda960d2c8e375b36c7d690e0d9dc8fba774c537af14a7e979129bca23d88d052fbeb9466955e447 - languageName: node - linkType: hard - -"negotiator@npm:0.6.3": - version: 0.6.3 - resolution: "negotiator@npm:0.6.3" - checksum: 10c0/3ec9fd413e7bf071c937ae60d572bc67155262068ed522cf4b3be5edbe6ddf67d095ec03a3a14ebf8fc8e95f8e1d61be4869db0dbb0de696f6b837358bd43fc2 - languageName: node - linkType: hard - -"negotiator@npm:^1.0.0": - version: 1.0.0 - resolution: "negotiator@npm:1.0.0" - checksum: 10c0/4c559dd52669ea48e1914f9d634227c561221dd54734070791f999c52ed0ff36e437b2e07d5c1f6e32909fc625fe46491c16e4a8f0572567d4dd15c3a4fda04b - languageName: node - linkType: hard - -"neo-async@npm:^2.6.0": - version: 2.6.2 - resolution: "neo-async@npm:2.6.2" - checksum: 10c0/c2f5a604a54a8ec5438a342e1f356dff4bc33ccccdb6dc668d94fe8e5eccfc9d2c2eea6064b0967a767ba63b33763f51ccf2cd2441b461a7322656c1f06b3f5d - languageName: node - linkType: hard - -"next-tick@npm:^1.1.0": - version: 1.1.0 - resolution: "next-tick@npm:1.1.0" - checksum: 10c0/3ba80dd805fcb336b4f52e010992f3e6175869c8d88bf4ff0a81d5d66e6049f89993463b28211613e58a6b7fe93ff5ccbba0da18d4fa574b96289e8f0b577f28 - languageName: node - linkType: hard - -"nice-try@npm:^1.0.4": - version: 1.0.5 - resolution: "nice-try@npm:1.0.5" - checksum: 10c0/95568c1b73e1d0d4069a3e3061a2102d854513d37bcfda73300015b7ba4868d3b27c198d1dbbd8ebdef4112fc2ed9e895d4a0f2e1cce0bd334f2a1346dc9205f - languageName: node - linkType: hard - -"node-addon-api@npm:^2.0.0": - version: 2.0.2 - resolution: "node-addon-api@npm:2.0.2" - dependencies: - node-gyp: "npm:latest" - checksum: 10c0/ade6c097ba829fa4aee1ca340117bb7f8f29fdae7b777e343a9d5cbd548481d1f0894b7b907d23ce615c70d932e8f96154caed95c3fa935cfe8cf87546510f64 - languageName: node - linkType: hard - -"node-fetch@npm:^2.6.1, node-fetch@npm:^2.6.7": - version: 2.6.7 - resolution: "node-fetch@npm:2.6.7" - dependencies: - whatwg-url: "npm:^5.0.0" - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - checksum: 10c0/fcae80f5ac52fbf5012f5e19df2bd3915e67d3b3ad51cb5942943df2238d32ba15890fecabd0e166876a9f98a581ab50f3f10eb942b09405c49ef8da36b826c7 - languageName: node - linkType: hard - -"node-fetch@npm:~1.7.1": - version: 1.7.3 - resolution: "node-fetch@npm:1.7.3" - dependencies: - encoding: "npm:^0.1.11" - is-stream: "npm:^1.0.1" - checksum: 10c0/5a6b56b3edf909ccd20414355867d24f15f1885da3b26be90840241c46e63754ebf4697050f897daab676e3952d969611ffe1d4bc4506cf50f70837e20ad5328 - languageName: node - linkType: hard - -"node-gyp-build@npm:^4.2.0": - version: 4.5.0 - resolution: "node-gyp-build@npm:4.5.0" - bin: - node-gyp-build: bin.js - node-gyp-build-optional: optional.js - node-gyp-build-test: build-test.js - checksum: 10c0/4ca30ae1f7ba570cd33ae6b71c7e3eb249c3901c0b8a02014cfe2ce18f7f23df621c8d087868973e4f32c90b1c4ad753b4dff1d8bf54666a3f848f414828c14f - languageName: node - linkType: hard - -"node-gyp@npm:latest": - version: 12.2.0 - resolution: "node-gyp@npm:12.2.0" - dependencies: - env-paths: "npm:^2.2.0" - exponential-backoff: "npm:^3.1.1" - graceful-fs: "npm:^4.2.6" - make-fetch-happen: "npm:^15.0.0" - nopt: "npm:^9.0.0" - proc-log: "npm:^6.0.0" - semver: "npm:^7.3.5" - tar: "npm:^7.5.4" - tinyglobby: "npm:^0.2.12" - which: "npm:^6.0.0" - bin: - node-gyp: bin/node-gyp.js - checksum: 10c0/3ed046746a5a7d90950cd8b0547332b06598443f31fe213ef4332a7174c7b7d259e1704835feda79b87d3f02e59d7791842aac60642ede4396ab25fdf0f8f759 - languageName: node - linkType: hard - -"nofilter@npm:^1.0.4": - version: 1.0.4 - resolution: "nofilter@npm:1.0.4" - checksum: 10c0/fcee4ed627e18c8d66dda5afca79607e569e6997c08bd12dfb8a1578fe2674a1de7761b36ae207d6a10c545f27e236aae18f0c2b33e0ef8971507bda419793b7 - languageName: node - linkType: hard - -"nofilter@npm:^3.1.0": - version: 3.1.0 - resolution: "nofilter@npm:3.1.0" - checksum: 10c0/92459f3864a067b347032263f0b536223cbfc98153913b5dce350cb39c8470bc1813366e41993f22c33cc6400c0f392aa324a4b51e24c22040635c1cdb046499 - languageName: node - linkType: hard - -"nopt@npm:^9.0.0": - version: 9.0.0 - resolution: "nopt@npm:9.0.0" - dependencies: - abbrev: "npm:^4.0.0" - bin: - nopt: bin/nopt.js - checksum: 10c0/1822eb6f9b020ef6f7a7516d7b64a8036e09666ea55ac40416c36e4b2b343122c3cff0e2f085675f53de1d2db99a2a89a60ccea1d120bcd6a5347bf6ceb4a7fd - languageName: node - linkType: hard - -"normalize-package-data@npm:^2.3.2": - version: 2.5.0 - resolution: "normalize-package-data@npm:2.5.0" - dependencies: - hosted-git-info: "npm:^2.1.4" - resolve: "npm:^1.10.0" - semver: "npm:2 || 3 || 4 || 5" - validate-npm-package-license: "npm:^3.0.1" - checksum: 10c0/357cb1646deb42f8eb4c7d42c4edf0eec312f3628c2ef98501963cc4bbe7277021b2b1d977f982b2edce78f5a1014613ce9cf38085c3df2d76730481357ca504 - languageName: node - linkType: hard - -"normalize-path@npm:^3.0.0, normalize-path@npm:~3.0.0": - version: 3.0.0 - resolution: "normalize-path@npm:3.0.0" - checksum: 10c0/e008c8142bcc335b5e38cf0d63cfd39d6cf2d97480af9abdbe9a439221fd4d749763bab492a8ee708ce7a194bb00c9da6d0a115018672310850489137b3da046 - languageName: node - linkType: hard - -"normalize-url@npm:^4.1.0": - version: 4.5.1 - resolution: "normalize-url@npm:4.5.1" - checksum: 10c0/6362e9274fdcc310f8b17e20de29754c94e1820d864114f03d3bfd6286a0028fc51705fb3fd4e475013357b5cd7421fc17f3aba93f2289056779a9bb23bccf59 - languageName: node - linkType: hard - -"number-is-nan@npm:^1.0.0": - version: 1.0.1 - resolution: "number-is-nan@npm:1.0.1" - checksum: 10c0/cb97149006acc5cd512c13c1838223abdf202e76ddfa059c5e8e7507aff2c3a78cd19057516885a2f6f5b576543dc4f7b6f3c997cc7df53ae26c260855466df5 - languageName: node - linkType: hard - -"number-to-bn@npm:1.7.0": - version: 1.7.0 - resolution: "number-to-bn@npm:1.7.0" - dependencies: - bn.js: "npm:4.11.6" - strip-hex-prefix: "npm:1.0.0" - checksum: 10c0/83d1540173c4fc60ef4e91e88ed17f2c38418c8e5e62f469d62404527efba48d9c40f364da5c5e6857234a6c1154ff32b3642d80f873ba6cb8d2dd05fb6bc303 - languageName: node - linkType: hard - -"oauth-sign@npm:~0.9.0": - version: 0.9.0 - resolution: "oauth-sign@npm:0.9.0" - checksum: 10c0/fc92a516f6ddbb2699089a2748b04f55c47b6ead55a77cd3a2cbbce5f7af86164cb9425f9ae19acfd066f1ad7d3a96a67b8928c6ea946426f6d6c29e448497c2 - languageName: node - linkType: hard - -"object-assign@npm:^4, object-assign@npm:^4.0.0, object-assign@npm:^4.1.0, object-assign@npm:^4.1.1": - version: 4.1.1 - resolution: "object-assign@npm:4.1.1" - checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414 - languageName: node - linkType: hard - -"object-copy@npm:^0.1.0": - version: 0.1.0 - resolution: "object-copy@npm:0.1.0" - dependencies: - copy-descriptor: "npm:^0.1.0" - define-property: "npm:^0.2.5" - kind-of: "npm:^3.0.3" - checksum: 10c0/79314b05e9d626159a04f1d913f4c4aba9eae8848511cf5f4c8e3b04bb3cc313b65f60357f86462c959a14c2d58380fedf89b6b32ecec237c452a5ef3900a293 - languageName: node - linkType: hard - -"object-inspect@npm:^1.11.0, object-inspect@npm:~1.11.0": - version: 1.11.0 - resolution: "object-inspect@npm:1.11.0" - checksum: 10c0/eb08be1fecb532088153a23d4beb83b3feb8d49c001844a64b88568a9cc2755020a865b1a62957276e2fe20423576b09fa6e3948000fb9d6cb516171bafbf898 - languageName: node - linkType: hard - -"object-inspect@npm:^1.9.0": - version: 1.12.2 - resolution: "object-inspect@npm:1.12.2" - checksum: 10c0/e1bd625f4c44a2f733bd69cfccce6469f71333fb09c6de151f4f346c16d658ef7555727b12652c108e20c2afb908ae7cd165f52ca53745a1d6cbf228cdb46ebe - languageName: node - linkType: hard - -"object-is@npm:^1.0.1": - version: 1.1.5 - resolution: "object-is@npm:1.1.5" - dependencies: - call-bind: "npm:^1.0.2" - define-properties: "npm:^1.1.3" - checksum: 10c0/8c263fb03fc28f1ffb54b44b9147235c5e233dc1ca23768e7d2569740b5d860154d7cc29a30220fe28ed6d8008e2422aefdebfe987c103e1c5d190cf02d9d886 - languageName: node - linkType: hard - -"object-keys@npm:^1.0.12, object-keys@npm:^1.1.1": - version: 1.1.1 - resolution: "object-keys@npm:1.1.1" - checksum: 10c0/b11f7ccdbc6d406d1f186cdadb9d54738e347b2692a14439ca5ac70c225fa6db46db809711b78589866d47b25fc3e8dee0b4c722ac751e11180f9380e3d8601d - languageName: node - linkType: hard - -"object-keys@npm:~0.4.0": - version: 0.4.0 - resolution: "object-keys@npm:0.4.0" - checksum: 10c0/91b5eefd2e0374b3d19000d4ea21d94b9f616c28a1e58f1c4f3e1fd6486a9f53ac00aa10e5ef85536be477dbd0f506bdeee6418e5fc86cc91ab0748655b08f5b - languageName: node - linkType: hard - -"object-visit@npm:^1.0.0": - version: 1.0.1 - resolution: "object-visit@npm:1.0.1" - dependencies: - isobject: "npm:^3.0.0" - checksum: 10c0/086b475bda24abd2318d2b187c3e928959b89f5cb5883d6fe5a42d03719b61fc18e765f658de9ac8730e67ba9ff26d61e73d991215948ff9ecefe771e0071029 - languageName: node - linkType: hard - -"object.assign@npm:^4.1.2": - version: 4.1.2 - resolution: "object.assign@npm:4.1.2" - dependencies: - call-bind: "npm:^1.0.0" - define-properties: "npm:^1.1.3" - has-symbols: "npm:^1.0.1" - object-keys: "npm:^1.1.1" - checksum: 10c0/ee0e796fad8952f05644d11632f046dc4b424f9a41d3816e11a612163b12a873c800456be9acdaec6221b72590ab5267e5fe4bf4cf1c67f88b05f82f133ac829 - languageName: node - linkType: hard - -"object.entries@npm:^1.1.2, object.entries@npm:^1.1.4": - version: 1.1.5 - resolution: "object.entries@npm:1.1.5" - dependencies: - call-bind: "npm:^1.0.2" - define-properties: "npm:^1.1.3" - es-abstract: "npm:^1.19.1" - checksum: 10c0/308c07970818b0fb2b0ed92120b8fad76fb69a63c853592eac48c8437bb2385bc43f00b80d263aa2920b352c66c944018df7221099fc8e2d3bfb778566ca4ebb - languageName: node - linkType: hard - -"object.fromentries@npm:^2.0.4": - version: 2.0.5 - resolution: "object.fromentries@npm:2.0.5" - dependencies: - call-bind: "npm:^1.0.2" - define-properties: "npm:^1.1.3" - es-abstract: "npm:^1.19.1" - checksum: 10c0/a1bedcdec0e1f15fc1f9dccecf7df18ae4678fc95deb42099b649a3660511f2d1dead3b09b8f7dcf15205b0f7ce69d74e3cc3368511abf85b021d86226aa77d4 - languageName: node - linkType: hard - -"object.getownpropertydescriptors@npm:^2.1.1": - version: 2.1.3 - resolution: "object.getownpropertydescriptors@npm:2.1.3" - dependencies: - call-bind: "npm:^1.0.2" - define-properties: "npm:^1.1.3" - es-abstract: "npm:^1.19.1" - checksum: 10c0/d10fe2304801e04425717266423cc0037f8162b8a0baa3dc5d3edad07974f8668059fd08bd0556f1abc5ae6155fd5219b48ddc57c6ed8efbf3fb1d98493e1c59 - languageName: node - linkType: hard - -"object.hasown@npm:^1.0.0": - version: 1.1.0 - resolution: "object.hasown@npm:1.1.0" - dependencies: - define-properties: "npm:^1.1.3" - es-abstract: "npm:^1.19.1" - checksum: 10c0/19ed5cc17695747a7750e0d42f7a3cd9f4b209435debaaad6b0bcbcde9b18207791d61bf3e4384e3c665bb32c7cad8b30d74c039276e31dfbaf0bf4442d1cc37 - languageName: node - linkType: hard - -"object.pick@npm:^1.3.0": - version: 1.3.0 - resolution: "object.pick@npm:1.3.0" - dependencies: - isobject: "npm:^3.0.1" - checksum: 10c0/cd316ec986e49895a28f2df9182de9cdeee57cd2a952c122aacc86344c28624fe002d9affc4f48b5014ec7c033da9942b08821ddb44db8c5bac5b3ec54bdc31e - languageName: node - linkType: hard - -"object.values@npm:^1.1.4": - version: 1.1.5 - resolution: "object.values@npm:1.1.5" - dependencies: - call-bind: "npm:^1.0.2" - define-properties: "npm:^1.1.3" - es-abstract: "npm:^1.19.1" - checksum: 10c0/9c6afa9a25ce36c27c8baef2321eaa719fc2b042ef17aa462b1fa1502ed7ce7acf18b269be2e7b0d91f228839f10a28fa30ebc8cb7e47dbf6a2e4e67cad466c1 - languageName: node - linkType: hard - -"obliterator@npm:^1.6.1": - version: 1.6.1 - resolution: "obliterator@npm:1.6.1" - checksum: 10c0/5fad57319aae0ef6e34efa640541d41c2dd9790a7ab808f17dcb66c83a81333963fc2dfcfa6e1b62158e5cef6291cdcf15c503ad6c3de54b2227dd4c3d7e1b55 - languageName: node - linkType: hard - -"oboe@npm:2.1.4": - version: 2.1.4 - resolution: "oboe@npm:2.1.4" - dependencies: - http-https: "npm:^1.0.0" - checksum: 10c0/29bfbdc0cb995c56d03635dc4fa2bbcd2906ca0738a5b2b2a44548bd94c4299210f0e664f65d864f6b41c7360dabd06c203bd51dbd17e5909b0bac8ca57c4786 - languageName: node - linkType: hard - -"on-finished@npm:2.4.1": - version: 2.4.1 - resolution: "on-finished@npm:2.4.1" - dependencies: - ee-first: "npm:1.1.1" - checksum: 10c0/46fb11b9063782f2d9968863d9cbba33d77aa13c17f895f56129c274318b86500b22af3a160fe9995aa41317efcd22941b6eba747f718ced08d9a73afdb087b4 - languageName: node - linkType: hard - -"once@npm:^1.3.0, once@npm:^1.3.1, once@npm:^1.4.0": - version: 1.4.0 - resolution: "once@npm:1.4.0" - dependencies: - wrappy: "npm:1" - checksum: 10c0/5d48aca287dfefabd756621c5dfce5c91a549a93e9fdb7b8246bc4c4790aa2ec17b34a260530474635147aeb631a2dcc8b32c613df0675f96041cbb8244517d0 - languageName: node - linkType: hard - -"onetime@npm:^2.0.0": - version: 2.0.1 - resolution: "onetime@npm:2.0.1" - dependencies: - mimic-fn: "npm:^1.0.0" - checksum: 10c0/b4e44a8c34e70e02251bfb578a6e26d6de6eedbed106cd78211d2fd64d28b6281d54924696554e4e966559644243753ac5df73c87f283b0927533d3315696215 - languageName: node - linkType: hard - -"open@npm:^7.4.2": - version: 7.4.2 - resolution: "open@npm:7.4.2" - dependencies: - is-docker: "npm:^2.0.0" - is-wsl: "npm:^2.1.1" - checksum: 10c0/77573a6a68f7364f3a19a4c80492712720746b63680ee304555112605ead196afe91052bd3c3d165efdf4e9d04d255e87de0d0a77acec11ef47fd5261251813f - languageName: node - linkType: hard - -"optionator@npm:^0.8.2": - version: 0.8.3 - resolution: "optionator@npm:0.8.3" - dependencies: - deep-is: "npm:~0.1.3" - fast-levenshtein: "npm:~2.0.6" - levn: "npm:~0.3.0" - prelude-ls: "npm:~1.1.2" - type-check: "npm:~0.3.2" - word-wrap: "npm:~1.2.3" - checksum: 10c0/ad7000ea661792b3ec5f8f86aac28895850988926f483b5f308f59f4607dfbe24c05df2d049532ee227c040081f39401a268cf7bbf3301512f74c4d760dc6dd8 - languageName: node - linkType: hard - -"optionator@npm:^0.9.1": - version: 0.9.1 - resolution: "optionator@npm:0.9.1" - dependencies: - deep-is: "npm:^0.1.3" - fast-levenshtein: "npm:^2.0.6" - levn: "npm:^0.4.1" - prelude-ls: "npm:^1.2.1" - type-check: "npm:^0.4.0" - word-wrap: "npm:^1.2.3" - checksum: 10c0/8b574d50b032f34713dc09bfacdc351824f713c3c80773ead3a05ab977364de88f2f3962a6f15437747b93a5e0636928253949970daea3aaeeefbd3a525da6a4 - languageName: node - linkType: hard - -"os-homedir@npm:^1.0.0": - version: 1.0.2 - resolution: "os-homedir@npm:1.0.2" - checksum: 10c0/6be4aa67317ee247b8d46142e243fb4ef1d2d65d3067f54bfc5079257a2f4d4d76b2da78cba7af3cb3f56dbb2e4202e0c47f26171d11ca1ed4008d842c90363f - languageName: node - linkType: hard - -"os-locale@npm:^1.4.0": - version: 1.4.0 - resolution: "os-locale@npm:1.4.0" - dependencies: - lcid: "npm:^1.0.0" - checksum: 10c0/302173159d562000ddf982ed75c493a0d861e91372c9e1b13aab21590ff2e1ba264a41995b29be8dc5278a6127ffcd2ad5591779e8164a570fc5fa6c0787b057 - languageName: node - linkType: hard - -"os-tmpdir@npm:^1.0.1, os-tmpdir@npm:~1.0.2": - version: 1.0.2 - resolution: "os-tmpdir@npm:1.0.2" - checksum: 10c0/f438450224f8e2687605a8dd318f0db694b6293c5d835ae509a69e97c8de38b6994645337e5577f5001115470414638978cc49da1cdcc25106dad8738dc69990 - languageName: node - linkType: hard - -"ox@npm:0.14.33": - version: 0.14.33 - resolution: "ox@npm:0.14.33" - dependencies: - "@adraffy/ens-normalize": "npm:^1.11.0" - "@noble/ciphers": "npm:^1.3.0" - "@noble/curves": "npm:1.9.1" - "@noble/hashes": "npm:^1.8.0" - "@scure/bip32": "npm:^1.7.0" - "@scure/bip39": "npm:^1.6.0" - abitype: "npm:^1.2.3" - eventemitter3: "npm:5.0.1" - peerDependencies: - typescript: ">=5.4.0" - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/3fae8d41cc9e8d56112d7f6e5cc2e90ba8dc4d3764b01ead34798b8d2436a8009c1ccbe2731ae587e69cd31dba8e7fe9f08c586abc1eadb588a42a174e46d766 - languageName: node - linkType: hard - -"p-cancelable@npm:^0.3.0": - version: 0.3.0 - resolution: "p-cancelable@npm:0.3.0" - checksum: 10c0/b8b2c8425b3d284b72097f1b97081ff3f431fd5680f8dfc2344e4f8544f6d8d9f9b545a737bca6a32a319cca1921a44cfd234602e58911dc5d3e144cbe685ea6 - languageName: node - linkType: hard - -"p-cancelable@npm:^1.0.0": - version: 1.1.0 - resolution: "p-cancelable@npm:1.1.0" - checksum: 10c0/9f16d7d58897edb07b1a9234b2bfce3665c747f0f13886e25e2144ecab4595412017cc8cc3b0042f89864b997d6dba76c130724e1c0923fc41ff3c9399b87449 - languageName: node - linkType: hard - -"p-finally@npm:^1.0.0": - version: 1.0.0 - resolution: "p-finally@npm:1.0.0" - checksum: 10c0/6b8552339a71fe7bd424d01d8451eea92d379a711fc62f6b2fe64cad8a472c7259a236c9a22b4733abca0b5666ad503cb497792a0478c5af31ded793d00937e7 - languageName: node - linkType: hard - -"p-limit@npm:^1.1.0": - version: 1.3.0 - resolution: "p-limit@npm:1.3.0" - dependencies: - p-try: "npm:^1.0.0" - checksum: 10c0/5c1b1d53d180b2c7501efb04b7c817448e10efe1ba46f4783f8951994d5027e4cd88f36ad79af50546682594c4ebd11702ac4b9364c47f8074890e2acad0edee - languageName: node - linkType: hard - -"p-limit@npm:^3.0.2": - version: 3.1.0 - resolution: "p-limit@npm:3.1.0" - dependencies: - yocto-queue: "npm:^0.1.0" - checksum: 10c0/9db675949dbdc9c3763c89e748d0ef8bdad0afbb24d49ceaf4c46c02c77d30db4e0652ed36d0a0a7a95154335fab810d95c86153105bb73b3a90448e2bb14e1a - languageName: node - linkType: hard - -"p-locate@npm:^2.0.0": - version: 2.0.0 - resolution: "p-locate@npm:2.0.0" - dependencies: - p-limit: "npm:^1.1.0" - checksum: 10c0/82da4be88fb02fd29175e66021610c881938d3cc97c813c71c1a605fac05617d57fd5d3b337494a6106c0edb2a37c860241430851411f1b265108cead34aee67 - languageName: node - linkType: hard - -"p-locate@npm:^5.0.0": - version: 5.0.0 - resolution: "p-locate@npm:5.0.0" - dependencies: - p-limit: "npm:^3.0.2" - checksum: 10c0/2290d627ab7903b8b70d11d384fee714b797f6040d9278932754a6860845c4d3190603a0772a663c8cb5a7b21d1b16acb3a6487ebcafa9773094edc3dfe6009a - languageName: node - linkType: hard - -"p-map@npm:^4.0.0": - version: 4.0.0 - resolution: "p-map@npm:4.0.0" - dependencies: - aggregate-error: "npm:^3.0.0" - checksum: 10c0/592c05bd6262c466ce269ff172bb8de7c6975afca9b50c975135b974e9bdaafbfe80e61aaaf5be6d1200ba08b30ead04b88cfa7e25ff1e3b93ab28c9f62a2c75 - languageName: node - linkType: hard - -"p-map@npm:^7.0.2": - version: 7.0.4 - resolution: "p-map@npm:7.0.4" - checksum: 10c0/a5030935d3cb2919d7e89454d1ce82141e6f9955413658b8c9403cfe379283770ed3048146b44cde168aa9e8c716505f196d5689db0ae3ce9a71521a2fef3abd - languageName: node - linkType: hard - -"p-timeout@npm:^1.1.1": - version: 1.2.1 - resolution: "p-timeout@npm:1.2.1" - dependencies: - p-finally: "npm:^1.0.0" - checksum: 10c0/09177278c4bc060f9cc1d2f06bf0b8deac29acc53415c093dfd2cc7f4844526c5657a506eb7cd879b6a41c262742551dc2b0f3e90c047f2bd0354b7bd17a5d73 - languageName: node - linkType: hard - -"p-try@npm:^1.0.0": - version: 1.0.0 - resolution: "p-try@npm:1.0.0" - checksum: 10c0/757ba31de5819502b80c447826fac8be5f16d3cb4fbf9bc8bc4971dba0682e84ac33e4b24176ca7058c69e29f64f34d8d9e9b08e873b7b7bb0aa89d620fa224a - languageName: node - linkType: hard - -"package-json-from-dist@npm:^1.0.0": - version: 1.0.1 - resolution: "package-json-from-dist@npm:1.0.1" - checksum: 10c0/62ba2785eb655fec084a257af34dbe24292ab74516d6aecef97ef72d4897310bc6898f6c85b5cd22770eaa1ce60d55a0230e150fb6a966e3ecd6c511e23d164b - languageName: node - linkType: hard - -"parent-module@npm:^1.0.0": - version: 1.0.1 - resolution: "parent-module@npm:1.0.1" - dependencies: - callsites: "npm:^3.0.0" - checksum: 10c0/c63d6e80000d4babd11978e0d3fee386ca7752a02b035fd2435960ffaa7219dc42146f07069fb65e6e8bf1caef89daf9af7535a39bddf354d78bf50d8294f556 - languageName: node - linkType: hard - -"parse-asn1@npm:^5.0.0, parse-asn1@npm:^5.1.5": - version: 5.1.6 - resolution: "parse-asn1@npm:5.1.6" - dependencies: - asn1.js: "npm:^5.2.0" - browserify-aes: "npm:^1.0.0" - evp_bytestokey: "npm:^1.0.0" - pbkdf2: "npm:^3.0.3" - safe-buffer: "npm:^5.1.1" - checksum: 10c0/4ed1d9b9e120c5484d29d67bb90171aac0b73422bc016d6294160aea983275c28a27ab85d862059a36a86a97dd31b7ddd97486802ca9fac67115fe3409e9dcbd - languageName: node - linkType: hard - -"parse-headers@npm:^2.0.0": - version: 2.0.5 - resolution: "parse-headers@npm:2.0.5" - checksum: 10c0/950d75034f46be8b77c491754aefa61b32954e675200d9247ec60b2acaf85c0cc053c44e44b35feed9034a34cc696a5b6fda693b5a0b23daf3294959dd216124 - languageName: node - linkType: hard - -"parse-json@npm:^2.2.0": - version: 2.2.0 - resolution: "parse-json@npm:2.2.0" - dependencies: - error-ex: "npm:^1.2.0" - checksum: 10c0/7a90132aa76016f518a3d5d746a21b3f1ad0f97a68436ed71b6f995b67c7151141f5464eea0c16c59aec9b7756519a0e3007a8f98cf3714632d509ec07736df6 - languageName: node - linkType: hard - -"parse-json@npm:^4.0.0": - version: 4.0.0 - resolution: "parse-json@npm:4.0.0" - dependencies: - error-ex: "npm:^1.3.1" - json-parse-better-errors: "npm:^1.0.1" - checksum: 10c0/8d80790b772ccb1bcea4e09e2697555e519d83d04a77c2b4237389b813f82898943a93ffff7d0d2406203bdd0c30dcf95b1661e3a53f83d0e417f053957bef32 - languageName: node - linkType: hard - -"parseurl@npm:~1.3.3": - version: 1.3.3 - resolution: "parseurl@npm:1.3.3" - checksum: 10c0/90dd4760d6f6174adb9f20cf0965ae12e23879b5f5464f38e92fce8073354341e4b3b76fa3d878351efe7d01e617121955284cfd002ab087fba1a0726ec0b4f5 - languageName: node - linkType: hard - -"pascalcase@npm:^0.1.1": - version: 0.1.1 - resolution: "pascalcase@npm:0.1.1" - checksum: 10c0/48dfe90618e33810bf58211d8f39ad2c0262f19ad6354da1ba563935b5f429f36409a1fb9187c220328f7a4dc5969917f8e3e01ee089b5f1627b02aefe39567b - languageName: node - linkType: hard - -"patch-package@npm:6.2.2": - version: 6.2.2 - resolution: "patch-package@npm:6.2.2" - dependencies: - "@yarnpkg/lockfile": "npm:^1.1.0" - chalk: "npm:^2.4.2" - cross-spawn: "npm:^6.0.5" - find-yarn-workspace-root: "npm:^1.2.1" - fs-extra: "npm:^7.0.1" - is-ci: "npm:^2.0.0" - klaw-sync: "npm:^6.0.0" - minimist: "npm:^1.2.0" - rimraf: "npm:^2.6.3" - semver: "npm:^5.6.0" - slash: "npm:^2.0.0" - tmp: "npm:^0.0.33" - bin: - patch-package: index.js - checksum: 10c0/61bee7746266c15f13de5c8f9ed4b1b2f20d2897a1b292cd5dd7b63fbdc98c5c9acf1fa8c3bb49621ae955e49f9dede314f7fe859ad82056ad93e54ba81ec993 - languageName: node - linkType: hard - -"patch-package@npm:^6.2.2": - version: 6.4.7 - resolution: "patch-package@npm:6.4.7" - dependencies: - "@yarnpkg/lockfile": "npm:^1.1.0" - chalk: "npm:^2.4.2" - cross-spawn: "npm:^6.0.5" - find-yarn-workspace-root: "npm:^2.0.0" - fs-extra: "npm:^7.0.1" - is-ci: "npm:^2.0.0" - klaw-sync: "npm:^6.0.0" - minimist: "npm:^1.2.0" - open: "npm:^7.4.2" - rimraf: "npm:^2.6.3" - semver: "npm:^5.6.0" - slash: "npm:^2.0.0" - tmp: "npm:^0.0.33" - bin: - patch-package: index.js - checksum: 10c0/fc5906dab7b4e5213be1aea36a825008d04da475c8f7b87e2b87579b5fca52927c200160f1f59a491b553db7e2a01427a1b3669bac5325e8b0d7e890241cbea0 - languageName: node - linkType: hard - -"path-browserify@npm:^1.0.0": - version: 1.0.1 - resolution: "path-browserify@npm:1.0.1" - checksum: 10c0/8b8c3fd5c66bd340272180590ae4ff139769e9ab79522e2eb82e3d571a89b8117c04147f65ad066dccfb42fcad902e5b7d794b3d35e0fd840491a8ddbedf8c66 - languageName: node - linkType: hard - -"path-exists@npm:^2.0.0": - version: 2.1.0 - resolution: "path-exists@npm:2.1.0" - dependencies: - pinkie-promise: "npm:^2.0.0" - checksum: 10c0/87352f1601c085d5a6eb202f60e5c016c1b790bd0bc09398af446ed3f5c4510b4531ff99cf8acac2d91868886e792927b4292f768b35a83dce12588fb7cbb46e - languageName: node - linkType: hard - -"path-exists@npm:^3.0.0": - version: 3.0.0 - resolution: "path-exists@npm:3.0.0" - checksum: 10c0/17d6a5664bc0a11d48e2b2127d28a0e58822c6740bde30403f08013da599182289c56518bec89407e3f31d3c2b6b296a4220bc3f867f0911fee6952208b04167 - languageName: node - linkType: hard - -"path-exists@npm:^4.0.0": - version: 4.0.0 - resolution: "path-exists@npm:4.0.0" - checksum: 10c0/8c0bd3f5238188197dc78dced15207a4716c51cc4e3624c44fc97acf69558f5ebb9a2afff486fe1b4ee148e0c133e96c5e11a9aa5c48a3006e3467da070e5e1b - languageName: node - linkType: hard - -"path-is-absolute@npm:^1.0.0, path-is-absolute@npm:^1.0.1": - version: 1.0.1 - resolution: "path-is-absolute@npm:1.0.1" - checksum: 10c0/127da03c82172a2a50099cddbf02510c1791fc2cc5f7713ddb613a56838db1e8168b121a920079d052e0936c23005562059756d653b7c544c53185efe53be078 - languageName: node - linkType: hard - -"path-is-inside@npm:^1.0.2": - version: 1.0.2 - resolution: "path-is-inside@npm:1.0.2" - checksum: 10c0/7fdd4b41672c70461cce734fc222b33e7b447fa489c7c4377c95e7e6852d83d69741f307d88ec0cc3b385b41cb4accc6efac3c7c511cd18512e95424f5fa980c - languageName: node - linkType: hard - -"path-key@npm:^2.0.1": - version: 2.0.1 - resolution: "path-key@npm:2.0.1" - checksum: 10c0/dd2044f029a8e58ac31d2bf34c34b93c3095c1481942960e84dd2faa95bbb71b9b762a106aead0646695330936414b31ca0bd862bf488a937ad17c8c5d73b32b - languageName: node - linkType: hard - -"path-key@npm:^3.1.0": - version: 3.1.1 - resolution: "path-key@npm:3.1.1" - checksum: 10c0/748c43efd5a569c039d7a00a03b58eecd1d75f3999f5a28303d75f521288df4823bc057d8784eb72358b2895a05f29a070bc9f1f17d28226cc4e62494cc58c4c - languageName: node - linkType: hard - -"path-parse@npm:^1.0.6": - version: 1.0.7 - resolution: "path-parse@npm:1.0.7" - checksum: 10c0/11ce261f9d294cc7a58d6a574b7f1b935842355ec66fba3c3fd79e0f036462eaf07d0aa95bb74ff432f9afef97ce1926c720988c6a7451d8a584930ae7de86e1 - languageName: node - linkType: hard - -"path-scurry@npm:^1.11.1": - version: 1.11.1 - resolution: "path-scurry@npm:1.11.1" - dependencies: - lru-cache: "npm:^10.2.0" - minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" - checksum: 10c0/32a13711a2a505616ae1cc1b5076801e453e7aae6ac40ab55b388bb91b9d0547a52f5aaceff710ea400205f18691120d4431e520afbe4266b836fadede15872d - languageName: node - linkType: hard - -"path-scurry@npm:^2.0.2": - version: 2.0.2 - resolution: "path-scurry@npm:2.0.2" - dependencies: - lru-cache: "npm:^11.0.0" - minipass: "npm:^7.1.2" - checksum: 10c0/b35ad37cf6557a87fd057121ce2be7695380c9138d93e87ae928609da259ea0a170fac6f3ef1eb3ece8a068e8b7f2f3adf5bb2374cf4d4a57fe484954fcc9482 - languageName: node - linkType: hard - -"path-to-regexp@npm:0.1.7": - version: 0.1.7 - resolution: "path-to-regexp@npm:0.1.7" - checksum: 10c0/50a1ddb1af41a9e68bd67ca8e331a705899d16fb720a1ea3a41e310480948387daf603abb14d7b0826c58f10146d49050a1291ba6a82b78a382d1c02c0b8f905 - languageName: node - linkType: hard - -"path-type@npm:^1.0.0": - version: 1.1.0 - resolution: "path-type@npm:1.1.0" - dependencies: - graceful-fs: "npm:^4.1.2" - pify: "npm:^2.0.0" - pinkie-promise: "npm:^2.0.0" - checksum: 10c0/2b8c348cb52bbc0c0568afa10a0a5d8f6233adfe5ae75feb56064f6aed6324ab74185c61c2545f4e52ca08acdc76005f615da4e127ed6eecb866002cf491f350 - languageName: node - linkType: hard - -"path-type@npm:^3.0.0": - version: 3.0.0 - resolution: "path-type@npm:3.0.0" - dependencies: - pify: "npm:^3.0.0" - checksum: 10c0/1332c632f1cac15790ebab8dd729b67ba04fc96f81647496feb1c2975d862d046f41e4b975dbd893048999b2cc90721f72924ad820acc58c78507ba7141a8e56 - languageName: node - linkType: hard - -"path-type@npm:^4.0.0": - version: 4.0.0 - resolution: "path-type@npm:4.0.0" - checksum: 10c0/666f6973f332f27581371efaf303fd6c272cc43c2057b37aa99e3643158c7e4b2626549555d88626e99ea9e046f82f32e41bbde5f1508547e9a11b149b52387c - languageName: node - linkType: hard - -"pathval@npm:^1.1.1": - version: 1.1.1 - resolution: "pathval@npm:1.1.1" - checksum: 10c0/f63e1bc1b33593cdf094ed6ff5c49c1c0dc5dc20a646ca9725cc7fe7cd9995002d51d5685b9b2ec6814342935748b711bafa840f84c0bb04e38ff40a335c94dc - languageName: node - linkType: hard - -"pbkdf2@npm:^3.0.17, pbkdf2@npm:^3.0.3, pbkdf2@npm:^3.0.9": - version: 3.1.2 - resolution: "pbkdf2@npm:3.1.2" - dependencies: - create-hash: "npm:^1.1.2" - create-hmac: "npm:^1.1.4" - ripemd160: "npm:^2.0.1" - safe-buffer: "npm:^5.0.1" - sha.js: "npm:^2.4.8" - checksum: 10c0/5a30374e87d33fa080a92734d778cf172542cc7e41b96198c4c88763997b62d7850de3fbda5c3111ddf79805ee7c1da7046881c90ac4920b5e324204518b05fd - languageName: node - linkType: hard - -"performance-now@npm:^2.1.0": - version: 2.1.0 - resolution: "performance-now@npm:2.1.0" - checksum: 10c0/22c54de06f269e29f640e0e075207af57de5052a3d15e360c09b9a8663f393f6f45902006c1e71aa8a5a1cdfb1a47fe268826f8496d6425c362f00f5bc3e85d9 - languageName: node - linkType: hard - -"picocolors@npm:^1.1.0, picocolors@npm:^1.1.1": - version: 1.1.1 - resolution: "picocolors@npm:1.1.1" - checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58 - languageName: node - linkType: hard - -"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1": - version: 2.3.1 - resolution: "picomatch@npm:2.3.1" - checksum: 10c0/26c02b8d06f03206fc2ab8d16f19960f2ff9e81a658f831ecb656d8f17d9edc799e8364b1f4a7873e89d9702dff96204be0fa26fe4181f6843f040f819dac4be - languageName: node - linkType: hard - -"picomatch@npm:^2.2.3": - version: 2.3.0 - resolution: "picomatch@npm:2.3.0" - checksum: 10c0/a65bde78212368e16afb82429a0ea033d20a836270446acb53ec6e31d939bccf1213f788bc49361f7aff47b67c1fb74d898f99964f67f26ca07a3cd815ddbcbb - languageName: node - linkType: hard - -"picomatch@npm:^4.0.4": - version: 4.0.4 - resolution: "picomatch@npm:4.0.4" - checksum: 10c0/e2c6023372cc7b5764719a5ffb9da0f8e781212fa7ca4bd0562db929df8e117460f00dff3cb7509dacfc06b86de924b247f504d0ce1806a37fac4633081466b0 - languageName: node - linkType: hard - -"pify@npm:^2.0.0, pify@npm:^2.3.0": - version: 2.3.0 - resolution: "pify@npm:2.3.0" - checksum: 10c0/551ff8ab830b1052633f59cb8adc9ae8407a436e06b4a9718bcb27dc5844b83d535c3a8512b388b6062af65a98c49bdc0dd523d8b2617b188f7c8fee457158dc - languageName: node - linkType: hard - -"pify@npm:^3.0.0": - version: 3.0.0 - resolution: "pify@npm:3.0.0" - checksum: 10c0/fead19ed9d801f1b1fcd0638a1ac53eabbb0945bf615f2f8806a8b646565a04a1b0e7ef115c951d225f042cca388fdc1cd3add46d10d1ed6951c20bd2998af10 - languageName: node - linkType: hard - -"pinkie-promise@npm:^2.0.0": - version: 2.0.1 - resolution: "pinkie-promise@npm:2.0.1" - dependencies: - pinkie: "npm:^2.0.0" - checksum: 10c0/11b5e5ce2b090c573f8fad7b517cbca1bb9a247587306f05ae71aef6f9b2cd2b923c304aa9663c2409cfde27b367286179f1379bc4ec18a3fbf2bb0d473b160a - languageName: node - linkType: hard - -"pinkie@npm:^2.0.0": - version: 2.0.4 - resolution: "pinkie@npm:2.0.4" - checksum: 10c0/25228b08b5597da42dc384221aa0ce56ee0fbf32965db12ba838e2a9ca0193c2f0609c45551ee077ccd2060bf109137fdb185b00c6d7e0ed7e35006d20fdcbc6 - languageName: node - linkType: hard - -"pkg-dir@npm:^2.0.0": - version: 2.0.0 - resolution: "pkg-dir@npm:2.0.0" - dependencies: - find-up: "npm:^2.1.0" - checksum: 10c0/7cdc46c4921bf2c5f9a438851d16243ddde9906928116647ec7784982dd9038ea61c964fbca6f489201845742188180ecd1001b4f69781de1d1dc7d100b14089 - languageName: node - linkType: hard - -"pkg-up@npm:^2.0.0": - version: 2.0.0 - resolution: "pkg-up@npm:2.0.0" - dependencies: - find-up: "npm:^2.1.0" - checksum: 10c0/9ce9eefba264430b7bd3e21eb90d3d215d588688a510e5f29c66e72df3067de9c6249664120dcc86141b68f9b1448039034e1abf401d98ba077d31a9ed87db83 - languageName: node - linkType: hard - -"posix-character-classes@npm:^0.1.0": - version: 0.1.1 - resolution: "posix-character-classes@npm:0.1.1" - checksum: 10c0/cce88011548a973b4af58361cd8f5f7b5a6faff8eef0901565802f067bcabf82597e920d4c97c22068464be3cbc6447af589f6cc8a7d813ea7165be60a0395bc - languageName: node - linkType: hard - -"postinstall-postinstall@npm:^2.1.0": - version: 2.1.0 - resolution: "postinstall-postinstall@npm:2.1.0" - checksum: 10c0/70488447292c712afa7806126824d6fe93362392cbe261ae60166d9119a350713e0dbf4deb2ca91637c1037bc030ed1de78d61d9041bf2504513070f1caacdfd - languageName: node - linkType: hard - -"precond@npm:0.2": - version: 0.2.3 - resolution: "precond@npm:0.2.3" - checksum: 10c0/289b71202c090286fab340acafc96bc1d719e6f2d2484a868ef5dff28efd5953bafda78aebe4416ebf907992aa88942e68cd53ed7e2ab9eaf0709a6b5ac72340 - languageName: node - linkType: hard - -"prelude-ls@npm:^1.2.1": - version: 1.2.1 - resolution: "prelude-ls@npm:1.2.1" - checksum: 10c0/b00d617431e7886c520a6f498a2e14c75ec58f6d93ba48c3b639cf241b54232d90daa05d83a9e9b9fef6baa63cb7e1e4602c2372fea5bc169668401eb127d0cd - languageName: node - linkType: hard - -"prelude-ls@npm:~1.1.2": - version: 1.1.2 - resolution: "prelude-ls@npm:1.1.2" - checksum: 10c0/7284270064f74e0bb7f04eb9bff7be677e4146417e599ccc9c1200f0f640f8b11e592d94eb1b18f7aa9518031913bb42bea9c86af07ba69902864e61005d6f18 - languageName: node - linkType: hard - -"prepend-http@npm:^1.0.1": - version: 1.0.4 - resolution: "prepend-http@npm:1.0.4" - checksum: 10c0/c6c173ca439e58163ba7bea7cbba52a1ed11e3e3da1c048da296f37d4b7654f78f7304e03f76d5923f4b83af7e2d55533e0f79064209c75b743ccddee13904f8 - languageName: node - linkType: hard - -"prepend-http@npm:^2.0.0": - version: 2.0.0 - resolution: "prepend-http@npm:2.0.0" - checksum: 10c0/b023721ffd967728e3a25e3a80dd73827e9444e586800ab90a21b3a8e67f362d28023085406ad53a36db1e4d98cb10e43eb37d45c6b733140a9165ead18a0987 - languageName: node - linkType: hard - -"prettier-linter-helpers@npm:^1.0.0": - version: 1.0.0 - resolution: "prettier-linter-helpers@npm:1.0.0" - dependencies: - fast-diff: "npm:^1.1.2" - checksum: 10c0/81e0027d731b7b3697ccd2129470ed9913ecb111e4ec175a12f0fcfab0096516373bf0af2fef132af50cafb0a905b74ff57996d615f59512bb9ac7378fcc64ab - languageName: node - linkType: hard - -"prettier-plugin-solidity@npm:^1.0.0-beta.18": - version: 1.0.0-beta.18 - resolution: "prettier-plugin-solidity@npm:1.0.0-beta.18" +"hardhat@npm:2.29.0": + version: 2.29.0 + resolution: "hardhat@npm:2.29.0" dependencies: - "@solidity-parser/parser": "npm:^0.13.2" - emoji-regex: "npm:^9.2.2" - escape-string-regexp: "npm:^4.0.0" - semver: "npm:^7.3.5" - solidity-comments-extractor: "npm:^0.0.7" - string-width: "npm:^4.2.2" + "@ethereumjs/util": "npm:^9.1.0" + "@ethersproject/abi": "npm:^5.1.2" + "@nomicfoundation/edr": "npm:0.12.0-next.23" + "@nomicfoundation/solidity-analyzer": "npm:^0.1.0" + "@sentry/node": "npm:^5.18.1" + adm-zip: "npm:^0.4.16" + aggregate-error: "npm:^3.0.0" + ansi-escapes: "npm:^4.3.0" + boxen: "npm:^5.1.2" + chokidar: "npm:^4.0.0" + ci-info: "npm:^2.0.0" + debug: "npm:^4.1.1" + enquirer: "npm:^2.3.0" + env-paths: "npm:^2.2.0" + ethereum-cryptography: "npm:^1.0.3" + find-up: "npm:^5.0.0" + fp-ts: "npm:1.19.3" + fs-extra: "npm:^7.0.1" + immutable: "npm:^4.0.0-rc.12" + io-ts: "npm:1.10.4" + json-stream-stringify: "npm:^3.1.4" + keccak: "npm:^3.0.2" + lodash: "npm:^4.17.11" + micro-eth-signer: "npm:^0.14.0" + mnemonist: "npm:^0.38.0" + mocha: "npm:^11.1.0" + p-map: "npm:^4.0.0" + picocolors: "npm:^1.1.0" + raw-body: "npm:^2.4.1" + resolve: "npm:1.17.0" + semver: "npm:^6.3.0" + solc: "npm:0.8.26" + source-map-support: "npm:^0.5.13" + stacktrace-parser: "npm:^0.1.10" + tinyglobby: "npm:^0.2.6" + tsort: "npm:0.0.1" + undici: "npm:^5.14.0" + uuid: "npm:^8.3.2" + ws: "npm:^7.4.6" peerDependencies: - prettier: ^2.3.0 - checksum: 10c0/f991084e3e9614e3eefea5cd7473390fa0205ccf9a72bb4d954e9a8570ae8adc5d3717034ddb3fdc4d8ffd999f35807df4f2dee1f642132a5bec69cc02f6c766 - languageName: node - linkType: hard - -"prettier@npm:^1.14.3": - version: 1.19.1 - resolution: "prettier@npm:1.19.1" - bin: - prettier: ./bin-prettier.js - checksum: 10c0/12efb4e486c1e1d006e9eadd3b6585fc6beb9481dc801080fc23d3e75ec599d88c6fea1b40aef167128069e8fe76b4205bb8306ad145575d1b051b8fa70cfaae - languageName: node - linkType: hard - -"prettier@npm:^2.1.2, prettier@npm:^2.4.1": - version: 2.4.1 - resolution: "prettier@npm:2.4.1" + ts-node: "*" + typescript: "*" + peerDependenciesMeta: + ts-node: + optional: true + typescript: + optional: true bin: - prettier: bin-prettier.js - checksum: 10c0/eccb2c486117d6f8d171a8589924324056648ad2a798a5222fab2ef751aa47c6048792dff03ecadeaac4b7e0a5aef8ef64e413f43947d651022bc7f4480882f5 - languageName: node - linkType: hard - -"private@npm:^0.1.6, private@npm:^0.1.8": - version: 0.1.8 - resolution: "private@npm:0.1.8" - checksum: 10c0/829a23723e5fd3105c72b2dadeeb65743a430f7e6967a8a6f3e49392a1b3ea52975a255376d8c513b0c988bdf162f1a5edf9d9bac27d1ab11f8dba8cdb58880e - languageName: node - linkType: hard - -"proc-log@npm:^6.0.0": - version: 6.1.0 - resolution: "proc-log@npm:6.1.0" - checksum: 10c0/4f178d4062733ead9d71a9b1ab24ebcecdfe2250916a5b1555f04fe2eda972a0ec76fbaa8df1ad9c02707add6749219d118a4fc46dc56bdfe4dde4b47d80bb82 - languageName: node - linkType: hard - -"process-nextick-args@npm:~2.0.0": - version: 2.0.1 - resolution: "process-nextick-args@npm:2.0.1" - checksum: 10c0/bec089239487833d46b59d80327a1605e1c5287eaad770a291add7f45fda1bb5e28b38e0e061add0a1d0ee0984788ce74fa394d345eed1c420cacf392c554367 - languageName: node - linkType: hard - -"process@npm:^0.11.10": - version: 0.11.10 - resolution: "process@npm:0.11.10" - checksum: 10c0/40c3ce4b7e6d4b8c3355479df77aeed46f81b279818ccdc500124e6a5ab882c0cc81ff7ea16384873a95a74c4570b01b120f287abbdd4c877931460eca6084b3 - languageName: node - linkType: hard - -"progress@npm:^2.0.0": - version: 2.0.3 - resolution: "progress@npm:2.0.3" - checksum: 10c0/1697e07cb1068055dbe9fe858d242368ff5d2073639e652b75a7eb1f2a1a8d4afd404d719de23c7b48481a6aa0040686310e2dac2f53d776daa2176d3f96369c - languageName: node - linkType: hard - -"promise-to-callback@npm:^1.0.0": - version: 1.0.0 - resolution: "promise-to-callback@npm:1.0.0" - dependencies: - is-fn: "npm:^1.0.0" - set-immediate-shim: "npm:^1.0.1" - checksum: 10c0/93652659c8ea3b51f2ff22a8228bb3b41687c67f7463db9bec31307162bd1e1988f4cf4406c5a5fbd8133d25e9c11f63b0f3adb9590fcc12d6464d8b04893399 - languageName: node - linkType: hard - -"prop-types@npm:^15.7.2": - version: 15.7.2 - resolution: "prop-types@npm:15.7.2" - dependencies: - loose-envify: "npm:^1.4.0" - object-assign: "npm:^4.1.1" - react-is: "npm:^16.8.1" - checksum: 10c0/4eb527daec962acd789c621ce3234a6f077ce202049291642d8efd13b19805adf07227672c570531cdb56a357640ea27e336527682b7ed4be0c5b392a01662ab - languageName: node - linkType: hard - -"proper-lockfile@npm:^4.1.1": - version: 4.1.2 - resolution: "proper-lockfile@npm:4.1.2" - dependencies: - graceful-fs: "npm:^4.2.4" - retry: "npm:^0.12.0" - signal-exit: "npm:^3.0.2" - checksum: 10c0/2f265dbad15897a43110a02dae55105c04d356ec4ed560723dcb9f0d34bc4fb2f13f79bb930e7561be10278e2314db5aca2527d5d3dcbbdee5e6b331d1571f6d - languageName: node - linkType: hard - -"proxy-addr@npm:~2.0.7": - version: 2.0.7 - resolution: "proxy-addr@npm:2.0.7" - dependencies: - forwarded: "npm:0.2.0" - ipaddr.js: "npm:1.9.1" - checksum: 10c0/c3eed999781a35f7fd935f398b6d8920b6fb00bbc14287bc6de78128ccc1a02c89b95b56742bf7cf0362cc333c61d138532049c7dedc7a328ef13343eff81210 - languageName: node - linkType: hard - -"proxy-from-env@npm:^2.1.0": - version: 2.1.0 - resolution: "proxy-from-env@npm:2.1.0" - checksum: 10c0/ed01729fd4d094eab619cd7e17ce3698b3413b31eb102c4904f9875e677cd207392795d5b4adee9cec359dfd31c44d5ad7595a3a3ad51c40250e141512281c58 - languageName: node - linkType: hard - -"prr@npm:~1.0.1": - version: 1.0.1 - resolution: "prr@npm:1.0.1" - checksum: 10c0/5b9272c602e4f4472a215e58daff88f802923b84bc39c8860376bb1c0e42aaf18c25d69ad974bd06ec6db6f544b783edecd5502cd3d184748d99080d68e4be5f - languageName: node - linkType: hard - -"pseudomap@npm:^1.0.1": - version: 1.0.2 - resolution: "pseudomap@npm:1.0.2" - checksum: 10c0/5a91ce114c64ed3a6a553aa7d2943868811377388bb31447f9d8028271bae9b05b340fe0b6961a64e45b9c72946aeb0a4ab635e8f7cb3715ffd0ff2beeb6a679 - languageName: node - linkType: hard - -"psl@npm:^1.1.28": - version: 1.9.0 - resolution: "psl@npm:1.9.0" - checksum: 10c0/6a3f805fdab9442f44de4ba23880c4eba26b20c8e8e0830eff1cb31007f6825dace61d17203c58bfe36946842140c97a1ba7f67bc63ca2d88a7ee052b65d97ab - languageName: node - linkType: hard - -"public-encrypt@npm:^4.0.0": - version: 4.0.3 - resolution: "public-encrypt@npm:4.0.3" - dependencies: - bn.js: "npm:^4.1.0" - browserify-rsa: "npm:^4.0.0" - create-hash: "npm:^1.1.0" - parse-asn1: "npm:^5.0.0" - randombytes: "npm:^2.0.1" - safe-buffer: "npm:^5.1.2" - checksum: 10c0/6c2cc19fbb554449e47f2175065d6b32f828f9b3badbee4c76585ac28ae8641aafb9bb107afc430c33c5edd6b05dbe318df4f7d6d7712b1093407b11c4280700 - languageName: node - linkType: hard - -"pull-cat@npm:^1.1.9": - version: 1.1.11 - resolution: "pull-cat@npm:1.1.11" - checksum: 10c0/e20d5f2db3962808816026c25246afe2b4369c27e13806d2354dcab3b9f0fd9c26396a74edcb948994eb9554dafee5ac93b072a0ad6303647d123472edeb9591 - languageName: node - linkType: hard - -"pull-defer@npm:^0.2.2": - version: 0.2.3 - resolution: "pull-defer@npm:0.2.3" - checksum: 10c0/5d7b76c6839ba778b2dd67e45c51d89e03ac753d571aea15b75fe98bf3d451925fdad24903a6adea71dd58d8b2df417a574f8e62bea5f7e4a3071a92135e7a62 - languageName: node - linkType: hard - -"pull-level@npm:^2.0.3": - version: 2.0.4 - resolution: "pull-level@npm:2.0.4" - dependencies: - level-post: "npm:^1.0.7" - pull-cat: "npm:^1.1.9" - pull-live: "npm:^1.0.1" - pull-pushable: "npm:^2.0.0" - pull-stream: "npm:^3.4.0" - pull-window: "npm:^2.1.4" - stream-to-pull-stream: "npm:^1.7.1" - checksum: 10c0/29008576b5db4bcad04d7b0dcd8015b6c648a9def0b1b5fcc40a2bd841a8eae5f19e398459408500d67fe492d9cdb87bf5bcaad6d6a4235d45eb3fd1a6aba1ad - languageName: node - linkType: hard - -"pull-live@npm:^1.0.1": - version: 1.0.1 - resolution: "pull-live@npm:1.0.1" - dependencies: - pull-cat: "npm:^1.1.9" - pull-stream: "npm:^3.4.0" - checksum: 10c0/74041775b3e250a9ea60053e7c7c04f1635382920f497fa8c90da04ff040cff5cf055d58cdea9b94ce836307f50e55a9699d5c3f378392ca33e97017cdda6345 + hardhat: internal/cli/bootstrap.js + checksum: 10c0/3cf2b446e64ca877bcf26e95259024bc872a9e44b63151c3bcfaf88b200672423d9c182ec0460d0944e506a3b096dd76bc4f1e6ade3ce908275f4e407b582f7f languageName: node linkType: hard -"pull-pushable@npm:^2.0.0": - version: 2.2.0 - resolution: "pull-pushable@npm:2.2.0" - checksum: 10c0/8187b9c9ba5c3bd1c55128d71a490849c95a16056fce78e4c0f1c111d8bdd844e4d8419ce472a411176116ff743cbf07fec29306cca2d0468b2211e778f95a9f +"has-flag@npm:^3.0.0": + version: 3.0.0 + resolution: "has-flag@npm:3.0.0" + checksum: 10c0/1c6c83b14b8b1b3c25b0727b8ba3e3b647f99e9e6e13eb7322107261de07a4c1be56fc0d45678fc376e09772a3a1642ccdaf8fc69bdf123b6c086598397ce473 languageName: node linkType: hard -"pull-stream@npm:^3.2.3, pull-stream@npm:^3.4.0, pull-stream@npm:^3.6.8": - version: 3.6.14 - resolution: "pull-stream@npm:3.6.14" - checksum: 10c0/ec1e8600345fb52fb027f7eab342cf7bca9b68bfb42567ab8ff470c8c26166af0a2b28b9ed99e68ae4063572fd1f39fd0102b66e762bcb62b0303d15c664c19b +"has-flag@npm:^4.0.0": + version: 4.0.0 + resolution: "has-flag@npm:4.0.0" + checksum: 10c0/2e789c61b7888d66993e14e8331449e525ef42aac53c627cc53d1c3334e768bcb6abdc4f5f0de1478a25beec6f0bd62c7549058b7ac53e924040d4f301f02fd1 languageName: node linkType: hard -"pull-window@npm:^2.1.4": - version: 2.1.4 - resolution: "pull-window@npm:2.1.4" - dependencies: - looper: "npm:^2.0.0" - checksum: 10c0/359670d91eef072374d8ccd7aca9c9163ade110cce8e2992f4cb799d1cbdb7045305764811a8abe1e4d9fa5ffd06c8041087478ebc7d5ef9e71fb7d1b7df6e9f +"has-symbols@npm:^1.0.3": + version: 1.0.3 + resolution: "has-symbols@npm:1.0.3" + checksum: 10c0/e6922b4345a3f37069cdfe8600febbca791c94988c01af3394d86ca3360b4b93928bbf395859158f88099cb10b19d98e3bbab7c9ff2c1bd09cf665ee90afa2c3 languageName: node linkType: hard -"pump@npm:^3.0.0": - version: 3.0.0 - resolution: "pump@npm:3.0.0" - dependencies: - end-of-stream: "npm:^1.1.0" - once: "npm:^1.3.1" - checksum: 10c0/bbdeda4f747cdf47db97428f3a135728669e56a0ae5f354a9ac5b74556556f5446a46f720a8f14ca2ece5be9b4d5d23c346db02b555f46739934cc6c093a5478 +"has-symbols@npm:^1.1.0": + version: 1.1.0 + resolution: "has-symbols@npm:1.1.0" + checksum: 10c0/dde0a734b17ae51e84b10986e651c664379018d10b91b6b0e9b293eddb32f0f069688c841fb40f19e9611546130153e0a2a48fd7f512891fb000ddfa36f5a20e languageName: node linkType: hard -"punycode@npm:1.3.2": - version: 1.3.2 - resolution: "punycode@npm:1.3.2" - checksum: 10c0/281fd20eaf4704f79d80cb0dc65065bf6452ee67989b3e8941aed6360a5a9a8a01d3e2ed71d0bde3cd74fb5a5dd9db4160bed5a8c20bed4b6764c24ce4c7d2d2 +"has-tostringtag@npm:^1.0.2": + version: 1.0.2 + resolution: "has-tostringtag@npm:1.0.2" + dependencies: + has-symbols: "npm:^1.0.3" + checksum: 10c0/a8b166462192bafe3d9b6e420a1d581d93dd867adb61be223a17a8d6dad147aa77a8be32c961bb2f27b3ef893cae8d36f564ab651f5e9b7938ae86f74027c48c languageName: node linkType: hard -"punycode@npm:2.1.0": - version: 2.1.0 - resolution: "punycode@npm:2.1.0" - checksum: 10c0/f427b54c0ce23da3eb07ef02f3f158a280bd0182cac7e409016390d2632d161fc759f99a2619e9f6dcdd9ea00e8640de844ffaffd9f9deb479494c3494ef5cfb +"hash-base@npm:^3.0.0": + version: 3.1.0 + resolution: "hash-base@npm:3.1.0" + dependencies: + inherits: "npm:^2.0.4" + readable-stream: "npm:^3.6.0" + safe-buffer: "npm:^5.2.0" + checksum: 10c0/663eabcf4173326fbb65a1918a509045590a26cc7e0964b754eef248d281305c6ec9f6b31cb508d02ffca383ab50028180ce5aefe013e942b44a903ac8dc80d0 languageName: node linkType: hard -"punycode@npm:^2.1.0, punycode@npm:^2.1.1": - version: 2.1.1 - resolution: "punycode@npm:2.1.1" - checksum: 10c0/83815ca9b9177f055771f31980cbec7ffaef10257d50a95ab99b4a30f0404846e85fa6887ee1bbc0aaddb7bad6d96e2fa150a016051ff0f6b92be4ad613ddca8 +"hash.js@npm:1.1.7, hash.js@npm:^1.0.0, hash.js@npm:^1.0.3, hash.js@npm:^1.1.7": + version: 1.1.7 + resolution: "hash.js@npm:1.1.7" + dependencies: + inherits: "npm:^2.0.3" + minimalistic-assert: "npm:^1.0.1" + checksum: 10c0/41ada59494eac5332cfc1ce6b7ebdd7b88a3864a6d6b08a3ea8ef261332ed60f37f10877e0c825aaa4bddebf164fbffa618286aeeec5296675e2671cbfa746c4 languageName: node linkType: hard -"qs@npm:6.10.3": - version: 6.10.3 - resolution: "qs@npm:6.10.3" +"hashery@npm:^1.4.0, hashery@npm:^1.5.1": + version: 1.5.1 + resolution: "hashery@npm:1.5.1" dependencies: - side-channel: "npm:^1.0.4" - checksum: 10c0/c6684df925fd2c6f0940b8fbfe5d8b5a8634dc96c0908309655cbe61a3fbf94cedc6b11e669fca1971b53459b6f732cccd4eeb6484b5b77b405ad0cfb936e6fe + hookified: "npm:^1.15.0" + checksum: 10c0/ab4225b655a7b0d05df99b1a59d5b3a51fe433f82422ca25e6f3f4c4ddd30adb49ebd38e0047ef9bded93319c1e9fc857e16aa382e554929c871cb77d39fc463 languageName: node linkType: hard -"qs@npm:^6.9.4": - version: 6.11.0 - resolution: "qs@npm:6.11.0" +"hasown@npm:^2.0.2, hasown@npm:^2.0.4": + version: 2.0.4 + resolution: "hasown@npm:2.0.4" dependencies: - side-channel: "npm:^1.0.4" - checksum: 10c0/4e4875e4d7c7c31c233d07a448e7e4650f456178b9dd3766b7cfa13158fdb24ecb8c4f059fa91e820dc6ab9f2d243721d071c9c0378892dcdad86e9e9a27c68f + function-bind: "npm:^1.1.2" + checksum: 10c0/2d8de939e270b70618f8cebb69746620db10617dbb495bc66ddad326955ea24d3ca4af133aff3eb7c1853e0218f867bc2b050ec26fe02e3aea58f880ffc5e506 languageName: node linkType: hard -"qs@npm:~6.5.2": - version: 6.5.3 - resolution: "qs@npm:6.5.3" - checksum: 10c0/6631d4f2fa9d315e480662646745a4aa3a708817fbffe2cbdacec8ab9be130f92740c66191770fe9b704bc5fa9c1cc1f6596f55ad132fef7bd3ad1582f199eb0 +"he@npm:^1.2.0": + version: 1.2.0 + resolution: "he@npm:1.2.0" + bin: + he: bin/he + checksum: 10c0/a27d478befe3c8192f006cdd0639a66798979dfa6e2125c6ac582a19a5ebfec62ad83e8382e6036170d873f46e4536a7e795bf8b95bf7c247f4cc0825ccc8c17 languageName: node linkType: hard -"query-string@npm:^5.0.1": - version: 5.1.1 - resolution: "query-string@npm:5.1.1" +"hmac-drbg@npm:^1.0.1": + version: 1.0.1 + resolution: "hmac-drbg@npm:1.0.1" dependencies: - decode-uri-component: "npm:^0.2.0" - object-assign: "npm:^4.1.0" - strict-uri-encode: "npm:^1.0.0" - checksum: 10c0/25adf37fe9a5b749da55ef91192d190163c44283826b425fa86eeb1fa567cf500a32afc2c602d4f661839d86ca49c2f8d49433b3c1b44b9129a37a5d3da55f89 + hash.js: "npm:^1.0.3" + minimalistic-assert: "npm:^1.0.0" + minimalistic-crypto-utils: "npm:^1.0.1" + checksum: 10c0/f3d9ba31b40257a573f162176ac5930109816036c59a09f901eb2ffd7e5e705c6832bedfff507957125f2086a0ab8f853c0df225642a88bf1fcaea945f20600d languageName: node linkType: hard -"querystring@npm:0.2.0": - version: 0.2.0 - resolution: "querystring@npm:0.2.0" - checksum: 10c0/2036c9424beaacd3978bac9e4ba514331cc73163bea7bf3ad7e2c7355e55501938ec195312c607753f9c6e70b1bf9dfcda38db6241bd299c034e27ac639d64ed +"hookified@npm:^1.15.0, hookified@npm:^1.15.1": + version: 1.15.1 + resolution: "hookified@npm:1.15.1" + checksum: 10c0/6b691374fa97ae57169fb29f90e723499fda5e85494654fbe55c4768b3ccbf3e14c0adc8d0f365f32c503b60d7c06f907781f5966c03d41c423575eb5e16860c languageName: node linkType: hard -"queue-microtask@npm:^1.2.2": - version: 1.2.3 - resolution: "queue-microtask@npm:1.2.3" - checksum: 10c0/900a93d3cdae3acd7d16f642c29a642aea32c2026446151f0778c62ac089d4b8e6c986811076e1ae180a694cedf077d453a11b58ff0a865629a4f82ab558e102 +"hookified@npm:^2.1.1": + version: 2.2.0 + resolution: "hookified@npm:2.2.0" + checksum: 10c0/7017d2b66945490293a5aba239e7b39f39071dd940fa019348c7ffea92b91b8c267853c4c51680ed0f3687b33352582fa4d2cff6dd4c5a1c5c44b037276f07aa languageName: node linkType: hard -"randombytes@npm:^2.0.0, randombytes@npm:^2.0.1, randombytes@npm:^2.0.5, randombytes@npm:^2.0.6, randombytes@npm:^2.1.0": - version: 2.1.0 - resolution: "randombytes@npm:2.1.0" - dependencies: - safe-buffer: "npm:^5.1.0" - checksum: 10c0/50395efda7a8c94f5dffab564f9ff89736064d32addf0cc7e8bf5e4166f09f8ded7a0849ca6c2d2a59478f7d90f78f20d8048bca3cdf8be09d8e8a10790388f3 +"http-cache-semantics@npm:^4.1.1": + version: 4.2.0 + resolution: "http-cache-semantics@npm:4.2.0" + checksum: 10c0/45b66a945cf13ec2d1f29432277201313babf4a01d9e52f44b31ca923434083afeca03f18417f599c9ab3d0e7b618ceb21257542338b57c54b710463b4a53e37 languageName: node linkType: hard -"randomfill@npm:^1.0.3": - version: 1.0.4 - resolution: "randomfill@npm:1.0.4" +"http-errors@npm:1.7.3": + version: 1.7.3 + resolution: "http-errors@npm:1.7.3" dependencies: - randombytes: "npm:^2.0.5" - safe-buffer: "npm:^5.1.0" - checksum: 10c0/11aeed35515872e8f8a2edec306734e6b74c39c46653607f03c68385ab8030e2adcc4215f76b5e4598e028c4750d820afd5c65202527d831d2a5f207fe2bc87c + depd: "npm:~1.1.2" + inherits: "npm:2.0.4" + setprototypeof: "npm:1.1.1" + statuses: "npm:>= 1.5.0 < 2" + toidentifier: "npm:1.0.0" + checksum: 10c0/5c3443c340d35b2f18ce908266c4ae93305b7d900bef765ac8dc56fa90125b9fe18a1ed9ebf6af23dc3ba7763731921a2682bf968e199eccf383eb8f508be6c2 languageName: node linkType: hard -"range-parser@npm:~1.2.1": - version: 1.2.1 - resolution: "range-parser@npm:1.2.1" - checksum: 10c0/96c032ac2475c8027b7a4e9fe22dc0dfe0f6d90b85e496e0f016fbdb99d6d066de0112e680805075bd989905e2123b3b3d002765149294dce0c1f7f01fcc2ea0 +"http-proxy-agent@npm:^7.0.0": + version: 7.0.2 + resolution: "http-proxy-agent@npm:7.0.2" + dependencies: + agent-base: "npm:^7.1.0" + debug: "npm:^4.3.4" + checksum: 10c0/4207b06a4580fb85dd6dff521f0abf6db517489e70863dca1a0291daa7f2d3d2d6015a57bd702af068ea5cf9f1f6ff72314f5f5b4228d299c0904135d2aef921 languageName: node linkType: hard -"raw-body@npm:2.5.1": - version: 2.5.1 - resolution: "raw-body@npm:2.5.1" +"http2-wrapper@npm:^2.1.10": + version: 2.2.1 + resolution: "http2-wrapper@npm:2.2.1" dependencies: - bytes: "npm:3.1.2" - http-errors: "npm:2.0.0" - iconv-lite: "npm:0.4.24" - unpipe: "npm:1.0.0" - checksum: 10c0/5dad5a3a64a023b894ad7ab4e5c7c1ce34d3497fc7138d02f8c88a3781e68d8a55aa7d4fd3a458616fa8647cc228be314a1c03fb430a07521de78b32c4dd09d2 + quick-lru: "npm:^5.1.1" + resolve-alpn: "npm:^1.2.0" + checksum: 10c0/7207201d3c6e53e72e510c9b8912e4f3e468d3ecc0cf3bf52682f2aac9cd99358b896d1da4467380adc151cf97c412bedc59dc13dae90c523f42053a7449eedb languageName: node linkType: hard -"raw-body@npm:^2.4.1": - version: 2.4.1 - resolution: "raw-body@npm:2.4.1" +"https-proxy-agent@npm:^5.0.0": + version: 5.0.0 + resolution: "https-proxy-agent@npm:5.0.0" dependencies: - bytes: "npm:3.1.0" - http-errors: "npm:1.7.3" - iconv-lite: "npm:0.4.24" - unpipe: "npm:1.0.0" - checksum: 10c0/e4107f4dd9101d703d40bd8ddd6969badfec39ec81f15fbb1ae9c63752190dd37d2f2c3ff61fdcaf37b1ca18c647abcf80d0519c4d2e082ce849f51acfbf34d7 + agent-base: "npm:6" + debug: "npm:4" + checksum: 10c0/670c04f7f0effb5a449c094ea037cbcfb28a5ab93ed22e8c343095202cc7288027869a5a21caf4ee3b8ea06f9624ef1e1fc9044669c0fd92617654ff39f30806 languageName: node linkType: hard -"react-is@npm:^16.8.1": - version: 16.13.1 - resolution: "react-is@npm:16.13.1" - checksum: 10c0/33977da7a5f1a287936a0c85639fec6ca74f4f15ef1e59a6bc20338fc73dc69555381e211f7a3529b8150a1f71e4225525b41b60b52965bda53ce7d47377ada1 +"https-proxy-agent@npm:^5.0.1": + version: 5.0.1 + resolution: "https-proxy-agent@npm:5.0.1" + dependencies: + agent-base: "npm:6" + debug: "npm:4" + checksum: 10c0/6dd639f03434003577c62b27cafdb864784ef19b2de430d8ae2a1d45e31c4fd60719e5637b44db1a88a046934307da7089e03d6089ec3ddacc1189d8de8897d1 languageName: node linkType: hard -"read-pkg-up@npm:^1.0.1": - version: 1.0.1 - resolution: "read-pkg-up@npm:1.0.1" +"https-proxy-agent@npm:^7.0.1": + version: 7.0.6 + resolution: "https-proxy-agent@npm:7.0.6" dependencies: - find-up: "npm:^1.0.0" - read-pkg: "npm:^1.0.0" - checksum: 10c0/36c4fc8bd73edf77a4eeb497b6e43010819ea4aef64cbf8e393439fac303398751c5a299feab84e179a74507e3a1416e1ed033a888b1dac3463bf46d1765f7ac + agent-base: "npm:^7.1.2" + debug: "npm:4" + checksum: 10c0/f729219bc735edb621fa30e6e84e60ee5d00802b8247aac0d7b79b0bd6d4b3294737a337b93b86a0bd9e68099d031858a39260c976dc14cdbba238ba1f8779ac languageName: node linkType: hard -"read-pkg-up@npm:^3.0.0": - version: 3.0.0 - resolution: "read-pkg-up@npm:3.0.0" +"iconv-lite@npm:0.4.24": + version: 0.4.24 + resolution: "iconv-lite@npm:0.4.24" dependencies: - find-up: "npm:^2.0.0" - read-pkg: "npm:^3.0.0" - checksum: 10c0/2cd0a180260b0d235990e6e9c8c2330a03882d36bc2eba8930e437ef23ee52a68a894e7e1ccb1c33f03bcceb270a861ee5f7eac686f238857755e2cddfb48ffd + safer-buffer: "npm:>= 2.1.2 < 3" + checksum: 10c0/c6886a24cc00f2a059767440ec1bc00d334a89f250db8e0f7feb4961c8727118457e27c495ba94d082e51d3baca378726cd110aaf7ded8b9bbfd6a44760cf1d4 languageName: node linkType: hard -"read-pkg@npm:^1.0.0": - version: 1.1.0 - resolution: "read-pkg@npm:1.1.0" +"iconv-lite@npm:^0.7.2": + version: 0.7.2 + resolution: "iconv-lite@npm:0.7.2" dependencies: - load-json-file: "npm:^1.0.0" - normalize-package-data: "npm:^2.3.2" - path-type: "npm:^1.0.0" - checksum: 10c0/51fce9f7066787dc7688ea7014324cedeb9f38daa7dace4f1147d526f22354a07189ef728710bc97e27fcf5ed3a03b68ad8b60afb4251984640b6f09c180d572 + safer-buffer: "npm:>= 2.1.2 < 3.0.0" + checksum: 10c0/3c228920f3bd307f56bf8363706a776f4a060eb042f131cd23855ceca962951b264d0997ab38a1ad340e1c5df8499ed26e1f4f0db6b2a2ad9befaff22f14b722 languageName: node linkType: hard -"read-pkg@npm:^3.0.0": - version: 3.0.0 - resolution: "read-pkg@npm:3.0.0" - dependencies: - load-json-file: "npm:^4.0.0" - normalize-package-data: "npm:^2.3.2" - path-type: "npm:^3.0.0" - checksum: 10c0/65acf2df89fbcd506b48b7ced56a255ba00adf7ecaa2db759c86cc58212f6fd80f1f0b7a85c848551a5d0685232e9b64f45c1fd5b48d85df2761a160767eeb93 +"ieee754@npm:^1.1.4": + version: 1.2.1 + resolution: "ieee754@npm:1.2.1" + checksum: 10c0/b0782ef5e0935b9f12883a2e2aa37baa75da6e66ce6515c168697b42160807d9330de9a32ec1ed73149aea02e0d822e572bca6f1e22bdcbd2149e13b050b17bb languageName: node linkType: hard -"readable-stream@npm:^1.0.33": - version: 1.1.14 - resolution: "readable-stream@npm:1.1.14" - dependencies: - core-util-is: "npm:~1.0.0" - inherits: "npm:~2.0.1" - isarray: "npm:0.0.1" - string_decoder: "npm:~0.10.x" - checksum: 10c0/b7f41b16b305103d598e3c8964fa30d52d6e0b5d9fdad567588964521691c24b279c7a8bb71f11927c3613acf355bac72d8396885a43d50425b2caafd49bc83d +"ignore@npm:^5.2.0, ignore@npm:^5.2.4": + version: 5.3.2 + resolution: "ignore@npm:5.3.2" + checksum: 10c0/f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337 languageName: node linkType: hard -"readable-stream@npm:^2.0.0, readable-stream@npm:^2.0.5, readable-stream@npm:^2.2.2, readable-stream@npm:^2.2.8, readable-stream@npm:^2.2.9, readable-stream@npm:^2.3.6, readable-stream@npm:~2.3.6": - version: 2.3.7 - resolution: "readable-stream@npm:2.3.7" - dependencies: - core-util-is: "npm:~1.0.0" - inherits: "npm:~2.0.3" - isarray: "npm:~1.0.0" - process-nextick-args: "npm:~2.0.0" - safe-buffer: "npm:~5.1.1" - string_decoder: "npm:~1.1.1" - util-deprecate: "npm:~1.0.1" - checksum: 10c0/1708755e6cf9daff6ff60fa5b4575636472289c5b95d38058a91f94732b8d024a940a0d4d955639195ce42c22cab16973ee8fea8deedd24b5fec3dd596465f86 +"ignore@npm:^7.0.5": + version: 7.0.8 + resolution: "ignore@npm:7.0.8" + checksum: 10c0/95ed888e66ad46c478680af1628ac1d242a623fcac418bd5533b91549f609a6756985a32ebfe087b1d97806f52a20f991c804e3b074e9cf16fd1404f2bcd9c0a languageName: node linkType: hard -"readable-stream@npm:^3.0.6, readable-stream@npm:^3.6.0": - version: 3.6.0 - resolution: "readable-stream@npm:3.6.0" - dependencies: - inherits: "npm:^2.0.3" - string_decoder: "npm:^1.1.1" - util-deprecate: "npm:^1.0.1" - checksum: 10c0/937bedd29ac8a68331666291922bea892fa2be1a33269e582de9f844a2002f146cf831e39cd49fe6a378d3f0c27358f259ed0e20d20f0bdc6a3f8fc21fce42dc +"immutable@npm:^4.0.0-rc.12": + version: 4.0.0-rc.15 + resolution: "immutable@npm:4.0.0-rc.15" + checksum: 10c0/122a69825e923a14346c8446f75165368c2cf53c021059a5eb8b55bf456e61d06d8295416a588c37ca4d32d365f3dfa309481caa4a41bd9aa0f804501b6587a9 languageName: node linkType: hard -"readable-stream@npm:~1.0.15": - version: 1.0.34 - resolution: "readable-stream@npm:1.0.34" +"import-fresh@npm:^3.3.0": + version: 3.3.1 + resolution: "import-fresh@npm:3.3.1" dependencies: - core-util-is: "npm:~1.0.0" - inherits: "npm:~2.0.1" - isarray: "npm:0.0.1" - string_decoder: "npm:~0.10.x" - checksum: 10c0/02272551396ed8930ddee1a088bdf0379f0f7cc47ac49ed8804e998076cb7daec9fbd2b1fd9c0490ec72e56e8bb3651abeb8080492b8e0a9c3f2158330908ed6 + parent-module: "npm:^1.0.0" + resolve-from: "npm:^4.0.0" + checksum: 10c0/bf8cc494872fef783249709385ae883b447e3eb09db0ebd15dcead7d9afe7224dad7bd7591c6b73b0b19b3c0f9640eb8ee884f01cfaf2887ab995b0b36a0cbec languageName: node linkType: hard -"readdirp@npm:^4.0.1": - version: 4.1.2 - resolution: "readdirp@npm:4.1.2" - checksum: 10c0/60a14f7619dec48c9c850255cd523e2717001b0e179dc7037cfa0895da7b9e9ab07532d324bfb118d73a710887d1e35f79c495fa91582784493e085d18c72c62 +"imul@npm:^1.0.0": + version: 1.0.1 + resolution: "imul@npm:1.0.1" + checksum: 10c0/d564c45a5017f01f965509ef409fad8175749bc96a52a95e1a09f05378d135fb37051cea7194d0eeca5147541d8e80d68853f5f681eef05f9f14f1d551edae2f languageName: node linkType: hard -"readdirp@npm:~3.6.0": - version: 3.6.0 - resolution: "readdirp@npm:3.6.0" - dependencies: - picomatch: "npm:^2.2.1" - checksum: 10c0/6fa848cf63d1b82ab4e985f4cf72bd55b7dcfd8e0a376905804e48c3634b7e749170940ba77b32804d5fe93b3cc521aa95a8d7e7d725f830da6d93f3669ce66b +"imurmurhash@npm:^0.1.4": + version: 0.1.4 + resolution: "imurmurhash@npm:0.1.4" + checksum: 10c0/8b51313850dd33605c6c9d3fd9638b714f4c4c40250cff658209f30d40da60f78992fb2df5dabee4acf589a6a82bbc79ad5486550754bd9ec4e3fc0d4a57d6a6 languageName: node linkType: hard -"reduce-flatten@npm:^2.0.0": - version: 2.0.0 - resolution: "reduce-flatten@npm:2.0.0" - checksum: 10c0/9275064535bc070a787824c835a4f18394942f8a78f08e69fb500920124ce1c46a287c8d9e565a7ffad8104875a6feda14efa8e951e8e4585370b8ff007b0abd +"indent-string@npm:^4.0.0": + version: 4.0.0 + resolution: "indent-string@npm:4.0.0" + checksum: 10c0/1e1904ddb0cb3d6cce7cd09e27a90184908b7a5d5c21b92e232c93579d314f0b83c246ffb035493d0504b1e9147ba2c9b21df0030f48673fba0496ecd698161f languageName: node linkType: hard -"regenerate@npm:^1.2.1": - version: 1.4.2 - resolution: "regenerate@npm:1.4.2" - checksum: 10c0/f73c9eba5d398c818edc71d1c6979eaa05af7a808682749dd079f8df2a6d91a9b913db216c2c9b03e0a8ba2bba8701244a93f45211afbff691c32c7b275db1b8 +"inflight@npm:^1.0.4": + version: 1.0.6 + resolution: "inflight@npm:1.0.6" + dependencies: + once: "npm:^1.3.0" + wrappy: "npm:1" + checksum: 10c0/7faca22584600a9dc5b9fca2cd5feb7135ac8c935449837b315676b4c90aa4f391ec4f42240178244b5a34e8bede1948627fda392ca3191522fc46b34e985ab2 languageName: node linkType: hard -"regenerator-runtime@npm:^0.11.0": - version: 0.11.1 - resolution: "regenerator-runtime@npm:0.11.1" - checksum: 10c0/69cfa839efcf2d627fe358bf302ab8b24e5f182cb69f13e66f0612d3640d7838aad1e55662135e3ef2c1cc4322315b757626094fab13a48f9a64ab4bdeb8795b +"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4": + version: 2.0.4 + resolution: "inherits@npm:2.0.4" + checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 languageName: node linkType: hard -"regenerator-runtime@npm:^0.13.4": - version: 0.13.9 - resolution: "regenerator-runtime@npm:0.13.9" - checksum: 10c0/b0f26612204f061a84064d2f3361629eae09993939112b9ffc3680bb369ecd125764d6654eace9ef11b36b44282ee52b988dda946ea52d372e7599a30eea73ee +"ini@npm:^1.3.4, ini@npm:~1.3.0": + version: 1.3.8 + resolution: "ini@npm:1.3.8" + checksum: 10c0/ec93838d2328b619532e4f1ff05df7909760b6f66d9c9e2ded11e5c1897d6f2f9980c54dd638f88654b00919ce31e827040631eab0a3969e4d1abefa0719516a languageName: node linkType: hard -"regenerator-transform@npm:^0.10.0": - version: 0.10.1 - resolution: "regenerator-transform@npm:0.10.1" +"io-ts@npm:1.10.4": + version: 1.10.4 + resolution: "io-ts@npm:1.10.4" dependencies: - babel-runtime: "npm:^6.18.0" - babel-types: "npm:^6.19.0" - private: "npm:^0.1.6" - checksum: 10c0/13d017b228cca6fe441f97542fb689cf96fefc422d13d94a7dc5aeca1777f8f06c1acf5396c537157166be887dca4c6d347bdbb2e69317749b267be196da01a3 + fp-ts: "npm:^1.0.0" + checksum: 10c0/9370988a7e17fc23c194115808168ccd1ccf7b7ebe92c39c1cc2fd91c1dc641552a5428bb04fe28c01c826fa4f230e856eb4f7d27c774a1400af3fecf2936ab5 languageName: node linkType: hard -"regex-not@npm:^1.0.0, regex-not@npm:^1.0.2": - version: 1.0.2 - resolution: "regex-not@npm:1.0.2" - dependencies: - extend-shallow: "npm:^3.0.2" - safe-regex: "npm:^1.1.0" - checksum: 10c0/a0f8d6045f63b22e9759db10e248369c443b41cedd7dba0922d002b66c2734bc2aef0d98c4d45772d1f756245f4c5203856b88b9624bba2a58708858a8d485d6 +"ip-address@npm:^10.0.1": + version: 10.1.0 + resolution: "ip-address@npm:10.1.0" + checksum: 10c0/0103516cfa93f6433b3bd7333fa876eb21263912329bfa47010af5e16934eeeff86f3d2ae700a3744a137839ddfad62b900c7a445607884a49b5d1e32a3d7566 languageName: node linkType: hard -"regexp.prototype.flags@npm:^1.2.0, regexp.prototype.flags@npm:^1.3.1": - version: 1.3.1 - resolution: "regexp.prototype.flags@npm:1.3.1" +"is-arrayish@npm:^0.2.1": + version: 0.2.1 + resolution: "is-arrayish@npm:0.2.1" + checksum: 10c0/e7fb686a739068bb70f860b39b67afc62acc62e36bb61c5f965768abce1873b379c563e61dd2adad96ebb7edf6651111b385e490cf508378959b0ed4cac4e729 + languageName: node + linkType: hard + +"is-binary-path@npm:~2.1.0": + version: 2.1.0 + resolution: "is-binary-path@npm:2.1.0" dependencies: - call-bind: "npm:^1.0.2" - define-properties: "npm:^1.1.3" - checksum: 10c0/499745fc4634e1619c050b09afe81aa1b88e0eac589543c8c78baa2e7090df313e1e8e6033bd7206ee498c2640b05593b3dfa3c603beb6ab9773277a8b7e5206 + binary-extensions: "npm:^2.0.0" + checksum: 10c0/a16eaee59ae2b315ba36fad5c5dcaf8e49c3e27318f8ab8fa3cdb8772bf559c8d1ba750a589c2ccb096113bb64497084361a25960899cb6172a6925ab6123d38 languageName: node linkType: hard -"regexpp@npm:^2.0.1": - version: 2.0.1 - resolution: "regexpp@npm:2.0.1" - checksum: 10c0/4ac2cf4c68941728bffbba5a8f597a23385c2c05afc5bf5de74744ee048765ab84ea3ce3c6a5bdce102a3a54514b75b7add48b4c1abd925ca3afd40e537f2b5f +"is-bun-module@npm:^2.0.0": + version: 2.0.0 + resolution: "is-bun-module@npm:2.0.0" + dependencies: + semver: "npm:^7.7.1" + checksum: 10c0/7d27a0679cfa5be1f5052650391f9b11040cd70c48d45112e312c56bc6b6ca9c9aea70dcce6cc40b1e8947bfff8567a5c5715d3b066fb478522dab46ea379240 languageName: node linkType: hard -"regexpp@npm:^3.1.0": - version: 3.2.0 - resolution: "regexpp@npm:3.2.0" - checksum: 10c0/d1da82385c8754a1681416b90b9cca0e21b4a2babef159099b88f640637d789c69011d0bc94705dacab85b81133e929d027d85210e8b8b03f8035164dbc14710 +"is-docker@npm:^2.0.0, is-docker@npm:^2.1.1": + version: 2.2.1 + resolution: "is-docker@npm:2.2.1" + bin: + is-docker: cli.js + checksum: 10c0/e828365958d155f90c409cdbe958f64051d99e8aedc2c8c4cd7c89dcf35329daed42f7b99346f7828df013e27deb8f721cf9408ba878c76eb9e8290235fbcdcc languageName: node linkType: hard -"regexpu-core@npm:^2.0.0": - version: 2.0.0 - resolution: "regexpu-core@npm:2.0.0" - dependencies: - regenerate: "npm:^1.2.1" - regjsgen: "npm:^0.2.0" - regjsparser: "npm:^0.1.4" - checksum: 10c0/685475fa04edbd4f8aa78811e16ef6c7e86ca4e4a2f73fbb1ba95db437a6c68e52664986efdea7afe0d78e773fb81624825976aba06de7a1ce80c94bd0126077 +"is-extglob@npm:^2.1.1": + version: 2.1.1 + resolution: "is-extglob@npm:2.1.1" + checksum: 10c0/5487da35691fbc339700bbb2730430b07777a3c21b9ebaecb3072512dfd7b4ba78ac2381a87e8d78d20ea08affb3f1971b4af629173a6bf435ff8a4c47747912 languageName: node linkType: hard -"regjsgen@npm:^0.2.0": - version: 0.2.0 - resolution: "regjsgen@npm:0.2.0" - checksum: 10c0/f09821f1a125d01433b6946bb653267572d619229d32f9ca5049f3a47add798effe66b7441fb08b738c3d71d97f783e565aad6c63b7ee4b7f891a3f90882a01b +"is-fullwidth-code-point@npm:^3.0.0": + version: 3.0.0 + resolution: "is-fullwidth-code-point@npm:3.0.0" + checksum: 10c0/bb11d825e049f38e04c06373a8d72782eee0205bda9d908cc550ccb3c59b99d750ff9537982e01733c1c94a58e35400661f57042158ff5e8f3e90cf936daf0fc languageName: node linkType: hard -"regjsparser@npm:^0.1.4": - version: 0.1.5 - resolution: "regjsparser@npm:0.1.5" +"is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3, is-glob@npm:~4.0.1": + version: 4.0.3 + resolution: "is-glob@npm:4.0.3" dependencies: - jsesc: "npm:~0.5.0" - bin: - regjsparser: bin/parser - checksum: 10c0/8b9bfbc27253cb6567c821cc0d4efac447e8300a6bd711a68f8400c5e4556bc27cd7f02e0ebe3d9cb884315cacbf7b00dda74d22fe4edb19c8f5f66758d0a8d1 + is-extglob: "npm:^2.1.1" + checksum: 10c0/17fb4014e22be3bbecea9b2e3a76e9e34ff645466be702f1693e8f1ee1adac84710d0be0bd9f967d6354036fd51ab7c2741d954d6e91dae6bb69714de92c197a languageName: node linkType: hard -"repeat-element@npm:^1.1.2": - version: 1.1.4 - resolution: "repeat-element@npm:1.1.4" - checksum: 10c0/81aa8d82bc845780803ef52df3533fa399974b99df571d0bb86e91f0ffca9ee4b9c4e8e5e72af087938cc28d2aef93d106a6d01da685d72ce96455b90a9f9f69 +"is-number@npm:^7.0.0": + version: 7.0.0 + resolution: "is-number@npm:7.0.0" + checksum: 10c0/b4686d0d3053146095ccd45346461bc8e53b80aeb7671cc52a4de02dbbf7dc0d1d2a986e2fe4ae206984b4d34ef37e8b795ebc4f4295c978373e6575e295d811 languageName: node linkType: hard -"repeat-string@npm:^1.0.0, repeat-string@npm:^1.6.1": - version: 1.6.1 - resolution: "repeat-string@npm:1.6.1" - checksum: 10c0/87fa21bfdb2fbdedc44b9a5b118b7c1239bdd2c2c1e42742ef9119b7d412a5137a1d23f1a83dc6bb686f4f27429ac6f542e3d923090b44181bafa41e8ac0174d +"is-path-inside@npm:^3.0.3": + version: 3.0.3 + resolution: "is-path-inside@npm:3.0.3" + checksum: 10c0/cf7d4ac35fb96bab6a1d2c3598fe5ebb29aafb52c0aaa482b5a3ed9d8ba3edc11631e3ec2637660c44b3ce0e61a08d54946e8af30dec0b60a7c27296c68ffd05 languageName: node linkType: hard -"repeating@npm:^2.0.0": - version: 2.0.1 - resolution: "repeating@npm:2.0.1" - dependencies: - is-finite: "npm:^1.0.0" - checksum: 10c0/7f5cd293ec47d9c074ef0852800d5ff5c49028ce65242a7528d84f32bd2fe200b142930562af58c96d869c5a3046e87253030058e45231acaa129c1a7087d2e7 - languageName: node - linkType: hard - -"request@npm:^2.79.0, request@npm:^2.85.0": - version: 2.88.2 - resolution: "request@npm:2.88.2" - dependencies: - aws-sign2: "npm:~0.7.0" - aws4: "npm:^1.8.0" - caseless: "npm:~0.12.0" - combined-stream: "npm:~1.0.6" - extend: "npm:~3.0.2" - forever-agent: "npm:~0.6.1" - form-data: "npm:~2.3.2" - har-validator: "npm:~5.1.3" - http-signature: "npm:~1.2.0" - is-typedarray: "npm:~1.0.0" - isstream: "npm:~0.1.2" - json-stringify-safe: "npm:~5.0.1" - mime-types: "npm:~2.1.19" - oauth-sign: "npm:~0.9.0" - performance-now: "npm:^2.1.0" - qs: "npm:~6.5.2" - safe-buffer: "npm:^5.1.2" - tough-cookie: "npm:~2.5.0" - tunnel-agent: "npm:^0.6.0" - uuid: "npm:^3.3.2" - checksum: 10c0/0ec66e7af1391e51ad231de3b1c6c6aef3ebd0a238aa50d4191c7a792dcdb14920eea8d570c702dc5682f276fe569d176f9b8ebc6031a3cf4a630a691a431a63 +"is-plain-obj@npm:^2.1.0": + version: 2.1.0 + resolution: "is-plain-obj@npm:2.1.0" + checksum: 10c0/e5c9814cdaa627a9ad0a0964ded0e0491bfd9ace405c49a5d63c88b30a162f1512c069d5b80997893c4d0181eadc3fed02b4ab4b81059aba5620bfcdfdeb9c53 languageName: node linkType: hard -"require-directory@npm:^2.1.1": - version: 2.1.1 - resolution: "require-directory@npm:2.1.1" - checksum: 10c0/83aa76a7bc1531f68d92c75a2ca2f54f1b01463cb566cf3fbc787d0de8be30c9dbc211d1d46be3497dac5785fe296f2dd11d531945ac29730643357978966e99 +"is-unicode-supported@npm:^0.1.0": + version: 0.1.0 + resolution: "is-unicode-supported@npm:0.1.0" + checksum: 10c0/00cbe3455c3756be68d2542c416cab888aebd5012781d6819749fefb15162ff23e38501fe681b3d751c73e8ff561ac09a5293eba6f58fdf0178462ce6dcb3453 languageName: node linkType: hard -"require-from-string@npm:^1.1.0": - version: 1.2.1 - resolution: "require-from-string@npm:1.2.1" - checksum: 10c0/29b4802dbeb78c76a589fe3d5bbe3b836624a38358d024e1855a882d91218d10fe353f9c0d265deda944b0f3f789244d6813ca748c9d846fbe69734319ffe0b5 +"is-wsl@npm:^2.2.0": + version: 2.2.0 + resolution: "is-wsl@npm:2.2.0" + dependencies: + is-docker: "npm:^2.0.0" + checksum: 10c0/a6fa2d370d21be487c0165c7a440d567274fbba1a817f2f0bfa41cc5e3af25041d84267baa22df66696956038a43973e72fca117918c91431920bdef490fa25e languageName: node linkType: hard -"require-from-string@npm:^2.0.0, require-from-string@npm:^2.0.2": - version: 2.0.2 - resolution: "require-from-string@npm:2.0.2" - checksum: 10c0/aaa267e0c5b022fc5fd4eef49d8285086b15f2a1c54b28240fdf03599cbd9c26049fee3eab894f2e1f6ca65e513b030a7c264201e3f005601e80c49fb2937ce2 +"isarray@npm:^1.0.0": + version: 1.0.0 + resolution: "isarray@npm:1.0.0" + checksum: 10c0/18b5be6669be53425f0b84098732670ed4e727e3af33bc7f948aac01782110eb9a18b3b329c5323bcdd3acdaae547ee077d3951317e7f133bff7105264b3003d languageName: node linkType: hard -"require-main-filename@npm:^1.0.1": - version: 1.0.1 - resolution: "require-main-filename@npm:1.0.1" - checksum: 10c0/1ab87efb72a0e223a667154e92f29ca753fd42eb87f22db142b91c86d134e29ecf18af929111ccd255fd340b57d84a9d39489498d8dfd5136b300ded30a5f0b6 +"isexe@npm:^2.0.0": + version: 2.0.0 + resolution: "isexe@npm:2.0.0" + checksum: 10c0/228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d languageName: node linkType: hard -"resolve-from@npm:^3.0.0": - version: 3.0.0 - resolution: "resolve-from@npm:3.0.0" - checksum: 10c0/24affcf8e81f4c62f0dcabc774afe0e19c1f38e34e43daac0ddb409d79435fc3037f612b0cc129178b8c220442c3babd673e88e870d27215c99454566e770ebc +"isexe@npm:^4.0.0": + version: 4.0.0 + resolution: "isexe@npm:4.0.0" + checksum: 10c0/5884815115bceac452877659a9c7726382531592f43dc29e5d48b7c4100661aed54018cb90bd36cb2eaeba521092570769167acbb95c18d39afdccbcca06c5ce languageName: node linkType: hard -"resolve-from@npm:^4.0.0": - version: 4.0.0 - resolution: "resolve-from@npm:4.0.0" - checksum: 10c0/8408eec31a3112ef96e3746c37be7d64020cda07c03a920f5024e77290a218ea758b26ca9529fd7b1ad283947f34b2291c1c0f6aa0ed34acfdda9c6014c8d190 +"isomorphic-unfetch@npm:^3.0.0": + version: 3.1.0 + resolution: "isomorphic-unfetch@npm:3.1.0" + dependencies: + node-fetch: "npm:^2.6.1" + unfetch: "npm:^4.2.0" + checksum: 10c0/d3b61fca06304db692b7f76bdfd3a00f410e42cfa7403c3b250546bf71589d18cf2f355922f57198e4cc4a9872d3647b20397a5c3edf1a347c90d57c83cf2a89 languageName: node linkType: hard -"resolve-url@npm:^0.2.1": - version: 0.2.1 - resolution: "resolve-url@npm:0.2.1" - checksum: 10c0/c285182cfcddea13a12af92129ce0569be27fb0074ffaefbd3ba3da2eac2acecdfc996d435c4982a9fa2b4708640e52837c9153a5ab9255886a00b0b9e8d2a54 +"isows@npm:1.0.7": + version: 1.0.7 + resolution: "isows@npm:1.0.7" + peerDependencies: + ws: "*" + checksum: 10c0/43c41fe89c7c07258d0be3825f87e12da8ac9023c5b5ae6741ec00b2b8169675c04331ea73ef8c172d37a6747066f4dc93947b17cd369f92828a3b3e741afbda languageName: node linkType: hard -"resolve@npm:1.17.0": - version: 1.17.0 - resolution: "resolve@npm:1.17.0" +"jackspeak@npm:^3.1.2": + version: 3.4.3 + resolution: "jackspeak@npm:3.4.3" dependencies: - path-parse: "npm:^1.0.6" - checksum: 10c0/4e6c76cc1a7b08bff637b092ce035d7901465067915605bc5a23ac0c10fe42ec205fc209d5d5f7a5f27f37ce71d687def7f656bbb003631cd46a8374f55ec73d + "@isaacs/cliui": "npm:^8.0.2" + "@pkgjs/parseargs": "npm:^0.11.0" + dependenciesMeta: + "@pkgjs/parseargs": + optional: true + checksum: 10c0/6acc10d139eaefdbe04d2f679e6191b3abf073f111edf10b1de5302c97ec93fffeb2fdd8681ed17f16268aa9dd4f8c588ed9d1d3bffbbfa6e8bf897cbb3149b9 languageName: node linkType: hard -"resolve@npm:^1.10.0, resolve@npm:^1.20.0, resolve@npm:^1.8.1, resolve@npm:~1.20.0": - version: 1.20.0 - resolution: "resolve@npm:1.20.0" - dependencies: - is-core-module: "npm:^2.2.0" - path-parse: "npm:^1.0.6" - checksum: 10c0/d2c99e3bfbfd1f5aa4d134fa893b0157b923d6bfdc36563cb126995982ebfd0d93d901f851e4577897580f7c87d9a62d307b811422009fd3d2a8ed0571c2eabb +"js-cookie@npm:^3.0.7": + version: 3.0.8 + resolution: "js-cookie@npm:3.0.8" + checksum: 10c0/421912a4a55535bda32b3059835864e1182c3af5b4516df00a060edc1fa5a53d38bb8d5a91d5d305e396206f4fd11e829f17850aa5aa8164118c04d8ebf1ff5d languageName: node linkType: hard -"resolve@npm:^2.0.0-next.3": - version: 2.0.0-next.3 - resolution: "resolve@npm:2.0.0-next.3" - dependencies: - is-core-module: "npm:^2.2.0" - path-parse: "npm:^1.0.6" - checksum: 10c0/669f6ad21d914df8c8d414092e263c7276598ad674c32edc2763b621bf03d0481816a5173ec552b0e97dd826c522b3109e5903db0c8eff085c1e1975a1ace8d2 +"js-sha3@npm:0.8.0, js-sha3@npm:^0.8.0": + version: 0.8.0 + resolution: "js-sha3@npm:0.8.0" + checksum: 10c0/43a21dc7967c871bd2c46cb1c2ae97441a97169f324e509f382d43330d8f75cf2c96dba7c806ab08a425765a9c847efdd4bffbac2d99c3a4f3de6c0218f40533 languageName: node linkType: hard -"resolve@patch:resolve@npm%3A1.17.0#optional!builtin": - version: 1.17.0 - resolution: "resolve@patch:resolve@npm%3A1.17.0#optional!builtin::version=1.17.0&hash=c3c19d" - dependencies: - path-parse: "npm:^1.0.6" - checksum: 10c0/e072e52be3c3dbfd086761115db4a5136753e7aefc0e665e66e7307ddcd9d6b740274516055c74aee44921625e95993f03570450aa310b8d73b1c9daa056c4cd +"js-tokens@npm:^4.0.0": + version: 4.0.0 + resolution: "js-tokens@npm:4.0.0" + checksum: 10c0/e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.10.0#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.8.1#optional!builtin, resolve@patch:resolve@npm%3A~1.20.0#optional!builtin": - version: 1.20.0 - resolution: "resolve@patch:resolve@npm%3A1.20.0#optional!builtin::version=1.20.0&hash=c3c19d" +"js-yaml@npm:^4.1.0": + version: 4.3.0 + resolution: "js-yaml@npm:4.3.0" dependencies: - is-core-module: "npm:^2.2.0" - path-parse: "npm:^1.0.6" - checksum: 10c0/b6a5345d1f015cebba11dffa6a1982b39fe9ef42ed86ed832e51bd01c10817666df6d7b11579bc88664f5d57f2a5fe073a7f46b4e72a3efe7ed0cb450ee786da + argparse: "npm:^2.0.1" + bin: + js-yaml: bin/js-yaml.js + checksum: 10c0/058b30473d6915ca5b4feb11e2f7d4d97242f98d00a798ed48dd90b46b7c640398afe9128c5db22c5300f8c6528fe2a174b9a93f351a70ebc28c6203938d8bff languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^2.0.0-next.3#optional!builtin": - version: 2.0.0-next.3 - resolution: "resolve@patch:resolve@npm%3A2.0.0-next.3#optional!builtin::version=2.0.0-next.3&hash=c3c19d" - dependencies: - is-core-module: "npm:^2.2.0" - path-parse: "npm:^1.0.6" - checksum: 10c0/ecd5da8e5f3042952bd9fd46725ef850144e7c3d707d963039df677809716660ccf5efa66742fbc6796d280c23d18915384fada76869a9c554e15cf1e6df9278 +"json-buffer@npm:3.0.1": + version: 3.0.1 + resolution: "json-buffer@npm:3.0.1" + checksum: 10c0/0d1c91569d9588e7eef2b49b59851f297f3ab93c7b35c7c221e288099322be6b562767d11e4821da500f3219542b9afd2e54c5dc573107c1126ed1080f8e96d7 languageName: node linkType: hard -"responselike@npm:^1.0.2": - version: 1.0.2 - resolution: "responselike@npm:1.0.2" - dependencies: - lowercase-keys: "npm:^1.0.0" - checksum: 10c0/1c2861d1950790da96159ca490eda645130eaf9ccc4d76db20f685ba944feaf30f45714b4318f550b8cd72990710ad68355ff15c41da43ed9a93c102c0ffa403 +"json-parse-even-better-errors@npm:^2.3.0": + version: 2.3.1 + resolution: "json-parse-even-better-errors@npm:2.3.1" + checksum: 10c0/140932564c8f0b88455432e0f33c4cb4086b8868e37524e07e723f4eaedb9425bdc2bafd71bd1d9765bd15fd1e2d126972bc83990f55c467168c228c24d665f3 languageName: node linkType: hard -"restore-cursor@npm:^2.0.0": - version: 2.0.0 - resolution: "restore-cursor@npm:2.0.0" - dependencies: - onetime: "npm:^2.0.0" - signal-exit: "npm:^3.0.2" - checksum: 10c0/f5b335bee06f440445e976a7031a3ef53691f9b7c4a9d42a469a0edaf8a5508158a0d561ff2b26a1f4f38783bcca2c0e5c3a44f927326f6694d5b44d7a4993e6 +"json-schema-traverse@npm:^0.4.1": + version: 0.4.1 + resolution: "json-schema-traverse@npm:0.4.1" + checksum: 10c0/108fa90d4cc6f08243aedc6da16c408daf81793bf903e9fd5ab21983cda433d5d2da49e40711da016289465ec2e62e0324dcdfbc06275a607fe3233fde4942ce languageName: node linkType: hard -"resumer@npm:~0.0.0": - version: 0.0.0 - resolution: "resumer@npm:0.0.0" - dependencies: - through: "npm:~2.3.4" - checksum: 10c0/7e6d5876efe574aa3a571129a6cc07f5f5970f55248e820a32290fc9183a919b6c3875823d0ad3f392d247b778ad023b402079b369ba0320e9000abe27ff567e +"json-schema-traverse@npm:^1.0.0": + version: 1.0.0 + resolution: "json-schema-traverse@npm:1.0.0" + checksum: 10c0/71e30015d7f3d6dc1c316d6298047c8ef98a06d31ad064919976583eb61e1018a60a0067338f0f79cabc00d84af3fcc489bd48ce8a46ea165d9541ba17fb30c6 languageName: node linkType: hard -"ret@npm:~0.1.10": - version: 0.1.15 - resolution: "ret@npm:0.1.15" - checksum: 10c0/01f77cad0f7ea4f955852c03d66982609893edc1240c0c964b4c9251d0f9fb6705150634060d169939b096d3b77f4c84d6b6098a5b5d340160898c8581f1f63f +"json-stable-stringify-without-jsonify@npm:^1.0.1": + version: 1.0.1 + resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" + checksum: 10c0/cb168b61fd4de83e58d09aaa6425ef71001bae30d260e2c57e7d09a5fd82223e2f22a042dedaab8db23b7d9ae46854b08bb1f91675a8be11c5cffebef5fb66a5 languageName: node linkType: hard -"retry@npm:^0.12.0": - version: 0.12.0 - resolution: "retry@npm:0.12.0" - checksum: 10c0/59933e8501727ba13ad73ef4a04d5280b3717fd650408460c987392efe9d7be2040778ed8ebe933c5cbd63da3dcc37919c141ef8af0a54a6e4fca5a2af177bfe +"json-stream-stringify@npm:^3.1.4": + version: 3.1.7 + resolution: "json-stream-stringify@npm:3.1.7" + checksum: 10c0/53d01e897e06b62e799b13eb6b2dc52e14fd77a99d2d079d2ae012acc3c9893062b563e5aa1782f3bbaf9bb0f1ef60b9de20e64b905170a1c47e81513bff1ac9 languageName: node linkType: hard -"reusify@npm:^1.0.4": - version: 1.0.4 - resolution: "reusify@npm:1.0.4" - checksum: 10c0/c19ef26e4e188f408922c46f7ff480d38e8dfc55d448310dfb518736b23ed2c4f547fb64a6ed5bdba92cd7e7ddc889d36ff78f794816d5e71498d645ef476107 +"jsonfile@npm:^4.0.0": + version: 4.0.0 + resolution: "jsonfile@npm:4.0.0" + dependencies: + graceful-fs: "npm:^4.1.6" + dependenciesMeta: + graceful-fs: + optional: true + checksum: 10c0/7dc94b628d57a66b71fb1b79510d460d662eb975b5f876d723f81549c2e9cd316d58a2ddf742b2b93a4fa6b17b2accaf1a738a0e2ea114bdfb13a32e5377e480 languageName: node linkType: hard -"rimraf@npm:2.6.3": - version: 2.6.3 - resolution: "rimraf@npm:2.6.3" +"jsonfile@npm:^6.0.1": + version: 6.1.0 + resolution: "jsonfile@npm:6.1.0" dependencies: - glob: "npm:^7.1.3" - bin: - rimraf: ./bin.js - checksum: 10c0/f1e646f8c567795f2916aef7aadf685b543da6b9a53e482bb04b07472c7eef2b476045ba1e29f401c301c66b630b22b815ab31fdd60c5e1ae6566ff523debf45 + graceful-fs: "npm:^4.1.6" + universalify: "npm:^2.0.0" + dependenciesMeta: + graceful-fs: + optional: true + checksum: 10c0/4f95b5e8a5622b1e9e8f33c96b7ef3158122f595998114d1e7f03985649ea99cb3cd99ce1ed1831ae94c8c8543ab45ebd044207612f31a56fd08462140e46865 languageName: node linkType: hard -"rimraf@npm:^2.2.8, rimraf@npm:^2.6.3": - version: 2.7.1 - resolution: "rimraf@npm:2.7.1" - dependencies: - glob: "npm:^7.1.3" - bin: - rimraf: ./bin.js - checksum: 10c0/4eef73d406c6940927479a3a9dee551e14a54faf54b31ef861250ac815172bade86cc6f7d64a4dc5e98b65e4b18a2e1c9ff3b68d296be0c748413f092bb0dd40 +"jsonpointer@npm:^5.0.1": + version: 5.0.1 + resolution: "jsonpointer@npm:5.0.1" + checksum: 10c0/89929e58b400fcb96928c0504fcf4fc3f919d81e9543ceb055df125538470ee25290bb4984251e172e6ef8fcc55761eb998c118da763a82051ad89d4cb073fe7 + languageName: node + linkType: hard + +"jsonschema@npm:^1.4.1": + version: 1.5.0 + resolution: "jsonschema@npm:1.5.0" + checksum: 10c0/c24ddb8d741f02efc0da3ad9b597a275f6b595062903d3edbfaa535c3f9c4c98613df68da5cb6635ed9aeab30d658986fea61d7662fc5b2b92840d5a1e21235e languageName: node linkType: hard -"rimraf@npm:^3.0.2": +"keccak@npm:^3.0.0": version: 3.0.2 - resolution: "rimraf@npm:3.0.2" + resolution: "keccak@npm:3.0.2" dependencies: - glob: "npm:^7.1.3" - bin: - rimraf: bin.js - checksum: 10c0/9cb7757acb489bd83757ba1a274ab545eafd75598a9d817e0c3f8b164238dd90eba50d6b848bd4dcc5f3040912e882dc7ba71653e35af660d77b25c381d402e8 + node-addon-api: "npm:^2.0.0" + node-gyp: "npm:latest" + node-gyp-build: "npm:^4.2.0" + readable-stream: "npm:^3.6.0" + checksum: 10c0/f1673e0f9bab4eb8a5bd232227916c592716d3b961e14e6ab3fabcf703c896c83fdbcd230f7b4a44f076d50fb0931ec1b093a98e4b0e74680b56be123a4a93f6 languageName: node linkType: hard -"ripemd160@npm:^2.0.0, ripemd160@npm:^2.0.1": - version: 2.0.2 - resolution: "ripemd160@npm:2.0.2" +"keccak@npm:^3.0.2": + version: 3.0.4 + resolution: "keccak@npm:3.0.4" dependencies: - hash-base: "npm:^3.0.0" - inherits: "npm:^2.0.1" - checksum: 10c0/f6f0df78817e78287c766687aed4d5accbebc308a8e7e673fb085b9977473c1f139f0c5335d353f172a915bb288098430755d2ad3c4f30612f4dd0c901cd2c3a + node-addon-api: "npm:^2.0.0" + node-gyp: "npm:latest" + node-gyp-build: "npm:^4.2.0" + readable-stream: "npm:^3.6.0" + checksum: 10c0/153525c1c1f770beadb8f8897dec2f1d2dcbee11d063fe5f61957a5b236bfd3d2a111ae2727e443aa6a848df5edb98b9ef237c78d56df49087b0ca8a232ca9cd languageName: node linkType: hard -"rlp@npm:^2.0.0, rlp@npm:^2.2.1, rlp@npm:^2.2.2, rlp@npm:^2.2.4": - version: 2.2.6 - resolution: "rlp@npm:2.2.6" +"keyv@npm:^4.5.3": + version: 4.5.4 + resolution: "keyv@npm:4.5.4" dependencies: - bn.js: "npm:^4.11.1" - bin: - rlp: bin/rlp - checksum: 10c0/e12b57bf74c44d94c7d9d6273655e0afa46844d89738ee34ebdcf00bc699f0025309759e834b4fbd3e9fdf54a0fbc9a5e4aa7cae49bbf33aaf76e4c01e643f66 + json-buffer: "npm:3.0.1" + checksum: 10c0/aa52f3c5e18e16bb6324876bb8b59dd02acf782a4b789c7b2ae21107fab95fab3890ed448d4f8dba80ce05391eeac4bfabb4f02a20221342982f806fa2cf271e languageName: node linkType: hard -"rlp@npm:^2.2.3": - version: 2.2.7 - resolution: "rlp@npm:2.2.7" +"keyv@npm:^5.6.0": + version: 5.6.0 + resolution: "keyv@npm:5.6.0" dependencies: - bn.js: "npm:^5.2.0" - bin: - rlp: bin/rlp - checksum: 10c0/166c449f4bc794d47f8e337bf0ffbcfdb26c33109030aac4b6e5a33a91fa85783f2290addeb7b3c89d6d9b90c8276e719494d193129bed0a60a2d4a6fd658277 + "@keyv/serialize": "npm:^1.1.1" + checksum: 10c0/c3ea795b6e03593ca57c8f70928a69bad14c13389a7fb75649a115ff55615244b04d8902798d841c17f0bb4a8a8866c97133b543b93f151b440170bba09176db languageName: node linkType: hard -"run-async@npm:^2.2.0": - version: 2.4.1 - resolution: "run-async@npm:2.4.1" - checksum: 10c0/35a68c8f1d9664f6c7c2e153877ca1d6e4f886e5ca067c25cdd895a6891ff3a1466ee07c63d6a9be306e9619ff7d509494e6d9c129516a36b9fd82263d579ee1 +"kleur@npm:^3.0.3": + version: 3.0.3 + resolution: "kleur@npm:3.0.3" + checksum: 10c0/cd3a0b8878e7d6d3799e54340efe3591ca787d9f95f109f28129bdd2915e37807bf8918bb295ab86afb8c82196beec5a1adcaf29042ce3f2bd932b038fe3aa4b languageName: node linkType: hard -"run-parallel@npm:^1.1.9": - version: 1.2.0 - resolution: "run-parallel@npm:1.2.0" +"latest-version@npm:^7.0.0": + version: 7.0.0 + resolution: "latest-version@npm:7.0.0" dependencies: - queue-microtask: "npm:^1.2.2" - checksum: 10c0/200b5ab25b5b8b7113f9901bfe3afc347e19bb7475b267d55ad0eb86a62a46d77510cb0f232507c9e5d497ebda569a08a9867d0d14f57a82ad5564d991588b39 + package-json: "npm:^8.1.0" + checksum: 10c0/68045f5e419e005c12e595ae19687dd88317dd0108b83a8773197876622c7e9d164fe43aacca4f434b2cba105c92848b89277f658eabc5d50e81fb743bbcddb1 languageName: node linkType: hard -"rustbn.js@npm:~0.2.0": - version: 0.2.0 - resolution: "rustbn.js@npm:0.2.0" - checksum: 10c0/be2d55d4a53465cfd5c7900153cfae54c904f0941acd30191009cf473cacbfcf45082ffd8dc473a354c8e3dcfe2c2bdf5d7ea9cc9b188d892b4aa8d012b94701 +"leven@npm:^3.1.0 < 4": + version: 3.1.0 + resolution: "leven@npm:3.1.0" + checksum: 10c0/cd778ba3fbab0f4d0500b7e87d1f6e1f041507c56fdcd47e8256a3012c98aaee371d4c15e0a76e0386107af2d42e2b7466160a2d80688aaa03e66e49949f42df languageName: node linkType: hard -"rxjs@npm:^6.4.0": - version: 6.6.7 - resolution: "rxjs@npm:6.6.7" +"levn@npm:^0.4.1": + version: 0.4.1 + resolution: "levn@npm:0.4.1" dependencies: - tslib: "npm:^1.9.0" - checksum: 10c0/e556a13a9aa89395e5c9d825eabcfa325568d9c9990af720f3f29f04a888a3b854f25845c2b55875d875381abcae2d8100af9cacdc57576e7ed6be030a01d2fe + prelude-ls: "npm:^1.2.1" + type-check: "npm:~0.4.0" + checksum: 10c0/effb03cad7c89dfa5bd4f6989364bfc79994c2042ec5966cb9b95990e2edee5cd8969ddf42616a0373ac49fac1403437deaf6e9050fbbaa3546093a59b9ac94e languageName: node linkType: hard -"safe-buffer@npm:5.2.1, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:^5.2.1, safe-buffer@npm:~5.2.0": - version: 5.2.1 - resolution: "safe-buffer@npm:5.2.1" - checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 +"lines-and-columns@npm:^1.1.6": + version: 1.2.4 + resolution: "lines-and-columns@npm:1.2.4" + checksum: 10c0/3da6ee62d4cd9f03f5dc90b4df2540fb85b352081bee77fe4bbcd12c9000ead7f35e0a38b8d09a9bb99b13223446dd8689ff3c4959807620726d788701a83d2d languageName: node linkType: hard -"safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": - version: 5.1.2 - resolution: "safe-buffer@npm:5.1.2" - checksum: 10c0/780ba6b5d99cc9a40f7b951d47152297d0e260f0df01472a1b99d4889679a4b94a13d644f7dbc4f022572f09ae9005fa2fbb93bbbd83643316f365a3e9a45b21 +"locate-path@npm:^6.0.0": + version: 6.0.0 + resolution: "locate-path@npm:6.0.0" + dependencies: + p-locate: "npm:^5.0.0" + checksum: 10c0/d3972ab70dfe58ce620e64265f90162d247e87159b6126b01314dd67be43d50e96a50b517bce2d9452a79409c7614054c277b5232377de50416564a77ac7aad3 languageName: node linkType: hard -"safe-event-emitter@npm:^1.0.1": - version: 1.0.1 - resolution: "safe-event-emitter@npm:1.0.1" - dependencies: - events: "npm:^3.0.0" - checksum: 10c0/97b960d9af510594337533888178b14bca4c057e8f915e83512041690d313a8fe4333240633592db0a290f1592b0a408f2c8c0416108bc9db33cef9f2a5bfe8f +"lodash.camelcase@npm:^4.3.0": + version: 4.3.0 + resolution: "lodash.camelcase@npm:4.3.0" + checksum: 10c0/fcba15d21a458076dd309fce6b1b4bf611d84a0ec252cb92447c948c533ac250b95d2e00955801ebc367e5af5ed288b996d75d37d2035260a937008e14eaf432 languageName: node linkType: hard -"safe-regex@npm:^1.1.0": - version: 1.1.0 - resolution: "safe-regex@npm:1.1.0" - dependencies: - ret: "npm:~0.1.10" - checksum: 10c0/547d58aa5184cbef368fd5ed5f28d20f911614748c5da6b35f53fd6626396707587251e6e3d1e3010fd3ff1212e413841b8825eaa5f317017ca62a30899af31a +"lodash.clonedeep@npm:^4.5.0": + version: 4.5.0 + resolution: "lodash.clonedeep@npm:4.5.0" + checksum: 10c0/2caf0e4808f319d761d2939ee0642fa6867a4bbf2cfce43276698828380756b99d4c4fa226d881655e6ac298dd453fe12a5ec8ba49861777759494c534936985 languageName: node linkType: hard -"safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0, safer-buffer@npm:^2.0.2, safer-buffer@npm:^2.1.0, safer-buffer@npm:~2.1.0": - version: 2.1.2 - resolution: "safer-buffer@npm:2.1.2" - checksum: 10c0/7e3c8b2e88a1841c9671094bbaeebd94448111dd90a81a1f606f3f67708a6ec57763b3b47f06da09fc6054193e0e6709e77325415dc8422b04497a8070fa02d4 +"lodash.isequal@npm:^4.5.0": + version: 4.5.0 + resolution: "lodash.isequal@npm:4.5.0" + checksum: 10c0/dfdb2356db19631a4b445d5f37868a095e2402292d59539a987f134a8778c62a2810c2452d11ae9e6dcac71fc9de40a6fedcb20e2952a15b431ad8b29e50e28f languageName: node linkType: hard -"scrypt-js@npm:3.0.1, scrypt-js@npm:^3.0.0, scrypt-js@npm:^3.0.1": - version: 3.0.1 - resolution: "scrypt-js@npm:3.0.1" - checksum: 10c0/e2941e1c8b5c84c7f3732b0153fee624f5329fc4e772a06270ee337d4d2df4174b8abb5e6ad53804a29f53890ecbc78f3775a319323568c0313040c0e55f5b10 +"lodash.truncate@npm:^4.4.2": + version: 4.4.2 + resolution: "lodash.truncate@npm:4.4.2" + checksum: 10c0/4e870d54e8a6c86c8687e057cec4069d2e941446ccab7f40b4d9555fa5872d917d0b6aa73bece7765500a3123f1723bcdba9ae881b679ef120bba9e1a0b0ed70 languageName: node linkType: hard -"scryptsy@npm:^1.2.1": - version: 1.2.1 - resolution: "scryptsy@npm:1.2.1" - dependencies: - pbkdf2: "npm:^3.0.3" - checksum: 10c0/41c0348a8f85e210c802b8f24b2b8b98e1911144d5834394d5eb1562582115f0dfea51badd381630a68bc60a5b393f91e022dee70bb12a79642bf8bde8d2f6e1 +"lodash@npm:^4.17.11, lodash@npm:^4.17.15": + version: 4.17.21 + resolution: "lodash@npm:4.17.21" + checksum: 10c0/d8cbea072bb08655bb4c989da418994b073a608dffa608b09ac04b43a791b12aeae7cd7ad919aa4c925f33b48490b5cfe6c1f71d827956071dae2e7bb3a6b74c languageName: node linkType: hard -"secp256k1@npm:^4.0.1": - version: 4.0.3 - resolution: "secp256k1@npm:4.0.3" - dependencies: - elliptic: "npm:^6.5.4" - node-addon-api: "npm:^2.0.0" - node-gyp: "npm:latest" - node-gyp-build: "npm:^4.2.0" - checksum: 10c0/de0a0e525a6f8eb2daf199b338f0797dbfe5392874285a145bb005a72cabacb9d42c0197d0de129a1a0f6094d2cc4504d1f87acb6a8bbfb7770d4293f252c401 +"lodash@npm:^4.17.19, lodash@npm:^4.17.21": + version: 4.18.1 + resolution: "lodash@npm:4.18.1" + checksum: 10c0/757228fc68805c59789e82185135cf85f05d0b2d3d54631d680ca79ec21944ec8314d4533639a14b8bcfbd97a517e78960933041a5af17ecb693ec6eecb99a27 languageName: node linkType: hard -"seedrandom@npm:3.0.1": - version: 3.0.1 - resolution: "seedrandom@npm:3.0.1" - checksum: 10c0/783f5370cb2593fe4aec93af858ccbb121b21c24ec424aa29e0cbb4fc3942b767cc67d17205e0adca78691916485fca692bbf3cb415a15e6bcc2de7cd60811e3 +"log-symbols@npm:^4.1.0": + version: 4.1.0 + resolution: "log-symbols@npm:4.1.0" + dependencies: + chalk: "npm:^4.1.0" + is-unicode-supported: "npm:^0.1.0" + checksum: 10c0/67f445a9ffa76db1989d0fa98586e5bc2fd5247260dafb8ad93d9f0ccd5896d53fb830b0e54dade5ad838b9de2006c826831a3c528913093af20dff8bd24aca6 languageName: node linkType: hard -"semaphore@npm:>=1.0.1, semaphore@npm:^1.0.3, semaphore@npm:^1.1.0": - version: 1.1.0 - resolution: "semaphore@npm:1.1.0" - checksum: 10c0/1eeb146c1ffe1283951573c356ba3a9b18a8513b18959ecbc0e3ba3a99e5da46edc509a9a5f0cb9d5d28895dcd828bdd6c29162c8e41a311ee79efaf3456a723 +"lowercase-keys@npm:^3.0.0": + version: 3.0.0 + resolution: "lowercase-keys@npm:3.0.0" + checksum: 10c0/ef62b9fa5690ab0a6e4ef40c94efce68e3ed124f583cc3be38b26ff871da0178a28b9a84ce0c209653bb25ca135520ab87fea7cd411a54ac4899cb2f30501430 languageName: node linkType: hard -"semver@npm:2 || 3 || 4 || 5, semver@npm:^5.3.0, semver@npm:^5.5.0, semver@npm:^5.5.1, semver@npm:^5.6.0": - version: 5.7.1 - resolution: "semver@npm:5.7.1" - bin: - semver: ./bin/semver - checksum: 10c0/d4884f2aeca28bff35d0bd40ff0a9b2dfc4b36a883bf0ea5dc15d10d9a01bdc9041035b05f825d4b5ac8a56e490703dbf0d986d054de82cc5e9bad3f02ca6e00 +"lru-cache@npm:^10.2.0": + version: 10.4.3 + resolution: "lru-cache@npm:10.4.3" + checksum: 10c0/ebd04fbca961e6c1d6c0af3799adcc966a1babe798f685bb84e6599266599cd95d94630b10262f5424539bc4640107e8a33aa28585374abf561d30d16f4b39fb languageName: node linkType: hard -"semver@npm:^6.3.0": - version: 6.3.0 - resolution: "semver@npm:6.3.0" - bin: - semver: ./bin/semver.js - checksum: 10c0/1f4959e15bcfbaf727e964a4920f9260141bb8805b399793160da4e7de128e42a7d1f79c1b7d5cd21a6073fba0d55feb9966f5fef3e5ccb8e1d7ead3d7527458 +"lru-cache@npm:^11.0.0, lru-cache@npm:^11.1.0, lru-cache@npm:^11.2.1": + version: 11.3.5 + resolution: "lru-cache@npm:11.3.5" + checksum: 10c0/5b54ef7b88afb4bd25b7a778f1b2b1cde32d9770913e530da34ab203cf0442413bcaa6e372800cbab9562557a4480e4d8bf32e3a368bb5a91b12218eca085c66 languageName: node linkType: hard -"semver@npm:^7.2.1, semver@npm:^7.3.5": - version: 7.3.5 - resolution: "semver@npm:7.3.5" +"lru-cache@npm:^6.0.0": + version: 6.0.0 + resolution: "lru-cache@npm:6.0.0" dependencies: - lru-cache: "npm:^6.0.0" - bin: - semver: bin/semver.js - checksum: 10c0/d450455b2601396dbc7d9f058a6709b1c0b99d74a911f9436c77887600ffcdb5f63d5adffa0c3b8f0092937d8a41cc61c6437bcba375ef4151cb1335ebe4f1f9 - languageName: node - linkType: hard - -"semver@npm:~5.4.1": - version: 5.4.1 - resolution: "semver@npm:5.4.1" - bin: - semver: ./bin/semver - checksum: 10c0/38122c0861f58ec18371352e079fc9de154649546126be4e23c6fb0fa4ec48dd9d59eabf2796c2fab7314911b66b306a047b6c9b6137989fd946528e0ea682db + yallist: "npm:^4.0.0" + checksum: 10c0/cb53e582785c48187d7a188d3379c181b5ca2a9c78d2bce3e7dee36f32761d1c42983da3fe12b55cb74e1779fa94cdc2e5367c028a9b35317184ede0c07a30a9 languageName: node linkType: hard -"send@npm:0.18.0": - version: 0.18.0 - resolution: "send@npm:0.18.0" - dependencies: - debug: "npm:2.6.9" - depd: "npm:2.0.0" - destroy: "npm:1.2.0" - encodeurl: "npm:~1.0.2" - escape-html: "npm:~1.0.3" - etag: "npm:~1.8.1" - fresh: "npm:0.5.2" - http-errors: "npm:2.0.0" - mime: "npm:1.6.0" - ms: "npm:2.1.3" - on-finished: "npm:2.4.1" - range-parser: "npm:~1.2.1" - statuses: "npm:2.0.1" - checksum: 10c0/0eb134d6a51fc13bbcb976a1f4214ea1e33f242fae046efc311e80aff66c7a43603e26a79d9d06670283a13000e51be6e0a2cb80ff0942eaf9f1cd30b7ae736a +"lru_map@npm:^0.3.3": + version: 0.3.3 + resolution: "lru_map@npm:0.3.3" + checksum: 10c0/d861f14a142a4a74ebf8d3ad57f2e768a5b820db4100ae53eed1a64eb6350912332e6ebc87cb7415ad6d0cd8f3ce6d20beab9a5e6042ccb5996ea0067a220448 languageName: node linkType: hard -"serialize-javascript@npm:^6.0.2": - version: 6.0.2 - resolution: "serialize-javascript@npm:6.0.2" - dependencies: - randombytes: "npm:^2.1.0" - checksum: 10c0/2dd09ef4b65a1289ba24a788b1423a035581bef60817bea1f01eda8e3bda623f86357665fe7ac1b50f6d4f583f97db9615b3f07b2a2e8cbcb75033965f771dd2 +"make-error@npm:^1.1.1": + version: 1.3.6 + resolution: "make-error@npm:1.3.6" + checksum: 10c0/171e458d86854c6b3fc46610cfacf0b45149ba043782558c6875d9f42f222124384ad0b468c92e996d815a8a2003817a710c0a160e49c1c394626f76fa45396f languageName: node linkType: hard -"serve-static@npm:1.15.0": - version: 1.15.0 - resolution: "serve-static@npm:1.15.0" +"make-fetch-happen@npm:^15.0.0": + version: 15.0.5 + resolution: "make-fetch-happen@npm:15.0.5" dependencies: - encodeurl: "npm:~1.0.2" - escape-html: "npm:~1.0.3" - parseurl: "npm:~1.3.3" - send: "npm:0.18.0" - checksum: 10c0/fa9f0e21a540a28f301258dfe1e57bb4f81cd460d28f0e973860477dd4acef946a1f41748b5bd41c73b621bea2029569c935faa38578fd34cd42a9b4947088ba + "@gar/promise-retry": "npm:^1.0.0" + "@npmcli/agent": "npm:^4.0.0" + "@npmcli/redact": "npm:^4.0.0" + cacache: "npm:^20.0.1" + http-cache-semantics: "npm:^4.1.1" + minipass: "npm:^7.0.2" + minipass-fetch: "npm:^5.0.0" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + negotiator: "npm:^1.0.0" + proc-log: "npm:^6.0.0" + ssri: "npm:^13.0.0" + checksum: 10c0/527580eb5e5476e6ad07a4e3bd017d13e935f4be815674b442081ae5a721c13d3af5715006619e6be79a85723067e047f83a0c9e699f41d8cec43609a8de4f7b languageName: node linkType: hard -"servify@npm:^0.1.12": - version: 0.1.12 - resolution: "servify@npm:0.1.12" +"markdown-table@npm:2.0.0": + version: 2.0.0 + resolution: "markdown-table@npm:2.0.0" dependencies: - body-parser: "npm:^1.16.0" - cors: "npm:^2.8.1" - express: "npm:^4.14.0" - request: "npm:^2.79.0" - xhr: "npm:^2.3.3" - checksum: 10c0/2a7af8ba9f79022325c1f1bfbcb02051c1e02252928c55028173d1ecbc5db49faebf3e8a865515b89cfd1e53eee7c2e5a9c47c264caaf98964708e5372b407c0 + repeat-string: "npm:^1.0.0" + checksum: 10c0/f257e0781ea50eb946919df84bdee4ba61f983971b277a369ca7276f89740fd0e2749b9b187163a42df4c48682b71962d4007215ce3523480028f06c11ddc2e6 languageName: node linkType: hard -"set-blocking@npm:^2.0.0": - version: 2.0.0 - resolution: "set-blocking@npm:2.0.0" - checksum: 10c0/9f8c1b2d800800d0b589de1477c753492de5c1548d4ade52f57f1d1f5e04af5481554d75ce5e5c43d4004b80a3eb714398d6907027dc0534177b7539119f4454 +"match-all@npm:^1.2.6": + version: 1.2.6 + resolution: "match-all@npm:1.2.6" + checksum: 10c0/4e0344bf3c39fdedf212bc0e61ce970a40f7f5c1cbbf34de0992a47515d999dab3aa8600a2a09487afb5f561e59d267f0b5dd7a74dfaec203cec77c1f8c52d5a languageName: node linkType: hard -"set-immediate-shim@npm:^1.0.1": - version: 1.0.1 - resolution: "set-immediate-shim@npm:1.0.1" - checksum: 10c0/8d21dbb2ad0299a1df9a90c4ddaf5d38ac7af4fafab3064e29d5d5434820a406362bb6b5def0adf189333e92daf50ec756848f48b281705355ed984491beeb93 +"math-intrinsics@npm:^1.1.0": + version: 1.1.0 + resolution: "math-intrinsics@npm:1.1.0" + checksum: 10c0/7579ff94e899e2f76ab64491d76cf606274c874d8f2af4a442c016bd85688927fcfca157ba6bf74b08e9439dc010b248ce05b96cc7c126a354c3bae7fcb48b7f languageName: node linkType: hard -"set-value@npm:^2.0.0, set-value@npm:^2.0.1": - version: 2.0.1 - resolution: "set-value@npm:2.0.1" +"md5.js@npm:^1.3.4": + version: 1.3.5 + resolution: "md5.js@npm:1.3.5" dependencies: - extend-shallow: "npm:^2.0.1" - is-extendable: "npm:^0.1.1" - is-plain-object: "npm:^2.0.3" - split-string: "npm:^3.0.1" - checksum: 10c0/4c40573c4f6540456e4b38b95f570272c4cfbe1d12890ad4057886da8535047cd772dfadf5b58e2e87aa244dfb4c57e3586f6716b976fc47c5144b6b09e1811b + hash-base: "npm:^3.0.0" + inherits: "npm:^2.0.1" + safe-buffer: "npm:^5.1.2" + checksum: 10c0/b7bd75077f419c8e013fc4d4dada48be71882e37d69a44af65a2f2804b91e253441eb43a0614423a1c91bb830b8140b0dc906bc797245e2e275759584f4efcc5 languageName: node linkType: hard -"setimmediate@npm:^1.0.5": - version: 1.0.5 - resolution: "setimmediate@npm:1.0.5" - checksum: 10c0/5bae81bfdbfbd0ce992893286d49c9693c82b1bcc00dcaaf3a09c8f428fdeacf4190c013598b81875dfac2b08a572422db7df779a99332d0fce186d15a3e4d49 +"memorystream@npm:^0.3.1": + version: 0.3.1 + resolution: "memorystream@npm:0.3.1" + checksum: 10c0/4bd164657711d9747ff5edb0508b2944414da3464b7fe21ac5c67cf35bba975c4b446a0124bd0f9a8be54cfc18faf92e92bd77563a20328b1ccf2ff04e9f39b9 languageName: node linkType: hard -"setprototypeof@npm:1.1.1": - version: 1.1.1 - resolution: "setprototypeof@npm:1.1.1" - checksum: 10c0/1084b783f2d77908b0a593619e1214c2118c44c7c3277f6099dd7ca8acfc056c009e5d1b2860eae5e8b0ba9bc0a978c15613ff102ccc1093bb48aa6e0ed75e2f +"micro-eth-signer@npm:^0.14.0": + version: 0.14.0 + resolution: "micro-eth-signer@npm:0.14.0" + dependencies: + "@noble/curves": "npm:~1.8.1" + "@noble/hashes": "npm:~1.7.1" + micro-packed: "npm:~0.7.2" + checksum: 10c0/62c90d54d2b97cb4eaf713c69bc4ceb5903012d0237c26f0966076cfb89c4527de68b395e1bc29e6f237152ce08f7b551fb57b332003518a1331c2c0890fb164 languageName: node linkType: hard -"setprototypeof@npm:1.2.0": - version: 1.2.0 - resolution: "setprototypeof@npm:1.2.0" - checksum: 10c0/68733173026766fa0d9ecaeb07f0483f4c2dc70ca376b3b7c40b7cda909f94b0918f6c5ad5ce27a9160bdfb475efaa9d5e705a11d8eaae18f9835d20976028bc +"micro-packed@npm:~0.7.2": + version: 0.7.3 + resolution: "micro-packed@npm:0.7.3" + dependencies: + "@scure/base": "npm:~1.2.5" + checksum: 10c0/1fde48a96d8d5606d3298ff36717bf7483d6d59e2d96f50cb88727379127a4d52881f48e7e1ce0d4906b2711b1902fb04d2128576326ce4d07e171ac022a4c2d languageName: node linkType: hard -"sha.js@npm:^2.4.0, sha.js@npm:^2.4.8": - version: 2.4.11 - resolution: "sha.js@npm:2.4.11" - dependencies: - inherits: "npm:^2.0.1" - safe-buffer: "npm:^5.0.1" - bin: - sha.js: ./bin.js - checksum: 10c0/b7a371bca8821c9cc98a0aeff67444a03d48d745cb103f17228b96793f455f0eb0a691941b89ea1e60f6359207e36081d9be193252b0f128e0daf9cfea2815a5 +"mime-db@npm:1.52.0": + version: 1.52.0 + resolution: "mime-db@npm:1.52.0" + checksum: 10c0/0557a01deebf45ac5f5777fe7740b2a5c309c6d62d40ceab4e23da9f821899ce7a900b7ac8157d4548ddbb7beffe9abc621250e6d182b0397ec7f10c7b91a5aa languageName: node linkType: hard -"sha1@npm:^1.1.1": - version: 1.1.1 - resolution: "sha1@npm:1.1.1" +"mime-types@npm:^2.1.12, mime-types@npm:^2.1.35": + version: 2.1.35 + resolution: "mime-types@npm:2.1.35" dependencies: - charenc: "npm:>= 0.0.1" - crypt: "npm:>= 0.0.1" - checksum: 10c0/1bb36c89c112c741c265cca66712f883ae01d5c55b71aec80635fe2ad5d0c976a1a8a994dda774ae9f93b2da99fd111238758a8bf985adc400bd86f0e4452865 + mime-db: "npm:1.52.0" + checksum: 10c0/82fb07ec56d8ff1fc999a84f2f217aa46cb6ed1033fefaabd5785b9a974ed225c90dc72fff460259e66b95b73648596dbcc50d51ed69cdf464af2d237d3149b2 languageName: node linkType: hard -"shebang-command@npm:^1.2.0": - version: 1.2.0 - resolution: "shebang-command@npm:1.2.0" - dependencies: - shebang-regex: "npm:^1.0.0" - checksum: 10c0/7b20dbf04112c456b7fc258622dafd566553184ac9b6938dd30b943b065b21dabd3776460df534cc02480db5e1b6aec44700d985153a3da46e7db7f9bd21326d +"mimic-response@npm:^3.1.0": + version: 3.1.0 + resolution: "mimic-response@npm:3.1.0" + checksum: 10c0/0d6f07ce6e03e9e4445bee655202153bdb8a98d67ee8dc965ac140900d7a2688343e6b4c9a72cfc9ef2f7944dfd76eef4ab2482eb7b293a68b84916bac735362 languageName: node linkType: hard -"shebang-command@npm:^2.0.0": - version: 2.0.0 - resolution: "shebang-command@npm:2.0.0" - dependencies: - shebang-regex: "npm:^3.0.0" - checksum: 10c0/a41692e7d89a553ef21d324a5cceb5f686d1f3c040759c50aab69688634688c5c327f26f3ecf7001ebfd78c01f3c7c0a11a7c8bfd0a8bc9f6240d4f40b224e4e +"mimic-response@npm:^4.0.0": + version: 4.0.0 + resolution: "mimic-response@npm:4.0.0" + checksum: 10c0/761d788d2668ae9292c489605ffd4fad220f442fbae6832adce5ebad086d691e906a6d5240c290293c7a11e99fbdbbef04abbbed498bf8699a4ee0f31315e3fb languageName: node linkType: hard -"shebang-regex@npm:^1.0.0": - version: 1.0.0 - resolution: "shebang-regex@npm:1.0.0" - checksum: 10c0/9abc45dee35f554ae9453098a13fdc2f1730e525a5eb33c51f096cc31f6f10a4b38074c1ebf354ae7bffa7229506083844008dfc3bb7818228568c0b2dc1fff2 +"minimalistic-assert@npm:^1.0.0, minimalistic-assert@npm:^1.0.1": + version: 1.0.1 + resolution: "minimalistic-assert@npm:1.0.1" + checksum: 10c0/96730e5601cd31457f81a296f521eb56036e6f69133c0b18c13fe941109d53ad23a4204d946a0d638d7f3099482a0cec8c9bb6d642604612ce43ee536be3dddd languageName: node linkType: hard -"shebang-regex@npm:^3.0.0": - version: 3.0.0 - resolution: "shebang-regex@npm:3.0.0" - checksum: 10c0/1dbed0726dd0e1152a92696c76c7f06084eb32a90f0528d11acd764043aacf76994b2fb30aa1291a21bd019d6699164d048286309a278855ee7bec06cf6fb690 +"minimalistic-crypto-utils@npm:^1.0.1": + version: 1.0.1 + resolution: "minimalistic-crypto-utils@npm:1.0.1" + checksum: 10c0/790ecec8c5c73973a4fbf2c663d911033e8494d5fb0960a4500634766ab05d6107d20af896ca2132e7031741f19888154d44b2408ada0852446705441383e9f8 languageName: node linkType: hard -"side-channel@npm:^1.0.4": - version: 1.0.4 - resolution: "side-channel@npm:1.0.4" +"minimatch@npm:^10.2.2": + version: 10.2.5 + resolution: "minimatch@npm:10.2.5" dependencies: - call-bind: "npm:^1.0.0" - get-intrinsic: "npm:^1.0.2" - object-inspect: "npm:^1.9.0" - checksum: 10c0/054a5d23ee35054b2c4609b9fd2a0587760737782b5d765a9c7852264710cc39c6dcb56a9bbd6c12cd84071648aea3edb2359d2f6e560677eedadce511ac1da5 + brace-expansion: "npm:^5.0.5" + checksum: 10c0/6bb058bd6324104b9ec2f763476a35386d05079c1f5fe4fbf1f324a25237cd4534d6813ecd71f48208f4e635c1221899bef94c3c89f7df55698fe373aaae20fd languageName: node linkType: hard -"signal-exit@npm:^3.0.2": - version: 3.0.7 - resolution: "signal-exit@npm:3.0.7" - checksum: 10c0/25d272fa73e146048565e08f3309d5b942c1979a6f4a58a8c59d5fa299728e9c2fcd1a759ec870863b1fd38653670240cd420dad2ad9330c71f36608a6a1c912 +"minimatch@npm:^10.2.4, minimatch@npm:^10.2.5, minimatch@npm:^9.0.3 || ^10.1.2": + version: 10.2.6 + resolution: "minimatch@npm:10.2.6" + dependencies: + brace-expansion: "npm:^5.0.8" + checksum: 10c0/4559a836243b98bd4d17ea9f7edae698717c76399eea7be374f3737f33164e4907f19e9726891ddeb122f750a5a7fa80d2ac43e851d6e5984dc4ff42ec127d3a languageName: node linkType: hard -"signal-exit@npm:^4.0.1": - version: 4.1.0 - resolution: "signal-exit@npm:4.1.0" - checksum: 10c0/41602dce540e46d599edba9d9860193398d135f7ff72cab629db5171516cfae628d21e7bfccde1bbfdf11c48726bc2a6d1a8fb8701125852fbfda7cf19c6aa83 +"minimatch@npm:^3.0.4": + version: 3.1.2 + resolution: "minimatch@npm:3.1.2" + dependencies: + brace-expansion: "npm:^1.1.7" + checksum: 10c0/0262810a8fc2e72cca45d6fd86bd349eee435eb95ac6aa45c9ea2180e7ee875ef44c32b55b5973ceabe95ea12682f6e3725cbb63d7a2d1da3ae1163c8b210311 languageName: node linkType: hard -"simple-concat@npm:^1.0.0": - version: 1.0.1 - resolution: "simple-concat@npm:1.0.1" - checksum: 10c0/62f7508e674414008910b5397c1811941d457dfa0db4fd5aa7fa0409eb02c3609608dfcd7508cace75b3a0bf67a2a77990711e32cd213d2c76f4fd12ee86d776 +"minimatch@npm:^9.0.4, minimatch@npm:^9.0.5": + version: 9.0.9 + resolution: "minimatch@npm:9.0.9" + dependencies: + brace-expansion: "npm:^2.0.2" + checksum: 10c0/0b6a58530dbb00361745aa6c8cffaba4c90f551afe7c734830bd95fd88ebf469dd7355a027824ea1d09e37181cfeb0a797fb17df60c15ac174303ac110eb7e86 languageName: node linkType: hard -"simple-get@npm:^2.7.0": - version: 2.8.2 - resolution: "simple-get@npm:2.8.2" - dependencies: - decompress-response: "npm:^3.3.0" - once: "npm:^1.3.1" - simple-concat: "npm:^1.0.0" - checksum: 10c0/12747f008848e573a3d09c88d15fae37d4a359d1ef56a0bed36713952b1d236a3829cd77e862816cf32c7779f6800a0c4076ba7f71fe3684127eaccffb831aba +"minimist@npm:^1.2.0, minimist@npm:^1.2.5": + version: 1.2.6 + resolution: "minimist@npm:1.2.6" + checksum: 10c0/d0b566204044481c4401abbd24cc75814e753b37268e7fe7ccc78612bf3e37bf1e45a6c43fb0b119445ea1c413c000bde013f320b7211974f2f49bcbec1d0dbf languageName: node linkType: hard -"slash@npm:^1.0.0": - version: 1.0.0 - resolution: "slash@npm:1.0.0" - checksum: 10c0/3944659885d905480f98810542fd314f3e1006eaad25ec78227a7835a469d9ed66fc3dd90abc7377dd2e71f4b5473e8f766bd08198fdd25152a80792e9ed464c +"minimist@npm:^1.2.7": + version: 1.2.8 + resolution: "minimist@npm:1.2.8" + checksum: 10c0/19d3fcdca050087b84c2029841a093691a91259a47def2f18222f41e7645a0b7c44ef4b40e88a1e58a40c84d2ef0ee6047c55594d298146d0eb3f6b737c20ce6 languageName: node linkType: hard -"slash@npm:^2.0.0": - version: 2.0.0 - resolution: "slash@npm:2.0.0" - checksum: 10c0/f83dbd3cb62c41bb8fcbbc6bf5473f3234b97fa1d008f571710a9d3757a28c7169e1811cad1554ccb1cc531460b3d221c9a7b37f549398d9a30707f0a5af9193 +"minipass-collect@npm:^2.0.1": + version: 2.0.1 + resolution: "minipass-collect@npm:2.0.1" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10c0/5167e73f62bb74cc5019594709c77e6a742051a647fe9499abf03c71dca75515b7959d67a764bdc4f8b361cf897fbf25e2d9869ee039203ed45240f48b9aa06e languageName: node linkType: hard -"slash@npm:^3.0.0": - version: 3.0.0 - resolution: "slash@npm:3.0.0" - checksum: 10c0/e18488c6a42bdfd4ac5be85b2ced3ccd0224773baae6ad42cfbb9ec74fc07f9fa8396bd35ee638084ead7a2a0818eb5e7151111544d4731ce843019dab4be47b +"minipass-fetch@npm:^5.0.0": + version: 5.0.2 + resolution: "minipass-fetch@npm:5.0.2" + dependencies: + iconv-lite: "npm:^0.7.2" + minipass: "npm:^7.0.3" + minipass-sized: "npm:^2.0.0" + minizlib: "npm:^3.0.1" + dependenciesMeta: + iconv-lite: + optional: true + checksum: 10c0/ce4ab9f21cfabaead2097d95dd33f485af8072fbc6b19611bce694965393453a1639d641c2bcf1c48f2ea7d41ea7fab8278373f1d0bee4e63b0a5b2cdd0ef649 languageName: node linkType: hard -"slice-ansi@npm:^2.1.0": - version: 2.1.0 - resolution: "slice-ansi@npm:2.1.0" +"minipass-flush@npm:^1.0.5": + version: 1.0.7 + resolution: "minipass-flush@npm:1.0.7" dependencies: - ansi-styles: "npm:^3.2.0" - astral-regex: "npm:^1.0.0" - is-fullwidth-code-point: "npm:^2.0.0" - checksum: 10c0/c317b21ec9e3d3968f3d5b548cbfc2eae331f58a03f1352621020799cbe695b3611ee972726f8f32d4ca530065a5ec9c74c97fde711c1f41b4a1585876b2c191 + minipass: "npm:^3.0.0" + checksum: 10c0/960915c02aa0991662c37c404517dd93708d17f96533b2ca8c1e776d158715d8107c5ced425ffc61674c167d93607f07f48a83c139ce1057f8781e5dfb4b90c2 languageName: node linkType: hard -"slice-ansi@npm:^4.0.0": - version: 4.0.0 - resolution: "slice-ansi@npm:4.0.0" +"minipass-pipeline@npm:^1.2.4": + version: 1.2.4 + resolution: "minipass-pipeline@npm:1.2.4" dependencies: - ansi-styles: "npm:^4.0.0" - astral-regex: "npm:^2.0.0" - is-fullwidth-code-point: "npm:^3.0.0" - checksum: 10c0/6c25678db1270d4793e0327620f1e0f9f5bea4630123f51e9e399191bc52c87d6e6de53ed33538609e5eacbd1fab769fae00f3705d08d029f02102a540648918 + minipass: "npm:^3.0.0" + checksum: 10c0/cbda57cea20b140b797505dc2cac71581a70b3247b84480c1fed5ca5ba46c25ecc25f68bfc9e6dcb1a6e9017dab5c7ada5eab73ad4f0a49d84e35093e0c643f2 languageName: node linkType: hard -"smart-buffer@npm:^4.2.0": - version: 4.2.0 - resolution: "smart-buffer@npm:4.2.0" - checksum: 10c0/a16775323e1404dd43fabafe7460be13a471e021637bc7889468eb45ce6a6b207261f454e4e530a19500cc962c4cc5348583520843b363f4193cee5c00e1e539 +"minipass-sized@npm:^2.0.0": + version: 2.0.0 + resolution: "minipass-sized@npm:2.0.0" + dependencies: + minipass: "npm:^7.1.2" + checksum: 10c0/f9201696a6f6d68610d04c9c83e3d2e5cb9c026aae1c8cbf7e17f386105cb79c1bb088dbc21bf0b1eb4f3fb5df384fd1e7aa3bf1f33868c416ae8c8a92679db8 languageName: node linkType: hard -"snapdragon-node@npm:^2.0.1": - version: 2.1.1 - resolution: "snapdragon-node@npm:2.1.1" +"minipass@npm:^3.0.0": + version: 3.3.6 + resolution: "minipass@npm:3.3.6" dependencies: - define-property: "npm:^1.0.0" - isobject: "npm:^3.0.0" - snapdragon-util: "npm:^3.0.1" - checksum: 10c0/7616e6a1ca054afe3ad8defda17ebe4c73b0800d2e0efd635c44ee1b286f8ac7900517314b5330862ce99b28cd2782348ee78bae573ff0f55832ad81d9657f3f + yallist: "npm:^4.0.0" + checksum: 10c0/a114746943afa1dbbca8249e706d1d38b85ed1298b530f5808ce51f8e9e941962e2a5ad2e00eae7dd21d8a4aae6586a66d4216d1a259385e9d0358f0c1eba16c languageName: node linkType: hard -"snapdragon-util@npm:^3.0.1": - version: 3.0.1 - resolution: "snapdragon-util@npm:3.0.1" - dependencies: - kind-of: "npm:^3.2.0" - checksum: 10c0/4441856d343399ba7f37f79681949d51b922e290fcc07e7bc94655a50f584befa4fb08f40c3471cd160e004660161964d8ff140cba49baa59aa6caba774240e3 +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2, minipass@npm:^7.1.3": + version: 7.1.3 + resolution: "minipass@npm:7.1.3" + checksum: 10c0/539da88daca16533211ea5a9ee98dc62ff5742f531f54640dd34429e621955e91cc280a91a776026264b7f9f6735947629f920944e9c1558369e8bf22eb33fbb languageName: node linkType: hard -"snapdragon@npm:^0.8.1": - version: 0.8.2 - resolution: "snapdragon@npm:0.8.2" +"minizlib@npm:^3.0.1, minizlib@npm:^3.1.0": + version: 3.1.0 + resolution: "minizlib@npm:3.1.0" dependencies: - base: "npm:^0.11.1" - debug: "npm:^2.2.0" - define-property: "npm:^0.2.5" - extend-shallow: "npm:^2.0.1" - map-cache: "npm:^0.2.2" - source-map: "npm:^0.5.6" - source-map-resolve: "npm:^0.5.0" - use: "npm:^3.1.0" - checksum: 10c0/dfdac1f73d47152d72fc07f4322da09bbddfa31c1c9c3ae7346f252f778c45afa5b03e90813332f02f04f6de8003b34a168c456f8bb719024d092f932520ffca + minipass: "npm:^7.1.2" + checksum: 10c0/5aad75ab0090b8266069c9aabe582c021ae53eb33c6c691054a13a45db3b4f91a7fb1bd79151e6b4e9e9a86727b522527c0a06ec7d45206b745d54cd3097bcec languageName: node linkType: hard -"socks-proxy-agent@npm:^8.0.3": - version: 8.0.5 - resolution: "socks-proxy-agent@npm:8.0.5" - dependencies: - agent-base: "npm:^7.1.2" - debug: "npm:^4.3.4" - socks: "npm:^2.8.3" - checksum: 10c0/5d2c6cecba6821389aabf18728325730504bf9bb1d9e342e7987a5d13badd7a98838cc9a55b8ed3cb866ad37cc23e1086f09c4d72d93105ce9dfe76330e9d2a6 +"mkdirp@npm:^1.0.4": + version: 1.0.4 + resolution: "mkdirp@npm:1.0.4" + bin: + mkdirp: bin/cmd.js + checksum: 10c0/46ea0f3ffa8bc6a5bc0c7081ffc3907777f0ed6516888d40a518c5111f8366d97d2678911ad1a6882bf592fa9de6c784fea32e1687bb94e1f4944170af48a5cf languageName: node linkType: hard -"socks@npm:^2.8.3": - version: 2.8.7 - resolution: "socks@npm:2.8.7" +"mnemonist@npm:^0.38.0": + version: 0.38.4 + resolution: "mnemonist@npm:0.38.4" dependencies: - ip-address: "npm:^10.0.1" - smart-buffer: "npm:^4.2.0" - checksum: 10c0/2805a43a1c4bcf9ebf6e018268d87b32b32b06fbbc1f9282573583acc155860dc361500f89c73bfbb157caa1b4ac78059eac0ef15d1811eb0ca75e0bdadbc9d2 + obliterator: "npm:^1.6.1" + checksum: 10c0/ca241e8c682f60ff4a68c15f6a20c07a5db1041359458fa4fbbb96775f8c2052b24af7c1cd79cd2184add9aba76a7677c8b0e31a03f2377402c2afd28e036e9f languageName: node linkType: hard -"solc@npm:0.8.26": - version: 0.8.26 - resolution: "solc@npm:0.8.26" +"mocha@npm:^11.1.0": + version: 11.7.6 + resolution: "mocha@npm:11.7.6" dependencies: - command-exists: "npm:^1.2.8" - commander: "npm:^8.1.0" - follow-redirects: "npm:^1.12.1" - js-sha3: "npm:0.8.0" - memorystream: "npm:^0.3.1" - semver: "npm:^5.5.0" - tmp: "npm:0.0.33" + browser-stdout: "npm:^1.3.1" + chokidar: "npm:^4.0.1" + debug: "npm:^4.3.5" + diff: "npm:^7.0.0" + escape-string-regexp: "npm:^4.0.0" + find-up: "npm:^5.0.0" + glob: "npm:^10.4.5" + he: "npm:^1.2.0" + is-path-inside: "npm:^3.0.3" + js-yaml: "npm:^4.1.0" + log-symbols: "npm:^4.1.0" + minimatch: "npm:^9.0.5" + ms: "npm:^2.1.3" + picocolors: "npm:^1.1.1" + serialize-javascript: "npm:^6.0.2" + strip-json-comments: "npm:^3.1.1" + supports-color: "npm:^8.1.1" + workerpool: "npm:^9.2.0" + yargs: "npm:^17.7.2" + yargs-parser: "npm:^21.1.1" + yargs-unparser: "npm:^2.0.0" bin: - solcjs: solc.js - checksum: 10c0/1eea35da99c228d0dc1d831c29f7819e7921b67824c889a5e5f2e471a2ef5856a15fabc0b5de067f5ba994fa36fb5a563361963646fe98dad58a0e4fa17c8b2d + _mocha: bin/_mocha + mocha: bin/mocha.js + checksum: 10c0/95b3eeb52eaf253167d335d1c1a46659f6f282dc112a74fd0ac46380637ae3ee52894319e00a46412a1e5a6e3056128153dc87c1fe36565c748b9fbe8d705ad0 languageName: node linkType: hard -"solc@npm:^0.4.20": - version: 0.4.26 - resolution: "solc@npm:0.4.26" - dependencies: - fs-extra: "npm:^0.30.0" - memorystream: "npm:^0.3.1" - require-from-string: "npm:^1.1.0" - semver: "npm:^5.3.0" - yargs: "npm:^4.7.1" - bin: - solcjs: solcjs - checksum: 10c0/6de113c966491d02b08bb5845a4a46989903af98ab2a99f7250d9385ecd939733d9514e91577e987443b7706f1d50b5317059f131e07fa940cdee0134733eac3 +"ms@npm:2.1.2": + version: 2.1.2 + resolution: "ms@npm:2.1.2" + checksum: 10c0/a437714e2f90dbf881b5191d35a6db792efbca5badf112f87b9e1c712aace4b4b9b742dd6537f3edf90fd6f684de897cec230abde57e87883766712ddda297cc languageName: node linkType: hard -"solc@npm:^0.6.3": - version: 0.6.12 - resolution: "solc@npm:0.6.12" - dependencies: - command-exists: "npm:^1.2.8" - commander: "npm:3.0.2" - fs-extra: "npm:^0.30.0" - js-sha3: "npm:0.8.0" - memorystream: "npm:^0.3.1" - require-from-string: "npm:^2.0.0" - semver: "npm:^5.5.0" - tmp: "npm:0.0.33" - bin: - solcjs: solcjs - checksum: 10c0/7803e011a2a5424e14fc0aa3d7e36eac90130bfe1498eff3298967faee212aa13ca7fb7b98db27de449f086fbf92e87c24483e84ea5faa6a50cbe24e2961d002 +"ms@npm:^2.1.3": + version: 2.1.3 + resolution: "ms@npm:2.1.3" + checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 languageName: node linkType: hard -"solhint-config-keep@https://codeload.github.com/keep-network/solhint-config-keep/tar.gz/5e1751e58c0f1c507305ffc8c7f6c58047657ada": - version: 0.1.0 - resolution: "solhint-config-keep@https://codeload.github.com/keep-network/solhint-config-keep/tar.gz/5e1751e58c0f1c507305ffc8c7f6c58047657ada" - peerDependencies: - solhint: ">=3.3.4" - checksum: 10c0/c4deed3efa00a6939042c8e94fdc7bb8abd18ddb3a3908688b3cd5bdf0d786594411809ad8527ee34a4b0c56413b161eeef9f3201942a3265537d9f37fa0919d +"murmur-128@npm:^0.2.1": + version: 0.2.1 + resolution: "murmur-128@npm:0.2.1" + dependencies: + encode-utf8: "npm:^1.0.2" + fmix: "npm:^0.1.0" + imul: "npm:^1.0.0" + checksum: 10c0/1ae871af53693a9159794b92ace63c1b5c1cc137d235cc954a56af00e48856625131605517e1ee00f60295d0223a13091b88d33a55686011774a63db3b94ecd5 languageName: node linkType: hard -"solhint@npm:^3.3.6": - version: 3.3.6 - resolution: "solhint@npm:3.3.6" - dependencies: - "@solidity-parser/parser": "npm:^0.13.2" - ajv: "npm:^6.6.1" - antlr4: "npm:4.7.1" - ast-parents: "npm:0.0.1" - chalk: "npm:^2.4.2" - commander: "npm:2.18.0" - cosmiconfig: "npm:^5.0.7" - eslint: "npm:^5.6.0" - fast-diff: "npm:^1.1.2" - glob: "npm:^7.1.3" - ignore: "npm:^4.0.6" - js-yaml: "npm:^3.12.0" - lodash: "npm:^4.17.11" - prettier: "npm:^1.14.3" - semver: "npm:^6.3.0" - dependenciesMeta: - prettier: - optional: true +"napi-postinstall@npm:^0.3.4": + version: 0.3.4 + resolution: "napi-postinstall@npm:0.3.4" bin: - solhint: solhint.js - checksum: 10c0/039dc509ba50971f299c8ad04792bec3f0402d8d12ff71a06e3abfd4a73b2321415eeaa00b457fd46ed46ef8534448c8d68fbaa9503db4bc6d9ba09d5aea926e + napi-postinstall: lib/cli.js + checksum: 10c0/b33d64150828bdade3a5d07368a8b30da22ee393f8dd8432f1b9e5486867be21c84ec443dd875dd3ef3c7401a079a7ab7e2aa9d3538a889abbcd96495d5104fe languageName: node linkType: hard -"solidity-ast@npm:^0.4.15": - version: 0.4.32 - resolution: "solidity-ast@npm:0.4.32" - checksum: 10c0/01a15ecf07878d0bbe8549775c13fc6d3de1923086305d9a736579e0bb2bae6b6c4687f23f496965b65811387ceea4f62a809c9d2b7044412a6154a9771b5ea3 +"natural-compare@npm:^1.4.0": + version: 1.4.0 + resolution: "natural-compare@npm:1.4.0" + checksum: 10c0/f5f9a7974bfb28a91afafa254b197f0f22c684d4a1731763dda960d2c8e375b36c7d690e0d9dc8fba774c537af14a7e979129bca23d88d052fbeb9466955e447 languageName: node linkType: hard -"solidity-ast@npm:^0.4.38": - version: 0.4.46 - resolution: "solidity-ast@npm:0.4.46" - checksum: 10c0/3c0cf84f98b9af7faa5458a3d5d6fae2f6582db7005dbf4fb614ec6eab3cf3600eb62f025cb3f491f11b11ca2858c458fc88cf7abc1c2e964366c5a647efdc17 +"negotiator@npm:^1.0.0": + version: 1.0.0 + resolution: "negotiator@npm:1.0.0" + checksum: 10c0/4c559dd52669ea48e1914f9d634227c561221dd54734070791f999c52ed0ff36e437b2e07d5c1f6e32909fc625fe46491c16e4a8f0572567d4dd15c3a4fda04b languageName: node linkType: hard -"solidity-comments-extractor@npm:^0.0.7": - version: 0.0.7 - resolution: "solidity-comments-extractor@npm:0.0.7" - checksum: 10c0/57fb166ff71812404288ae1a386bb9bbb6330662aedc3b45d89f6f0ce51ee0e36c9f4b9d4fd363c2b37fbf607e42df088e734c532fb93e2f345601b429813d9e +"neo-async@npm:^2.6.0": + version: 2.6.2 + resolution: "neo-async@npm:2.6.2" + checksum: 10c0/c2f5a604a54a8ec5438a342e1f356dff4bc33ccccdb6dc668d94fe8e5eccfc9d2c2eea6064b0967a767ba63b33763f51ccf2cd2441b461a7322656c1f06b3f5d languageName: node linkType: hard -"solidity-docgen@npm:^0.6.0-beta.35": - version: 0.6.0-beta.35 - resolution: "solidity-docgen@npm:0.6.0-beta.35" - dependencies: - handlebars: "npm:^4.7.7" - solidity-ast: "npm:^0.4.38" - peerDependencies: - hardhat: ^2.8.0 - checksum: 10c0/d44ab7b12309c2dd89b039f695d4248827fe2cbcb26d7d6083c70a4687337a089edfb338f33f27ee4a4e1c03d9b5fb993a81e63bff174c9612e7d5248bf9e659 +"neoqs@npm:^6.13.0": + version: 6.13.0 + resolution: "neoqs@npm:6.13.0" + checksum: 10c0/646f4698b44e2479ca53be8530ebff704495db1db382b6a774ef621ef3456d17defad396d9256dd85c46b7ce5c7b7344e0231913e3b79ffbc84773efa8976810 languageName: node linkType: hard -"source-map-resolve@npm:^0.5.0": - version: 0.5.3 - resolution: "source-map-resolve@npm:0.5.3" +"node-addon-api@npm:^2.0.0": + version: 2.0.2 + resolution: "node-addon-api@npm:2.0.2" dependencies: - atob: "npm:^2.1.2" - decode-uri-component: "npm:^0.2.0" - resolve-url: "npm:^0.2.1" - source-map-url: "npm:^0.4.0" - urix: "npm:^0.1.0" - checksum: 10c0/410acbe93882e058858d4c1297be61da3e1533f95f25b95903edddc1fb719654e705663644677542d1fb78a66390238fad1a57115fc958a0724cf9bb509caf57 + node-gyp: "npm:latest" + checksum: 10c0/ade6c097ba829fa4aee1ca340117bb7f8f29fdae7b777e343a9d5cbd548481d1f0894b7b907d23ce615c70d932e8f96154caed95c3fa935cfe8cf87546510f64 languageName: node linkType: hard -"source-map-support@npm:0.5.12": - version: 0.5.12 - resolution: "source-map-support@npm:0.5.12" +"node-fetch@npm:^2.6.0, node-fetch@npm:^2.6.1": + version: 2.7.0 + resolution: "node-fetch@npm:2.7.0" dependencies: - buffer-from: "npm:^1.0.0" - source-map: "npm:^0.6.0" - checksum: 10c0/e37f0dd5e78bae64493cc201a4869ee8bd08f409b372ddb8452aab355dead19e2060a5a2e9c2ab981c6ade45122419562320710fade1b694fe848a48c01c2960 + whatwg-url: "npm:^5.0.0" + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + checksum: 10c0/b55786b6028208e6fbe594ccccc213cab67a72899c9234eb59dba51062a299ea853210fcf526998eaa2867b0963ad72338824450905679ff0fa304b8c5093ae8 languageName: node linkType: hard -"source-map-support@npm:^0.4.15": - version: 0.4.18 - resolution: "source-map-support@npm:0.4.18" - dependencies: - source-map: "npm:^0.5.6" - checksum: 10c0/cd9f0309c1632b1e01a7715a009e0b036d565f3af8930fa8cda2a06aeec05ad1d86180e743b7e1f02cc3c97abe8b6d8de7c3878c2d8e01e86e17f876f7ecf98e +"node-gyp-build@npm:^4.2.0": + version: 4.5.0 + resolution: "node-gyp-build@npm:4.5.0" + bin: + node-gyp-build: bin.js + node-gyp-build-optional: optional.js + node-gyp-build-test: build-test.js + checksum: 10c0/4ca30ae1f7ba570cd33ae6b71c7e3eb249c3901c0b8a02014cfe2ce18f7f23df621c8d087868973e4f32c90b1c4ad753b4dff1d8bf54666a3f848f414828c14f languageName: node linkType: hard -"source-map-support@npm:^0.5.13": - version: 0.5.20 - resolution: "source-map-support@npm:0.5.20" +"node-gyp@npm:latest": + version: 12.2.0 + resolution: "node-gyp@npm:12.2.0" dependencies: - buffer-from: "npm:^1.0.0" - source-map: "npm:^0.6.0" - checksum: 10c0/84a909248b1b7971d37fde1f2488a5e3b7aa2d676f92373a8bddcf5b059574d09971b82d2911ae91feb8245f9f2b0e0766f73b9c51ffb26c0fd2df5d44938307 + env-paths: "npm:^2.2.0" + exponential-backoff: "npm:^3.1.1" + graceful-fs: "npm:^4.2.6" + make-fetch-happen: "npm:^15.0.0" + nopt: "npm:^9.0.0" + proc-log: "npm:^6.0.0" + semver: "npm:^7.3.5" + tar: "npm:^7.5.4" + tinyglobby: "npm:^0.2.12" + which: "npm:^6.0.0" + bin: + node-gyp: bin/node-gyp.js + checksum: 10c0/3ed046746a5a7d90950cd8b0547332b06598443f31fe213ef4332a7174c7b7d259e1704835feda79b87d3f02e59d7791842aac60642ede4396ab25fdf0f8f759 languageName: node linkType: hard -"source-map-url@npm:^0.4.0": - version: 0.4.1 - resolution: "source-map-url@npm:0.4.1" - checksum: 10c0/f8af0678500d536c7f643e32094d6718a4070ab4ca2d2326532512cfbe2d5d25a45849b4b385879326f2d7523bb3b686d0360dd347a3cda09fd89a5c28d4bc58 +"nofilter@npm:^3.0.2, nofilter@npm:^3.1.0": + version: 3.1.0 + resolution: "nofilter@npm:3.1.0" + checksum: 10c0/92459f3864a067b347032263f0b536223cbfc98153913b5dce350cb39c8470bc1813366e41993f22c33cc6400c0f392aa324a4b51e24c22040635c1cdb046499 languageName: node linkType: hard -"source-map@npm:^0.5.6, source-map@npm:^0.5.7": - version: 0.5.7 - resolution: "source-map@npm:0.5.7" - checksum: 10c0/904e767bb9c494929be013017380cbba013637da1b28e5943b566031e29df04fba57edf3f093e0914be094648b577372bd8ad247fa98cfba9c600794cd16b599 +"nopt@npm:^9.0.0": + version: 9.0.0 + resolution: "nopt@npm:9.0.0" + dependencies: + abbrev: "npm:^4.0.0" + bin: + nopt: bin/nopt.js + checksum: 10c0/1822eb6f9b020ef6f7a7516d7b64a8036e09666ea55ac40416c36e4b2b343122c3cff0e2f085675f53de1d2db99a2a89a60ccea1d120bcd6a5347bf6ceb4a7fd languageName: node linkType: hard -"source-map@npm:^0.6.0, source-map@npm:^0.6.1": - version: 0.6.1 - resolution: "source-map@npm:0.6.1" - checksum: 10c0/ab55398007c5e5532957cb0beee2368529618ac0ab372d789806f5718123cc4367d57de3904b4e6a4170eb5a0b0f41373066d02ca0735a0c4d75c7d328d3e011 +"normalize-path@npm:^3.0.0, normalize-path@npm:~3.0.0": + version: 3.0.0 + resolution: "normalize-path@npm:3.0.0" + checksum: 10c0/e008c8142bcc335b5e38cf0d63cfd39d6cf2d97480af9abdbe9a439221fd4d749763bab492a8ee708ce7a194bb00c9da6d0a115018672310850489137b3da046 languageName: node linkType: hard -"spdx-correct@npm:^3.0.0": - version: 3.1.1 - resolution: "spdx-correct@npm:3.1.1" - dependencies: - spdx-expression-parse: "npm:^3.0.0" - spdx-license-ids: "npm:^3.0.0" - checksum: 10c0/25909eecc4024963a8e398399dbdd59ddb925bd7dbecd9c9cf6df0d75c29b68cd30b82123564acc51810eb02cfc4b634a2e16e88aa982433306012e318849249 +"normalize-url@npm:^8.0.0": + version: 8.1.1 + resolution: "normalize-url@npm:8.1.1" + checksum: 10c0/1beb700ce42acb2288f39453cdf8001eead55bbf046d407936a40404af420b8c1c6be97a869884ae9e659d7b1c744e40e905c875ac9290644eec2e3e6fb0b370 languageName: node linkType: hard -"spdx-exceptions@npm:^2.1.0": - version: 2.3.0 - resolution: "spdx-exceptions@npm:2.3.0" - checksum: 10c0/83089e77d2a91cb6805a5c910a2bedb9e50799da091f532c2ba4150efdef6e53f121523d3e2dc2573a340dc0189e648b03157097f65465b3a0c06da1f18d7e8a +"object-assign@npm:^4.1.0": + version: 4.1.1 + resolution: "object-assign@npm:4.1.1" + checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414 languageName: node linkType: hard -"spdx-expression-parse@npm:^3.0.0": - version: 3.0.1 - resolution: "spdx-expression-parse@npm:3.0.1" - dependencies: - spdx-exceptions: "npm:^2.1.0" - spdx-license-ids: "npm:^3.0.0" - checksum: 10c0/6f8a41c87759fa184a58713b86c6a8b028250f158159f1d03ed9d1b6ee4d9eefdc74181c8ddc581a341aa971c3e7b79e30b59c23b05d2436d5de1c30bdef7171 +"object-inspect@npm:^1.13.3, object-inspect@npm:^1.13.4": + version: 1.13.4 + resolution: "object-inspect@npm:1.13.4" + checksum: 10c0/d7f8711e803b96ea3191c745d6f8056ce1f2496e530e6a19a0e92d89b0fa3c76d910c31f0aa270432db6bd3b2f85500a376a83aaba849a8d518c8845b3211692 languageName: node linkType: hard -"spdx-license-ids@npm:^3.0.0": - version: 3.0.10 - resolution: "spdx-license-ids@npm:3.0.10" - checksum: 10c0/18993d1594c5e29f5ad9beabfd33ed9e38eeca8c2a4649a382207e1835a2526aeb624a3d22afa5aff270264d7604f80ba1877af2a667d785a846ff94bcf9da3b +"obliterator@npm:^1.6.1": + version: 1.6.1 + resolution: "obliterator@npm:1.6.1" + checksum: 10c0/5fad57319aae0ef6e34efa640541d41c2dd9790a7ab808f17dcb66c83a81333963fc2dfcfa6e1b62158e5cef6291cdcf15c503ad6c3de54b2227dd4c3d7e1b55 languageName: node linkType: hard -"split-string@npm:^3.0.1, split-string@npm:^3.0.2": - version: 3.1.0 - resolution: "split-string@npm:3.1.0" +"once@npm:^1.3.0": + version: 1.4.0 + resolution: "once@npm:1.4.0" dependencies: - extend-shallow: "npm:^3.0.0" - checksum: 10c0/72d7cd625445c7af215130e1e2bc183013bb9dd48a074eda1d35741e2b0dcb355e6df5b5558a62543a24dcec37dd1d6eb7a6228ff510d3c9de0f3dc1d1da8a70 - languageName: node - linkType: hard - -"sprintf-js@npm:~1.0.2": - version: 1.0.3 - resolution: "sprintf-js@npm:1.0.3" - checksum: 10c0/ecadcfe4c771890140da5023d43e190b7566d9cf8b2d238600f31bec0fc653f328da4450eb04bd59a431771a8e9cc0e118f0aa3974b683a4981b4e07abc2a5bb + wrappy: "npm:1" + checksum: 10c0/5d48aca287dfefabd756621c5dfce5c91a549a93e9fdb7b8246bc4c4790aa2ec17b34a260530474635147aeb631a2dcc8b32c613df0675f96041cbb8244517d0 languageName: node linkType: hard -"sshpk@npm:^1.7.0": - version: 1.17.0 - resolution: "sshpk@npm:1.17.0" - dependencies: - asn1: "npm:~0.2.3" - assert-plus: "npm:^1.0.0" - bcrypt-pbkdf: "npm:^1.0.0" - dashdash: "npm:^1.12.0" - ecc-jsbn: "npm:~0.1.1" - getpass: "npm:^0.1.1" - jsbn: "npm:~0.1.0" - safer-buffer: "npm:^2.0.2" - tweetnacl: "npm:~0.14.0" - bin: - sshpk-conv: bin/sshpk-conv - sshpk-sign: bin/sshpk-sign - sshpk-verify: bin/sshpk-verify - checksum: 10c0/cf5e7f4c72e8a505ef41daac9f9ca26da365cfe26ae265a01ce98a8868991943857a8526c1cf98a42ef0dc4edf1dbe4e77aeea378cfeb58054beb78505e85402 +"open@npm:^8.4.0": + version: 8.4.2 + resolution: "open@npm:8.4.2" + dependencies: + define-lazy-prop: "npm:^2.0.0" + is-docker: "npm:^2.1.1" + is-wsl: "npm:^2.2.0" + checksum: 10c0/bb6b3a58401dacdb0aad14360626faf3fb7fba4b77816b373495988b724fb48941cad80c1b65d62bb31a17609b2cd91c41a181602caea597ca80dfbcc27e84c9 languageName: node linkType: hard -"ssri@npm:^13.0.0": - version: 13.0.1 - resolution: "ssri@npm:13.0.1" +"optionator@npm:^0.9.3": + version: 0.9.4 + resolution: "optionator@npm:0.9.4" dependencies: - minipass: "npm:^7.0.3" - checksum: 10c0/cf6408a18676c57ff2ed06b8a20dc64bb3e748e5c7e095332e6aecaa2b8422b1e94a739a8453bf65156a8a47afe23757ba4ab52d3ea3b62322dc40875763e17a + deep-is: "npm:^0.1.3" + fast-levenshtein: "npm:^2.0.6" + levn: "npm:^0.4.1" + prelude-ls: "npm:^1.2.1" + type-check: "npm:^0.4.0" + word-wrap: "npm:^1.2.5" + checksum: 10c0/4afb687a059ee65b61df74dfe87d8d6815cd6883cb8b3d5883a910df72d0f5d029821f37025e4bccf4048873dbdb09acc6d303d27b8f76b1a80dd5a7d5334675 languageName: node linkType: hard -"stacktrace-parser@npm:^0.1.10": - version: 0.1.10 - resolution: "stacktrace-parser@npm:0.1.10" - dependencies: - type-fest: "npm:^0.7.1" - checksum: 10c0/f9c9cd55b0642a546e5f0516a87124fc496dcc2c082b96b156ed094c51e423314795cd1839cd4c59026349cf392d3414f54fc42165255602728588a58a9f72d3 +"ordinal@npm:^1.0.3": + version: 1.0.3 + resolution: "ordinal@npm:1.0.3" + checksum: 10c0/faa276fc1b1660477fd5c8749323c9715ae4f482c21fb8e67e57d1eb57845ba1b902796ecdcf6405325a8c3b042360970f5dc3b7f8cc7d79e0b2a756ab09174d languageName: node linkType: hard -"static-extend@npm:^0.1.1": - version: 0.1.2 - resolution: "static-extend@npm:0.1.2" - dependencies: - define-property: "npm:^0.2.5" - object-copy: "npm:^0.1.0" - checksum: 10c0/284f5865a9e19d079f1badbcd70d5f9f82e7a08393f818a220839cd5f71729e89105e1c95322bd28e833161d484cee671380ca443869ae89578eef2bf55c0653 +"os-tmpdir@npm:~1.0.2": + version: 1.0.2 + resolution: "os-tmpdir@npm:1.0.2" + checksum: 10c0/f438450224f8e2687605a8dd318f0db694b6293c5d835ae509a69e97c8de38b6994645337e5577f5001115470414638978cc49da1cdcc25106dad8738dc69990 languageName: node linkType: hard -"statuses@npm:2.0.1": - version: 2.0.1 - resolution: "statuses@npm:2.0.1" - checksum: 10c0/34378b207a1620a24804ce8b5d230fea0c279f00b18a7209646d5d47e419d1cc23e7cbf33a25a1e51ac38973dc2ac2e1e9c647a8e481ef365f77668d72becfd0 +"ox@npm:0.14.33": + version: 0.14.33 + resolution: "ox@npm:0.14.33" + dependencies: + "@adraffy/ens-normalize": "npm:^1.11.0" + "@noble/ciphers": "npm:^1.3.0" + "@noble/curves": "npm:1.9.1" + "@noble/hashes": "npm:^1.8.0" + "@scure/bip32": "npm:^1.7.0" + "@scure/bip39": "npm:^1.6.0" + abitype: "npm:^1.2.3" + eventemitter3: "npm:5.0.1" + peerDependencies: + typescript: ">=5.4.0" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/3fae8d41cc9e8d56112d7f6e5cc2e90ba8dc4d3764b01ead34798b8d2436a8009c1ccbe2731ae587e69cd31dba8e7fe9f08c586abc1eadb588a42a174e46d766 languageName: node linkType: hard -"statuses@npm:>= 1.5.0 < 2": - version: 1.5.0 - resolution: "statuses@npm:1.5.0" - checksum: 10c0/e433900956357b3efd79b1c547da4d291799ac836960c016d10a98f6a810b1b5c0dcc13b5a7aa609a58239b5190e1ea176ad9221c2157d2fd1c747393e6b2940 +"p-cancelable@npm:^3.0.0": + version: 3.0.0 + resolution: "p-cancelable@npm:3.0.0" + checksum: 10c0/948fd4f8e87b956d9afc2c6c7392de9113dac817cb1cecf4143f7a3d4c57ab5673614a80be3aba91ceec5e4b69fd8c869852d7e8048bc3d9273c4c36ce14b9aa languageName: node linkType: hard -"stream-to-pull-stream@npm:^1.7.1": - version: 1.7.3 - resolution: "stream-to-pull-stream@npm:1.7.3" +"p-limit@npm:^3.0.2": + version: 3.1.0 + resolution: "p-limit@npm:3.1.0" dependencies: - looper: "npm:^3.0.0" - pull-stream: "npm:^3.2.3" - checksum: 10c0/7deab5bdf3d352a2c1b5e0515a579a27d1e9e0f1791194126efaa84162dcb731ed9b5dcdf3d84717700e9de7fae9b7503539881eb87fab9263387b3a5ed08256 + yocto-queue: "npm:^0.1.0" + checksum: 10c0/9db675949dbdc9c3763c89e748d0ef8bdad0afbb24d49ceaf4c46c02c77d30db4e0652ed36d0a0a7a95154335fab810d95c86153105bb73b3a90448e2bb14e1a languageName: node linkType: hard -"streamsearch@npm:^1.1.0": - version: 1.1.0 - resolution: "streamsearch@npm:1.1.0" - checksum: 10c0/fbd9aecc2621364384d157f7e59426f4bfd385e8b424b5aaa79c83a6f5a1c8fd2e4e3289e95de1eb3511cb96bb333d6281a9919fafce760e4edb35b2cd2facab +"p-locate@npm:^5.0.0": + version: 5.0.0 + resolution: "p-locate@npm:5.0.0" + dependencies: + p-limit: "npm:^3.0.2" + checksum: 10c0/2290d627ab7903b8b70d11d384fee714b797f6040d9278932754a6860845c4d3190603a0772a663c8cb5a7b21d1b16acb3a6487ebcafa9773094edc3dfe6009a languageName: node linkType: hard -"strict-uri-encode@npm:^1.0.0": - version: 1.1.0 - resolution: "strict-uri-encode@npm:1.1.0" - checksum: 10c0/eb8a4109ba2588239787389313ba58ec49e043d4c64a1d44716defe5821a68ae49abe0cdefed9946ca9fc2a4af7ecf321da92422b0a67258ec0a3638b053ae62 +"p-map@npm:^4.0.0": + version: 4.0.0 + resolution: "p-map@npm:4.0.0" + dependencies: + aggregate-error: "npm:^3.0.0" + checksum: 10c0/592c05bd6262c466ce269ff172bb8de7c6975afca9b50c975135b974e9bdaafbfe80e61aaaf5be6d1200ba08b30ead04b88cfa7e25ff1e3b93ab28c9f62a2c75 languageName: node linkType: hard -"string-format@npm:^2.0.0": - version: 2.0.0 - resolution: "string-format@npm:2.0.0" - checksum: 10c0/7bca13ba9f942f635c74d637da5e9e375435cbd428f35eeef28c3a30f81d4e63b95ff2c6cca907d897dd3951bbf52e03e3b945a0e9681358e33bd67222436538 +"p-map@npm:^7.0.2": + version: 7.0.4 + resolution: "p-map@npm:7.0.4" + checksum: 10c0/a5030935d3cb2919d7e89454d1ce82141e6f9955413658b8c9403cfe379283770ed3048146b44cde168aa9e8c716505f196d5689db0ae3ce9a71521a2fef3abd languageName: node linkType: hard -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.0.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.2, string-width@npm:^4.2.3": - version: 4.2.3 - resolution: "string-width@npm:4.2.3" - dependencies: - emoji-regex: "npm:^8.0.0" - is-fullwidth-code-point: "npm:^3.0.0" - strip-ansi: "npm:^6.0.1" - checksum: 10c0/1e525e92e5eae0afd7454086eed9c818ee84374bb80328fc41217ae72ff5f065ef1c9d7f72da41de40c75fa8bb3dee63d92373fd492c84260a552c636392a47b +"package-json-from-dist@npm:^1.0.0": + version: 1.0.1 + resolution: "package-json-from-dist@npm:1.0.1" + checksum: 10c0/62ba2785eb655fec084a257af34dbe24292ab74516d6aecef97ef72d4897310bc6898f6c85b5cd22770eaa1ce60d55a0230e150fb6a966e3ecd6c511e23d164b languageName: node linkType: hard -"string-width@npm:^1.0.1": - version: 1.0.2 - resolution: "string-width@npm:1.0.2" +"package-json@npm:^8.1.0": + version: 8.1.1 + resolution: "package-json@npm:8.1.1" dependencies: - code-point-at: "npm:^1.0.0" - is-fullwidth-code-point: "npm:^1.0.0" - strip-ansi: "npm:^3.0.0" - checksum: 10c0/c558438baed23a9ab9370bb6a939acbdb2b2ffc517838d651aad0f5b2b674fb85d460d9b1d0b6a4c210dffd09e3235222d89a5bd4c0c1587f78b2bb7bc00c65e + got: "npm:^12.1.0" + registry-auth-token: "npm:^5.0.1" + registry-url: "npm:^6.0.0" + semver: "npm:^7.3.7" + checksum: 10c0/83b057878bca229033aefad4ef51569b484e63a65831ddf164dc31f0486817e17ffcb58c819c7af3ef3396042297096b3ffc04e107fd66f8f48756f6d2071c8f languageName: node linkType: hard -"string-width@npm:^2.1.0": - version: 2.1.1 - resolution: "string-width@npm:2.1.1" +"parent-module@npm:^1.0.0": + version: 1.0.1 + resolution: "parent-module@npm:1.0.1" dependencies: - is-fullwidth-code-point: "npm:^2.0.0" - strip-ansi: "npm:^4.0.0" - checksum: 10c0/e5f2b169fcf8a4257a399f95d069522f056e92ec97dbdcb9b0cdf14d688b7ca0b1b1439a1c7b9773cd79446cbafd582727279d6bfdd9f8edd306ea5e90e5b610 + callsites: "npm:^3.0.0" + checksum: 10c0/c63d6e80000d4babd11978e0d3fee386ca7752a02b035fd2435960ffaa7219dc42146f07069fb65e6e8bf1caef89daf9af7535a39bddf354d78bf50d8294f556 languageName: node linkType: hard -"string-width@npm:^3.0.0": - version: 3.1.0 - resolution: "string-width@npm:3.1.0" +"parse-json@npm:^5.2.0": + version: 5.2.0 + resolution: "parse-json@npm:5.2.0" dependencies: - emoji-regex: "npm:^7.0.1" - is-fullwidth-code-point: "npm:^2.0.0" - strip-ansi: "npm:^5.1.0" - checksum: 10c0/85fa0d4f106e7999bb68c1c640c76fa69fb8c069dab75b009e29c123914e2d3b532e6cfa4b9d1bd913176fc83dedd7a2d7bf40d21a81a8a1978432cedfb65b91 + "@babel/code-frame": "npm:^7.0.0" + error-ex: "npm:^1.3.1" + json-parse-even-better-errors: "npm:^2.3.0" + lines-and-columns: "npm:^1.1.6" + checksum: 10c0/77947f2253005be7a12d858aedbafa09c9ae39eb4863adf330f7b416ca4f4a08132e453e08de2db46459256fb66afaac5ee758b44fe6541b7cdaf9d252e59585 languageName: node linkType: hard -"string-width@npm:^5.0.1, string-width@npm:^5.1.2": - version: 5.1.2 - resolution: "string-width@npm:5.1.2" - dependencies: - eastasianwidth: "npm:^0.2.0" - emoji-regex: "npm:^9.2.2" - strip-ansi: "npm:^7.0.1" - checksum: 10c0/ab9c4264443d35b8b923cbdd513a089a60de339216d3b0ed3be3ba57d6880e1a192b70ae17225f764d7adbf5994e9bb8df253a944736c15a0240eff553c678ca +"path-exists@npm:^4.0.0": + version: 4.0.0 + resolution: "path-exists@npm:4.0.0" + checksum: 10c0/8c0bd3f5238188197dc78dced15207a4716c51cc4e3624c44fc97acf69558f5ebb9a2afff486fe1b4ee148e0c133e96c5e11a9aa5c48a3006e3467da070e5e1b languageName: node linkType: hard -"string.prototype.matchall@npm:^4.0.5": - version: 4.0.6 - resolution: "string.prototype.matchall@npm:4.0.6" - dependencies: - call-bind: "npm:^1.0.2" - define-properties: "npm:^1.1.3" - es-abstract: "npm:^1.19.1" - get-intrinsic: "npm:^1.1.1" - has-symbols: "npm:^1.0.2" - internal-slot: "npm:^1.0.3" - regexp.prototype.flags: "npm:^1.3.1" - side-channel: "npm:^1.0.4" - checksum: 10c0/967bf965b7f2aa565abe05773d066ae1d17e631e1e64576036c0543bd257f0f166f71ad252500061a6c3783bc047963ab3cce23c9000941f42e230c59db2c6cc +"path-is-absolute@npm:^1.0.0": + version: 1.0.1 + resolution: "path-is-absolute@npm:1.0.1" + checksum: 10c0/127da03c82172a2a50099cddbf02510c1791fc2cc5f7713ddb613a56838db1e8168b121a920079d052e0936c23005562059756d653b7c544c53185efe53be078 languageName: node linkType: hard -"string.prototype.trim@npm:~1.2.4": - version: 1.2.5 - resolution: "string.prototype.trim@npm:1.2.5" - dependencies: - call-bind: "npm:^1.0.2" - define-properties: "npm:^1.1.3" - es-abstract: "npm:^1.19.1" - checksum: 10c0/184395a7d1e296149ab8ef067314b93894822f614dbe07877d105ea3f3c24cd835b1de088007189d911fc6e38eb9ec68190980748220ff17def60bbc2080759d +"path-key@npm:^3.1.0": + version: 3.1.1 + resolution: "path-key@npm:3.1.1" + checksum: 10c0/748c43efd5a569c039d7a00a03b58eecd1d75f3999f5a28303d75f521288df4823bc057d8784eb72358b2895a05f29a070bc9f1f17d28226cc4e62494cc58c4c languageName: node linkType: hard -"string.prototype.trimend@npm:^1.0.4": - version: 1.0.4 - resolution: "string.prototype.trimend@npm:1.0.4" - dependencies: - call-bind: "npm:^1.0.2" - define-properties: "npm:^1.1.3" - checksum: 10c0/9fca11ab237f31cf55736e3e987deb312dd8e1bea7515e0f62949f1494f714083089a432ad5d99ea83f690a9290f58d0ce3d3f3356f5717e4c349d7d1b642af7 +"path-parse@npm:^1.0.6": + version: 1.0.7 + resolution: "path-parse@npm:1.0.7" + checksum: 10c0/11ce261f9d294cc7a58d6a574b7f1b935842355ec66fba3c3fd79e0f036462eaf07d0aa95bb74ff432f9afef97ce1926c720988c6a7451d8a584930ae7de86e1 languageName: node linkType: hard -"string.prototype.trimstart@npm:^1.0.4": - version: 1.0.4 - resolution: "string.prototype.trimstart@npm:1.0.4" +"path-scurry@npm:^1.11.1": + version: 1.11.1 + resolution: "path-scurry@npm:1.11.1" dependencies: - call-bind: "npm:^1.0.2" - define-properties: "npm:^1.1.3" - checksum: 10c0/4e4f836f9416c3db176587ab4e9b62f45b11489ab93c2b14e796c82a4f1c912278f31a4793cc00c2bee11002e56c964e9f131b8f78d96ffbd89822a11bd786fe + lru-cache: "npm:^10.2.0" + minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" + checksum: 10c0/32a13711a2a505616ae1cc1b5076801e453e7aae6ac40ab55b388bb91b9d0547a52f5aaceff710ea400205f18691120d4431e520afbe4266b836fadede15872d languageName: node linkType: hard -"string_decoder@npm:^1.1.1": - version: 1.3.0 - resolution: "string_decoder@npm:1.3.0" +"path-scurry@npm:^2.0.2": + version: 2.0.2 + resolution: "path-scurry@npm:2.0.2" dependencies: - safe-buffer: "npm:~5.2.0" - checksum: 10c0/810614ddb030e271cd591935dcd5956b2410dd079d64ff92a1844d6b7588bf992b3e1b69b0f4d34a3e06e0bd73046ac646b5264c1987b20d0601f81ef35d731d + lru-cache: "npm:^11.0.0" + minipass: "npm:^7.1.2" + checksum: 10c0/b35ad37cf6557a87fd057121ce2be7695380c9138d93e87ae928609da259ea0a170fac6f3ef1eb3ece8a068e8b7f2f3adf5bb2374cf4d4a57fe484954fcc9482 languageName: node linkType: hard -"string_decoder@npm:~0.10.x": - version: 0.10.31 - resolution: "string_decoder@npm:0.10.31" - checksum: 10c0/1c628d78f974aa7539c496029f48e7019acc32487fc695464f9d6bdfec98edd7d933a06b3216bc2016918f6e75074c611d84430a53cb0e43071597d6c1ac5e25 +"path-type@npm:^4.0.0": + version: 4.0.0 + resolution: "path-type@npm:4.0.0" + checksum: 10c0/666f6973f332f27581371efaf303fd6c272cc43c2057b37aa99e3643158c7e4b2626549555d88626e99ea9e046f82f32e41bbde5f1508547e9a11b149b52387c languageName: node linkType: hard -"string_decoder@npm:~1.1.1": +"pathval@npm:^1.1.1": version: 1.1.1 - resolution: "string_decoder@npm:1.1.1" - dependencies: - safe-buffer: "npm:~5.1.0" - checksum: 10c0/b4f89f3a92fd101b5653ca3c99550e07bdf9e13b35037e9e2a1c7b47cec4e55e06ff3fc468e314a0b5e80bfbaf65c1ca5a84978764884ae9413bec1fc6ca924e + resolution: "pathval@npm:1.1.1" + checksum: 10c0/f63e1bc1b33593cdf094ed6ff5c49c1c0dc5dc20a646ca9725cc7fe7cd9995002d51d5685b9b2ec6814342935748b711bafa840f84c0bb04e38ff40a335c94dc languageName: node linkType: hard -"strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": - version: 6.0.1 - resolution: "strip-ansi@npm:6.0.1" +"pbkdf2@npm:^3.0.17": + version: 3.1.2 + resolution: "pbkdf2@npm:3.1.2" dependencies: - ansi-regex: "npm:^5.0.1" - checksum: 10c0/1ae5f212a126fe5b167707f716942490e3933085a5ff6c008ab97ab2f272c8025d3aa218b7bd6ab25729ca20cc81cddb252102f8751e13482a5199e873680952 + create-hash: "npm:^1.1.2" + create-hmac: "npm:^1.1.4" + ripemd160: "npm:^2.0.1" + safe-buffer: "npm:^5.0.1" + sha.js: "npm:^2.4.8" + checksum: 10c0/5a30374e87d33fa080a92734d778cf172542cc7e41b96198c4c88763997b62d7850de3fbda5c3111ddf79805ee7c1da7046881c90ac4920b5e324204518b05fd languageName: node linkType: hard -"strip-ansi@npm:^3.0.0, strip-ansi@npm:^3.0.1": - version: 3.0.1 - resolution: "strip-ansi@npm:3.0.1" - dependencies: - ansi-regex: "npm:^2.0.0" - checksum: 10c0/f6e7fbe8e700105dccf7102eae20e4f03477537c74b286fd22cfc970f139002ed6f0d9c10d0e21aa9ed9245e0fa3c9275930e8795c5b947da136e4ecb644a70f +"picocolors@npm:^1.1.0, picocolors@npm:^1.1.1": + version: 1.1.1 + resolution: "picocolors@npm:1.1.1" + checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58 languageName: node linkType: hard -"strip-ansi@npm:^4.0.0": - version: 4.0.0 - resolution: "strip-ansi@npm:4.0.0" - dependencies: - ansi-regex: "npm:^3.0.0" - checksum: 10c0/d75d9681e0637ea316ddbd7d4d3be010b1895a17e885155e0ed6a39755ae0fd7ef46e14b22162e66a62db122d3a98ab7917794e255532ab461bb0a04feb03e7d +"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1": + version: 2.3.1 + resolution: "picomatch@npm:2.3.1" + checksum: 10c0/26c02b8d06f03206fc2ab8d16f19960f2ff9e81a658f831ecb656d8f17d9edc799e8364b1f4a7873e89d9702dff96204be0fa26fe4181f6843f040f819dac4be languageName: node linkType: hard -"strip-ansi@npm:^5.1.0": - version: 5.2.0 - resolution: "strip-ansi@npm:5.2.0" - dependencies: - ansi-regex: "npm:^4.1.0" - checksum: 10c0/de4658c8a097ce3b15955bc6008f67c0790f85748bdc025b7bc8c52c7aee94bc4f9e50624516150ed173c3db72d851826cd57e7a85fe4e4bb6dbbebd5d297fdf +"picomatch@npm:^4.0.3": + version: 4.0.7 + resolution: "picomatch@npm:4.0.7" + checksum: 10c0/beb6ae02c43ae44e84883b90830196d9046b1726ead292adcf7f57945e0bb0d992d68563d87e03b484b6f3c9a5c6defda7523477f047d7f0e663f126cc01787f languageName: node linkType: hard -"strip-ansi@npm:^7.0.1": - version: 7.2.0 - resolution: "strip-ansi@npm:7.2.0" - dependencies: - ansi-regex: "npm:^6.2.2" - checksum: 10c0/544d13b7582f8254811ea97db202f519e189e59d35740c46095897e254e4f1aa9fe1524a83ad6bc5ad67d4dd6c0281d2e0219ed62b880a6238a16a17d375f221 +"picomatch@npm:^4.0.4": + version: 4.0.4 + resolution: "picomatch@npm:4.0.4" + checksum: 10c0/e2c6023372cc7b5764719a5ffb9da0f8e781212fa7ca4bd0562db929df8e117460f00dff3cb7509dacfc06b86de924b247f504d0ce1806a37fac4633081466b0 languageName: node linkType: hard -"strip-bom@npm:^2.0.0": - version: 2.0.0 - resolution: "strip-bom@npm:2.0.0" - dependencies: - is-utf8: "npm:^0.2.0" - checksum: 10c0/4fcbb248af1d5c1f2d710022b7d60245077e7942079bfb7ef3fc8c1ae78d61e96278525ba46719b15ab12fced5c7603777105bc898695339d7c97c64d300ed0b +"pluralize@npm:^8.0.0": + version: 8.0.0 + resolution: "pluralize@npm:8.0.0" + checksum: 10c0/2044cfc34b2e8c88b73379ea4a36fc577db04f651c2909041b054c981cd863dd5373ebd030123ab058d194ae615d3a97cfdac653991e499d10caf592e8b3dc33 languageName: node linkType: hard -"strip-bom@npm:^3.0.0": - version: 3.0.0 - resolution: "strip-bom@npm:3.0.0" - checksum: 10c0/51201f50e021ef16672593d7434ca239441b7b760e905d9f33df6e4f3954ff54ec0e0a06f100d028af0982d6f25c35cd5cda2ce34eaebccd0250b8befb90d8f1 +"prelude-ls@npm:^1.2.1": + version: 1.2.1 + resolution: "prelude-ls@npm:1.2.1" + checksum: 10c0/b00d617431e7886c520a6f498a2e14c75ec58f6d93ba48c3b639cf241b54232d90daa05d83a9e9b9fef6baa63cb7e1e4602c2372fea5bc169668401eb127d0cd languageName: node linkType: hard -"strip-hex-prefix@npm:1.0.0": - version: 1.0.0 - resolution: "strip-hex-prefix@npm:1.0.0" +"prettier-plugin-solidity@npm:^2.4.1": + version: 2.4.1 + resolution: "prettier-plugin-solidity@npm:2.4.1" dependencies: - is-hex-prefixed: "npm:1.0.0" - checksum: 10c0/ec9a48c334c2ba4afff2e8efebb42c3ab5439f0e1ec2b8525e184eabef7fecade7aee444af802b1be55d2df6da5b58c55166c32f8461cc7559b401137ad51851 - languageName: node - linkType: hard - -"strip-json-comments@npm:^2.0.1": - version: 2.0.1 - resolution: "strip-json-comments@npm:2.0.1" - checksum: 10c0/b509231cbdee45064ff4f9fd73609e2bcc4e84a4d508e9dd0f31f70356473fde18abfb5838c17d56fb236f5a06b102ef115438de0600b749e818a35fbbc48c43 + "@nomicfoundation/slang": "npm:1.3.8" + "@solidity-parser/parser": "npm:^0.20.2" + semver: "npm:^7.8.5" + peerDependencies: + prettier: ">=3.0.0" + checksum: 10c0/20ea46e5e9e406d5eb6df50335b5c08be098afc6cc392d32b8bb0e140c2a41d02c8e83a8da79ce5a1223e361d7a497e86e95bfe6caf1eb8546c4f6ff3d085a76 languageName: node linkType: hard -"strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1": - version: 3.1.1 - resolution: "strip-json-comments@npm:3.1.1" - checksum: 10c0/9681a6257b925a7fa0f285851c0e613cc934a50661fa7bb41ca9cbbff89686bb4a0ee366e6ecedc4daafd01e83eee0720111ab294366fe7c185e935475ebcecd +"prettier@npm:^2.3.1": + version: 2.8.8 + resolution: "prettier@npm:2.8.8" + bin: + prettier: bin-prettier.js + checksum: 10c0/463ea8f9a0946cd5b828d8cf27bd8b567345cf02f56562d5ecde198b91f47a76b7ac9eae0facd247ace70e927143af6135e8cf411986b8cb8478784a4d6d724a languageName: node linkType: hard -"supports-color@npm:^2.0.0": - version: 2.0.0 - resolution: "supports-color@npm:2.0.0" - checksum: 10c0/570e0b63be36cccdd25186350a6cb2eaad332a95ff162fa06d9499982315f2fe4217e69dd98e862fbcd9c81eaff300a825a1fe7bf5cc752e5b84dfed042b0dda +"prettier@npm:^3.0.0, prettier@npm:^3.9.6": + version: 3.9.6 + resolution: "prettier@npm:3.9.6" + bin: + prettier: bin/prettier.cjs + checksum: 10c0/9f7ddae234035868f3daab3dc34e6de7e54622185afb017378029f0c09a9c023248ccf6f34def0b17a0538e18c47aa1b3188bab72965d1bf735919baa0747e99 languageName: node linkType: hard -"supports-color@npm:^5.3.0": - version: 5.5.0 - resolution: "supports-color@npm:5.5.0" - dependencies: - has-flag: "npm:^3.0.0" - checksum: 10c0/6ae5ff319bfbb021f8a86da8ea1f8db52fac8bd4d499492e30ec17095b58af11f0c55f8577390a749b1c4dde691b6a0315dab78f5f54c9b3d83f8fb5905c1c05 +"proc-log@npm:^6.0.0": + version: 6.1.0 + resolution: "proc-log@npm:6.1.0" + checksum: 10c0/4f178d4062733ead9d71a9b1ab24ebcecdfe2250916a5b1555f04fe2eda972a0ec76fbaa8df1ad9c02707add6749219d118a4fc46dc56bdfe4dde4b47d80bb82 languageName: node linkType: hard -"supports-color@npm:^7.1.0": - version: 7.2.0 - resolution: "supports-color@npm:7.2.0" +"prompts@npm:^2.4.2": + version: 2.4.2 + resolution: "prompts@npm:2.4.2" dependencies: - has-flag: "npm:^4.0.0" - checksum: 10c0/afb4c88521b8b136b5f5f95160c98dee7243dc79d5432db7efc27efb219385bbc7d9427398e43dd6cc730a0f87d5085ce1652af7efbe391327bc0a7d0f7fc124 + kleur: "npm:^3.0.3" + sisteransi: "npm:^1.0.5" + checksum: 10c0/16f1ac2977b19fe2cf53f8411cc98db7a3c8b115c479b2ca5c82b5527cd937aa405fa04f9a5960abeb9daef53191b53b4d13e35c1f5d50e8718c76917c5f1ea4 languageName: node linkType: hard -"supports-color@npm:^8.1.1": - version: 8.1.1 - resolution: "supports-color@npm:8.1.1" +"proper-lockfile@npm:^4.1.1": + version: 4.1.2 + resolution: "proper-lockfile@npm:4.1.2" dependencies: - has-flag: "npm:^4.0.0" - checksum: 10c0/ea1d3c275dd604c974670f63943ed9bd83623edc102430c05adb8efc56ba492746b6e95386e7831b872ec3807fd89dd8eb43f735195f37b5ec343e4234cc7e89 + graceful-fs: "npm:^4.2.4" + retry: "npm:^0.12.0" + signal-exit: "npm:^3.0.2" + checksum: 10c0/2f265dbad15897a43110a02dae55105c04d356ec4ed560723dcb9f0d34bc4fb2f13f79bb930e7561be10278e2314db5aca2527d5d3dcbbdee5e6b331d1571f6d languageName: node linkType: hard -"swarm-js@npm:^0.1.40": - version: 0.1.40 - resolution: "swarm-js@npm:0.1.40" - dependencies: - bluebird: "npm:^3.5.0" - buffer: "npm:^5.0.5" - eth-lib: "npm:^0.1.26" - fs-extra: "npm:^4.0.2" - got: "npm:^7.1.0" - mime-types: "npm:^2.1.16" - mkdirp-promise: "npm:^5.0.1" - mock-fs: "npm:^4.1.0" - setimmediate: "npm:^1.0.5" - tar: "npm:^4.0.2" - xhr-request: "npm:^1.0.1" - checksum: 10c0/a6d79330174c14b750b478b394b9e3dd090891f98fc54b6b18ee5f1ef478b302b84cce836f4750e4bbbb6344b397803c9d7597b91debff31b23c51a19bd1ea6b +"proto-list@npm:~1.2.1": + version: 1.2.4 + resolution: "proto-list@npm:1.2.4" + checksum: 10c0/b9179f99394ec8a68b8afc817690185f3b03933f7b46ce2e22c1930dc84b60d09f5ad222beab4e59e58c6c039c7f7fcf620397235ef441a356f31f9744010e12 languageName: node linkType: hard -"table-layout@npm:^1.0.1": - version: 1.0.2 - resolution: "table-layout@npm:1.0.2" - dependencies: - array-back: "npm:^4.0.1" - deep-extend: "npm:~0.6.0" - typical: "npm:^5.2.0" - wordwrapjs: "npm:^4.0.0" - checksum: 10c0/c1d16d5ba2199571606ff574a5c91cff77f14e8477746e191e7dfd294da03e61af4e8004f1f6f783da9582e1365f38d3c469980428998750d558bf29462cc6c3 +"proxy-from-env@npm:^2.1.0": + version: 2.1.0 + resolution: "proxy-from-env@npm:2.1.0" + checksum: 10c0/ed01729fd4d094eab619cd7e17ce3698b3413b31eb102c4904f9875e677cd207392795d5b4adee9cec359dfd31c44d5ad7595a3a3ad51c40250e141512281c58 languageName: node linkType: hard -"table@npm:^5.2.3": - version: 5.4.6 - resolution: "table@npm:5.4.6" - dependencies: - ajv: "npm:^6.10.2" - lodash: "npm:^4.17.14" - slice-ansi: "npm:^2.1.0" - string-width: "npm:^3.0.0" - checksum: 10c0/87ad7b7cc926aa06e0e2a91a0fb4fcb8b365da87969bc5c74b54cae5d518a089245f44bf80f945ec1aa74c405782db15eeb1dd1926315d842cdc9dbb9371672e +"punycode@npm:^2.1.0": + version: 2.1.1 + resolution: "punycode@npm:2.1.1" + checksum: 10c0/83815ca9b9177f055771f31980cbec7ffaef10257d50a95ab99b4a30f0404846e85fa6887ee1bbc0aaddb7bad6d96e2fa150a016051ff0f6b92be4ad613ddca8 languageName: node linkType: hard -"table@npm:^6.0.9": - version: 6.7.2 - resolution: "table@npm:6.7.2" +"qified@npm:^0.10.1": + version: 0.10.1 + resolution: "qified@npm:0.10.1" dependencies: - ajv: "npm:^8.0.1" - lodash.clonedeep: "npm:^4.5.0" - lodash.truncate: "npm:^4.4.2" - slice-ansi: "npm:^4.0.0" - string-width: "npm:^4.2.3" - strip-ansi: "npm:^6.0.1" - checksum: 10c0/e3ca1d79e133f6b65bf88f363b3a32ed0a6d0e7a95d4caba5332bbf928deee3daa830840abe86e0af780d1af797d825fc4853b900beb8e2ac7928d28553f5cd3 + hookified: "npm:^2.1.1" + checksum: 10c0/4a39d45492c65a4b9795381acede1bd566028ce9764ead5b41d776b391a898bf0855dd2b59d724a6711fe253ba3cacf7c9a8832887cf9dc6d48a2c5e4997c82d languageName: node linkType: hard -"table@npm:^6.8.0": - version: 6.8.0 - resolution: "table@npm:6.8.0" +"qs@npm:^6.9.4": + version: 6.15.3 + resolution: "qs@npm:6.15.3" dependencies: - ajv: "npm:^8.0.1" - lodash.truncate: "npm:^4.4.2" - slice-ansi: "npm:^4.0.0" - string-width: "npm:^4.2.3" - strip-ansi: "npm:^6.0.1" - checksum: 10c0/e03ba3ea1d625368d196eeedebaf0df072bbd8ce1604fd149cd5f3d988487062dda016638099df952bb28cefc3418ab108fcf0084bef7a9121d20985d6358298 + es-define-property: "npm:^1.0.1" + side-channel: "npm:^1.1.1" + checksum: 10c0/8f3f6e45ece255347d57696628401cde29e9ec649fff698b53bd3150dea7cefdf33036e1bc1826b9f110bfa7cb0ec4ab9f5297eca628ce216c55af82c304e08e languageName: node linkType: hard -"tape@npm:^4.6.3": - version: 4.14.0 - resolution: "tape@npm:4.14.0" - dependencies: - call-bind: "npm:~1.0.2" - deep-equal: "npm:~1.1.1" - defined: "npm:~1.0.0" - dotignore: "npm:~0.1.2" - for-each: "npm:~0.3.3" - glob: "npm:~7.1.7" - has: "npm:~1.0.3" - inherits: "npm:~2.0.4" - is-regex: "npm:~1.1.3" - minimist: "npm:~1.2.5" - object-inspect: "npm:~1.11.0" - resolve: "npm:~1.20.0" - resumer: "npm:~0.0.0" - string.prototype.trim: "npm:~1.2.4" - through: "npm:~2.3.8" - bin: - tape: bin/tape - checksum: 10c0/3c7d17519ad7cd0b26e3d9650f8862982712b5f37077732ec3428501ef2df73209290a9611b4c0d2e2ccce5fcfbc55a0f4f6aab7ef7198639bce011e0caf6091 +"quick-lru@npm:^5.1.1": + version: 5.1.1 + resolution: "quick-lru@npm:5.1.1" + checksum: 10c0/a24cba5da8cec30d70d2484be37622580f64765fb6390a928b17f60cd69e8dbd32a954b3ff9176fa1b86d86ff2ba05252fae55dc4d40d0291c60412b0ad096da languageName: node linkType: hard -"tar@npm:^4.0.2": - version: 4.4.19 - resolution: "tar@npm:4.4.19" +"randombytes@npm:^2.1.0": + version: 2.1.0 + resolution: "randombytes@npm:2.1.0" dependencies: - chownr: "npm:^1.1.4" - fs-minipass: "npm:^1.2.7" - minipass: "npm:^2.9.0" - minizlib: "npm:^1.3.3" - mkdirp: "npm:^0.5.5" - safe-buffer: "npm:^5.2.1" - yallist: "npm:^3.1.1" - checksum: 10c0/1a32a68feabd55e040f399f75fed37c35fd76202bb60e393986312cdee0175ff0dfd1aec9cc04ad2ade8a252d2a08c7d191fda877ce23f14a3da954d91d301d7 + safe-buffer: "npm:^5.1.0" + checksum: 10c0/50395efda7a8c94f5dffab564f9ff89736064d32addf0cc7e8bf5e4166f09f8ded7a0849ca6c2d2a59478f7d90f78f20d8048bca3cdf8be09d8e8a10790388f3 languageName: node linkType: hard -"tar@npm:^7.5.4": - version: 7.5.13 - resolution: "tar@npm:7.5.13" +"raw-body@npm:^2.4.1": + version: 2.4.1 + resolution: "raw-body@npm:2.4.1" dependencies: - "@isaacs/fs-minipass": "npm:^4.0.0" - chownr: "npm:^3.0.0" - minipass: "npm:^7.1.2" - minizlib: "npm:^3.1.0" - yallist: "npm:^5.0.0" - checksum: 10c0/5c65b8084799bde7a791593a1c1a45d3d6ee98182e3700b24c247b7b8f8654df4191642abbdb07ff25043d45dcff35620827c3997b88ae6c12040f64bed5076b + bytes: "npm:3.1.0" + http-errors: "npm:1.7.3" + iconv-lite: "npm:0.4.24" + unpipe: "npm:1.0.0" + checksum: 10c0/e4107f4dd9101d703d40bd8ddd6969badfec39ec81f15fbb1ae9c63752190dd37d2f2c3ff61fdcaf37b1ca18c647abcf80d0519c4d2e082ce849f51acfbf34d7 languageName: node linkType: hard -"test-value@npm:^2.1.0": - version: 2.1.0 - resolution: "test-value@npm:2.1.0" +"rc@npm:1.2.8": + version: 1.2.8 + resolution: "rc@npm:1.2.8" dependencies: - array-back: "npm:^1.0.3" - typical: "npm:^2.6.0" - checksum: 10c0/4f2830712641522408d790435e6527e277c54a76c9046db6616527045de4f1ac143e181e67fd3b0047e748cb477c48c59381a8f3a1b3599ccf13996aedf75688 + deep-extend: "npm:^0.6.0" + ini: "npm:~1.3.0" + minimist: "npm:^1.2.0" + strip-json-comments: "npm:~2.0.1" + bin: + rc: ./cli.js + checksum: 10c0/24a07653150f0d9ac7168e52943cc3cb4b7a22c0e43c7dff3219977c2fdca5a2760a304a029c20811a0e79d351f57d46c9bde216193a0f73978496afc2b85b15 languageName: node linkType: hard -"testrpc@npm:0.0.1": - version: 0.0.1 - resolution: "testrpc@npm:0.0.1" - checksum: 10c0/567acfb2f993a0f3b9a88431f1dc575b582218236cd876f3c7e38d689b5195d4a8e153ac8c8cffb09ef6379e8f0e465a574ce3484dfaf8e3551bb63626d8ab94 +"readable-stream@npm:^3.6.0": + version: 3.6.0 + resolution: "readable-stream@npm:3.6.0" + dependencies: + inherits: "npm:^2.0.3" + string_decoder: "npm:^1.1.1" + util-deprecate: "npm:^1.0.1" + checksum: 10c0/937bedd29ac8a68331666291922bea892fa2be1a33269e582de9f844a2002f146cf831e39cd49fe6a378d3f0c27358f259ed0e20d20f0bdc6a3f8fc21fce42dc languageName: node linkType: hard -"text-table@npm:^0.2.0": - version: 0.2.0 - resolution: "text-table@npm:0.2.0" - checksum: 10c0/02805740c12851ea5982686810702e2f14369a5f4c5c40a836821e3eefc65ffeec3131ba324692a37608294b0fd8c1e55a2dd571ffed4909822787668ddbee5c +"readdirp@npm:^4.0.1": + version: 4.1.2 + resolution: "readdirp@npm:4.1.2" + checksum: 10c0/60a14f7619dec48c9c850255cd523e2717001b0e179dc7037cfa0895da7b9e9ab07532d324bfb118d73a710887d1e35f79c495fa91582784493e085d18c72c62 languageName: node linkType: hard -"through2@npm:^2.0.3": - version: 2.0.5 - resolution: "through2@npm:2.0.5" +"readdirp@npm:~3.6.0": + version: 3.6.0 + resolution: "readdirp@npm:3.6.0" dependencies: - readable-stream: "npm:~2.3.6" - xtend: "npm:~4.0.1" - checksum: 10c0/cbfe5b57943fa12b4f8c043658c2a00476216d79c014895cef1ac7a1d9a8b31f6b438d0e53eecbb81054b93128324a82ecd59ec1a4f91f01f7ac113dcb14eade + picomatch: "npm:^2.2.1" + checksum: 10c0/6fa848cf63d1b82ab4e985f4cf72bd55b7dcfd8e0a376905804e48c3634b7e749170940ba77b32804d5fe93b3cc521aa95a8d7e7d725f830da6d93f3669ce66b languageName: node linkType: hard -"through@npm:^2.3.6, through@npm:~2.3.4, through@npm:~2.3.8": - version: 2.3.8 - resolution: "through@npm:2.3.8" - checksum: 10c0/4b09f3774099de0d4df26d95c5821a62faee32c7e96fb1f4ebd54a2d7c11c57fe88b0a0d49cf375de5fee5ae6bf4eb56dbbf29d07366864e2ee805349970d3cc +"reduce-flatten@npm:^2.0.0": + version: 2.0.0 + resolution: "reduce-flatten@npm:2.0.0" + checksum: 10c0/9275064535bc070a787824c835a4f18394942f8a78f08e69fb500920124ce1c46a287c8d9e565a7ffad8104875a6feda14efa8e951e8e4585370b8ff007b0abd languageName: node linkType: hard -"timed-out@npm:^4.0.0, timed-out@npm:^4.0.1": - version: 4.0.1 - resolution: "timed-out@npm:4.0.1" - checksum: 10c0/86f03ffce5b80c5a066e02e59e411d3fbbfcf242b19290ba76817b4180abd1b85558489586b6022b798fb1cf26fc644c0ce0efb9c271d67ec83fada4b9542a56 +"registry-auth-token@npm:^5.0.1": + version: 5.1.1 + resolution: "registry-auth-token@npm:5.1.1" + dependencies: + "@pnpm/npm-conf": "npm:^3.0.2" + checksum: 10c0/86b0f7fd87d327cb4177fee69bcf96563147ea72e206bc9c7a6a50a51c785a31b83a6c45956a489ed292d23b908b2755a075d0b2f7fec1ba91b1fb800b24cee3 languageName: node linkType: hard -"tinyglobby@npm:^0.2.12": - version: 0.2.16 - resolution: "tinyglobby@npm:0.2.16" +"registry-url@npm:^6.0.0": + version: 6.0.1 + resolution: "registry-url@npm:6.0.1" dependencies: - fdir: "npm:^6.5.0" - picomatch: "npm:^4.0.4" - checksum: 10c0/f2e09fd93dd95c41e522113b686ff6f7c13020962f8698a864a257f3d7737599afc47722b7ab726e12f8a813f779906187911ff8ee6701ede65072671a7e934b + rc: "npm:1.2.8" + checksum: 10c0/66e2221c8113fc35ee9d23fe58cb516fc8d556a189fb8d6f1011a02efccc846c4c9b5075b4027b99a5d5c9ad1345ac37f297bea3c0ca30d607ec8084bf561b90 languageName: node linkType: hard -"tinyglobby@npm:^0.2.6": - version: 0.2.17 - resolution: "tinyglobby@npm:0.2.17" - dependencies: - fdir: "npm:^6.5.0" - picomatch: "npm:^4.0.4" - checksum: 10c0/7f7bb0f197c88bc4b20c231e0deca4240ca3bf313a88f5a7fee93a872b84966a4d50220947c0455ad07a60b3b360961c5b7fd979222aeb716a9f99b412002e4c +"repeat-string@npm:^1.0.0": + version: 1.6.1 + resolution: "repeat-string@npm:1.6.1" + checksum: 10c0/87fa21bfdb2fbdedc44b9a5b118b7c1239bdd2c2c1e42742ef9119b7d412a5137a1d23f1a83dc6bb686f4f27429ac6f542e3d923090b44181bafa41e8ac0174d languageName: node linkType: hard -"tmp@npm:0.0.33, tmp@npm:^0.0.33": - version: 0.0.33 - resolution: "tmp@npm:0.0.33" - dependencies: - os-tmpdir: "npm:~1.0.2" - checksum: 10c0/69863947b8c29cabad43fe0ce65cec5bb4b481d15d4b4b21e036b060b3edbf3bc7a5541de1bacb437bb3f7c4538f669752627fdf9b4aaf034cebd172ba373408 +"require-directory@npm:^2.1.1": + version: 2.1.1 + resolution: "require-directory@npm:2.1.1" + checksum: 10c0/83aa76a7bc1531f68d92c75a2ca2f54f1b01463cb566cf3fbc787d0de8be30c9dbc211d1d46be3497dac5785fe296f2dd11d531945ac29730643357978966e99 languageName: node linkType: hard -"tmp@npm:0.1.0": - version: 0.1.0 - resolution: "tmp@npm:0.1.0" - dependencies: - rimraf: "npm:^2.6.3" - checksum: 10c0/195f96a194b34827b75e5742de09211ddd6d50b199c141e95cf399a574386031b4be03d2b6d33c3a0c364a3167affe3ece122bfe1b75485c8d5cf3f4320a8c48 +"require-from-string@npm:^2.0.2": + version: 2.0.2 + resolution: "require-from-string@npm:2.0.2" + checksum: 10c0/aaa267e0c5b022fc5fd4eef49d8285086b15f2a1c54b28240fdf03599cbd9c26049fee3eab894f2e1f6ca65e513b030a7c264201e3f005601e80c49fb2937ce2 languageName: node linkType: hard -"to-fast-properties@npm:^1.0.3": - version: 1.0.3 - resolution: "to-fast-properties@npm:1.0.3" - checksum: 10c0/78974a4f4528700d18e4c2bbf0b1fb1b19862dcc20a18dc5ed659843dea2dff4f933d167a11d3819865c1191042003aea65f7f035791af9e65d070f2e05af787 +"resolve-alpn@npm:^1.2.0": + version: 1.2.1 + resolution: "resolve-alpn@npm:1.2.1" + checksum: 10c0/b70b29c1843bc39781ef946c8cd4482e6d425976599c0f9c138cec8209e4e0736161bf39319b01676a847000085dfdaf63583c6fb4427bf751a10635bd2aa0c4 languageName: node linkType: hard -"to-object-path@npm:^0.3.0": - version: 0.3.0 - resolution: "to-object-path@npm:0.3.0" - dependencies: - kind-of: "npm:^3.0.2" - checksum: 10c0/731832a977614c03a770363ad2bd9e9c82f233261861724a8e612bb90c705b94b1a290a19f52958e8e179180bb9b71121ed65e245691a421467726f06d1d7fc3 +"resolve-from@npm:^4.0.0": + version: 4.0.0 + resolution: "resolve-from@npm:4.0.0" + checksum: 10c0/8408eec31a3112ef96e3746c37be7d64020cda07c03a920f5024e77290a218ea758b26ca9529fd7b1ad283947f34b2291c1c0f6aa0ed34acfdda9c6014c8d190 languageName: node linkType: hard -"to-readable-stream@npm:^1.0.0": +"resolve-pkg-maps@npm:^1.0.0": version: 1.0.0 - resolution: "to-readable-stream@npm:1.0.0" - checksum: 10c0/79cb836e2fb4f2885745a8c212eab7ebc52e93758ff0737feceaed96df98e4d04b8903fe8c27f2e9f3f856a5068ac332918b235c5d801b3efe02a51a3fa0eb36 + resolution: "resolve-pkg-maps@npm:1.0.0" + checksum: 10c0/fb8f7bbe2ca281a73b7ef423a1cbc786fb244bd7a95cbe5c3fba25b27d327150beca8ba02f622baea65919a57e061eb5005204daa5f93ed590d9b77463a567ab languageName: node linkType: hard -"to-regex-range@npm:^2.1.0": - version: 2.1.1 - resolution: "to-regex-range@npm:2.1.1" +"resolve@npm:1.17.0": + version: 1.17.0 + resolution: "resolve@npm:1.17.0" dependencies: - is-number: "npm:^3.0.0" - repeat-string: "npm:^1.6.1" - checksum: 10c0/440d82dbfe0b2e24f36dd8a9467240406ad1499fc8b2b0f547372c22ed1d092ace2a3eb522bb09bfd9c2f39bf1ca42eb78035cf6d2b8c9f5c78da3abc96cd949 + path-parse: "npm:^1.0.6" + checksum: 10c0/4e6c76cc1a7b08bff637b092ce035d7901465067915605bc5a23ac0c10fe42ec205fc209d5d5f7a5f27f37ce71d687def7f656bbb003631cd46a8374f55ec73d languageName: node linkType: hard -"to-regex-range@npm:^5.0.1": - version: 5.0.1 - resolution: "to-regex-range@npm:5.0.1" +"resolve@patch:resolve@npm%3A1.17.0#optional!builtin": + version: 1.17.0 + resolution: "resolve@patch:resolve@npm%3A1.17.0#optional!builtin::version=1.17.0&hash=c3c19d" dependencies: - is-number: "npm:^7.0.0" - checksum: 10c0/487988b0a19c654ff3e1961b87f471702e708fa8a8dd02a298ef16da7206692e8552a0250e8b3e8759270f62e9d8314616f6da274734d3b558b1fc7b7724e892 + path-parse: "npm:^1.0.6" + checksum: 10c0/e072e52be3c3dbfd086761115db4a5136753e7aefc0e665e66e7307ddcd9d6b740274516055c74aee44921625e95993f03570450aa310b8d73b1c9daa056c4cd languageName: node linkType: hard -"to-regex@npm:^3.0.1, to-regex@npm:^3.0.2": - version: 3.0.2 - resolution: "to-regex@npm:3.0.2" +"responselike@npm:^3.0.0": + version: 3.0.0 + resolution: "responselike@npm:3.0.0" dependencies: - define-property: "npm:^2.0.2" - extend-shallow: "npm:^3.0.2" - regex-not: "npm:^1.0.2" - safe-regex: "npm:^1.1.0" - checksum: 10c0/99d0b8ef397b3f7abed4bac757b0f0bb9f52bfd39167eb7105b144becfaa9a03756892352d01ac6a911f0c1ceef9f81db68c46899521a3eed054082042796120 + lowercase-keys: "npm:^3.0.0" + checksum: 10c0/8af27153f7e47aa2c07a5f2d538cb1e5872995f0e9ff77def858ecce5c3fe677d42b824a62cde502e56d275ab832b0a8bd350d5cd6b467ac0425214ac12ae658 languageName: node linkType: hard -"toidentifier@npm:1.0.0": - version: 1.0.0 - resolution: "toidentifier@npm:1.0.0" - checksum: 10c0/27a37b8b21126e7216d40c02f410065b1de35b0f844368d0ccaabba7987595703006d45e5c094b086220cbbc5864d4b99766b460110e4bc15b9db574c5c58be2 +"retry@npm:0.13.1": + version: 0.13.1 + resolution: "retry@npm:0.13.1" + checksum: 10c0/9ae822ee19db2163497e074ea919780b1efa00431d197c7afdb950e42bf109196774b92a49fc9821f0b8b328a98eea6017410bfc5e8a0fc19c85c6d11adb3772 languageName: node linkType: hard -"toidentifier@npm:1.0.1": - version: 1.0.1 - resolution: "toidentifier@npm:1.0.1" - checksum: 10c0/93937279934bd66cc3270016dd8d0afec14fb7c94a05c72dc57321f8bd1fa97e5bea6d1f7c89e728d077ca31ea125b78320a616a6c6cd0e6b9cb94cb864381c1 +"retry@npm:^0.12.0": + version: 0.12.0 + resolution: "retry@npm:0.12.0" + checksum: 10c0/59933e8501727ba13ad73ef4a04d5280b3717fd650408460c987392efe9d7be2040778ed8ebe933c5cbd63da3dcc37919c141ef8af0a54a6e4fca5a2af177bfe languageName: node linkType: hard -"tough-cookie@npm:~2.5.0": - version: 2.5.0 - resolution: "tough-cookie@npm:2.5.0" +"ripemd160@npm:^2.0.0, ripemd160@npm:^2.0.1": + version: 2.0.2 + resolution: "ripemd160@npm:2.0.2" dependencies: - psl: "npm:^1.1.28" - punycode: "npm:^2.1.1" - checksum: 10c0/e1cadfb24d40d64ca16de05fa8192bc097b66aeeb2704199b055ff12f450e4f30c927ce250f53d01f39baad18e1c11d66f65e545c5c6269de4c366fafa4c0543 + hash-base: "npm:^3.0.0" + inherits: "npm:^2.0.1" + checksum: 10c0/f6f0df78817e78287c766687aed4d5accbebc308a8e7e673fb085b9977473c1f139f0c5335d353f172a915bb288098430755d2ad3c4f30612f4dd0c901cd2c3a languageName: node linkType: hard -"tr46@npm:~0.0.3": - version: 0.0.3 - resolution: "tr46@npm:0.0.3" - checksum: 10c0/047cb209a6b60c742f05c9d3ace8fa510bff609995c129a37ace03476a9b12db4dbf975e74600830ef0796e18882b2381fb5fb1f6b4f96b832c374de3ab91a11 +"rlp@npm:^2.2.4": + version: 2.2.6 + resolution: "rlp@npm:2.2.6" + dependencies: + bn.js: "npm:^4.11.1" + bin: + rlp: bin/rlp + checksum: 10c0/e12b57bf74c44d94c7d9d6273655e0afa46844d89738ee34ebdcf00bc699f0025309759e834b4fbd3e9fdf54a0fbc9a5e4aa7cae49bbf33aaf76e4c01e643f66 languageName: node linkType: hard -"trim-right@npm:^1.0.1": - version: 1.0.1 - resolution: "trim-right@npm:1.0.1" - checksum: 10c0/71989ec179c6b42a56e03db68e60190baabf39d32d4e1252fa1501c4e478398ae29d7191beffe015b9d9dc76f04f4b3a946bdb9949ad6b0c0b0c5db65f3eb672 +"safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:~5.2.0": + version: 5.2.1 + resolution: "safe-buffer@npm:5.2.1" + checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 languageName: node linkType: hard -"ts-command-line-args@npm:^2.2.0": - version: 2.2.1 - resolution: "ts-command-line-args@npm:2.2.1" - dependencies: - chalk: "npm:^4.1.0" - command-line-args: "npm:^5.1.1" - command-line-usage: "npm:^6.1.0" - string-format: "npm:^2.0.0" - bin: - write-markdown: dist/write-markdown.js - checksum: 10c0/6e925ea38ffa727644bd121f3af5399653c5a79d3069dabe6c826c9226ed4affce40ed91acbdc1b3235b93450183eb5b3795d23844a10e78d280ae4e78345997 +"safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0": + version: 2.1.2 + resolution: "safer-buffer@npm:2.1.2" + checksum: 10c0/7e3c8b2e88a1841c9671094bbaeebd94448111dd90a81a1f606f3f67708a6ec57763b3b47f06da09fc6054193e0e6709e77325415dc8422b04497a8070fa02d4 languageName: node linkType: hard -"ts-essentials@npm:^1.0.0": - version: 1.0.4 - resolution: "ts-essentials@npm:1.0.4" - checksum: 10c0/91f77f3d5722e31d824f7a92cdb53021d9ce6bcd659124bcf8b8df67f000d5c1a70e1c23e436c956e2827e28321c7cc0f67a6780f891a94bf18d413ac6301ba8 +"scrypt-js@npm:3.0.1, scrypt-js@npm:^3.0.0": + version: 3.0.1 + resolution: "scrypt-js@npm:3.0.1" + checksum: 10c0/e2941e1c8b5c84c7f3732b0153fee624f5329fc4e772a06270ee337d4d2df4174b8abb5e6ad53804a29f53890ecbc78f3775a319323568c0313040c0e55f5b10 languageName: node linkType: hard -"ts-essentials@npm:^6.0.3": - version: 6.0.7 - resolution: "ts-essentials@npm:6.0.7" - peerDependencies: - typescript: ">=3.7.0" - checksum: 10c0/fffe3f8e383ab0a62cd090b32d0afeab2ad723e96699e1590e8970213631aaef22518fe47866f64356651d8595b81f220a2e9226247730a16f394eb7b1551862 +"secp256k1@npm:^4.0.1": + version: 4.0.3 + resolution: "secp256k1@npm:4.0.3" + dependencies: + elliptic: "npm:^6.5.4" + node-addon-api: "npm:^2.0.0" + node-gyp: "npm:latest" + node-gyp-build: "npm:^4.2.0" + checksum: 10c0/de0a0e525a6f8eb2daf199b338f0797dbfe5392874285a145bb005a72cabacb9d42c0197d0de129a1a0f6094d2cc4504d1f87acb6a8bbfb7770d4293f252c401 languageName: node linkType: hard -"ts-essentials@npm:^7.0.1": - version: 7.0.3 - resolution: "ts-essentials@npm:7.0.3" - peerDependencies: - typescript: ">=3.7.0" - checksum: 10c0/ea1919534ec6ce4ca4d9cb0ff1ab8e053509237da8d4298762ab3bfba4e78ca5649a599ce78a5c7c2624f3a7a971f62b265b7b0c3c881336e4fa6acaf6f37544 +"semver@npm:^5.5.0": + version: 5.7.1 + resolution: "semver@npm:5.7.1" + bin: + semver: ./bin/semver + checksum: 10c0/d4884f2aeca28bff35d0bd40ff0a9b2dfc4b36a883bf0ea5dc15d10d9a01bdc9041035b05f825d4b5ac8a56e490703dbf0d986d054de82cc5e9bad3f02ca6e00 languageName: node linkType: hard -"ts-generator@npm:^0.1.1": - version: 0.1.1 - resolution: "ts-generator@npm:0.1.1" - dependencies: - "@types/mkdirp": "npm:^0.5.2" - "@types/prettier": "npm:^2.1.1" - "@types/resolve": "npm:^0.0.8" - chalk: "npm:^2.4.1" - glob: "npm:^7.1.2" - mkdirp: "npm:^0.5.1" - prettier: "npm:^2.1.2" - resolve: "npm:^1.8.1" - ts-essentials: "npm:^1.0.0" +"semver@npm:^6.3.0": + version: 6.3.0 + resolution: "semver@npm:6.3.0" bin: - ts-generator: dist/cli/run.js - checksum: 10c0/9c33b156da3166c131f6264f9f0148caa9a065ee0d5ad25cd9fde671fe119a892107062d16273fb72e77ff9b519b459140176f22ceee2e6cc388dea040bd870d + semver: ./bin/semver.js + checksum: 10c0/1f4959e15bcfbaf727e964a4920f9260141bb8805b399793160da4e7de128e42a7d1f79c1b7d5cd21a6073fba0d55feb9966f5fef3e5ccb8e1d7ead3d7527458 languageName: node linkType: hard -"ts-node@npm:^10.2.1": - version: 10.2.1 - resolution: "ts-node@npm:10.2.1" +"semver@npm:^7.3.5": + version: 7.3.5 + resolution: "semver@npm:7.3.5" dependencies: - "@cspotcode/source-map-support": "npm:0.6.1" - "@tsconfig/node10": "npm:^1.0.7" - "@tsconfig/node12": "npm:^1.0.7" - "@tsconfig/node14": "npm:^1.0.0" - "@tsconfig/node16": "npm:^1.0.2" - acorn: "npm:^8.4.1" - acorn-walk: "npm:^8.1.1" - arg: "npm:^4.1.0" - create-require: "npm:^1.1.0" - diff: "npm:^4.0.1" - make-error: "npm:^1.1.1" - yn: "npm:3.1.1" - peerDependencies: - "@swc/core": ">=1.2.50" - "@swc/wasm": ">=1.2.50" - "@types/node": "*" - typescript: ">=2.7" - peerDependenciesMeta: - "@swc/core": - optional: true - "@swc/wasm": - optional: true + lru-cache: "npm:^6.0.0" bin: - ts-node: dist/bin.js - ts-node-cwd: dist/bin-cwd.js - ts-node-script: dist/bin-script.js - ts-node-transpile-only: dist/bin-transpile.js - ts-script: dist/bin-script-deprecated.js - checksum: 10c0/15755a09a97797036aed3672a9551a441958271c3e77a99714b41db3fcfc5829ae22aac3365d48bcf94f88a78c5cc8e3e2cd13240d948d19b7aa1a47f210bfe3 + semver: bin/semver.js + checksum: 10c0/d450455b2601396dbc7d9f058a6709b1c0b99d74a911f9436c77887600ffcdb5f63d5adffa0c3b8f0092937d8a41cc61c6437bcba375ef4151cb1335ebe4f1f9 + languageName: node + linkType: hard + +"semver@npm:^7.3.7, semver@npm:^7.5.2, semver@npm:^7.7.1, semver@npm:^7.7.2, semver@npm:^7.7.3, semver@npm:^7.8.5": + version: 7.8.5 + resolution: "semver@npm:7.8.5" + bin: + semver: bin/semver.js + checksum: 10c0/b1f3127a5be8125a94f37188b361c212466c292c6910adce3ec106cff5dc211ccaedc4739c11bb70fda59d6fc1f040a9bca289f4e093451521a2372e5231fe0c languageName: node linkType: hard -"tsconfig-paths@npm:^3.11.0": - version: 3.11.0 - resolution: "tsconfig-paths@npm:3.11.0" +"serialize-javascript@npm:^6.0.2": + version: 6.0.2 + resolution: "serialize-javascript@npm:6.0.2" dependencies: - "@types/json5": "npm:^0.0.29" - json5: "npm:^1.0.1" - minimist: "npm:^1.2.0" - strip-bom: "npm:^3.0.0" - checksum: 10c0/91fc8e1c3ce784e4677860eb526465fdbcfbb8488937db0e232ad4a4454abd1ecf6021c83a1ca404b81ed1d9efff80b5b194e6d6f103815649843f42c341d2c9 + randombytes: "npm:^2.1.0" + checksum: 10c0/2dd09ef4b65a1289ba24a788b1423a035581bef60817bea1f01eda8e3bda623f86357665fe7ac1b50f6d4f583f97db9615b3f07b2a2e8cbcb75033965f771dd2 languageName: node linkType: hard -"tslib@npm:^1.8.1, tslib@npm:^1.9.0, tslib@npm:^1.9.3": - version: 1.14.1 - resolution: "tslib@npm:1.14.1" - checksum: 10c0/69ae09c49eea644bc5ebe1bca4fa4cc2c82b7b3e02f43b84bd891504edf66dbc6b2ec0eef31a957042de2269139e4acff911e6d186a258fb14069cd7f6febce2 +"setimmediate@npm:^1.0.5": + version: 1.0.5 + resolution: "setimmediate@npm:1.0.5" + checksum: 10c0/5bae81bfdbfbd0ce992893286d49c9693c82b1bcc00dcaaf3a09c8f428fdeacf4190c013598b81875dfac2b08a572422db7df779a99332d0fce186d15a3e4d49 languageName: node linkType: hard -"tsort@npm:0.0.1": - version: 0.0.1 - resolution: "tsort@npm:0.0.1" - checksum: 10c0/ea3d034ab341dd9282c972710496e98539408d77f1cd476ad0551a9731f40586b65ab917b39745f902bf32037a3161eee3821405f6ab15bcd2ce4cc0a52d1da6 +"setprototypeof@npm:1.1.1": + version: 1.1.1 + resolution: "setprototypeof@npm:1.1.1" + checksum: 10c0/1084b783f2d77908b0a593619e1214c2118c44c7c3277f6099dd7ca8acfc056c009e5d1b2860eae5e8b0ba9bc0a978c15613ff102ccc1093bb48aa6e0ed75e2f languageName: node linkType: hard -"tsutils@npm:^3.21.0": - version: 3.21.0 - resolution: "tsutils@npm:3.21.0" +"sha.js@npm:^2.4.0, sha.js@npm:^2.4.8": + version: 2.4.11 + resolution: "sha.js@npm:2.4.11" dependencies: - tslib: "npm:^1.8.1" - peerDependencies: - typescript: ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - checksum: 10c0/02f19e458ec78ead8fffbf711f834ad8ecd2cc6ade4ec0320790713dccc0a412b99e7fd907c4cda2a1dc602c75db6f12e0108e87a5afad4b2f9e90a24cabd5a2 + inherits: "npm:^2.0.1" + safe-buffer: "npm:^5.0.1" + bin: + sha.js: ./bin.js + checksum: 10c0/b7a371bca8821c9cc98a0aeff67444a03d48d745cb103f17228b96793f455f0eb0a691941b89ea1e60f6359207e36081d9be193252b0f128e0daf9cfea2815a5 languageName: node linkType: hard -"tunnel-agent@npm:^0.6.0": - version: 0.6.0 - resolution: "tunnel-agent@npm:0.6.0" +"sha1@npm:^1.1.1": + version: 1.1.1 + resolution: "sha1@npm:1.1.1" dependencies: - safe-buffer: "npm:^5.0.1" - checksum: 10c0/4c7a1b813e7beae66fdbf567a65ec6d46313643753d0beefb3c7973d66fcec3a1e7f39759f0a0b4465883499c6dc8b0750ab8b287399af2e583823e40410a17a + charenc: "npm:>= 0.0.1" + crypt: "npm:>= 0.0.1" + checksum: 10c0/1bb36c89c112c741c265cca66712f883ae01d5c55b71aec80635fe2ad5d0c976a1a8a994dda774ae9f93b2da99fd111238758a8bf985adc400bd86f0e4452865 languageName: node linkType: hard -"tweetnacl-util@npm:^0.15.0": - version: 0.15.1 - resolution: "tweetnacl-util@npm:0.15.1" - checksum: 10c0/796fad76238e40e853dff79516406a27b41549bfd6fabf4ba89d87ca31acf232122f825daf955db8c8573cc98190d7a6d39ece9ed8ae0163370878c310650a80 +"shebang-command@npm:^2.0.0": + version: 2.0.0 + resolution: "shebang-command@npm:2.0.0" + dependencies: + shebang-regex: "npm:^3.0.0" + checksum: 10c0/a41692e7d89a553ef21d324a5cceb5f686d1f3c040759c50aab69688634688c5c327f26f3ecf7001ebfd78c01f3c7c0a11a7c8bfd0a8bc9f6240d4f40b224e4e languageName: node linkType: hard -"tweetnacl@npm:^0.14.3, tweetnacl@npm:~0.14.0": - version: 0.14.5 - resolution: "tweetnacl@npm:0.14.5" - checksum: 10c0/4612772653512c7bc19e61923fbf42903f5e0389ec76a4a1f17195859d114671ea4aa3b734c2029ce7e1fa7e5cc8b80580f67b071ecf0b46b5636d030a0102a2 +"shebang-regex@npm:^3.0.0": + version: 3.0.0 + resolution: "shebang-regex@npm:3.0.0" + checksum: 10c0/1dbed0726dd0e1152a92696c76c7f06084eb32a90f0528d11acd764043aacf76994b2fb30aa1291a21bd019d6699164d048286309a278855ee7bec06cf6fb690 languageName: node linkType: hard -"tweetnacl@npm:^1.0.0": - version: 1.0.3 - resolution: "tweetnacl@npm:1.0.3" - checksum: 10c0/069d9df51e8ad4a89fbe6f9806c68e06c65be3c7d42f0701cc43dba5f0d6064686b238bbff206c5addef8854e3ce00c643bff59432ea2f2c639feab0ee1a93f9 +"side-channel-list@npm:^1.0.1": + version: 1.0.1 + resolution: "side-channel-list@npm:1.0.1" + dependencies: + es-errors: "npm:^1.3.0" + object-inspect: "npm:^1.13.4" + checksum: 10c0/d346c787fd2f9f1c2fdea14f00e8250118db0e7596d85a6cb9faa75f105d31a73a8f7a341c93d7df2a2429098c3d37a77bd3be9e88c37094b8c01807bc77c7a2 languageName: node linkType: hard -"type-check@npm:^0.4.0, type-check@npm:~0.4.0": - version: 0.4.0 - resolution: "type-check@npm:0.4.0" +"side-channel-map@npm:^1.0.1": + version: 1.0.1 + resolution: "side-channel-map@npm:1.0.1" dependencies: - prelude-ls: "npm:^1.2.1" - checksum: 10c0/7b3fd0ed43891e2080bf0c5c504b418fbb3e5c7b9708d3d015037ba2e6323a28152ec163bcb65212741fa5d2022e3075ac3c76440dbd344c9035f818e8ecee58 + call-bound: "npm:^1.0.2" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.5" + object-inspect: "npm:^1.13.3" + checksum: 10c0/010584e6444dd8a20b85bc926d934424bd809e1a3af941cace229f7fdcb751aada0fb7164f60c2e22292b7fa3c0ff0bce237081fd4cdbc80de1dc68e95430672 languageName: node linkType: hard -"type-check@npm:~0.3.2": - version: 0.3.2 - resolution: "type-check@npm:0.3.2" +"side-channel-weakmap@npm:^1.0.2": + version: 1.0.2 + resolution: "side-channel-weakmap@npm:1.0.2" dependencies: - prelude-ls: "npm:~1.1.2" - checksum: 10c0/776217116b2b4e50e368c7ee0c22c0a85e982881c16965b90d52f216bc296d6a52ef74f9202d22158caacc092a7645b0b8d5fe529a96e3fe35d0fb393966c875 + call-bound: "npm:^1.0.2" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.5" + object-inspect: "npm:^1.13.3" + side-channel-map: "npm:^1.0.1" + checksum: 10c0/71362709ac233e08807ccd980101c3e2d7efe849edc51455030327b059f6c4d292c237f94dc0685031dd11c07dd17a68afde235d6cf2102d949567f98ab58185 languageName: node linkType: hard -"type-detect@npm:4.0.8, type-detect@npm:^4.0.0, type-detect@npm:^4.0.5": - version: 4.0.8 - resolution: "type-detect@npm:4.0.8" - checksum: 10c0/8fb9a51d3f365a7de84ab7f73b653534b61b622aa6800aecdb0f1095a4a646d3f5eb295322127b6573db7982afcd40ab492d038cf825a42093a58b1e1353e0bd +"side-channel@npm:^1.1.1": + version: 1.1.1 + resolution: "side-channel@npm:1.1.1" + dependencies: + es-errors: "npm:^1.3.0" + object-inspect: "npm:^1.13.4" + side-channel-list: "npm:^1.0.1" + side-channel-map: "npm:^1.0.1" + side-channel-weakmap: "npm:^1.0.2" + checksum: 10c0/dc0ab81d67f61bda9247d053ce93f41c3fd8ad2bdcb9cf9d8d2f8540d488f26d87a5e99ebfc07eea49ec025867b2452b705442d974b1478f0395e69f6bfb3270 languageName: node linkType: hard -"type-fest@npm:^0.20.2": - version: 0.20.2 - resolution: "type-fest@npm:0.20.2" - checksum: 10c0/dea9df45ea1f0aaa4e2d3bed3f9a0bfe9e5b2592bddb92eb1bf06e50bcf98dbb78189668cd8bc31a0511d3fc25539b4cd5c704497e53e93e2d40ca764b10bfc3 +"signal-exit@npm:^3.0.2": + version: 3.0.7 + resolution: "signal-exit@npm:3.0.7" + checksum: 10c0/25d272fa73e146048565e08f3309d5b942c1979a6f4a58a8c59d5fa299728e9c2fcd1a759ec870863b1fd38653670240cd420dad2ad9330c71f36608a6a1c912 languageName: node linkType: hard -"type-fest@npm:^0.21.3": - version: 0.21.3 - resolution: "type-fest@npm:0.21.3" - checksum: 10c0/902bd57bfa30d51d4779b641c2bc403cdf1371fb9c91d3c058b0133694fcfdb817aef07a47f40faf79039eecbaa39ee9d3c532deff244f3a19ce68cea71a61e8 +"signal-exit@npm:^4.0.1": + version: 4.1.0 + resolution: "signal-exit@npm:4.1.0" + checksum: 10c0/41602dce540e46d599edba9d9860193398d135f7ff72cab629db5171516cfae628d21e7bfccde1bbfdf11c48726bc2a6d1a8fb8701125852fbfda7cf19c6aa83 languageName: node linkType: hard -"type-fest@npm:^0.7.1": - version: 0.7.1 - resolution: "type-fest@npm:0.7.1" - checksum: 10c0/ce6b5ef806a76bf08d0daa78d65e61f24d9a0380bd1f1df36ffb61f84d14a0985c3a921923cf4b97831278cb6fa9bf1b89c751df09407e0510b14e8c081e4e0f +"sisteransi@npm:^1.0.5": + version: 1.0.5 + resolution: "sisteransi@npm:1.0.5" + checksum: 10c0/230ac975cca485b7f6fe2b96a711aa62a6a26ead3e6fb8ba17c5a00d61b8bed0d7adc21f5626b70d7c33c62ff4e63933017a6462942c719d1980bb0b1207ad46 languageName: node linkType: hard -"type-is@npm:~1.6.18": - version: 1.6.18 - resolution: "type-is@npm:1.6.18" +"slice-ansi@npm:^4.0.0": + version: 4.0.0 + resolution: "slice-ansi@npm:4.0.0" dependencies: - media-typer: "npm:0.3.0" - mime-types: "npm:~2.1.24" - checksum: 10c0/a23daeb538591b7efbd61ecf06b6feb2501b683ffdc9a19c74ef5baba362b4347e42f1b4ed81f5882a8c96a3bfff7f93ce3ffaf0cbbc879b532b04c97a55db9d + ansi-styles: "npm:^4.0.0" + astral-regex: "npm:^2.0.0" + is-fullwidth-code-point: "npm:^3.0.0" + checksum: 10c0/6c25678db1270d4793e0327620f1e0f9f5bea4630123f51e9e399191bc52c87d6e6de53ed33538609e5eacbd1fab769fae00f3705d08d029f02102a540648918 languageName: node linkType: hard -"type@npm:^1.0.1": - version: 1.2.0 - resolution: "type@npm:1.2.0" - checksum: 10c0/444660849aaebef8cbb9bc43b28ec2068952064cfce6a646f88db97aaa2e2d6570c5629cd79238b71ba23aa3f75146a0b96e24e198210ee0089715a6f8889bf7 +"smart-buffer@npm:^4.2.0": + version: 4.2.0 + resolution: "smart-buffer@npm:4.2.0" + checksum: 10c0/a16775323e1404dd43fabafe7460be13a471e021637bc7889468eb45ce6a6b207261f454e4e530a19500cc962c4cc5348583520843b363f4193cee5c00e1e539 languageName: node linkType: hard -"type@npm:^2.7.2": - version: 2.7.2 - resolution: "type@npm:2.7.2" - checksum: 10c0/84c2382788fe24e0bc3d64c0c181820048f672b0f06316aa9c7bdb373f8a09f8b5404f4e856bc4539fb931f2f08f2adc4c53f6c08c9c0314505d70c29a1289e1 +"socks-proxy-agent@npm:^8.0.3": + version: 8.0.5 + resolution: "socks-proxy-agent@npm:8.0.5" + dependencies: + agent-base: "npm:^7.1.2" + debug: "npm:^4.3.4" + socks: "npm:^2.8.3" + checksum: 10c0/5d2c6cecba6821389aabf18728325730504bf9bb1d9e342e7987a5d13badd7a98838cc9a55b8ed3cb866ad37cc23e1086f09c4d72d93105ce9dfe76330e9d2a6 languageName: node linkType: hard -"typechain@npm:^3.0.0": - version: 3.0.0 - resolution: "typechain@npm:3.0.0" +"socks@npm:^2.8.3": + version: 2.8.7 + resolution: "socks@npm:2.8.7" dependencies: - command-line-args: "npm:^4.0.7" - debug: "npm:^4.1.1" - fs-extra: "npm:^7.0.0" - js-sha3: "npm:^0.8.0" - lodash: "npm:^4.17.15" - ts-essentials: "npm:^6.0.3" - ts-generator: "npm:^0.1.1" - bin: - typechain: ./dist/cli/cli.js - checksum: 10c0/2de8431d128da6ff3eaedea445a9398988c68111751e0147b96161bf8d8fc2f538a595c9e4078625fa01cd98cb2d939d574d9d7db8cf5a97eaa18e69cf645c08 + ip-address: "npm:^10.0.1" + smart-buffer: "npm:^4.2.0" + checksum: 10c0/2805a43a1c4bcf9ebf6e018268d87b32b32b06fbbc1f9282573583acc155860dc361500f89c73bfbb157caa1b4ac78059eac0ef15d1811eb0ca75e0bdadbc9d2 languageName: node linkType: hard -"typechain@npm:^7.0.0": - version: 7.0.0 - resolution: "typechain@npm:7.0.0" +"solc@npm:0.8.26": + version: 0.8.26 + resolution: "solc@npm:0.8.26" dependencies: - "@types/prettier": "npm:^2.1.1" - debug: "npm:^4.1.1" - fs-extra: "npm:^7.0.0" - glob: "npm:^7.1.6" - js-sha3: "npm:^0.8.0" - lodash: "npm:^4.17.15" - mkdirp: "npm:^1.0.4" - prettier: "npm:^2.1.2" - ts-command-line-args: "npm:^2.2.0" - ts-essentials: "npm:^7.0.1" - peerDependencies: - typescript: ">=4.1.0" + command-exists: "npm:^1.2.8" + commander: "npm:^8.1.0" + follow-redirects: "npm:^1.12.1" + js-sha3: "npm:0.8.0" + memorystream: "npm:^0.3.1" + semver: "npm:^5.5.0" + tmp: "npm:0.0.33" bin: - typechain: dist/cli/cli.js - checksum: 10c0/b8a724f019cd6886c82f982aeb43ec1055cb64ab87a3c86452704677a334d193a3b0014a1fc82813af385e9c4ad959742085cd0b3f4d955e6630fb701a69672e + solcjs: solc.js + checksum: 10c0/1eea35da99c228d0dc1d831c29f7819e7921b67824c889a5e5f2e471a2ef5856a15fabc0b5de067f5ba994fa36fb5a563361963646fe98dad58a0e4fa17c8b2d languageName: node linkType: hard -"typedarray-to-buffer@npm:^3.1.5": - version: 3.1.5 - resolution: "typedarray-to-buffer@npm:3.1.5" +"solhint@npm:^6.2.4": + version: 6.2.4 + resolution: "solhint@npm:6.2.4" dependencies: - is-typedarray: "npm:^1.0.0" - checksum: 10c0/4ac5b7a93d604edabf3ac58d3a2f7e07487e9f6e98195a080e81dbffdc4127817f470f219d794a843b87052cedef102b53ac9b539855380b8c2172054b7d5027 + "@solidity-parser/parser": "npm:^0.20.2" + ajv: "npm:^8.18.0" + ast-parents: "npm:^0.0.1" + better-ajv-errors: "npm:^2.0.2" + chalk: "npm:^4.1.2" + commander: "npm:^10.0.0" + cosmiconfig: "npm:^8.0.0" + fast-diff: "npm:^1.2.0" + glob: "npm:^13.0.6" + ignore: "npm:^5.2.4" + js-yaml: "npm:^4.1.0" + latest-version: "npm:^7.0.0" + lodash: "npm:^4.17.21" + pluralize: "npm:^8.0.0" + prettier: "npm:^3.0.0" + semver: "npm:^7.5.2" + table: "npm:^6.8.1" + text-table: "npm:^0.2.0" + dependenciesMeta: + prettier: + optional: true + bin: + solhint: solhint.js + checksum: 10c0/7d30963faeb3a542904abdda722d50507314efea6d862169a6be8648b28572f02808c786014b84b039c02033f0096662c0f31428749565fb3f774c8cd173a384 languageName: node linkType: hard -"typedarray@npm:^0.0.6": - version: 0.0.6 - resolution: "typedarray@npm:0.0.6" - checksum: 10c0/6005cb31df50eef8b1f3c780eb71a17925f3038a100d82f9406ac2ad1de5eb59f8e6decbdc145b3a1f8e5836e17b0c0002fb698b9fe2516b8f9f9ff602d36412 +"solidity-ast@npm:^0.4.38": + version: 0.4.46 + resolution: "solidity-ast@npm:0.4.46" + checksum: 10c0/3c0cf84f98b9af7faa5458a3d5d6fae2f6582db7005dbf4fb614ec6eab3cf3600eb62f025cb3f491f11b11ca2858c458fc88cf7abc1c2e964366c5a647efdc17 languageName: node linkType: hard -"typescript@npm:^4.4.3": - version: 4.4.3 - resolution: "typescript@npm:4.4.3" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 10c0/91ad8993cb9292d8117b537b894501995d1d8b9473b93bdd406749b0b9d59406b97c5d79364dfdac2033e266a67aea318d9b17b1560479e628c60bbec3dcd358 +"solidity-ast@npm:^0.4.60": + version: 0.4.62 + resolution: "solidity-ast@npm:0.4.62" + checksum: 10c0/8f9bfb41dddaa68e48d8620785cae43583a6711e79b132d3110f8cbf8f028a41004ca6ff8a3896f1e7f408932efb28b9f0390a67e729c12033ec95895430efeb languageName: node linkType: hard -"typescript@patch:typescript@npm%3A^4.4.3#optional!builtin": - version: 4.4.3 - resolution: "typescript@patch:typescript@npm%3A4.4.3#optional!builtin::version=4.4.3&hash=bbeadb" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 10c0/9051000445e39cc44d90f2e7e1e57d4f8d8b802103b80d66971d89182696047314cc1b11eb6f59ec3244e6cbaebc3b4bb31e72944d3d3f67c7be416d6d300702 +"solidity-docgen@npm:^0.6.0-beta.35": + version: 0.6.0-beta.35 + resolution: "solidity-docgen@npm:0.6.0-beta.35" + dependencies: + handlebars: "npm:^4.7.7" + solidity-ast: "npm:^0.4.38" + peerDependencies: + hardhat: ^2.8.0 + checksum: 10c0/d44ab7b12309c2dd89b039f695d4248827fe2cbcb26d7d6083c70a4687337a089edfb338f33f27ee4a4e1c03d9b5fb993a81e63bff174c9612e7d5248bf9e659 languageName: node linkType: hard -"typewise-core@npm:^1.2, typewise-core@npm:^1.2.0": - version: 1.2.0 - resolution: "typewise-core@npm:1.2.0" - checksum: 10c0/0c574b036e430ef29a3c71dca1f88c041597734448db50e697ec4b7d03d71af4f8afeec556a2553f7db1cf98f9313b983071f0731d784108b2daf4f2e0c37d9e +"source-map-support@npm:^0.5.13": + version: 0.5.20 + resolution: "source-map-support@npm:0.5.20" + dependencies: + buffer-from: "npm:^1.0.0" + source-map: "npm:^0.6.0" + checksum: 10c0/84a909248b1b7971d37fde1f2488a5e3b7aa2d676f92373a8bddcf5b059574d09971b82d2911ae91feb8245f9f2b0e0766f73b9c51ffb26c0fd2df5d44938307 languageName: node linkType: hard -"typewise@npm:^1.0.3": - version: 1.0.3 - resolution: "typewise@npm:1.0.3" - dependencies: - typewise-core: "npm:^1.2.0" - checksum: 10c0/0e300a963cd344f9f4216343eb1c9714e1aee12c5b928ae3ff4a19b4b1edcd82356b8bd763905bd72528718a3c863612f8259cb047934b59bdd849f305e12e80 +"source-map@npm:^0.6.0, source-map@npm:^0.6.1": + version: 0.6.1 + resolution: "source-map@npm:0.6.1" + checksum: 10c0/ab55398007c5e5532957cb0beee2368529618ac0ab372d789806f5718123cc4367d57de3904b4e6a4170eb5a0b0f41373066d02ca0735a0c4d75c7d328d3e011 languageName: node linkType: hard -"typewiselite@npm:~1.0.0": - version: 1.0.0 - resolution: "typewiselite@npm:1.0.0" - checksum: 10c0/f4b85fdc0016d05049d016207bd76283f7734a9644ca95638a686cd0d78d0fbcf9dfde81270e24ad97aed63cbf5592fe0163df694df180e865f1c85a237c85a6 +"ssri@npm:^13.0.0": + version: 13.0.1 + resolution: "ssri@npm:13.0.1" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10c0/cf6408a18676c57ff2ed06b8a20dc64bb3e748e5c7e095332e6aecaa2b8422b1e94a739a8453bf65156a8a47afe23757ba4ab52d3ea3b62322dc40875763e17a languageName: node linkType: hard -"typical@npm:^2.6.0, typical@npm:^2.6.1": - version: 2.6.1 - resolution: "typical@npm:2.6.1" - checksum: 10c0/b3dee3aa4e8bbc2821c95dc98cb4618cac47735a399b0b24594f541049593381c5e01ff1ce3a35c9ebb3166ebd3edc62a3f6e34a99ccd2bdf20f205597f0df99 +"stable-hash-x@npm:^0.2.0": + version: 0.2.0 + resolution: "stable-hash-x@npm:0.2.0" + checksum: 10c0/c757df58366ee4bb266a9486b8932eab7c1ba730469eaf4b68d2dee404814e9f84089c44c9b5205f8c7d99a0ab036cce2af69139ce5ed44b635923c011a8aea8 languageName: node linkType: hard -"typical@npm:^4.0.0": - version: 4.0.0 - resolution: "typical@npm:4.0.0" - checksum: 10c0/f300b198fb9fe743859b75ec761d53c382723dc178bbce4957d9cb754f2878a44ce17dc0b6a5156c52be1065449271f63754ba594dac225b80ce3aa39f9241ed +"stacktrace-parser@npm:^0.1.10": + version: 0.1.10 + resolution: "stacktrace-parser@npm:0.1.10" + dependencies: + type-fest: "npm:^0.7.1" + checksum: 10c0/f9c9cd55b0642a546e5f0516a87124fc496dcc2c082b96b156ed094c51e423314795cd1839cd4c59026349cf392d3414f54fc42165255602728588a58a9f72d3 languageName: node linkType: hard -"typical@npm:^5.2.0": - version: 5.2.0 - resolution: "typical@npm:5.2.0" - checksum: 10c0/1cceaa20d4b77a02ab8eccfe4a20500729431aecc1e1b7dc70c0e726e7966efdca3bf0b4bee285555b751647e37818fd99154ea73f74b5c29adc95d3c13f5973 +"statuses@npm:>= 1.5.0 < 2": + version: 1.5.0 + resolution: "statuses@npm:1.5.0" + checksum: 10c0/e433900956357b3efd79b1c547da4d291799ac836960c016d10a98f6a810b1b5c0dcc13b5a7aa609a58239b5190e1ea176ad9221c2157d2fd1c747393e6b2940 languageName: node linkType: hard -"uglify-js@npm:^3.1.4": - version: 3.17.4 - resolution: "uglify-js@npm:3.17.4" - bin: - uglifyjs: bin/uglifyjs - checksum: 10c0/8b7fcdca69deb284fed7d2025b73eb747ce37f9aca6af53422844f46427152d5440601b6e2a033e77856a2f0591e4167153d5a21b68674ad11f662034ec13ced +"string-format@npm:^2.0.0": + version: 2.0.0 + resolution: "string-format@npm:2.0.0" + checksum: 10c0/7bca13ba9f942f635c74d637da5e9e375435cbd428f35eeef28c3a30f81d4e63b95ff2c6cca907d897dd3951bbf52e03e3b945a0e9681358e33bd67222436538 languageName: node linkType: hard -"ultron@npm:~1.1.0": - version: 1.1.1 - resolution: "ultron@npm:1.1.1" - checksum: 10c0/527d7f687012898e3af8d646936ecba776a7099ef8d3d983f9b3ccd5e84e266af0f714d859be15090b55b93f331bb95e5798bce555d9bb08e2f4bf2faac16517 +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.0.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.2, string-width@npm:^4.2.3": + version: 4.2.3 + resolution: "string-width@npm:4.2.3" + dependencies: + emoji-regex: "npm:^8.0.0" + is-fullwidth-code-point: "npm:^3.0.0" + strip-ansi: "npm:^6.0.1" + checksum: 10c0/1e525e92e5eae0afd7454086eed9c818ee84374bb80328fc41217ae72ff5f065ef1c9d7f72da41de40c75fa8bb3dee63d92373fd492c84260a552c636392a47b languageName: node linkType: hard -"unbox-primitive@npm:^1.0.1": - version: 1.0.1 - resolution: "unbox-primitive@npm:1.0.1" +"string-width@npm:^5.0.1, string-width@npm:^5.1.2": + version: 5.1.2 + resolution: "string-width@npm:5.1.2" dependencies: - function-bind: "npm:^1.1.1" - has-bigints: "npm:^1.0.1" - has-symbols: "npm:^1.0.2" - which-boxed-primitive: "npm:^1.0.2" - checksum: 10c0/6f0b91b0744c6f9fd05afa70484914b70686596be628543a143fab018733f902ff39fad2c3cf8f00fd5d32ba8bce8edf9cf61cee940c1af892316e112b25812b + eastasianwidth: "npm:^0.2.0" + emoji-regex: "npm:^9.2.2" + strip-ansi: "npm:^7.0.1" + checksum: 10c0/ab9c4264443d35b8b923cbdd513a089a60de339216d3b0ed3be3ba57d6880e1a192b70ae17225f764d7adbf5994e9bb8df253a944736c15a0240eff553c678ca languageName: node linkType: hard -"underscore@npm:1.9.1": - version: 1.9.1 - resolution: "underscore@npm:1.9.1" - checksum: 10c0/63415f33b1ba4d7f8a9c8bdd00d457ce7ebdfcb9b1bf9dd596d7550550a790986e5ce7f2319d5e5076dbd56c4a359ebd3c914dd98f6eb33122d41fd439fcb4fa +"string_decoder@npm:^1.1.1": + version: 1.3.0 + resolution: "string_decoder@npm:1.3.0" + dependencies: + safe-buffer: "npm:~5.2.0" + checksum: 10c0/810614ddb030e271cd591935dcd5956b2410dd079d64ff92a1844d6b7588bf992b3e1b69b0f4d34a3e06e0bd73046ac646b5264c1987b20d0601f81ef35d731d languageName: node linkType: hard -"undici@npm:^5.14.0": - version: 5.29.0 - resolution: "undici@npm:5.29.0" +"strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": + version: 6.0.1 + resolution: "strip-ansi@npm:6.0.1" dependencies: - "@fastify/busboy": "npm:^2.0.0" - checksum: 10c0/e4e4d631ca54ee0ad82d2e90e7798fa00a106e27e6c880687e445cc2f13b4bc87c5eba2a88c266c3eecffb18f26e227b778412da74a23acc374fca7caccec49b + ansi-regex: "npm:^5.0.1" + checksum: 10c0/1ae5f212a126fe5b167707f716942490e3933085a5ff6c008ab97ab2f272c8025d3aa218b7bd6ab25729ca20cc81cddb252102f8751e13482a5199e873680952 languageName: node linkType: hard -"undici@npm:^5.4.0": - version: 5.19.1 - resolution: "undici@npm:5.19.1" +"strip-ansi@npm:^7.0.1": + version: 7.2.0 + resolution: "strip-ansi@npm:7.2.0" dependencies: - busboy: "npm:^1.6.0" - checksum: 10c0/1a3d452532c4e8a668c66af69ed17fe6d4568b1745401eb814177f48b297d21cebdeaa07307aa9d07e629541e9dd71d0395b8c28bc7020dc61fa4fc0a1a4e336 + ansi-regex: "npm:^6.2.2" + checksum: 10c0/544d13b7582f8254811ea97db202f519e189e59d35740c46095897e254e4f1aa9fe1524a83ad6bc5ad67d4dd6c0281d2e0219ed62b880a6238a16a17d375f221 languageName: node linkType: hard -"union-value@npm:^1.0.0": - version: 1.0.1 - resolution: "union-value@npm:1.0.1" - dependencies: - arr-union: "npm:^3.1.0" - get-value: "npm:^2.0.6" - is-extendable: "npm:^0.1.1" - set-value: "npm:^2.0.1" - checksum: 10c0/8758d880cb9545f62ce9cfb9b791b2b7a206e0ff5cc4b9d7cd6581da2c6839837fbb45e639cf1fd8eef3cae08c0201b614b7c06dd9f5f70d9dbe7c5fe2fbf592 +"strip-json-comments@npm:^3.1.1": + version: 3.1.1 + resolution: "strip-json-comments@npm:3.1.1" + checksum: 10c0/9681a6257b925a7fa0f285851c0e613cc934a50661fa7bb41ca9cbbff89686bb4a0ee366e6ecedc4daafd01e83eee0720111ab294366fe7c185e935475ebcecd languageName: node linkType: hard -"universalify@npm:^0.1.0": - version: 0.1.2 - resolution: "universalify@npm:0.1.2" - checksum: 10c0/e70e0339f6b36f34c9816f6bf9662372bd241714dc77508d231d08386d94f2c4aa1ba1318614f92015f40d45aae1b9075cd30bd490efbe39387b60a76ca3f045 +"strip-json-comments@npm:~2.0.1": + version: 2.0.1 + resolution: "strip-json-comments@npm:2.0.1" + checksum: 10c0/b509231cbdee45064ff4f9fd73609e2bcc4e84a4d508e9dd0f31f70356473fde18abfb5838c17d56fb236f5a06b102ef115438de0600b749e818a35fbbc48c43 languageName: node linkType: hard -"universalify@npm:^2.0.0": - version: 2.0.0 - resolution: "universalify@npm:2.0.0" - checksum: 10c0/07092b9f46df61b823d8ab5e57f0ee5120c178b39609a95e4a15a98c42f6b0b8e834e66fbb47ff92831786193be42f1fd36347169b88ce8639d0f9670af24a71 +"supports-color@npm:^5.3.0": + version: 5.5.0 + resolution: "supports-color@npm:5.5.0" + dependencies: + has-flag: "npm:^3.0.0" + checksum: 10c0/6ae5ff319bfbb021f8a86da8ea1f8db52fac8bd4d499492e30ec17095b58af11f0c55f8577390a749b1c4dde691b6a0315dab78f5f54c9b3d83f8fb5905c1c05 languageName: node linkType: hard -"unorm@npm:^1.3.3": - version: 1.6.0 - resolution: "unorm@npm:1.6.0" - checksum: 10c0/ff0caa3292f318e2e832d02ad019a401118fe42f5e554dca3b9c7e4a2a3100eda051945711234a6ffbd74088cf51930755782456d30864240936cb3485f80a01 +"supports-color@npm:^7.1.0": + version: 7.2.0 + resolution: "supports-color@npm:7.2.0" + dependencies: + has-flag: "npm:^4.0.0" + checksum: 10c0/afb4c88521b8b136b5f5f95160c98dee7243dc79d5432db7efc27efb219385bbc7d9427398e43dd6cc730a0f87d5085ce1652af7efbe391327bc0a7d0f7fc124 languageName: node linkType: hard -"unpipe@npm:1.0.0, unpipe@npm:~1.0.0": - version: 1.0.0 - resolution: "unpipe@npm:1.0.0" - checksum: 10c0/193400255bd48968e5c5383730344fbb4fa114cdedfab26e329e50dd2d81b134244bb8a72c6ac1b10ab0281a58b363d06405632c9d49ca9dfd5e90cbd7d0f32c +"supports-color@npm:^8.1.1": + version: 8.1.1 + resolution: "supports-color@npm:8.1.1" + dependencies: + has-flag: "npm:^4.0.0" + checksum: 10c0/ea1d3c275dd604c974670f63943ed9bd83623edc102430c05adb8efc56ba492746b6e95386e7831b872ec3807fd89dd8eb43f735195f37b5ec343e4234cc7e89 languageName: node linkType: hard -"unset-value@npm:^1.0.0": - version: 1.0.0 - resolution: "unset-value@npm:1.0.0" +"table-layout@npm:^1.0.1": + version: 1.0.2 + resolution: "table-layout@npm:1.0.2" dependencies: - has-value: "npm:^0.3.1" - isobject: "npm:^3.0.0" - checksum: 10c0/68a796dde4a373afdbf017de64f08490a3573ebee549136da0b3a2245299e7f65f647ef70dc13c4ac7f47b12fba4de1646fa0967a365638578fedce02b9c0b1f + array-back: "npm:^4.0.1" + deep-extend: "npm:~0.6.0" + typical: "npm:^5.2.0" + wordwrapjs: "npm:^4.0.0" + checksum: 10c0/c1d16d5ba2199571606ff574a5c91cff77f14e8477746e191e7dfd294da03e61af4e8004f1f6f783da9582e1365f38d3c469980428998750d558bf29462cc6c3 languageName: node linkType: hard -"untildify@npm:^4.0.0": - version: 4.0.0 - resolution: "untildify@npm:4.0.0" - checksum: 10c0/d758e624c707d49f76f7511d75d09a8eda7f2020d231ec52b67ff4896bcf7013be3f9522d8375f57e586e9a2e827f5641c7e06ee46ab9c435fc2b2b2e9de517a +"table@npm:^6.8.0": + version: 6.8.0 + resolution: "table@npm:6.8.0" + dependencies: + ajv: "npm:^8.0.1" + lodash.truncate: "npm:^4.4.2" + slice-ansi: "npm:^4.0.0" + string-width: "npm:^4.2.3" + strip-ansi: "npm:^6.0.1" + checksum: 10c0/e03ba3ea1d625368d196eeedebaf0df072bbd8ce1604fd149cd5f3d988487062dda016638099df952bb28cefc3418ab108fcf0084bef7a9121d20985d6358298 languageName: node linkType: hard -"uri-js@npm:^4.2.2": - version: 4.4.1 - resolution: "uri-js@npm:4.4.1" +"table@npm:^6.8.1": + version: 6.9.0 + resolution: "table@npm:6.9.0" dependencies: - punycode: "npm:^2.1.0" - checksum: 10c0/4ef57b45aa820d7ac6496e9208559986c665e49447cb072744c13b66925a362d96dd5a46c4530a6b8e203e5db5fe849369444440cb22ecfc26c679359e5dfa3c + ajv: "npm:^8.0.1" + lodash.truncate: "npm:^4.4.2" + slice-ansi: "npm:^4.0.0" + string-width: "npm:^4.2.3" + strip-ansi: "npm:^6.0.1" + checksum: 10c0/35646185712bb65985fbae5975dda46696325844b78735f95faefae83e86df0a265277819a3e67d189de6e858c509b54e66ca3958ffd51bde56ef1118d455bf4 languageName: node linkType: hard -"urix@npm:^0.1.0": - version: 0.1.0 - resolution: "urix@npm:0.1.0" - checksum: 10c0/264f1b29360c33c0aec5fb9819d7e28f15d1a3b83175d2bcc9131efe8583f459f07364957ae3527f1478659ec5b2d0f1ad401dfb625f73e4d424b3ae35fc5fc0 +"tar@npm:^7.5.4": + version: 7.5.13 + resolution: "tar@npm:7.5.13" + dependencies: + "@isaacs/fs-minipass": "npm:^4.0.0" + chownr: "npm:^3.0.0" + minipass: "npm:^7.1.2" + minizlib: "npm:^3.1.0" + yallist: "npm:^5.0.0" + checksum: 10c0/5c65b8084799bde7a791593a1c1a45d3d6ee98182e3700b24c247b7b8f8654df4191642abbdb07ff25043d45dcff35620827c3997b88ae6c12040f64bed5076b languageName: node linkType: hard -"url-parse-lax@npm:^1.0.0": - version: 1.0.0 - resolution: "url-parse-lax@npm:1.0.0" +"tenderly@npm:^0.8.0": + version: 0.8.0 + resolution: "tenderly@npm:0.8.0" dependencies: - prepend-http: "npm:^1.0.1" - checksum: 10c0/7578d90d18297c0896ab3c98350b61b59be56211baad543ea55eb570dfbd403b0987e499a817abb55d755df6f47ec2e748a49bd09f8d39766066a6871853cea1 + axios: "npm:^0.27.2" + cli-table3: "npm:^0.6.2" + commander: "npm:^9.4.0" + js-yaml: "npm:^4.1.0" + open: "npm:^8.4.0" + prompts: "npm:^2.4.2" + tslog: "npm:^4.4.0" + peerDependencies: + ts-node: "*" + typescript: "*" + peerDependenciesMeta: + ts-node: + optional: true + typescript: + optional: true + checksum: 10c0/090d3a526d9881968a1bb4f6d2fbe33db3a00677adfcf05ae54c7a585cab14760651982d0a5ded3caa9efdc3f6744cbf55abfcca74e4713941f2167be76cbfea languageName: node linkType: hard -"url-parse-lax@npm:^3.0.0": - version: 3.0.0 - resolution: "url-parse-lax@npm:3.0.0" - dependencies: - prepend-http: "npm:^2.0.0" - checksum: 10c0/16f918634d41a4fab9e03c5f9702968c9930f7c29aa1a8c19a6dc01f97d02d9b700ab9f47f8da0b9ace6e0c0e99c27848994de1465b494bced6940c653481e55 +"text-table@npm:^0.2.0": + version: 0.2.0 + resolution: "text-table@npm:0.2.0" + checksum: 10c0/02805740c12851ea5982686810702e2f14369a5f4c5c40a836821e3eefc65ffeec3131ba324692a37608294b0fd8c1e55a2dd571ffed4909822787668ddbee5c languageName: node linkType: hard -"url-set-query@npm:^1.0.0": - version: 1.0.0 - resolution: "url-set-query@npm:1.0.0" - checksum: 10c0/88f52b16b213598763aafe1128f0b48d080d6b63b4f735c01b87effe4e21c463ba6df5c075499bc03c6af1357728b287d629c3d15b4a895c0c87dad8913fccef +"tinyglobby@npm:^0.2.12": + version: 0.2.16 + resolution: "tinyglobby@npm:0.2.16" + dependencies: + fdir: "npm:^6.5.0" + picomatch: "npm:^4.0.4" + checksum: 10c0/f2e09fd93dd95c41e522113b686ff6f7c13020962f8698a864a257f3d7737599afc47722b7ab726e12f8a813f779906187911ff8ee6701ede65072671a7e934b languageName: node linkType: hard -"url-to-options@npm:^1.0.1": - version: 1.0.1 - resolution: "url-to-options@npm:1.0.1" - checksum: 10c0/3d8143bbc2ab0ead3cbc0c60803c274847bf69aa3ef8b2b77a7d58b1739de01efbfbcd7d7b15c8b6b540bb266ae10895a50a1477ce2d9895dfa2c67243e39c51 +"tinyglobby@npm:^0.2.14, tinyglobby@npm:^0.2.15, tinyglobby@npm:^0.2.6": + version: 0.2.17 + resolution: "tinyglobby@npm:0.2.17" + dependencies: + fdir: "npm:^6.5.0" + picomatch: "npm:^4.0.4" + checksum: 10c0/7f7bb0f197c88bc4b20c231e0deca4240ca3bf313a88f5a7fee93a872b84966a4d50220947c0455ad07a60b3b360961c5b7fd979222aeb716a9f99b412002e4c languageName: node linkType: hard -"url@npm:^0.11.0": - version: 0.11.0 - resolution: "url@npm:0.11.0" +"tmp@npm:0.0.33": + version: 0.0.33 + resolution: "tmp@npm:0.0.33" dependencies: - punycode: "npm:1.3.2" - querystring: "npm:0.2.0" - checksum: 10c0/bbe05f9f570ec5c06421c50ca63f287e61279092eed0891db69a9619323703ccd3987e6eed234c468794cf25680c599680d5c1f58d26090f1956c8e9ed8346a2 + os-tmpdir: "npm:~1.0.2" + checksum: 10c0/69863947b8c29cabad43fe0ce65cec5bb4b481d15d4b4b21e036b060b3edbf3bc7a5541de1bacb437bb3f7c4538f669752627fdf9b4aaf034cebd172ba373408 languageName: node linkType: hard -"use@npm:^3.1.0": - version: 3.1.1 - resolution: "use@npm:3.1.1" - checksum: 10c0/75b48673ab80d5139c76922630d5a8a44e72ed58dbaf54dee1b88352d10e1c1c1fc332066c782d8ae9a56503b85d3dc67ff6d2ffbd9821120466d1280ebb6d6e +"to-regex-range@npm:^5.0.1": + version: 5.0.1 + resolution: "to-regex-range@npm:5.0.1" + dependencies: + is-number: "npm:^7.0.0" + checksum: 10c0/487988b0a19c654ff3e1961b87f471702e708fa8a8dd02a298ef16da7206692e8552a0250e8b3e8759270f62e9d8314616f6da274734d3b558b1fc7b7724e892 languageName: node linkType: hard -"utf-8-validate@npm:^5.0.2": - version: 5.0.6 - resolution: "utf-8-validate@npm:5.0.6" - dependencies: - node-gyp: "npm:latest" - node-gyp-build: "npm:^4.2.0" - checksum: 10c0/93709b5c55fa53c51295e6de3ebebdf6fdbd4e2c16dd217e59bd13b36f75d85d1c3096acd97f0e90cf1f39a72def684a9ba9e3039e20814258ebb89621a55533 +"toidentifier@npm:1.0.0": + version: 1.0.0 + resolution: "toidentifier@npm:1.0.0" + checksum: 10c0/27a37b8b21126e7216d40c02f410065b1de35b0f844368d0ccaabba7987595703006d45e5c094b086220cbbc5864d4b99766b460110e4bc15b9db574c5c58be2 languageName: node linkType: hard -"utf8@npm:3.0.0, utf8@npm:^3.0.0": - version: 3.0.0 - resolution: "utf8@npm:3.0.0" - checksum: 10c0/675d008bab65fc463ce718d5cae8fd4c063540f269e4f25afebce643098439d53e7164bb1f193e0c3852825c7e3e32fbd8641163d19a618dbb53f1f09acb0d5a +"tr46@npm:~0.0.3": + version: 0.0.3 + resolution: "tr46@npm:0.0.3" + checksum: 10c0/047cb209a6b60c742f05c9d3ace8fa510bff609995c129a37ace03476a9b12db4dbf975e74600830ef0796e18882b2381fb5fb1f6b4f96b832c374de3ab91a11 languageName: node linkType: hard -"util-deprecate@npm:^1.0.1, util-deprecate@npm:~1.0.1": - version: 1.0.2 - resolution: "util-deprecate@npm:1.0.2" - checksum: 10c0/41a5bdd214df2f6c3ecf8622745e4a366c4adced864bc3c833739791aeeeb1838119af7daed4ba36428114b5c67dcda034a79c882e97e43c03e66a4dd7389942 +"ts-api-utils@npm:^2.5.0": + version: 2.5.0 + resolution: "ts-api-utils@npm:2.5.0" + peerDependencies: + typescript: ">=4.8.4" + checksum: 10c0/767849383c114e7f1971fa976b20e73ac28fd0c70d8d65c0004790bf4d8f89888c7e4cf6d5949f9c1beae9bc3c64835bef77bbe27fddf45a3c7b60cebcf85c8c languageName: node linkType: hard -"util.promisify@npm:^1.0.0": - version: 1.1.1 - resolution: "util.promisify@npm:1.1.1" +"ts-command-line-args@npm:^2.2.0": + version: 2.2.1 + resolution: "ts-command-line-args@npm:2.2.1" dependencies: - call-bind: "npm:^1.0.0" - define-properties: "npm:^1.1.3" - for-each: "npm:^0.3.3" - has-symbols: "npm:^1.0.1" - object.getownpropertydescriptors: "npm:^2.1.1" - checksum: 10c0/aacccbf770c667430ca3b7fce9a2a04a80fcd1f9f4de5507ea54cc3bbbcdcd33cbd2501ac23d1c477c5c40817234f6068b89cf7792f0610fe6e7df7ac0fe83ce + chalk: "npm:^4.1.0" + command-line-args: "npm:^5.1.1" + command-line-usage: "npm:^6.1.0" + string-format: "npm:^2.0.0" + bin: + write-markdown: dist/write-markdown.js + checksum: 10c0/6e925ea38ffa727644bd121f3af5399653c5a79d3069dabe6c826c9226ed4affce40ed91acbdc1b3235b93450183eb5b3795d23844a10e78d280ae4e78345997 languageName: node linkType: hard -"utils-merge@npm:1.0.1": - version: 1.0.1 - resolution: "utils-merge@npm:1.0.1" - checksum: 10c0/02ba649de1b7ca8854bfe20a82f1dfbdda3fb57a22ab4a8972a63a34553cf7aa51bc9081cf7e001b035b88186d23689d69e71b510e610a09a4c66f68aa95b672 +"ts-essentials@npm:^7.0.1": + version: 7.0.3 + resolution: "ts-essentials@npm:7.0.3" + peerDependencies: + typescript: ">=3.7.0" + checksum: 10c0/ea1919534ec6ce4ca4d9cb0ff1ab8e053509237da8d4298762ab3bfba4e78ca5649a599ce78a5c7c2624f3a7a971f62b265b7b0c3c881336e4fa6acaf6f37544 languageName: node linkType: hard -"uuid@npm:3.3.2": - version: 3.3.2 - resolution: "uuid@npm:3.3.2" +"ts-node@npm:^10.2.1": + version: 10.2.1 + resolution: "ts-node@npm:10.2.1" + dependencies: + "@cspotcode/source-map-support": "npm:0.6.1" + "@tsconfig/node10": "npm:^1.0.7" + "@tsconfig/node12": "npm:^1.0.7" + "@tsconfig/node14": "npm:^1.0.0" + "@tsconfig/node16": "npm:^1.0.2" + acorn: "npm:^8.4.1" + acorn-walk: "npm:^8.1.1" + arg: "npm:^4.1.0" + create-require: "npm:^1.1.0" + diff: "npm:^4.0.1" + make-error: "npm:^1.1.1" + yn: "npm:3.1.1" + peerDependencies: + "@swc/core": ">=1.2.50" + "@swc/wasm": ">=1.2.50" + "@types/node": "*" + typescript: ">=2.7" + peerDependenciesMeta: + "@swc/core": + optional: true + "@swc/wasm": + optional: true bin: - uuid: ./bin/uuid - checksum: 10c0/847bd7b389f44d05cf5341134d52803116b616c7344f12c74040effd75280b58273ea3a2bee6ba6e5405688c5edbb0696f4adcbc89e1206dc1d8650bdaece7a6 + ts-node: dist/bin.js + ts-node-cwd: dist/bin-cwd.js + ts-node-script: dist/bin-script.js + ts-node-transpile-only: dist/bin-transpile.js + ts-script: dist/bin-script-deprecated.js + checksum: 10c0/15755a09a97797036aed3672a9551a441958271c3e77a99714b41db3fcfc5829ae22aac3365d48bcf94f88a78c5cc8e3e2cd13240d948d19b7aa1a47f210bfe3 languageName: node linkType: hard -"uuid@npm:^3.3.2": - version: 3.4.0 - resolution: "uuid@npm:3.4.0" +"ts-node@npm:^10.9.1": + version: 10.9.2 + resolution: "ts-node@npm:10.9.2" + dependencies: + "@cspotcode/source-map-support": "npm:^0.8.0" + "@tsconfig/node10": "npm:^1.0.7" + "@tsconfig/node12": "npm:^1.0.7" + "@tsconfig/node14": "npm:^1.0.0" + "@tsconfig/node16": "npm:^1.0.2" + acorn: "npm:^8.4.1" + acorn-walk: "npm:^8.1.1" + arg: "npm:^4.1.0" + create-require: "npm:^1.1.0" + diff: "npm:^4.0.1" + make-error: "npm:^1.1.1" + v8-compile-cache-lib: "npm:^3.0.1" + yn: "npm:3.1.1" + peerDependencies: + "@swc/core": ">=1.2.50" + "@swc/wasm": ">=1.2.50" + "@types/node": "*" + typescript: ">=2.7" + peerDependenciesMeta: + "@swc/core": + optional: true + "@swc/wasm": + optional: true bin: - uuid: ./bin/uuid - checksum: 10c0/1c13950df865c4f506ebfe0a24023571fa80edf2e62364297a537c80af09c618299797bbf2dbac6b1f8ae5ad182ba474b89db61e0e85839683991f7e08795347 + ts-node: dist/bin.js + ts-node-cwd: dist/bin-cwd.js + ts-node-esm: dist/bin-esm.js + ts-node-script: dist/bin-script.js + ts-node-transpile-only: dist/bin-transpile.js + ts-script: dist/bin-script-deprecated.js + checksum: 10c0/5f29938489f96982a25ba650b64218e83a3357d76f7bede80195c65ab44ad279c8357264639b7abdd5d7e75fc269a83daa0e9c62fd8637a3def67254ecc9ddc2 languageName: node linkType: hard -"uuid@npm:^8.3.2": - version: 8.3.2 - resolution: "uuid@npm:8.3.2" - bin: - uuid: dist/bin/uuid - checksum: 10c0/bcbb807a917d374a49f475fae2e87fdca7da5e5530820ef53f65ba1d12131bd81a92ecf259cc7ce317cbe0f289e7d79fdfebcef9bfa3087c8c8a2fa304c9be54 +"tslib@npm:2.7.0": + version: 2.7.0 + resolution: "tslib@npm:2.7.0" + checksum: 10c0/469e1d5bf1af585742128827000711efa61010b699cb040ab1800bcd3ccdd37f63ec30642c9e07c4439c1db6e46345582614275daca3e0f4abae29b0083f04a6 languageName: node linkType: hard -"v8-compile-cache@npm:^2.0.3": - version: 2.3.0 - resolution: "v8-compile-cache@npm:2.3.0" - checksum: 10c0/b2d866febf943fbbf0b5e8d43ae9a9b0dacd11dd76e6a9c8e8032268f0136f081e894a2723774ae2d86befa994be4d4046b0717d82df4f3a10e067994ad5c688 +"tslib@npm:^1.11.1, tslib@npm:^1.9.3": + version: 1.14.1 + resolution: "tslib@npm:1.14.1" + checksum: 10c0/69ae09c49eea644bc5ebe1bca4fa4cc2c82b7b3e02f43b84bd891504edf66dbc6b2ec0eef31a957042de2269139e4acff911e6d186a258fb14069cd7f6febce2 languageName: node linkType: hard -"validate-npm-package-license@npm:^3.0.1": - version: 3.0.4 - resolution: "validate-npm-package-license@npm:3.0.4" - dependencies: - spdx-correct: "npm:^3.0.0" - spdx-expression-parse: "npm:^3.0.0" - checksum: 10c0/7b91e455a8de9a0beaa9fe961e536b677da7f48c9a493edf4d4d4a87fd80a7a10267d438723364e432c2fcd00b5650b5378275cded362383ef570276e6312f4f +"tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:^2.6.2": + version: 2.8.1 + resolution: "tslib@npm:2.8.1" + checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 languageName: node linkType: hard -"varint@npm:^5.0.0": - version: 5.0.2 - resolution: "varint@npm:5.0.2" - checksum: 10c0/a8e6c304cb140389cc56f14c808cd2ad4764d81f8afdaf4e49e9804231f2a62d9443098dba6b1249b0bd160b823fc7886d51e1cb0fca54209f842310d1d2591d +"tslog@npm:^4.3.1, tslog@npm:^4.4.0": + version: 4.11.0 + resolution: "tslog@npm:4.11.0" + checksum: 10c0/1bf7aa08d110da69bfe34aadf24fd1e61d3823d5fe82986e35d3279f3dd11ce1c94430620d55dccc05c280351060b6cd0ef31944abf9320884e8572576f4d71d languageName: node linkType: hard -"vary@npm:^1, vary@npm:~1.1.2": - version: 1.1.2 - resolution: "vary@npm:1.1.2" - checksum: 10c0/f15d588d79f3675135ba783c91a4083dcd290a2a5be9fcb6514220a1634e23df116847b1cc51f66bfb0644cf9353b2abb7815ae499bab06e46dd33c1a6bf1f4f +"tsort@npm:0.0.1": + version: 0.0.1 + resolution: "tsort@npm:0.0.1" + checksum: 10c0/ea3d034ab341dd9282c972710496e98539408d77f1cd476ad0551a9731f40586b65ab917b39745f902bf32037a3161eee3821405f6ab15bcd2ce4cc0a52d1da6 languageName: node linkType: hard -"verror@npm:1.10.0": - version: 1.10.0 - resolution: "verror@npm:1.10.0" +"type-check@npm:^0.4.0, type-check@npm:~0.4.0": + version: 0.4.0 + resolution: "type-check@npm:0.4.0" dependencies: - assert-plus: "npm:^1.0.0" - core-util-is: "npm:1.0.2" - extsprintf: "npm:^1.2.0" - checksum: 10c0/37ccdf8542b5863c525128908ac80f2b476eed36a32cb944de930ca1e2e78584cc435c4b9b4c68d0fc13a47b45ff364b4be43aa74f8804f9050140f660fb660d + prelude-ls: "npm:^1.2.1" + checksum: 10c0/7b3fd0ed43891e2080bf0c5c504b418fbb3e5c7b9708d3d015037ba2e6323a28152ec163bcb65212741fa5d2022e3075ac3c76440dbd344c9035f818e8ecee58 languageName: node linkType: hard -"viem@npm:^2.27.0": - version: 2.55.10 - resolution: "viem@npm:2.55.10" - dependencies: - "@noble/curves": "npm:1.9.1" - "@noble/hashes": "npm:1.8.0" - "@scure/bip32": "npm:1.7.0" - "@scure/bip39": "npm:1.6.0" - abitype: "npm:1.2.3" - isows: "npm:1.0.7" - ox: "npm:0.14.33" - ws: "npm:8.21.0" - peerDependencies: - typescript: ">=5.0.4" - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/8d77abf56da107a0fb41b81da82bf4e6f9c54ede8b3bf1bc6508ea324487c643b263adeea11049d10593ee80841c7f5fb876dab5837dafddeb34bfbe0cfd4a8a +"type-detect@npm:^4.0.0, type-detect@npm:^4.0.5": + version: 4.0.8 + resolution: "type-detect@npm:4.0.8" + checksum: 10c0/8fb9a51d3f365a7de84ab7f73b653534b61b622aa6800aecdb0f1095a4a646d3f5eb295322127b6573db7982afcd40ab492d038cf825a42093a58b1e1353e0bd languageName: node linkType: hard -"web3-bzz@npm:1.2.11": - version: 1.2.11 - resolution: "web3-bzz@npm:1.2.11" - dependencies: - "@types/node": "npm:^12.12.6" - got: "npm:9.6.0" - swarm-js: "npm:^0.1.40" - underscore: "npm:1.9.1" - checksum: 10c0/1c1a33b0168d5a5369bb6a139854866b2d0ce7da63f08848683143c8eee2be4a32f8842eddc2074a688a17bdd863bda0ba360e977acbe0fa7c113417b63f67dc +"type-fest@npm:^0.20.2": + version: 0.20.2 + resolution: "type-fest@npm:0.20.2" + checksum: 10c0/dea9df45ea1f0aaa4e2d3bed3f9a0bfe9e5b2592bddb92eb1bf06e50bcf98dbb78189668cd8bc31a0511d3fc25539b4cd5c704497e53e93e2d40ca764b10bfc3 languageName: node linkType: hard -"web3-core-helpers@npm:1.2.11": - version: 1.2.11 - resolution: "web3-core-helpers@npm:1.2.11" - dependencies: - underscore: "npm:1.9.1" - web3-eth-iban: "npm:1.2.11" - web3-utils: "npm:1.2.11" - checksum: 10c0/a07b7b2dad6a48ec7fd571b30e2d9719e497f5afe27b2a38883d80b7683aa058dff2ba3bf7d2195710f8ddd73edad7c5913f615d89c7530e04768f5e4f415e23 +"type-fest@npm:^0.21.3": + version: 0.21.3 + resolution: "type-fest@npm:0.21.3" + checksum: 10c0/902bd57bfa30d51d4779b641c2bc403cdf1371fb9c91d3c058b0133694fcfdb817aef07a47f40faf79039eecbaa39ee9d3c532deff244f3a19ce68cea71a61e8 languageName: node linkType: hard -"web3-core-method@npm:1.2.11": - version: 1.2.11 - resolution: "web3-core-method@npm:1.2.11" - dependencies: - "@ethersproject/transactions": "npm:^5.0.0-beta.135" - underscore: "npm:1.9.1" - web3-core-helpers: "npm:1.2.11" - web3-core-promievent: "npm:1.2.11" - web3-core-subscriptions: "npm:1.2.11" - web3-utils: "npm:1.2.11" - checksum: 10c0/5355ea541e6b305801166afa678832306121ad86db385dba711de7b85a50ab4c37f6d428142cc8af422c420eaf469e7f71ead4edcb631c8a015ae9ebe98c9569 +"type-fest@npm:^0.7.1": + version: 0.7.1 + resolution: "type-fest@npm:0.7.1" + checksum: 10c0/ce6b5ef806a76bf08d0daa78d65e61f24d9a0380bd1f1df36ffb61f84d14a0985c3a921923cf4b97831278cb6fa9bf1b89c751df09407e0510b14e8c081e4e0f languageName: node linkType: hard -"web3-core-promievent@npm:1.2.11": - version: 1.2.11 - resolution: "web3-core-promievent@npm:1.2.11" +"typechain@npm:^8.3.2": + version: 8.3.2 + resolution: "typechain@npm:8.3.2" dependencies: - eventemitter3: "npm:4.0.4" - checksum: 10c0/7e7f0499042ea82dd66a580ae186b2eda9a94016466d05582efd4804aa030b46ff30c7b7e5abd7fae9fd905fcd7e962a50216f6e7a8635cec5aaf22f44dca3ba + "@types/prettier": "npm:^2.1.1" + debug: "npm:^4.3.1" + fs-extra: "npm:^7.0.0" + glob: "npm:7.1.7" + js-sha3: "npm:^0.8.0" + lodash: "npm:^4.17.15" + mkdirp: "npm:^1.0.4" + prettier: "npm:^2.3.1" + ts-command-line-args: "npm:^2.2.0" + ts-essentials: "npm:^7.0.1" + peerDependencies: + typescript: ">=4.3.0" + bin: + typechain: dist/cli/cli.js + checksum: 10c0/1ea660cc7c699c6ac68da67b76454eb4e9395c54666d924ca67f983ae8eb5b5e7dab0a576beb55dbfad75ea784a3f68cb1ca019d332293b7291731c156ead5b5 languageName: node linkType: hard -"web3-core-requestmanager@npm:1.2.11": - version: 1.2.11 - resolution: "web3-core-requestmanager@npm:1.2.11" +"typescript-eslint@npm:^8.70.0": + version: 8.70.0 + resolution: "typescript-eslint@npm:8.70.0" dependencies: - underscore: "npm:1.9.1" - web3-core-helpers: "npm:1.2.11" - web3-providers-http: "npm:1.2.11" - web3-providers-ipc: "npm:1.2.11" - web3-providers-ws: "npm:1.2.11" - checksum: 10c0/9c0770fc1cd2ecafcc5c260ead72321de21d465448374abb1641a881e24ce512b1244f8503d7277ccefb61ecc4fd6538724662833b75ec8f3dd74b2b017eb8a0 + "@typescript-eslint/eslint-plugin": "npm:8.70.0" + "@typescript-eslint/parser": "npm:8.70.0" + "@typescript-eslint/typescript-estree": "npm:8.70.0" + "@typescript-eslint/utils": "npm:8.70.0" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/bf6625631bfcc7392bb1403681ef934f4f428c41a6a090b081a77ed0d342326c31097956900d701d078ac0c8a599d53377b504455fa9ce7214365c4c8d4635a3 languageName: node linkType: hard -"web3-core-subscriptions@npm:1.2.11": - version: 1.2.11 - resolution: "web3-core-subscriptions@npm:1.2.11" - dependencies: - eventemitter3: "npm:4.0.4" - underscore: "npm:1.9.1" - web3-core-helpers: "npm:1.2.11" - checksum: 10c0/cfcca968e5aa289c663e3ea2bf496431533c3c917f6f1bf78035ac4b17a6b336fb2b9d8f3e6f28ea3add7d955635fca41a1e424431a69987294c1de2e4559ead +"typescript@npm:^5.2.2": + version: 5.9.3 + resolution: "typescript@npm:5.9.3" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/6bd7552ce39f97e711db5aa048f6f9995b53f1c52f7d8667c1abdc1700c68a76a308f579cd309ce6b53646deb4e9a1be7c813a93baaf0a28ccd536a30270e1c5 languageName: node linkType: hard -"web3-core@npm:1.2.11": - version: 1.2.11 - resolution: "web3-core@npm:1.2.11" - dependencies: - "@types/bn.js": "npm:^4.11.5" - "@types/node": "npm:^12.12.6" - bignumber.js: "npm:^9.0.0" - web3-core-helpers: "npm:1.2.11" - web3-core-method: "npm:1.2.11" - web3-core-requestmanager: "npm:1.2.11" - web3-utils: "npm:1.2.11" - checksum: 10c0/ab9fcefe570dd15d590d4f03df26a149928cabdac096c9bfa8728ba29fe8fa0f522d7b68baab30fde685d7b509bf515d33fe15194c51e6e5fe18f0a737d1501a +"typescript@npm:^6.0.3": + version: 6.0.3 + resolution: "typescript@npm:6.0.3" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/4a25ff5045b984370f48f196b3a0120779b1b343d40b9a68d114ea5e5fff099809b2bb777576991a63a5cd59cf7bffd96ff6fe10afcefbcb8bd6fb96ad4b6606 languageName: node linkType: hard -"web3-eth-abi@npm:1.2.11": - version: 1.2.11 - resolution: "web3-eth-abi@npm:1.2.11" - dependencies: - "@ethersproject/abi": "npm:5.0.0-beta.153" - underscore: "npm:1.9.1" - web3-utils: "npm:1.2.11" - checksum: 10c0/18dee331dc337385a3d41239d72f4208c4c9f080ccc5d395c2da4150dc2a3989637f4b32d9536089df931722396062399b99c3901c01599974b411df69bb8fc5 +"typescript@patch:typescript@npm%3A^5.2.2#optional!builtin": + version: 5.9.3 + resolution: "typescript@patch:typescript@npm%3A5.9.3#optional!builtin::version=5.9.3&hash=5786d5" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/ad09fdf7a756814dce65bc60c1657b40d44451346858eea230e10f2e95a289d9183b6e32e5c11e95acc0ccc214b4f36289dcad4bf1886b0adb84d711d336a430 languageName: node linkType: hard -"web3-eth-accounts@npm:1.2.11": - version: 1.2.11 - resolution: "web3-eth-accounts@npm:1.2.11" - dependencies: - crypto-browserify: "npm:3.12.0" - eth-lib: "npm:0.2.8" - ethereumjs-common: "npm:^1.3.2" - ethereumjs-tx: "npm:^2.1.1" - scrypt-js: "npm:^3.0.1" - underscore: "npm:1.9.1" - uuid: "npm:3.3.2" - web3-core: "npm:1.2.11" - web3-core-helpers: "npm:1.2.11" - web3-core-method: "npm:1.2.11" - web3-utils: "npm:1.2.11" - checksum: 10c0/81b4a141296c97785bbaf9f390381277574b291148004e4006ea6ba148f1fe6386206b0fde21ebb0da5e846e585e9892c8680128213bc4a0aa3340a8859ec3f3 +"typescript@patch:typescript@npm%3A^6.0.3#optional!builtin": + version: 6.0.3 + resolution: "typescript@patch:typescript@npm%3A6.0.3#optional!builtin::version=6.0.3&hash=5786d5" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/2f25c74e65663c248fa1ade2b8459d9ce5372ff9dad07067310f132966ebec1d93f6c42f0baf77a6b6a7a91460463f708e6887013aaade22111037457c6b25df languageName: node linkType: hard -"web3-eth-contract@npm:1.2.11": - version: 1.2.11 - resolution: "web3-eth-contract@npm:1.2.11" - dependencies: - "@types/bn.js": "npm:^4.11.5" - underscore: "npm:1.9.1" - web3-core: "npm:1.2.11" - web3-core-helpers: "npm:1.2.11" - web3-core-method: "npm:1.2.11" - web3-core-promievent: "npm:1.2.11" - web3-core-subscriptions: "npm:1.2.11" - web3-eth-abi: "npm:1.2.11" - web3-utils: "npm:1.2.11" - checksum: 10c0/3ed8a3e2dd21fc48834eca3867f999bef2ae06b0dc48568d08cac4d2226fdcc9301d9909fa8b2bda4dd09834aedcf3187a3dd8216e7833321950cd7b15f07f35 +"typical@npm:^4.0.0": + version: 4.0.0 + resolution: "typical@npm:4.0.0" + checksum: 10c0/f300b198fb9fe743859b75ec761d53c382723dc178bbce4957d9cb754f2878a44ce17dc0b6a5156c52be1065449271f63754ba594dac225b80ce3aa39f9241ed languageName: node linkType: hard -"web3-eth-ens@npm:1.2.11": - version: 1.2.11 - resolution: "web3-eth-ens@npm:1.2.11" - dependencies: - content-hash: "npm:^2.5.2" - eth-ens-namehash: "npm:2.0.8" - underscore: "npm:1.9.1" - web3-core: "npm:1.2.11" - web3-core-helpers: "npm:1.2.11" - web3-core-promievent: "npm:1.2.11" - web3-eth-abi: "npm:1.2.11" - web3-eth-contract: "npm:1.2.11" - web3-utils: "npm:1.2.11" - checksum: 10c0/da281289dea92cd1dfef09be4bd5e6bb1d1f9d31f96dd5cc1dc0372ffe560e79896184a28ff6371b957c518ee54663346b2a1efd31bd736abe965dc46fcf7647 +"typical@npm:^5.2.0": + version: 5.2.0 + resolution: "typical@npm:5.2.0" + checksum: 10c0/1cceaa20d4b77a02ab8eccfe4a20500729431aecc1e1b7dc70c0e726e7966efdca3bf0b4bee285555b751647e37818fd99154ea73f74b5c29adc95d3c13f5973 languageName: node linkType: hard -"web3-eth-iban@npm:1.2.11": - version: 1.2.11 - resolution: "web3-eth-iban@npm:1.2.11" - dependencies: - bn.js: "npm:^4.11.9" - web3-utils: "npm:1.2.11" - checksum: 10c0/9ce91997af608b3b8bd9e8c953c3da4bc59e5f5045efd1ff107ad0981692fa7ae644d7fc35e1c1812a72aef443c24062af4cc01f27b75200511008c5a0954636 +"uglify-js@npm:^3.1.4": + version: 3.17.4 + resolution: "uglify-js@npm:3.17.4" + bin: + uglifyjs: bin/uglifyjs + checksum: 10c0/8b7fcdca69deb284fed7d2025b73eb747ce37f9aca6af53422844f46427152d5440601b6e2a033e77856a2f0591e4167153d5a21b68674ad11f662034ec13ced languageName: node linkType: hard -"web3-eth-personal@npm:1.2.11": - version: 1.2.11 - resolution: "web3-eth-personal@npm:1.2.11" - dependencies: - "@types/node": "npm:^12.12.6" - web3-core: "npm:1.2.11" - web3-core-helpers: "npm:1.2.11" - web3-core-method: "npm:1.2.11" - web3-net: "npm:1.2.11" - web3-utils: "npm:1.2.11" - checksum: 10c0/cc7f60b81a54d309f09e4ad339299b1f4d9f2685776e71286f13405a9082e21bab7c526e0711a64fcf104db4593df6459a457e796fb38825cbec8df6d58b9c35 +"undici-types@npm:~6.19.2": + version: 6.19.8 + resolution: "undici-types@npm:6.19.8" + checksum: 10c0/078afa5990fba110f6824823ace86073b4638f1d5112ee26e790155f481f2a868cc3e0615505b6f4282bdf74a3d8caad715fd809e870c2bb0704e3ea6082f344 languageName: node linkType: hard -"web3-eth@npm:1.2.11": - version: 1.2.11 - resolution: "web3-eth@npm:1.2.11" - dependencies: - underscore: "npm:1.9.1" - web3-core: "npm:1.2.11" - web3-core-helpers: "npm:1.2.11" - web3-core-method: "npm:1.2.11" - web3-core-subscriptions: "npm:1.2.11" - web3-eth-abi: "npm:1.2.11" - web3-eth-accounts: "npm:1.2.11" - web3-eth-contract: "npm:1.2.11" - web3-eth-ens: "npm:1.2.11" - web3-eth-iban: "npm:1.2.11" - web3-eth-personal: "npm:1.2.11" - web3-net: "npm:1.2.11" - web3-utils: "npm:1.2.11" - checksum: 10c0/62c229c795fbbb3afa7b105f35ea69f318a4a9f6aa6b39b3ad64f93a8783749df129ecbea805eb0a8042e4750c1cd3f8af6c8abdedf6a443e3a6f13701f11ea9 +"undici-types@npm:~7.18.0": + version: 7.18.2 + resolution: "undici-types@npm:7.18.2" + checksum: 10c0/85a79189113a238959d7a647368e4f7c5559c3a404ebdb8fc4488145ce9426fcd82252a844a302798dfc0e37e6fb178ff481ed03bc4caf634c5757d9ef43521d languageName: node linkType: hard -"web3-net@npm:1.2.11": - version: 1.2.11 - resolution: "web3-net@npm:1.2.11" +"undici@npm:^5.14.0": + version: 5.29.0 + resolution: "undici@npm:5.29.0" dependencies: - web3-core: "npm:1.2.11" - web3-core-method: "npm:1.2.11" - web3-utils: "npm:1.2.11" - checksum: 10c0/9d3e777dcc78dad719f847115a93687d8eb7f6187c3f4b15a4ceebea58cc6d4fd80002ec516720b2c2de265d51033967673b6362c6b2f79318ea1c807223b550 + "@fastify/busboy": "npm:^2.0.0" + checksum: 10c0/e4e4d631ca54ee0ad82d2e90e7798fa00a106e27e6c880687e445cc2f13b4bc87c5eba2a88c266c3eecffb18f26e227b778412da74a23acc374fca7caccec49b languageName: node linkType: hard -"web3-provider-engine@npm:14.2.1": - version: 14.2.1 - resolution: "web3-provider-engine@npm:14.2.1" - dependencies: - async: "npm:^2.5.0" - backoff: "npm:^2.5.0" - clone: "npm:^2.0.0" - cross-fetch: "npm:^2.1.0" - eth-block-tracker: "npm:^3.0.0" - eth-json-rpc-infura: "npm:^3.1.0" - eth-sig-util: "npm:^1.4.2" - ethereumjs-block: "npm:^1.2.2" - ethereumjs-tx: "npm:^1.2.0" - ethereumjs-util: "npm:^5.1.5" - ethereumjs-vm: "npm:^2.3.4" - json-rpc-error: "npm:^2.0.0" - json-stable-stringify: "npm:^1.0.1" - promise-to-callback: "npm:^1.0.0" - readable-stream: "npm:^2.2.9" - request: "npm:^2.85.0" - semaphore: "npm:^1.0.3" - ws: "npm:^5.1.1" - xhr: "npm:^2.2.0" - xtend: "npm:^4.0.1" - checksum: 10c0/4d22b4de9f2a01b2ce561c02148bfaf4fb75e27c33cc1710f1d56e5681af4c7a19451ef8fcf50726420b8b3178e27d3b4c5e3de101652cd721ecce894e002568 +"unfetch@npm:^4.2.0": + version: 4.2.0 + resolution: "unfetch@npm:4.2.0" + checksum: 10c0/a5c0a896a6f09f278b868075aea65652ad185db30e827cb7df45826fe5ab850124bf9c44c4dafca4bf0c55a0844b17031e8243467fcc38dd7a7d435007151f1b languageName: node linkType: hard -"web3-providers-http@npm:1.2.11": - version: 1.2.11 - resolution: "web3-providers-http@npm:1.2.11" - dependencies: - web3-core-helpers: "npm:1.2.11" - xhr2-cookies: "npm:1.1.0" - checksum: 10c0/9997cd3ff010cf752b36f28edb711d1af91bf4ac772a5cea73a91ffb61f601dc1731c0aef3916606b4aec14aca63d5962a87ca9f0374731395e54eb1ffe1aa01 +"universalify@npm:^0.1.0": + version: 0.1.2 + resolution: "universalify@npm:0.1.2" + checksum: 10c0/e70e0339f6b36f34c9816f6bf9662372bd241714dc77508d231d08386d94f2c4aa1ba1318614f92015f40d45aae1b9075cd30bd490efbe39387b60a76ca3f045 languageName: node linkType: hard -"web3-providers-ipc@npm:1.2.11": - version: 1.2.11 - resolution: "web3-providers-ipc@npm:1.2.11" - dependencies: - oboe: "npm:2.1.4" - underscore: "npm:1.9.1" - web3-core-helpers: "npm:1.2.11" - checksum: 10c0/0e08ded199fefa26c0b5969571d202c202992ccba1ef6da07176ab253b4d6c7d1f2dfce57824f7ecded2baa3bd6131dfd2e8747e424e1f207a912f38cbec1778 +"universalify@npm:^2.0.0": + version: 2.0.0 + resolution: "universalify@npm:2.0.0" + checksum: 10c0/07092b9f46df61b823d8ab5e57f0ee5120c178b39609a95e4a15a98c42f6b0b8e834e66fbb47ff92831786193be42f1fd36347169b88ce8639d0f9670af24a71 languageName: node linkType: hard -"web3-providers-ws@npm:1.2.11": - version: 1.2.11 - resolution: "web3-providers-ws@npm:1.2.11" - dependencies: - eventemitter3: "npm:4.0.4" - underscore: "npm:1.9.1" - web3-core-helpers: "npm:1.2.11" - websocket: "npm:^1.0.31" - checksum: 10c0/e52c6907cb06937c740ccde934ffc202d148518e974ce3f4806702b24c173e04402690af71705a13254fba3996901118288b64cba991839b5f0b6e563be4fe9d +"unpipe@npm:1.0.0": + version: 1.0.0 + resolution: "unpipe@npm:1.0.0" + checksum: 10c0/193400255bd48968e5c5383730344fbb4fa114cdedfab26e329e50dd2d81b134244bb8a72c6ac1b10ab0281a58b363d06405632c9d49ca9dfd5e90cbd7d0f32c languageName: node linkType: hard -"web3-shh@npm:1.2.11": - version: 1.2.11 - resolution: "web3-shh@npm:1.2.11" - dependencies: - web3-core: "npm:1.2.11" - web3-core-method: "npm:1.2.11" - web3-core-subscriptions: "npm:1.2.11" - web3-net: "npm:1.2.11" - checksum: 10c0/5716031471a067a4537ed37e6f064fe312ceb8450c312e324ac292c0f5f6ac824d731e4a6a2451637061449229377c693c51991a2152a50dee4b442dfad89538 +"unrs-resolver@npm:^1.7.11, unrs-resolver@npm:^1.9.2": + version: 1.12.2 + resolution: "unrs-resolver@npm:1.12.2" + dependencies: + "@unrs/resolver-binding-android-arm-eabi": "npm:1.12.2" + "@unrs/resolver-binding-android-arm64": "npm:1.12.2" + "@unrs/resolver-binding-darwin-arm64": "npm:1.12.2" + "@unrs/resolver-binding-darwin-x64": "npm:1.12.2" + "@unrs/resolver-binding-freebsd-x64": "npm:1.12.2" + "@unrs/resolver-binding-linux-arm-gnueabihf": "npm:1.12.2" + "@unrs/resolver-binding-linux-arm-musleabihf": "npm:1.12.2" + "@unrs/resolver-binding-linux-arm64-gnu": "npm:1.12.2" + "@unrs/resolver-binding-linux-arm64-musl": "npm:1.12.2" + "@unrs/resolver-binding-linux-loong64-gnu": "npm:1.12.2" + "@unrs/resolver-binding-linux-loong64-musl": "npm:1.12.2" + "@unrs/resolver-binding-linux-ppc64-gnu": "npm:1.12.2" + "@unrs/resolver-binding-linux-riscv64-gnu": "npm:1.12.2" + "@unrs/resolver-binding-linux-riscv64-musl": "npm:1.12.2" + "@unrs/resolver-binding-linux-s390x-gnu": "npm:1.12.2" + "@unrs/resolver-binding-linux-x64-gnu": "npm:1.12.2" + "@unrs/resolver-binding-linux-x64-musl": "npm:1.12.2" + "@unrs/resolver-binding-openharmony-arm64": "npm:1.12.2" + "@unrs/resolver-binding-wasm32-wasi": "npm:1.12.2" + "@unrs/resolver-binding-win32-arm64-msvc": "npm:1.12.2" + "@unrs/resolver-binding-win32-ia32-msvc": "npm:1.12.2" + "@unrs/resolver-binding-win32-x64-msvc": "npm:1.12.2" + napi-postinstall: "npm:^0.3.4" + dependenciesMeta: + "@unrs/resolver-binding-android-arm-eabi": + optional: true + "@unrs/resolver-binding-android-arm64": + optional: true + "@unrs/resolver-binding-darwin-arm64": + optional: true + "@unrs/resolver-binding-darwin-x64": + optional: true + "@unrs/resolver-binding-freebsd-x64": + optional: true + "@unrs/resolver-binding-linux-arm-gnueabihf": + optional: true + "@unrs/resolver-binding-linux-arm-musleabihf": + optional: true + "@unrs/resolver-binding-linux-arm64-gnu": + optional: true + "@unrs/resolver-binding-linux-arm64-musl": + optional: true + "@unrs/resolver-binding-linux-loong64-gnu": + optional: true + "@unrs/resolver-binding-linux-loong64-musl": + optional: true + "@unrs/resolver-binding-linux-ppc64-gnu": + optional: true + "@unrs/resolver-binding-linux-riscv64-gnu": + optional: true + "@unrs/resolver-binding-linux-riscv64-musl": + optional: true + "@unrs/resolver-binding-linux-s390x-gnu": + optional: true + "@unrs/resolver-binding-linux-x64-gnu": + optional: true + "@unrs/resolver-binding-linux-x64-musl": + optional: true + "@unrs/resolver-binding-openharmony-arm64": + optional: true + "@unrs/resolver-binding-wasm32-wasi": + optional: true + "@unrs/resolver-binding-win32-arm64-msvc": + optional: true + "@unrs/resolver-binding-win32-ia32-msvc": + optional: true + "@unrs/resolver-binding-win32-x64-msvc": + optional: true + checksum: 10c0/ddc27f6d920eabdafeac0077ebff9fd799c895cea025751dc17b360bf9be7c93c471fafebf65f205eec476f90d7daa36aef889d47362b2dd4705d68852bcfea4 languageName: node linkType: hard -"web3-utils@npm:1.2.11": - version: 1.2.11 - resolution: "web3-utils@npm:1.2.11" - dependencies: - bn.js: "npm:^4.11.9" - eth-lib: "npm:0.2.8" - ethereum-bloom-filters: "npm:^1.0.6" - ethjs-unit: "npm:0.1.6" - number-to-bn: "npm:1.7.0" - randombytes: "npm:^2.1.0" - underscore: "npm:1.9.1" - utf8: "npm:3.0.0" - checksum: 10c0/bcf8ba89182c5c43b690c41a8078aa77275b3006383d266f43d563c20bcb1f6de2e5133707f9f4ee42ce46f6b9cb69e62b024327dfed67dd3f30dfe1ec946ac8 +"untildify@npm:^4.0.0": + version: 4.0.0 + resolution: "untildify@npm:4.0.0" + checksum: 10c0/d758e624c707d49f76f7511d75d09a8eda7f2020d231ec52b67ff4896bcf7013be3f9522d8375f57e586e9a2e827f5641c7e06ee46ab9c435fc2b2b2e9de517a languageName: node linkType: hard -"web3-utils@npm:^1.0.0-beta.31": - version: 1.6.0 - resolution: "web3-utils@npm:1.6.0" +"uri-js@npm:^4.2.2": + version: 4.4.1 + resolution: "uri-js@npm:4.4.1" dependencies: - bn.js: "npm:^4.11.9" - ethereum-bloom-filters: "npm:^1.0.6" - ethereumjs-util: "npm:^7.1.0" - ethjs-unit: "npm:0.1.6" - number-to-bn: "npm:1.7.0" - randombytes: "npm:^2.1.0" - utf8: "npm:3.0.0" - checksum: 10c0/6400ca09cde920a340180ff5610695935a94b5feaf32d47a04e2153acbb26f24fab91f7fce2d39e8508868beb2bb95e0fba18344d38043b84603f301ecb43ce6 + punycode: "npm:^2.1.0" + checksum: 10c0/4ef57b45aa820d7ac6496e9208559986c665e49447cb072744c13b66925a362d96dd5a46c4530a6b8e203e5db5fe849369444440cb22ecfc26c679359e5dfa3c languageName: node linkType: hard -"web3@npm:1.2.11": - version: 1.2.11 - resolution: "web3@npm:1.2.11" - dependencies: - web3-bzz: "npm:1.2.11" - web3-core: "npm:1.2.11" - web3-eth: "npm:1.2.11" - web3-eth-personal: "npm:1.2.11" - web3-net: "npm:1.2.11" - web3-shh: "npm:1.2.11" - web3-utils: "npm:1.2.11" - checksum: 10c0/6d52d6e8580eb64425cdeac49b2303111e1d76483d74619fa94a6bfc2b77bf5c04e46ed6c2bc9c9ee7e0eeb8ab387d9c845868f673cad8b6414fd043b132c926 +"util-deprecate@npm:^1.0.1": + version: 1.0.2 + resolution: "util-deprecate@npm:1.0.2" + checksum: 10c0/41a5bdd214df2f6c3ecf8622745e4a366c4adced864bc3c833739791aeeeb1838119af7daed4ba36428114b5c67dcda034a79c882e97e43c03e66a4dd7389942 languageName: node linkType: hard -"webidl-conversions@npm:^3.0.0": - version: 3.0.1 - resolution: "webidl-conversions@npm:3.0.1" - checksum: 10c0/5612d5f3e54760a797052eb4927f0ddc01383550f542ccd33d5238cfd65aeed392a45ad38364970d0a0f4fea32e1f4d231b3d8dac4a3bdd385e5cf802ae097db +"uuid@npm:^8.3.2": + version: 8.3.2 + resolution: "uuid@npm:8.3.2" + bin: + uuid: dist/bin/uuid + checksum: 10c0/bcbb807a917d374a49f475fae2e87fdca7da5e5530820ef53f65ba1d12131bd81a92ecf259cc7ce317cbe0f289e7d79fdfebcef9bfa3087c8c8a2fa304c9be54 languageName: node linkType: hard -"websocket@npm:1.0.32": - version: 1.0.32 - resolution: "websocket@npm:1.0.32" - dependencies: - bufferutil: "npm:^4.0.1" - debug: "npm:^2.2.0" - es5-ext: "npm:^0.10.50" - typedarray-to-buffer: "npm:^3.1.5" - utf-8-validate: "npm:^5.0.2" - yaeti: "npm:^0.0.6" - checksum: 10c0/277d3903ca35bf5eedc164522b51879bfe0036385b51b433586c8ddc5676a1051e2934ee9d13eb635d434d775c34b8f861911c57587e09cd0c96659a43a2524c +"v8-compile-cache-lib@npm:^3.0.1": + version: 3.0.1 + resolution: "v8-compile-cache-lib@npm:3.0.1" + checksum: 10c0/bdc36fb8095d3b41df197f5fb6f11e3a26adf4059df3213e3baa93810d8f0cc76f9a74aaefc18b73e91fe7e19154ed6f134eda6fded2e0f1c8d2272ed2d2d391 languageName: node linkType: hard -"websocket@npm:^1.0.31": - version: 1.0.34 - resolution: "websocket@npm:1.0.34" +"viem@npm:^2.27.0": + version: 2.55.10 + resolution: "viem@npm:2.55.10" dependencies: - bufferutil: "npm:^4.0.1" - debug: "npm:^2.2.0" - es5-ext: "npm:^0.10.50" - typedarray-to-buffer: "npm:^3.1.5" - utf-8-validate: "npm:^5.0.2" - yaeti: "npm:^0.0.6" - checksum: 10c0/a7e17d24edec685fdf055940ff9c6a15e726df5bb5e537382390bd1ab978fc8c0d71cd2842bb628e361d823aafd43934cc56aa5b979d08e52461be7da8d01eee + "@noble/curves": "npm:1.9.1" + "@noble/hashes": "npm:1.8.0" + "@scure/bip32": "npm:1.7.0" + "@scure/bip39": "npm:1.6.0" + abitype: "npm:1.2.3" + isows: "npm:1.0.7" + ox: "npm:0.14.33" + ws: "npm:8.21.0" + peerDependencies: + typescript: ">=5.0.4" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/8d77abf56da107a0fb41b81da82bf4e6f9c54ede8b3bf1bc6508ea324487c643b263adeea11049d10593ee80841c7f5fb876dab5837dafddeb34bfbe0cfd4a8a languageName: node linkType: hard -"whatwg-fetch@npm:^2.0.4": - version: 2.0.4 - resolution: "whatwg-fetch@npm:2.0.4" - checksum: 10c0/bf2bc1617218c63f2be86edefb95ac5e7f967ae402e468ed550729436369725c3b03a5d1110f62ea789b6f7f399969b1ef720b0bb04e8947fdf94eab7ffac829 +"webidl-conversions@npm:^3.0.0": + version: 3.0.1 + resolution: "webidl-conversions@npm:3.0.1" + checksum: 10c0/5612d5f3e54760a797052eb4927f0ddc01383550f542ccd33d5238cfd65aeed392a45ad38364970d0a0f4fea32e1f4d231b3d8dac4a3bdd385e5cf802ae097db languageName: node linkType: hard @@ -14298,37 +7836,6 @@ __metadata: languageName: node linkType: hard -"which-boxed-primitive@npm:^1.0.2": - version: 1.0.2 - resolution: "which-boxed-primitive@npm:1.0.2" - dependencies: - is-bigint: "npm:^1.0.1" - is-boolean-object: "npm:^1.1.0" - is-number-object: "npm:^1.0.4" - is-string: "npm:^1.0.5" - is-symbol: "npm:^1.0.3" - checksum: 10c0/0a62a03c00c91dd4fb1035b2f0733c341d805753b027eebd3a304b9cb70e8ce33e25317add2fe9b5fea6f53a175c0633ae701ff812e604410ddd049777cd435e - languageName: node - linkType: hard - -"which-module@npm:^1.0.0": - version: 1.0.0 - resolution: "which-module@npm:1.0.0" - checksum: 10c0/ce5088fb12dae0b6d5997b6221342943ff6275c3b2cd9c569f04ec23847c71013d254c6127d531010dccc22c0fc0f8dce2b6ecf6898941a60b576adb2018af22 - languageName: node - linkType: hard - -"which@npm:^1.2.9": - version: 1.3.1 - resolution: "which@npm:1.3.1" - dependencies: - isexe: "npm:^2.0.0" - bin: - which: ./bin/which - checksum: 10c0/e945a8b6bbf6821aaaef7f6e0c309d4b615ef35699576d5489b4261da9539f70393c6b2ce700ee4321c18f914ebe5644bc4631b15466ffbaad37d83151f6af59 - languageName: node - linkType: hard - "which@npm:^2.0.1": version: 2.0.2 resolution: "which@npm:2.0.2" @@ -14360,19 +7867,10 @@ __metadata: languageName: node linkType: hard -"window-size@npm:^0.2.0": - version: 0.2.0 - resolution: "window-size@npm:0.2.0" - bin: - window-size: cli.js - checksum: 10c0/378c9d7a1c903ca57f08db40dd8960252f566910ea9dea6d8552e9d61cebe9e536dcabc1b5a6edb776eebe8e5bcbcfb5b27ba13fe128625bc2033516acdc95cc - languageName: node - linkType: hard - -"word-wrap@npm:^1.2.3, word-wrap@npm:~1.2.3": - version: 1.2.3 - resolution: "word-wrap@npm:1.2.3" - checksum: 10c0/1cb6558996deb22c909330db1f01d672feee41d7f0664492912de3de282da3f28ba2d49e87b723024e99d56ba2dac2f3ab28f8db07ac199f5e5d5e2e437833de +"word-wrap@npm:^1.2.5": + version: 1.2.5 + resolution: "word-wrap@npm:1.2.5" + checksum: 10c0/e0e4a1ca27599c92a6ca4c32260e8a92e8a44f4ef6ef93f803f8ed823f486e0889fc0b93be4db59c8d51b3064951d25e43d434e95dc8c960cc3a63d65d00ba20 languageName: node linkType: hard @@ -14411,16 +7909,6 @@ __metadata: languageName: node linkType: hard -"wrap-ansi@npm:^2.0.0": - version: 2.1.0 - resolution: "wrap-ansi@npm:2.1.0" - dependencies: - string-width: "npm:^1.0.1" - strip-ansi: "npm:^3.0.1" - checksum: 10c0/1a47367eef192fc9ecaf00238bad5de8987c3368082b619ab36c5e2d6d7b0a2aef95a2ca65840be598c56ced5090a3ba487956c7aee0cac7c45017502fa980fb - languageName: node - linkType: hard - "wrap-ansi@npm:^8.1.0": version: 8.1.0 resolution: "wrap-ansi@npm:8.1.0" @@ -14439,15 +7927,6 @@ __metadata: languageName: node linkType: hard -"write@npm:1.0.3": - version: 1.0.3 - resolution: "write@npm:1.0.3" - dependencies: - mkdirp: "npm:^0.5.1" - checksum: 10c0/2ab5472e32ce2d25279a9d22365c5dd5b95fe40497ca43fa329aa61687fca56e36837615a1b6adfc4ca540389383185680a23497d75a1698b1dcbb52741d29a4 - languageName: node - linkType: hard - "ws@npm:7.4.6": version: 7.4.6 resolution: "ws@npm:7.4.6" @@ -14463,6 +7942,21 @@ __metadata: languageName: node linkType: hard +"ws@npm:8.18.0": + version: 8.18.0 + resolution: "ws@npm:8.18.0" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 10c0/25eb33aff17edcb90721ed6b0eb250976328533ad3cd1a28a274bd263682e7296a6591ff1436d6cbc50fa67463158b062f9d1122013b361cec99a05f84680e06 + languageName: node + linkType: hard + "ws@npm:8.21.0": version: 8.21.0 resolution: "ws@npm:8.21.0" @@ -14478,26 +7972,6 @@ __metadata: languageName: node linkType: hard -"ws@npm:^3.0.0": - version: 3.3.3 - resolution: "ws@npm:3.3.3" - dependencies: - async-limiter: "npm:~1.0.0" - safe-buffer: "npm:~5.1.0" - ultron: "npm:~1.1.0" - checksum: 10c0/bed856f4fd85388a78b80e5ea92c7a6ff8df09ece1621218c4e366faa1551b42b5a0b66a5dd1a47d7f0d97be21d1df528b6d54f04b327e5b94c9dbcab753c94c - languageName: node - linkType: hard - -"ws@npm:^5.1.1": - version: 5.2.3 - resolution: "ws@npm:5.2.3" - dependencies: - async-limiter: "npm:~1.0.0" - checksum: 10c0/3f329b29a893c660b01be81654c9bca422a0de3396e644aae165e4e998e74b2b713adcbba876f183cd74a4f488376cbb7442d1c87455084d69fce1e2f25ef088 - languageName: node - linkType: hard - "ws@npm:^7.4.6": version: 7.5.5 resolution: "ws@npm:7.5.5" @@ -14513,74 +7987,6 @@ __metadata: languageName: node linkType: hard -"xhr-request-promise@npm:^0.1.2": - version: 0.1.3 - resolution: "xhr-request-promise@npm:0.1.3" - dependencies: - xhr-request: "npm:^1.1.0" - checksum: 10c0/c5674a395a75a2b788cc80ac9e7913b3a67ef924db51fa67c0958f986b2840583d44de179ac26cf45b872960766a4dd40b36cfab809b76dc80277ba163b75d44 - languageName: node - linkType: hard - -"xhr-request@npm:^1.0.1, xhr-request@npm:^1.1.0": - version: 1.1.0 - resolution: "xhr-request@npm:1.1.0" - dependencies: - buffer-to-arraybuffer: "npm:^0.0.5" - object-assign: "npm:^4.1.1" - query-string: "npm:^5.0.1" - simple-get: "npm:^2.7.0" - timed-out: "npm:^4.0.1" - url-set-query: "npm:^1.0.0" - xhr: "npm:^2.0.4" - checksum: 10c0/12bf79e11fa909c01058e654e954b0e3ed0638e6a62a42bd705251c920b39c3980720d0c2d8c2b97ceaeb8bf21bb08fd75c733a909b76555d252014bd3acbc79 - languageName: node - linkType: hard - -"xhr2-cookies@npm:1.1.0": - version: 1.1.0 - resolution: "xhr2-cookies@npm:1.1.0" - dependencies: - cookiejar: "npm:^2.1.1" - checksum: 10c0/38faf4ebecdc003559c58a19e389b51ea227c92d0d38f385e9b43f75df675eae9b7ac6335ecba813990af804d448f69109806e76b07eaf689ad863b303222a6c - languageName: node - linkType: hard - -"xhr@npm:^2.0.4, xhr@npm:^2.2.0, xhr@npm:^2.3.3": - version: 2.6.0 - resolution: "xhr@npm:2.6.0" - dependencies: - global: "npm:~4.4.0" - is-function: "npm:^1.0.1" - parse-headers: "npm:^2.0.0" - xtend: "npm:^4.0.0" - checksum: 10c0/b73b6413b678846c422559cbc0afb2acb34c3a75b4c3bbee1f258e984255a8b8d65c1749b51691278bbdc28781782950d77a759ef5a9adf7774bed2f5dabc954 - languageName: node - linkType: hard - -"xtend@npm:^4.0.0, xtend@npm:^4.0.1, xtend@npm:~4.0.0, xtend@npm:~4.0.1": - version: 4.0.2 - resolution: "xtend@npm:4.0.2" - checksum: 10c0/366ae4783eec6100f8a02dff02ac907bf29f9a00b82ac0264b4d8b832ead18306797e283cf19de776538babfdcb2101375ec5646b59f08c52128ac4ab812ed0e - languageName: node - linkType: hard - -"xtend@npm:~2.1.1": - version: 2.1.2 - resolution: "xtend@npm:2.1.2" - dependencies: - object-keys: "npm:~0.4.0" - checksum: 10c0/5b0289152e845041cfcb07d5fb31873a71e4fa9c0279299f9cce0e2a210a0177d071aac48546c998df2a44ff2c19d1cde8a9ab893e27192a0c2061c2837d8cb5 - languageName: node - linkType: hard - -"y18n@npm:^3.2.1": - version: 3.2.2 - resolution: "y18n@npm:3.2.2" - checksum: 10c0/08dc1880f6f766057ed25cd61ef0c7dab3db93639db9a7487a84f75dac7a349dface8dff8d1d8b7bdf50969fcd69ab858ab26b06968b4e4b12ee60d195233c46 - languageName: node - linkType: hard - "y18n@npm:^5.0.5": version: 5.0.8 resolution: "y18n@npm:5.0.8" @@ -14588,20 +7994,6 @@ __metadata: languageName: node linkType: hard -"yaeti@npm:^0.0.6": - version: 0.0.6 - resolution: "yaeti@npm:0.0.6" - checksum: 10c0/4e88702d8b34d7b61c1c4ec674422b835d453b8f8a6232be41e59fc98bc4d9ab6d5abd2da55bab75dfc07ae897fdc0c541f856ce3ab3b17de1630db6161aa3f6 - languageName: node - linkType: hard - -"yallist@npm:^3.0.0, yallist@npm:^3.0.2, yallist@npm:^3.1.1": - version: 3.1.1 - resolution: "yallist@npm:3.1.1" - checksum: 10c0/c66a5c46bc89af1625476f7f0f2ec3653c1a1791d2f9407cfb4c2ba812a1e1c9941416d71ba9719876530e3340a99925f697142989371b72d93b9ee628afd8c1 - languageName: node - linkType: hard - "yallist@npm:^4.0.0": version: 4.0.0 resolution: "yallist@npm:4.0.0" @@ -14616,16 +8008,6 @@ __metadata: languageName: node linkType: hard -"yargs-parser@npm:^2.4.1": - version: 2.4.1 - resolution: "yargs-parser@npm:2.4.1" - dependencies: - camelcase: "npm:^3.0.0" - lodash.assign: "npm:^4.0.6" - checksum: 10c0/746ba04072029ad4ce3b0aae4805810e5bbbf5ac762a3ff35ee25b3bb8eaf61acc0c3bddd0fab0ab8f902d806d750757917e6a5d5e1a267ed38cab3c32ac14d5 - languageName: node - linkType: hard - "yargs-parser@npm:^21.1.1": version: 21.1.1 resolution: "yargs-parser@npm:21.1.1" @@ -14660,28 +8042,6 @@ __metadata: languageName: node linkType: hard -"yargs@npm:^4.7.1": - version: 4.8.1 - resolution: "yargs@npm:4.8.1" - dependencies: - cliui: "npm:^3.2.0" - decamelize: "npm:^1.1.1" - get-caller-file: "npm:^1.0.1" - lodash.assign: "npm:^4.0.3" - os-locale: "npm:^1.4.0" - read-pkg-up: "npm:^1.0.1" - require-directory: "npm:^2.1.1" - require-main-filename: "npm:^1.0.1" - set-blocking: "npm:^2.0.0" - string-width: "npm:^1.0.1" - which-module: "npm:^1.0.0" - window-size: "npm:^0.2.0" - y18n: "npm:^3.2.1" - yargs-parser: "npm:^2.4.1" - checksum: 10c0/7e183a1d96192d6a681ea9587052d7c2019c01cccb1ac24877a4f0fd948fb4b72eff474c21226c41dc1123128ecba29a26d46a9d022e8456efa0d600d96a70b9 - languageName: node - linkType: hard - "yn@npm:3.1.1": version: 3.1.1 resolution: "yn@npm:3.1.1" @@ -14696,11 +8056,22 @@ __metadata: languageName: node linkType: hard -"zksync-web3@npm:^0.7.8": - version: 0.7.8 - resolution: "zksync-web3@npm:0.7.8" +"zksync-ethers@npm:^5.0.0": + version: 5.11.2 + resolution: "zksync-ethers@npm:5.11.2" + dependencies: + ethers: "npm:~5.7.0" + peerDependencies: + ethers: ~5.7.0 + checksum: 10c0/a6065dcc484ac9bc96cc2163b939a26caf0f12619ea64d171dcac74d1ac37495d7e31a4a043f4adf51740a93a32f5d144b5e0092dd0df18386d9a46a9f0ce493 + languageName: node + linkType: hard + +"zksync-web3@npm:^0.14.3": + version: 0.14.4 + resolution: "zksync-web3@npm:0.14.4" peerDependencies: - ethers: ~5.5.0 - checksum: 10c0/48df47d138e8eeccf3280cb64cf2d693992aa15f86965239c15a85345d8f33e22a1991858d2f700d3dada056588df8a1e8e9afe3759282d64cc9b8d60622d1ce + ethers: ^5.7.0 + checksum: 10c0/1ee87dc33f2c45dfc5a93abb3ffda92f5e7190d90448aacb4859374975fd72bf269c72126ec06043e57e02c925273ecb936189ea2350a6ac4a620b95b86f7f97 languageName: node linkType: hard diff --git a/solidity/scripts/ethers-v6-compatibility/capture.cjs b/solidity/scripts/ethers-v6-compatibility/capture.cjs new file mode 100644 index 0000000000..084c233c21 --- /dev/null +++ b/solidity/scripts/ethers-v6-compatibility/capture.cjs @@ -0,0 +1,140 @@ +const fs = require("fs"); +const path = require("path"); +require( + path.join(process.cwd(), "node_modules/ts-node/register/transpile-only"), +); +const hre = require(path.join(process.cwd(), "node_modules/hardhat")); +(async () => { + if (hre.network.name !== "hardhat" || hre.network.config.forking?.enabled) + throw new Error("Capture requires a non-forked in-process Hardhat network"); + if ( + process.env.TEST_USE_STUBS_BEACON === "true" || + process.env.TEST_USE_STUBS_ECDSA === "true" + ) + throw new Error( + "Capture requires production contracts, without test stubs", + ); + const destination = process.env.MIGRATION_CAPTURE_DIR; + if (!destination) throw new Error("MIGRATION_CAPTURE_DIR is required"); + if (fs.existsSync(destination)) + throw new Error("Capture destination already exists"); + fs.mkdirSync(destination, { recursive: true }); + fs.writeFileSync( + path.join(destination, "inputs.json"), + JSON.stringify( + { + deploy: hre.config.paths.deploy, + externalContracts: hre.config.external?.contracts, + }, + null, + 2, + ) + "\n", + ); + await hre.run("deploy", { + reset: true, + write: false, + export: path.join(destination, "export.json"), + }); + const records = await hre.deployments.all(); + const send = (method, params) => hre.network.provider.send(method, params); + const id = hre.ethers.id || hre.ethers.utils.id; + const slot = (label) => + "0x" + (BigInt(id(label)) - 1n).toString(16).padStart(64, "0"); + const adminSlot = slot("eip1967.proxy.admin"); + const implementationSlot = slot("eip1967.proxy.implementation"); + const state = { contracts: {}, code: {} }; + for (const [name, record] of Object.entries(records)) { + const address = record.address; + const adminWord = await send("eth_getStorageAt", [ + address, + adminSlot, + "latest", + ]); + const implementationWord = await send("eth_getStorageAt", [ + address, + implementationSlot, + "latest", + ]); + const row = { address, adminWord, implementationWord, readers: {} }; + for (const getter of ["owner", "governance", "walletOwner"]) { + if ( + record.abi.some( + (entry) => + entry.type === "function" && + entry.name === getter && + entry.inputs.length === 0, + ) + ) { + row.readers[getter] = await send("eth_call", [ + { to: address, data: id(getter + "()").slice(0, 10) }, + "latest", + ]); + } + } + state.contracts[name] = row; + for (const target of [ + address, + "0x" + adminWord.slice(-40), + "0x" + implementationWord.slice(-40), + ]) { + if (BigInt(target) === 0n) continue; + state.code[target.toLowerCase()] = await send("eth_getCode", [ + target, + "latest", + ]); + } + if (BigInt(adminWord) !== 0n) + row.adminOwner = await send("eth_call", [ + { to: "0x" + adminWord.slice(-40), data: id("owner()").slice(0, 10) }, + "latest", + ]); + } + const blocks = []; + const height = Number(BigInt(await send("eth_blockNumber", []))); + for (let number = 0; number <= height; number++) { + const block = await send("eth_getBlockByNumber", [ + "0x" + number.toString(16), + true, + ]); + const receipts = []; + for (const transaction of block.transactions) + receipts.push( + await send("eth_getTransactionReceipt", [transaction.hash]), + ); + blocks.push({ block, receipts }); + } + const artifactRoot = path.join(process.cwd(), "export/artifacts"); + if (!fs.existsSync(artifactRoot)) + throw new Error("Run prepack before capturing exported artifacts"); + fs.cpSync(artifactRoot, path.join(destination, "artifacts"), { + recursive: true, + }); + const tokenStakingName = + "@threshold-network/solidity-contracts/contracts/staking/TokenStaking.sol:TokenStaking"; + const buildInfo = await hre.artifacts.getBuildInfo(tokenStakingName); + const compilerLayout = + buildInfo?.output.contracts[tokenStakingName.split(":")[0]].TokenStaking + .storageLayout; + fs.writeFileSync( + path.join(destination, "compiler-storage-layout.json"), + JSON.stringify(compilerLayout ?? null, null, 2) + "\n", + ); + fs.writeFileSync( + path.join(destination, "chain.json"), + JSON.stringify(blocks, null, 2) + "\n", + ); + fs.writeFileSync( + path.join(destination, "state.json"), + JSON.stringify(state, null, 2) + "\n", + ); + fs.writeFileSync( + path.join(destination, "deployments.json"), + JSON.stringify(records, null, 2) + "\n", + ); + console.log( + `Captured ${Object.keys(records).length} deployments and ${Object.keys(state.code).length} code addresses`, + ); +})().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/solidity/scripts/ethers-v6-compatibility/compare.cjs b/solidity/scripts/ethers-v6-compatibility/compare.cjs new file mode 100644 index 0000000000..6f2b155cd5 --- /dev/null +++ b/solidity/scripts/ethers-v6-compatibility/compare.cjs @@ -0,0 +1,150 @@ +// Usage: node compare.cjs BASELINE_CAPTURE CANDIDATE_CAPTURE [--ethers-v6] +// The optional flag permits only the reviewed Hardhat 2 ethers v5 -> v6 gas +// changes. Without it, packed-package/fallback captures must match exactly. +const assert = require("node:assert/strict"); +const fs = require("node:fs"); +const path = require("node:path"); +const { createHash } = require("node:crypto"); + +const [baseline, candidate, mode] = process.argv.slice(2); +assert(baseline && candidate, "Two capture directories are required"); +assert(!mode || mode === "--ethers-v6", "Unknown comparison mode"); +const read = (root, file) => JSON.parse(fs.readFileSync(path.join(root, file))); +const byteEqual = (file) => + fs + .readFileSync(path.join(baseline, file)) + .equals(fs.readFileSync(path.join(candidate, file))); +for (const file of ["export.json", "state.json"]) { + assert(byteEqual(file), `${file} differs`); +} + +const before = read(baseline, "chain.json"); +const after = read(candidate, "chain.json"); +assert.equal(after.length, before.length, "Block count differs"); +const isEcdsa = Object.hasOwn( + read(candidate, "deployments.json"), + "WalletRegistry", +); +const gasChanges = + mode && isEcdsa + ? new Map([ + [33, 5222326], + [34, 443289], + [35, 1065225], + [42, 15799896], + [45, 809383], + [46, 683960], + ]) + : new Map(); +const hashes = new Map(); +const changedTransactions = new Set(); +for (let i = 0; i < before.length; i++) { + const a = before[i].block; + const b = after[i].block; + assert.equal(b.stateRoot, a.stateRoot, `State root differs at block ${i}`); + assert.equal(b.transactions.length, a.transactions.length); + if (gasChanges.size && i >= 33) hashes.set(b.hash, a.hash); + if (gasChanges.has(i)) { + assert.equal(a.transactions.length, 1); + const oldTx = a.transactions[0]; + const newTx = b.transactions[0]; + assert.equal(Number(BigInt(oldTx.gas)), gasChanges.get(i)); + assert.equal(Number(BigInt(newTx.gas)), 16777216); + hashes.set(newTx.hash, oldTx.hash); + changedTransactions.add(oldTx.hash); + } +} + +// Only hash-bearing fields are translated. Calldata, topics, bytecode, storage, +// ABI fields and all receipt fields other than hashes remain strict comparisons. +function translateHashes(value, key = "") { + if (Array.isArray(value)) return value.map((entry) => translateHashes(entry)); + if (value && typeof value === "object") { + return Object.fromEntries( + Object.entries(value).map(([name, entry]) => [ + name, + translateHashes(entry, name), + ]), + ); + } + return ["hash", "parentHash", "blockHash", "transactionHash"].includes(key) + ? (hashes.get(value) ?? value) + : value; +} + +const normalizedBefore = structuredClone(before); +const normalizedAfter = translateHashes(after); +for (const i of gasChanges.keys()) { + for (const chain of [normalizedBefore, normalizedAfter]) { + // These two headers encode the differently signed transaction. Everything + // else, including receiptsRoot, gasUsed, base fee and timestamp, must match. + delete chain[i].block.size; + delete chain[i].block.transactionsRoot; + const transaction = chain[i].block.transactions[0]; + assert(changedTransactions.has(transaction.hash)); + for (const field of ["gas", "r", "s", "v"]) delete transaction[field]; + } +} +assert.deepEqual(normalizedAfter, normalizedBefore, "Chain execution differs"); +assert.deepEqual( + translateHashes(read(candidate, "deployments.json")), + read(baseline, "deployments.json"), + "Deployment records differ beyond reviewed transaction/block hashes", +); + +function inventory(root, relative = "") { + return fs + .readdirSync(path.join(root, relative), { withFileTypes: true }) + .flatMap((entry) => { + const name = path.join(relative, entry.name); + return entry.isDirectory() ? inventory(root, name) : [name]; + }) + .sort(); +} +const oldArtifacts = path.join(baseline, "artifacts"); +const newArtifacts = path.join(candidate, "artifacts"); +const files = inventory(oldArtifacts); +assert.deepEqual(inventory(newArtifacts), files, "Artifact inventory differs"); +const additions = []; +for (const file of files) { + const oldBytes = fs.readFileSync(path.join(oldArtifacts, file)); + const newBytes = fs.readFileSync(path.join(newArtifacts, file)); + if (oldBytes.equals(newBytes)) continue; + assert(mode, `Artifact bytes differ: ${file}`); + assert.equal( + file, + "@threshold-network/solidity-contracts/contracts/staking/TokenStaking.sol/TokenStaking.json", + ); + const oldArtifact = JSON.parse(oldBytes); + const newArtifact = JSON.parse(newBytes); + assert(!Object.hasOwn(oldArtifact, "storageLayout")); + assert(newArtifact.storageLayout?.storage?.length > 0); + assert.deepEqual( + newArtifact.storageLayout, + read(candidate, "compiler-storage-layout.json"), + "Layout differs from compiler output", + ); + delete newArtifact.storageLayout; + assert.deepEqual(newArtifact, oldArtifact, "Other artifact fields differ"); + additions.push(`${file}: compiler storageLayout added`); +} +console.log( + JSON.stringify( + { + exportSha256: createHash("sha256") + .update(fs.readFileSync(path.join(candidate, "export.json"))) + .digest("hex"), + contracts: Object.keys(read(candidate, "deployments.json")).length, + transactionsWithIdenticalState: before.reduce( + (total, entry) => total + entry.block.transactions.length, + 0, + ), + deploymentRecordsByteIdentical: byteEqual("deployments.json"), + reviewedGasLimitChanges: [...gasChanges.keys()], + artifacts: files.length, + artifactAdditions: additions, + }, + null, + 2, + ), +); diff --git a/solidity/scripts/ethers-v6-compatibility/hardhat.config.cjs b/solidity/scripts/ethers-v6-compatibility/hardhat.config.cjs new file mode 100644 index 0000000000..ffa15cfd35 --- /dev/null +++ b/solidity/scripts/ethers-v6-compatibility/hardhat.config.cjs @@ -0,0 +1,90 @@ +const fs = require("node:fs"); +const path = require("node:path"); +const { createRequire } = require("node:module"); + +const requirePackage = createRequire(path.join(process.cwd(), "package.json")); +requirePackage("ts-node/register/transpile-only"); +const { extendProvider, task } = requirePackage("hardhat/config"); +const { ProviderWrapper } = requirePackage("hardhat/plugins"); +// Loading the packed configuration also registers only its own task exports. +// Registering source and packed tasks together would redefine required params. +const ecdsaExport = process.env.ECDSA_EXPORT_PATH; +const packageConfig = require( + ecdsaExport + ? path.resolve(ecdsaExport, "hardhat.config.js") + : path.join(process.cwd(), "hardhat.config.ts"), +); +const config = packageConfig.default; + +class FixedClockProvider extends ProviderWrapper { + async request(args) { + if ( + ["eth_sendTransaction", "eth_sendRawTransaction"].includes(args.method) + ) { + const latest = await this._wrapped.request({ + method: "eth_getBlockByNumber", + params: ["latest", false], + }); + await this._wrapped.request({ + method: "evm_setNextBlockTimestamp", + params: [Number.parseInt(latest.timestamp, 16) + 1], + }); + } + return this._wrapped.request(args); + } +} + +extendProvider(async (provider, resolvedConfig, network) => { + if ( + network !== "hardhat" || + resolvedConfig.networks.hardhat.forking?.enabled + ) { + throw new Error( + "Compatibility capture requires non-forked in-process Hardhat", + ); + } + return new FixedClockProvider(provider); +}); + +// Test the executable ECDSA export from an actual packed producer. +if (ecdsaExport) { + // The full-suite account guard imports test fixtures omitted from npm. + // These task tests need only the named slots and one set of staking roles. + task("check-accounts-count").setAction(async (_args, hre) => { + const { nonStakingAccountsCount, stakingRolesCount } = + packageConfig.testConfig; + const required = nonStakingAccountsCount + stakingRolesCount; + if ((await hre.ethers.getSigners()).length < required) { + throw new Error( + `Packed task checks require at least ${required} accounts`, + ); + } + }); + const root = path.resolve(ecdsaExport); + for (const subdir of ["deploy", "artifacts", "tasks"]) { + const directory = path.join(root, subdir); + if (!fs.existsSync(directory) || !fs.statSync(directory).isDirectory()) { + throw new Error(`ECDSA ${subdir} export is missing: ${root}`); + } + } + config.paths = { ...config.paths, deploy: path.join(root, "deploy") }; + config.external = { + ...config.external, + contracts: [ + ...(config.external?.contracts ?? []), + { artifacts: path.join(root, "artifacts") }, + ], + }; +} + +module.exports = { + ...config, + paths: { ...config.paths, root: process.cwd() }, + networks: { + ...config.networks, + hardhat: { + ...config.networks.hardhat, + initialDate: "2024-01-01T00:00:00.000Z", + }, + }, +}; diff --git a/solidity/scripts/ethers-v6-compatibility/pack-and-capture.cjs b/solidity/scripts/ethers-v6-compatibility/pack-and-capture.cjs new file mode 100644 index 0000000000..76800eca48 --- /dev/null +++ b/solidity/scripts/ethers-v6-compatibility/pack-and-capture.cjs @@ -0,0 +1,193 @@ +// Run from solidity/ecdsa; packing runs each package's prepack step: +// node ../scripts/ethers-v6-compatibility/pack-and-capture.cjs NEW_DIRECTORY REFERENCE_CAPTURE +const assert = require("node:assert/strict"); +const fs = require("node:fs"); +const path = require("node:path"); +const { execFileSync } = require("node:child_process"); + +const [destination, reference] = process.argv.slice(2); +assert( + destination && reference, + "A new destination and reference capture are required", +); +assert.equal( + JSON.parse(fs.readFileSync("package.json")).name, + "@keep-network/ecdsa", +); +const root = path.resolve(destination); +assert(!fs.existsSync(root), "Destination already exists"); +fs.mkdirSync(root, { recursive: true }); +const consumerModules = path.join(root, "node_modules"); +fs.mkdirSync(path.join(consumerModules, "@keep-network"), { recursive: true }); + +// Reuse the installed consumer runtime/plugins. Producer contents come solely +// from the archives; no source-directory or sibling-export symlinks are used. +const installed = path.join(process.cwd(), "node_modules"); +for (const name of fs.readdirSync(installed)) { + if (name.startsWith(".")) continue; + if (name === "@keep-network") { + for (const dependency of fs.readdirSync(path.join(installed, name))) { + if (["random-beacon", "ecdsa"].includes(dependency)) continue; + fs.symlinkSync( + path.join(installed, name, dependency), + path.join(consumerModules, name, dependency), + "dir", + ); + } + } else { + fs.symlinkSync( + path.join(installed, name), + path.join(consumerModules, name), + "dir", + ); + } +} + +const packages = {}; +for (const name of ["random-beacon", "ecdsa"]) { + const source = path.resolve("..", name); + // Lifecycle scripts stay enabled so prepack regenerates export/ for the + // archive. npm runs prepare/prepack for `npm pack`, never prepublishOnly. + const output = execFileSync( + "npm", + ["pack", "--json", "--pack-destination", root], + { cwd: source, encoding: "utf8" }, + ); + const [packed] = JSON.parse(output); + const target = path.join(consumerModules, "@keep-network", name); + fs.mkdirSync(target); + execFileSync("tar", [ + "-xzf", + path.join(root, packed.filename), + "--strip-components=1", + "-C", + target, + ]); + for (const file of packed.files) { + if ( + !file.path.startsWith("export/") && + !file.path.startsWith("external/random-beacon-export/") + ) + continue; + assert( + fs + .readFileSync(path.join(source, file.path)) + .equals(fs.readFileSync(path.join(target, file.path))), + `Packed file differs: ${name}/${file.path}`, + ); + } + const artifactCount = packed.files.filter((file) => + file.path.startsWith("export/artifacts/"), + ).length; + const expectedArtifacts = name === "random-beacon" ? 51 : 52; + assert.equal( + artifactCount, + expectedArtifacts, + `${name} packed ${artifactCount} export/artifacts entries, ` + + `expected ${expectedArtifacts}. Update it here and the artifact ` + + `inventory row in solidity/docs/ethers-v6-compatibility.md`, + ); + if (name === "random-beacon") { + assert( + packed.files.some( + (file) => file.path === "export/utils/wait-for-confirmations.js", + ), + ); + } else { + for (const required of [ + "export/tasks/random-beacon.js", + "export/utils/random-beacon-export.js", + "external/random-beacon-export/tasks/initialize.js", + "external/random-beacon-export/tasks/unlock-eth-accounts.js", + "external/random-beacon-export/tasks/utils/index.js", + ]) { + assert( + packed.files.some((file) => file.path === required), + required, + ); + } + const prefix = "external/random-beacon-export/"; + for (const file of packed.files) { + if (!file.path.startsWith(prefix) || !file.path.endsWith(".js")) continue; + assert( + fs + .readFileSync(path.join(target, file.path)) + .equals( + fs.readFileSync( + path.resolve( + "../random-beacon/export", + file.path.slice(prefix.length), + ), + ), + ), + `Bundled Beacon export is stale: ${file.path}`, + ); + } + } + packages[name] = packed; +} +fs.writeFileSync( + path.join(root, "packed-files.json"), + JSON.stringify(packages, null, 2) + "\n", +); +const capture = path.join(root, "capture"); +const producerEnvironment = { + ...process.env, + HARDHAT_CONFIG: path.join(__dirname, "hardhat.config.cjs"), + USE_EXTERNAL_DEPLOY: "true", + RANDOM_BEACON_EXPORT_PATH: path.join( + consumerModules, + "@keep-network/random-beacon/export", + ), + ECDSA_EXPORT_PATH: path.join(consumerModules, "@keep-network/ecdsa/export"), +}; +execFileSync(process.execPath, [path.join(__dirname, "capture.cjs")], { + stdio: "inherit", + env: { + ...producerEnvironment, + MIGRATION_CAPTURE_DIR: capture, + }, +}); +execFileSync( + process.execPath, + [path.join(__dirname, "compare.cjs"), path.resolve(reference), capture], + { stdio: "inherit" }, +); + +const taskTests = [ + path.join(installed, "hardhat/internal/cli/cli.js"), + "test", + "--no-compile", + "--network", + "hardhat", + "test/tasks/initialize.test.ts", + "test/tasks/unlock-accounts.test.ts", +]; +console.log("Checking packed ECDSA tasks with the packed v6 Beacon producer"); +execFileSync(process.execPath, taskTests, { + stdio: "inherit", + env: producerEnvironment, +}); + +// Recreate the locked consumer dependency while retaining ECDSA's real tarball. +// Its compiled task imports must use the shipped v6 bundle, not the v5 neighbor. +const packedBeacon = path.join(consumerModules, "@keep-network/random-beacon"); +const savedPackedBeacon = path.join(root, "packed-random-beacon"); +fs.renameSync(packedBeacon, savedPackedBeacon); +fs.symlinkSync( + path.join(installed, "@keep-network/random-beacon"), + packedBeacon, + "dir", +); +const bundledEnvironment = { ...producerEnvironment }; +delete bundledEnvironment.RANDOM_BEACON_EXPORT_PATH; +try { + console.log("Checking packed ECDSA tasks with the pinned Beacon dependency"); + execFileSync(process.execPath, taskTests, { + stdio: "inherit", + env: bundledEnvironment, + }); +} finally { + fs.unlinkSync(packedBeacon); + fs.renameSync(savedPackedBeacon, packedBeacon); +} diff --git a/test/config.json b/test/config.json index 0792a2b49d..d33a9a66d1 100644 --- a/test/config.json +++ b/test/config.json @@ -50,7 +50,8 @@ "HistoryDepth": 25000, "TransactionLimit": 80, "RestartBackoffTime": "2h", - "IdleBackoffTime": "15m" + "IdleBackoffTime": "15m", + "MaxProofHeaders": 144 } }, "Developer": { diff --git a/test/config.toml b/test/config.toml index 8e22dae494..7089b5b72e 100644 --- a/test/config.toml +++ b/test/config.toml @@ -46,7 +46,7 @@ HistoryDepth = 25000 TransactionLimit = 80 RestartBackoffTime = "2h" IdleBackoffTime = "15m" - +MaxProofHeaders = 144 [developer] RandomBeaconAddress = "0xcf64c2a367341170cb4e09cf8c0ed137d8473ceb" WalletRegistryAddress = "0x143ba24e66fce8bca22f7d739f9a932c519b1c76" diff --git a/test/config.yaml b/test/config.yaml index 8809033eeb..7c26d26cb0 100644 --- a/test/config.yaml +++ b/test/config.yaml @@ -41,6 +41,7 @@ Maintainer: TransactionLimit: 80 RestartBackoffTime: "2h" IdleBackoffTime: "15m" + MaxProofHeaders: 144 Developer: RandomBeaconAddress: "0xcf64c2a367341170cb4e09cf8c0ed137d8473ceb" WalletRegistryAddress: "0x143ba24e66fce8bca22f7d739f9a932c519b1c76" diff --git a/test/config_flags.toml b/test/config_flags.toml index e6597b2ea1..9e4efc474e 100644 --- a/test/config_flags.toml +++ b/test/config_flags.toml @@ -20,3 +20,17 @@ Dir = "/my/secure/location" [clientinfo] # Port is expected to be read from the file, not passed as a flag. Port = 3097 + +[tbtc.transactionMonitor] +# StuckThreshold is overridden by a flag; the other values come from this file. +StuckThreshold = "1h" +CheckInterval = "45s" +MaxTracked = 50 +MaxTrackingAge = "12h" + +[maintainer.spv] +MaxProofHeaders = 144 +HistoryDepth = 25000 +TransactionLimit = 80 +RestartBackoffTime = "2h" +IdleBackoffTime = "15m" diff --git a/test/config_mixed_contracts.toml b/test/config_mixed_contracts.toml index a3c4f69b8e..8628a78bbe 100644 --- a/test/config_mixed_contracts.toml +++ b/test/config_mixed_contracts.toml @@ -15,3 +15,10 @@ Dir = "/my/secure/location" [developer] WalletRegistryAddress = "0x143ba24e66fce8bca22f7d739f9a932c519b1c76" + +[Maintainer.Spv] +MaxProofHeaders = 144 +HistoryDepth = 25000 +TransactionLimit = 80 +RestartBackoffTime = "2h" +IdleBackoffTime = "15m" diff --git a/test/config_no_contracts.toml b/test/config_no_contracts.toml index 1456a034a5..fd2d989383 100644 --- a/test/config_no_contracts.toml +++ b/test/config_no_contracts.toml @@ -12,3 +12,10 @@ Port = 27001 [Storage] Dir = "/my/secure/location" + +[Maintainer.Spv] +MaxProofHeaders = 144 +HistoryDepth = 25000 +TransactionLimit = 80 +RestartBackoffTime = "2h" +IdleBackoffTime = "15m" diff --git a/test/config_no_password.toml b/test/config_no_password.toml index 15e264c13d..0d4f7ffe65 100644 --- a/test/config_no_password.toml +++ b/test/config_no_password.toml @@ -12,3 +12,10 @@ Port = 27001 [Storage] Dir = "/my/secure/location" + +[Maintainer.Spv] +MaxProofHeaders = 144 +HistoryDepth = 25000 +TransactionLimit = 80 +RestartBackoffTime = "2h" +IdleBackoffTime = "15m" diff --git a/third_party/go-electrum/LICENSE b/third_party/go-electrum/LICENSE new file mode 100644 index 0000000000..d323e46d79 --- /dev/null +++ b/third_party/go-electrum/LICENSE @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) 2022 Roman Maklakov +Copyright (c) 2019 Ian Descôteaux +Copyright (c) 2015 Tristan Rice + +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/third_party/go-electrum/VENDOR.md b/third_party/go-electrum/VENDOR.md new file mode 100644 index 0000000000..425a3855ba --- /dev/null +++ b/third_party/go-electrum/VENDOR.md @@ -0,0 +1,97 @@ +# Vendored go-electrum + +Source: https://github.com/keep-network/go-electrum/tree/6038cb594daa66c69ea0482fa849b165b115c97b + +This is the same revision previously selected by the root `go.mod` replacement: +`github.com/keep-network/go-electrum v0.0.0-20240206170935-6038cb594daa`. +Its module checksum is `h1:AKTJr+STc4rP9NcN2ppP9Zft3GbYechFW8q/S8UNQrQ=`. +The original MIT license is retained in `LICENSE`. + +The copy is based on that module's `electrum/*.go`, `go.mod`, `go.sum`, and +`LICENSE`. Examples and README/media assets are omitted. Go files were +formatted with gofmt. Four files materially differ from upstream — +`network.go`, `transport.go`, `transport_ws.go`, and `scripthash.go` — and are +documented below. `cancellation_test.go` and `network_test.go` are local +additions with no upstream counterpart. RPC encoding, response types, and +Bitcoin address logic are otherwise unchanged. + +Local patches: + +- `network.go` adds idempotent `Client.Abort`. `Shutdown` uses the same abort. + Closing the transport releases socket reads and writes and pending RPCs. + Transport and handler references remain stable during shutdown; maps are + reclaimed with the client instead of being cleared concurrently with RPCs. + Error and response delivery can no longer strand the reader after abort. + Response handlers are installed before sending to accept immediate replies. + `apiErr.UnmarshalJSON` now guards the `code` field with a checked type + assertion instead of an unchecked cast, so a server that sends a + non-numeric `code` (e.g. electrs/esplora) cannot panic the read loop. + `Client.listen` recovers from a panic raised while processing a single + message and keeps the loop running instead of letting the panic escape the + read-loop goroutine. +- `transport.go` closes the TCP/TLS socket and unblocks reader channel sends. + It also bounds a single line read to 32 MiB (`readBoundedLine`), closing the + transport with a distinguishable `ErrMessageTooLarge`-wrapped error instead + of buffering without limit when a server withholds the trailing newline or + sends an oversized message. +- `transport_ws.go` closes Gorilla's underlying connection directly. It never + sends a WebSocket close frame from cancellation: `Conn.Close` supports + concurrent writes, whereas `WriteMessage` does not. Reader channel sends are + also interrupted. Shutdown is deliberately an abort rather than a graceful + WebSocket close handshake. It also calls `Conn.SetReadLimit(32 << 20)` after + dialing to bound per-message allocation. +- `scripthash.go` changes `ListUnspentResult.Height` from `uint32` to + `int32`, matching `GetMempoolResult.Height` and the Electrum protocol's use + of `-1` for a mempool entry. +- `cancellation_test.go` exercises real Gorilla `ws` and `wss` writers with + controlled socket backpressure, a TCPTransport parity case, plus concurrent + shutdown of a pending RPC and transport readers. The WebSocket and TCP + cases reproduce the concurrent-write panic and un-abortable write with the + original transport. +- `network_test.go` regression-tests that unmarshaling an `apiErr` with a + non-numeric `code` field does not panic. + +Run from the repository root so the tests use the application's dependency graph: + +```sh +go test -race -timeout 3m github.com/checksum0/go-electrum/electrum +``` + +The `electrum-lifecycle` CI job runs these tests explicitly, along with the +application's Electrum and config tests. Root `go test ./...` does not discover +tests within nested modules. + +To compare the local patch with the pinned source, mirroring the +verification recipe used for `third_party/btcsuite/btcec`: + +```sh +go mod download github.com/keep-network/go-electrum@v0.0.0-20240206170935-6038cb594daa +upstream="$(go env GOMODCACHE)/github.com/keep-network/go-electrum@v0.0.0-20240206170935-6038cb594daa" +cp -R "$upstream/electrum" /tmp/go-electrum-upstream +chmod -R u+w /tmp/go-electrum-upstream +gofmt -w /tmp/go-electrum-upstream +diff -r /tmp/go-electrum-upstream third_party/go-electrum/electrum +``` + +The only differences reported must be content diffs in the four patched +files (`network.go`, `transport.go`, `transport_ws.go`, `scripthash.go`) and +two files present only on our side (`cancellation_test.go`, +`network_test.go`). `go.mod`, `go.sum`, `LICENSE`, and this file live one +directory up, in `third_party/go-electrum/`, alongside the `electrum/` +package copy, so they are outside this `electrum/`-scoped diff; `go.mod`'s +module path intentionally differs from upstream +(`github.com/checksum0/go-electrum` here vs. +`github.com/keep-network/go-electrum` upstream) to match the root module's +`replace` target, and `VENDOR.md` has no upstream counterpart by definition. + +## Exit path + +The lifecycle, hardening, and `Height`-typing patches in `network.go`, +`transport.go`, `transport_ws.go`, and `scripthash.go` should be upstreamed +to `keep-network/go-electrum` (the previous `replace` target, pinned at +`v0.0.0-20240206170935-6038cb594daa`). Once that fork carries the patch, this +directory can be removed and the root `go.mod` restored to a `replace` +pointing at the fork. If the patch is instead adopted directly in +`checksum0/go-electrum` (the module path this copy currently declares), this +vendored copy can be archived in favor of a normal module dependency on that +fork. diff --git a/third_party/go-electrum/electrum/address.go b/third_party/go-electrum/electrum/address.go new file mode 100644 index 0000000000..a4253c98ed --- /dev/null +++ b/third_party/go-electrum/electrum/address.go @@ -0,0 +1,31 @@ +package electrum + +import ( + "crypto/sha256" + "encoding/hex" + + "github.com/btcsuite/btcd/btcutil" + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/txscript" +) + +// AddressToElectrumScriptHash converts valid bitcoin address to electrum scriptHash sha256 encoded, reversed and encoded in hex +// https://electrumx.readthedocs.io/en/latest/protocol-basics.html#script-hashes +func AddressToElectrumScriptHash(addressStr string) (string, error) { + address, err := btcutil.DecodeAddress(addressStr, &chaincfg.MainNetParams) + if err != nil { + return "", err + } + script, err := txscript.PayToAddrScript(address) + if err != nil { + return "", err + } + + hashSum := sha256.Sum256(script) + + for i, j := 0, len(hashSum)-1; i < j; i, j = i+1, j-1 { + hashSum[i], hashSum[j] = hashSum[j], hashSum[i] + } + + return hex.EncodeToString(hashSum[:]), nil +} diff --git a/third_party/go-electrum/electrum/address_test.go b/third_party/go-electrum/electrum/address_test.go new file mode 100644 index 0000000000..faba113346 --- /dev/null +++ b/third_party/go-electrum/electrum/address_test.go @@ -0,0 +1,29 @@ +package electrum + +import ( + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "testing" +) + +func TestAddressToElectrumScriptHash(t *testing.T) { + tests := []struct { + address string + wantScriptHash string + }{ + { + address: "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa", + wantScriptHash: "8b01df4e368ea28f8dc0423bcf7a4923e3a12d307c875e47a0cfbf90b5c39161", + }, + { + address: "34xp4vRoCGJym3xR7yCVPFHoCNxv4Twseo", + wantScriptHash: "2375f2bbf7815e3cdc835074b052d65c9b2f101bab28d37250cc96b2ed9a6809", + }, + } + + for _, tc := range tests { + scriptHash, err := AddressToElectrumScriptHash(tc.address) + require.NoError(t, err) + assert.Equal(t, scriptHash, tc.wantScriptHash) + } +} diff --git a/third_party/go-electrum/electrum/block.go b/third_party/go-electrum/electrum/block.go new file mode 100644 index 0000000000..5111d8b03d --- /dev/null +++ b/third_party/go-electrum/electrum/block.go @@ -0,0 +1,91 @@ +package electrum + +import ( + "context" + "errors" +) + +var ( + // ErrCheckpointHeight is thrown if the checkpoint height is smaller than the block height. + ErrCheckpointHeight = errors.New("checkpoint height must be greater than or equal to block height") +) + +// GetBlockHeaderResp represents the response to GetBlockHeader(). +type GetBlockHeaderResp struct { + Result *GetBlockHeaderResult `json:"result"` +} + +// GetBlockHeaderResult represents the content of the result field in the response to GetBlockHeader(). +type GetBlockHeaderResult struct { + Branch []string `json:"branch"` + Header string `json:"header"` + Root string `json:"root"` +} + +// GetBlockHeader returns the block header at a specific height. +// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-block-header +func (s *Client) GetBlockHeader(ctx context.Context, height uint32, checkpointHeight ...uint32) (*GetBlockHeaderResult, error) { + if checkpointHeight != nil && checkpointHeight[0] != 0 { + if height > checkpointHeight[0] { + return nil, ErrCheckpointHeight + } + + var resp GetBlockHeaderResp + err := s.request(ctx, "blockchain.block.header", []interface{}{height, checkpointHeight[0]}, &resp) + + return resp.Result, err + } + + var resp basicResp + err := s.request(ctx, "blockchain.block.header", []interface{}{height, 0}, &resp) + if err != nil { + return nil, err + } + + result := &GetBlockHeaderResult{ + Branch: nil, + Header: resp.Result, + Root: "", + } + + return result, err +} + +// GetBlockHeadersResp represents the response to GetBlockHeaders(). +type GetBlockHeadersResp struct { + Result *GetBlockHeadersResult `json:"result"` +} + +// GetBlockHeadersResult represents the content of the result field in the response to GetBlockHeaders(). +type GetBlockHeadersResult struct { + Count uint32 `json:"count"` + Headers string `json:"hex"` + Max uint32 `json:"max"` + Branch []string `json:"branch,omitempty"` + Root string `json:"root,omitempty"` +} + +// GetBlockHeaders return a concatenated chunk of block headers. +// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-block-headers +func (s *Client) GetBlockHeaders(ctx context.Context, startHeight, count uint32, + checkpointHeight ...uint32) (*GetBlockHeadersResult, error) { + + var resp GetBlockHeadersResp + var err error + + if checkpointHeight != nil && checkpointHeight[0] != 0 { + if (startHeight + (count - 1)) > checkpointHeight[0] { + return nil, ErrCheckpointHeight + } + + err = s.request(ctx, "blockchain.block.headers", []interface{}{startHeight, count, checkpointHeight[0]}, &resp) + } else { + err = s.request(ctx, "blockchain.block.headers", []interface{}{startHeight, count, 0}, &resp) + } + + if err != nil { + return nil, err + } + + return resp.Result, err +} diff --git a/third_party/go-electrum/electrum/cancellation_test.go b/third_party/go-electrum/electrum/cancellation_test.go new file mode 100644 index 0000000000..362d502a81 --- /dev/null +++ b/third_party/go-electrum/electrum/cancellation_test.go @@ -0,0 +1,331 @@ +package electrum + +import ( + "bufio" + "context" + "crypto/tls" + "encoding/json" + "errors" + "net" + "net/http" + "net/http/httptest" + "strings" + "sync" + "sync/atomic" + "testing" + "time" + + "github.com/gorilla/websocket" +) + +// Gate the socket write after the real HTTP/TLS upgrade. Gorilla's writer is +// active while Write waits, as it would be under network backpressure. +type gatedWriteConn struct { + net.Conn + gate uint32 + started chan struct{} + closed chan struct{} + once sync.Once + start sync.Once +} + +func (c *gatedWriteConn) Write(p []byte) (int, error) { + if atomic.LoadUint32(&c.gate) != 0 { + c.start.Do(func() { close(c.started) }) + <-c.closed + return 0, net.ErrClosed + } + return c.Conn.Write(p) +} + +func (c *gatedWriteConn) Close() error { + c.once.Do(func() { close(c.closed) }) + return c.Conn.Close() +} + +func TestShutdownInterruptsWebSocketWrite(t *testing.T) { + for _, secure := range []bool{false, true} { + for _, method := range []string{"verification", "keepalive"} { + scheme := "ws" + if secure { + scheme = "wss" + } + t.Run(scheme+"/"+method, func(t *testing.T) { + releaseServer := make(chan struct{}) + server := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + upgrader := websocket.Upgrader{} + peer, err := upgrader.Upgrade(w, r, nil) + if err != nil { + return + } + defer peer.Close() + <-releaseServer + })) + if secure { + server.StartTLS() + } else { + server.Start() + } + defer server.Close() + defer close(releaseServer) + var socket *gatedWriteConn + dial := func(ctx context.Context, network, address string) (net.Conn, error) { + var conn net.Conn + var err error + if secure { + config := server.Client().Transport.(*http.Transport).TLSClientConfig + dialer := tls.Dialer{Config: config} + conn, err = dialer.DialContext(ctx, network, address) + } else { + var dialer net.Dialer + conn, err = dialer.DialContext(ctx, network, address) + } + if err != nil { + return nil, err + } + socket = &gatedWriteConn{Conn: conn, started: make(chan struct{}), closed: make(chan struct{})} + return socket, nil + } + dialer := websocket.Dialer{NetDialContext: dial, NetDialTLSContext: dial} + conn, response, err := dialer.Dial(strings.Replace(server.URL, "http", "ws", 1), nil) + if response != nil { + response.Body.Close() + } + if err != nil { + t.Fatal(err) + } + defer conn.Close() + transport := &WebSocketTransport{conn: conn, done: make(chan struct{})} + // No reader is needed for a write that fails on socket closure. + client := &Client{transport: transport, quit: make(chan struct{}), handlers: make(map[uint64]chan *container)} + atomic.StoreUint32(&socket.gate, 1) + result := make(chan error, 1) + go func() { + if method == "verification" { + _, _, err := client.ServerVersion(context.Background()) + result <- err + } else { + result <- client.Ping(context.Background()) + } + }() + select { + case <-socket.started: + case <-time.After(time.Second): + t.Fatal("RPC did not enter the WebSocket write") + } + func() { + defer func() { + if p := recover(); p != nil { + t.Errorf("shutdown panicked during an active WebSocket write: %v", p) + } + }() + client.Shutdown() + }() + select { + case <-socket.closed: + default: + t.Error("shutdown returned without aborting the socket") + } + // Release and join the writer even when the regression is present. + socket.Close() + select { + case err := <-result: + if err == nil { + t.Error("expected the aborted write to fail") + } + case <-time.After(time.Second): + t.Fatal("shutdown did not unblock the WebSocket writer") + } + }) + } + } +} + +// TestShutdownInterruptsTCPWrite is the TCPTransport parity case for +// TestShutdownInterruptsWebSocketWrite: a blocked write must be unblocked by +// Client.Shutdown aborting the transport, not left hanging on the socket. +func TestShutdownInterruptsTCPWrite(t *testing.T) { + for _, method := range []string{"verification", "keepalive"} { + t.Run(method, func(t *testing.T) { + clientConn, serverConn := net.Pipe() + defer serverConn.Close() + socket := &gatedWriteConn{Conn: clientConn, started: make(chan struct{}), closed: make(chan struct{})} + transport := &TCPTransport{conn: socket, done: make(chan struct{})} + // No reader is needed for a write that fails on socket closure. + client := &Client{transport: transport, quit: make(chan struct{}), handlers: make(map[uint64]chan *container)} + atomic.StoreUint32(&socket.gate, 1) + result := make(chan error, 1) + go func() { + if method == "verification" { + _, _, err := client.ServerVersion(context.Background()) + result <- err + } else { + result <- client.Ping(context.Background()) + } + }() + select { + case <-socket.started: + case <-time.After(time.Second): + t.Fatal("RPC did not enter the TCP write") + } + func() { + defer func() { + if p := recover(); p != nil { + t.Errorf("shutdown panicked during an active TCP write: %v", p) + } + }() + client.Shutdown() + }() + select { + case <-socket.closed: + default: + t.Error("shutdown returned without aborting the socket") + } + // Release and join the writer even when the regression is present. + socket.Close() + select { + case err := <-result: + if err == nil { + t.Error("expected the aborted write to fail") + } + case <-time.After(time.Second): + t.Fatal("shutdown did not unblock the TCP writer") + } + }) + } +} + +func TestAbortReleasesPendingResponseAndReaders(t *testing.T) { + conn, peer := net.Pipe() + defer peer.Close() + transport := &TCPTransport{ + conn: conn, done: make(chan struct{}), + responses: make(chan []byte), errors: make(chan error), + } + client := &Client{ + transport: transport, quit: make(chan struct{}), Error: make(chan error, 1), + handlers: make(map[uint64]chan *container), + } + transportDone := make(chan struct{}) + clientDone := make(chan struct{}) + rpcDone := make(chan struct{}) + peerDone := make(chan struct{}) + result := make(chan error, 1) + go func() { defer close(transportDone); transport.listen() }() + go func() { defer close(clientDone); client.listen() }() + go func() { + defer close(rpcDone) + _, _, err := client.ServerVersion(context.Background()) + result <- err + }() + go func() { + defer close(peerDone) + _, _ = bufio.NewReader(peer).ReadString('\n') + }() + t.Cleanup(func() { + client.Abort() + peer.Close() + for _, done := range []chan struct{}{transportDone, clientDone, rpcDone, peerDone} { + select { + case <-done: + case <-time.After(time.Second): + t.Error("abort left a client goroutine blocked") + } + } + }) + select { + case <-peerDone: + case <-time.After(time.Second): + t.Fatal("peer did not receive the version request") + } + // Abort may race with a caller, the reader, or failed-write cleanup. + var group sync.WaitGroup + for i := 0; i < 3; i++ { + group.Add(1) + go func() { defer group.Done(); client.Shutdown() }() + } + group.Wait() + select { + case err := <-result: + if !errors.Is(err, ErrServerShutdown) { + t.Errorf("pending response returned %v instead of shutdown", err) + } + case <-time.After(time.Second): + t.Fatal("abort did not interrupt the pending response") + } +} + +// syncReplyTransport is a Transport double that answers a request from +// inside SendMessage, before SendMessage returns to its caller -- the way a +// fast local server can. It exercises the handler-registration-before-send +// ordering in Client.request: the reply must never be dropped for want of a +// handler that hadn't been registered yet. +type syncReplyTransport struct { + responses chan []byte + errors chan error +} + +func (t *syncReplyTransport) SendMessage(body []byte) error { + var msg request + if err := json.Unmarshal(body, &msg); err != nil { + return err + } + + reply, err := json.Marshal(struct { + ID uint64 `json:"id"` + Result [2]string `json:"result"` + }{ID: msg.ID, Result: [2]string{"ElectrumX 1.0", ProtocolVersion}}) + if err != nil { + return err + } + + t.responses <- reply + return nil +} + +func (t *syncReplyTransport) Responses() <-chan []byte { return t.responses } +func (t *syncReplyTransport) Errors() <-chan error { return t.errors } +func (t *syncReplyTransport) Close() error { return nil } + +// TestRequestHandlerRegisteredBeforeSend regression-tests the ordering fix in +// Client.request: the pending handler must be registered in s.handlers +// before SendMessage is called. syncReplyTransport answers from inside +// SendMessage, so if registration ever moved back after the send, the reply +// would arrive at listen() before any handler existed for it, get dropped, +// and leave the request blocked on <-c forever. +func TestRequestHandlerRegisteredBeforeSend(t *testing.T) { + transport := &syncReplyTransport{ + responses: make(chan []byte), + errors: make(chan error), + } + client := &Client{ + transport: transport, quit: make(chan struct{}), Error: make(chan error, 1), + handlers: make(map[uint64]chan *container), + } + + listenDone := make(chan struct{}) + go func() { defer close(listenDone); client.listen() }() + t.Cleanup(func() { + client.Shutdown() + select { + case <-listenDone: + case <-time.After(time.Second): + t.Error("shutdown left the listen goroutine blocked") + } + }) + + result := make(chan error, 1) + go func() { + _, _, err := client.ServerVersion(context.Background()) + result <- err + }() + + select { + case err := <-result: + if err != nil { + t.Errorf("ServerVersion returned %v, want nil", err) + } + case <-time.After(time.Second): + t.Fatal("request never returned: the reply raced past an unregistered handler and was dropped") + } +} diff --git a/third_party/go-electrum/electrum/misc.go b/third_party/go-electrum/electrum/misc.go new file mode 100644 index 0000000000..cca054316b --- /dev/null +++ b/third_party/go-electrum/electrum/misc.go @@ -0,0 +1,64 @@ +package electrum + +import "context" + +type basicResp struct { + Result string `json:"result"` +} + +// GetFeeResp represents the response to GetFee(). +type GetFeeResp struct { + Result float32 `json:"result"` +} + +// GetFee returns the estimated transaction fee per kilobytes for a transaction +// to be confirmed within a target number of blocks. +// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-estimatefee +func (s *Client) GetFee(ctx context.Context, target uint32) (float32, error) { + var resp GetFeeResp + + err := s.request(ctx, "blockchain.estimatefee", []interface{}{target}, &resp) + if err != nil { + return -1, err + } + + return resp.Result, err +} + +// GetRelayFee returns the minimum fee a transaction must pay to be accepted into the +// remote server memory pool. +// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-relayfee +func (s *Client) GetRelayFee(ctx context.Context) (float32, error) { + var resp GetFeeResp + + err := s.request(ctx, "blockchain.relayfee", []interface{}{}, &resp) + if err != nil { + return -1, err + } + + return resp.Result, err +} + +// GetFeeHistogramResp represents the response to GetFee(). +type getFeeHistogramResp struct { + Result [][2]uint64 `json:"result"` +} + +// GetFeeHistogram returns a histogram of the fee rates paid by transactions in the +// memory pool, weighted by transacation size. +// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#mempool-get-fee-histogram +func (s *Client) GetFeeHistogram(ctx context.Context) (map[uint32]uint64, error) { + var resp getFeeHistogramResp + + err := s.request(ctx, "mempool.get_fee_histogram", []interface{}{}, &resp) + if err != nil { + return nil, err + } + + feeMap := make(map[uint32]uint64) + for i := 0; i < len(resp.Result); i++ { + feeMap[uint32(resp.Result[i][0])] = resp.Result[i][1] + } + + return feeMap, err +} diff --git a/third_party/go-electrum/electrum/network.go b/third_party/go-electrum/electrum/network.go new file mode 100644 index 0000000000..12936cae4a --- /dev/null +++ b/third_party/go-electrum/electrum/network.go @@ -0,0 +1,385 @@ +package electrum + +import ( + "context" + "crypto/tls" + "encoding/json" + "errors" + "fmt" + "log" + "net/url" + "sync" + "sync/atomic" +) + +const ( + // ClientVersion identifies the client version/name to the remote server + ClientVersion = "go-electrum1.1" + + // ProtocolVersion identifies the support protocol version to the remote server + ProtocolVersion = "1.4" + + nl = byte('\n') +) + +var ( + // DebugMode provides debug output on communications with the remote server if enabled. + DebugMode bool + + // ErrServerConnected throws an error if remote server is already connected. + ErrServerConnected = errors.New("server is already connected") + + // ErrServerShutdown throws an error if remote server has shutdown. + ErrServerShutdown = errors.New("server has shutdown") + + // ErrTimeout throws an error if request has timed out + ErrTimeout = errors.New("request timeout") + + // ErrNotImplemented throws an error if this RPC call has not been implemented yet. + ErrNotImplemented = errors.New("RPC call is not implemented") + + // ErrDeprecated throws an error if this RPC call is deprecated. + ErrDeprecated = errors.New("RPC call has been deprecated") +) + +// Transport provides interface to server transport. +type Transport interface { + SendMessage([]byte) error + Responses() <-chan []byte + Errors() <-chan error + Close() error +} + +type container struct { + content []byte + err error +} + +// Client stores information about the remote server. +type Client struct { + transport Transport + + handlers map[uint64]chan *container + handlersLock sync.RWMutex + + pushHandlers map[string][]chan *container + pushHandlersLock sync.RWMutex + + Error chan error + quit chan struct{} + shutdownOnce sync.Once + + nextID uint64 +} + +// NewClient initializes a new client for remote server and connects to it using +// a transport protocol resolved from the URL's protocol scheme. +// A remote server URL should be provided in the `scheme://hostname:port` format +// (e.g. `tcp://electrum.io:50001`). +func NewClient(ctx context.Context, urlStr string, tlsConfig *tls.Config) (*Client, error) { + u, err := url.Parse(urlStr) + if err != nil { + return nil, fmt.Errorf("failed to parse url [%s]: [%w]", urlStr, err) + } + + switch u.Scheme { + case "tcp": + return NewClientTCP(ctx, u.Host) + case "ssl": + return NewClientSSL(ctx, u.Host, tlsConfig) + case "ws", "wss": + return NewClientWebSocket(ctx, u.String(), tlsConfig) + } + + return nil, fmt.Errorf("unsupported protocol scheme: [%s]", u.Scheme) +} + +// NewClientTCP initialize a new client for remote server and connects to the remote server using TCP +func NewClientTCP(ctx context.Context, addr string) (*Client, error) { + transport, err := NewTCPTransport(ctx, addr) + if err != nil { + return nil, err + } + + c := &Client{ + handlers: make(map[uint64]chan *container), + pushHandlers: make(map[string][]chan *container), + + Error: make(chan error, 1), + quit: make(chan struct{}), + } + + c.transport = transport + go c.listen() + + return c, nil +} + +// NewClientSSL initialize a new client for remote server and connects to the remote server using SSL +func NewClientSSL(ctx context.Context, addr string, config *tls.Config) (*Client, error) { + transport, err := NewSSLTransport(ctx, addr, config) + if err != nil { + return nil, err + } + + c := &Client{ + handlers: make(map[uint64]chan *container), + pushHandlers: make(map[string][]chan *container), + + Error: make(chan error, 1), + quit: make(chan struct{}), + } + + c.transport = transport + go c.listen() + + return c, nil +} + +// NewClientWebSocket initialize a new client for remote server and connects to +// the remote server using WebSocket. +func NewClientWebSocket(ctx context.Context, url string, config *tls.Config) (*Client, error) { + transport, err := NewWebSocketTransport(ctx, url, config) + if err != nil { + return nil, err + } + + c := &Client{ + handlers: make(map[uint64]chan *container), + pushHandlers: make(map[string][]chan *container), + + Error: make(chan error, 1), + quit: make(chan struct{}), + } + + c.transport = transport + go c.listen() + + return c, nil +} + +// JSON-RPC 2.0 Error Object +// See: https://www.jsonrpc.org/specificationJSON#error_object +type apiErr struct { + Code int `json:"code"` + Message string `json:"message"` +} + +func (e *apiErr) Error() string { + return fmt.Sprintf("errNo: %d, errMsg: %s", e.Code, e.Message) +} + +// UnmarshalJSON defines a workaround for servers that respond with error +// that doesn't follow the JSON-RPC 2.0 Error Object format, i.e. electrs/esplora. +// See: https://github.com/Blockstream/esplora/issues/453 +func (e *apiErr) UnmarshalJSON(data []byte) error { + var v interface{} + if err := json.Unmarshal(data, &v); err != nil { + return fmt.Errorf("failed to unmarshal error [%s]: %v", data, err) + } + + switch v := v.(type) { + case string: + e.Message = v + case map[string]interface{}: + if code, ok := v["code"].(float64); ok { + e.Code = int(code) + } + + if _, ok := v["message"]; ok { + e.Message = fmt.Sprint(v["message"]) + } + default: + return fmt.Errorf("unsupported type: %v", v) + } + + return nil +} + +// JSON-RPC 2.0 Response Object +// See: https://www.jsonrpc.org/specification#response_object +type response struct { + ID uint64 `json:"id"` + Method string `json:"method"` + Error *apiErr `json:"error"` +} + +func (s *Client) listen() { + for { + if s.IsShutdown() { + break + } + if s.transport == nil { + break + } + + exit := func() (exit bool) { + // A hostile or malformed response must never propagate a panic + // out of the read loop goroutine; recover, log, and keep the + // loop running unless the client is shutting down anyway. + defer func() { + if r := recover(); r != nil { + log.Printf("recovered from panic while processing message: %v", r) + exit = s.IsShutdown() + } + }() + + select { + case <-s.quit: + return true + case err := <-s.transport.Errors(): + select { + case s.Error <- err: + default: + } + s.Shutdown() + return true + case bytes := <-s.transport.Responses(): + result := &container{ + content: bytes, + } + + msg := &response{} + err := json.Unmarshal(bytes, msg) + if err != nil { + if DebugMode { + log.Printf("unmarshal received message [%s] failed: [%v]", bytes, err) + } + result.err = fmt.Errorf("Unmarshal received message failed: %v", err) + } else if msg.Error != nil { + result.err = msg.Error + } + + if len(msg.Method) > 0 { + s.pushHandlersLock.RLock() + handlers := s.pushHandlers[msg.Method] + s.pushHandlersLock.RUnlock() + + for _, handler := range handlers { + select { + case handler <- result: + default: + } + } + } + + s.handlersLock.RLock() + c, ok := s.handlers[msg.ID] + s.handlersLock.RUnlock() + + if ok { + select { + case c <- result: + case <-s.quit: + return true + } + } + } + return false + }() + + if exit { + return + } + } +} + +func (s *Client) listenPush(method string) <-chan *container { + c := make(chan *container, 1) + s.pushHandlersLock.Lock() + s.pushHandlers[method] = append(s.pushHandlers[method], c) + s.pushHandlersLock.Unlock() + + return c +} + +type request struct { + ID uint64 `json:"id"` + Method string `json:"method"` + Params []interface{} `json:"params"` +} + +func (s *Client) request(ctx context.Context, method string, params []interface{}, v interface{}) error { + select { + case <-s.quit: + return ErrServerShutdown + default: + } + + msg := request{ + ID: atomic.AddUint64(&s.nextID, 1), + Method: method, + Params: params, + } + + bytes, err := json.Marshal(msg) + if err != nil { + return err + } + + bytes = append(bytes, nl) + + c := make(chan *container, 1) + + s.handlersLock.Lock() + s.handlers[msg.ID] = c + s.handlersLock.Unlock() + + defer func() { + s.handlersLock.Lock() + delete(s.handlers, msg.ID) + s.handlersLock.Unlock() + }() + + // Register the response handler before sending: a local or fast server can + // reply before SendMessage returns. + err = s.transport.SendMessage(bytes) + if err != nil { + s.Shutdown() + return err + } + + var resp *container + select { + case resp = <-c: + case <-ctx.Done(): + return ErrTimeout + case <-s.quit: + return ErrServerShutdown + } + + if resp.err != nil { + return resp.err + } + + if v != nil { + err = json.Unmarshal(resp.content, v) + if err != nil { + return err + } + } + + return nil +} + +// Abort interrupts outstanding reads and writes without a protocol close +// handshake. It is safe to call concurrently with an RPC or another shutdown. +func (s *Client) Abort() { + s.shutdownOnce.Do(func() { + close(s.quit) + _ = s.transport.Close() + }) +} + +func (s *Client) Shutdown() { + s.Abort() +} + +func (s *Client) IsShutdown() bool { + select { + case <-s.quit: + return true + default: + } + return false +} diff --git a/third_party/go-electrum/electrum/network_test.go b/third_party/go-electrum/electrum/network_test.go new file mode 100644 index 0000000000..a9694ca10b --- /dev/null +++ b/third_party/go-electrum/electrum/network_test.go @@ -0,0 +1,25 @@ +package electrum + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/require" +) + +// TestApiErrUnmarshalNonNumericCode regression-tests a server response whose +// error.code is not a JSON number (e.g. electrs/esplora sending a string +// error code instead of the JSON-RPC 2.0 integer). This previously panicked +// on an unchecked type assertion in apiErr.UnmarshalJSON. +func TestApiErrUnmarshalNonNumericCode(t *testing.T) { + raw := []byte(`{"error":{"code":"RPC_ERROR"}}`) + + var msg response + require.NotPanics(t, func() { + require.NoError(t, json.Unmarshal(raw, &msg)) + }) + + require.NotNil(t, msg.Error) + require.Zero(t, msg.Error.Code, "code must stay zero when the server sends a non-numeric value") + require.NotEmpty(t, msg.Error.Error(), "the resulting error must still be usable") +} diff --git a/third_party/go-electrum/electrum/scripthash.go b/third_party/go-electrum/electrum/scripthash.go new file mode 100644 index 0000000000..8a24830d96 --- /dev/null +++ b/third_party/go-electrum/electrum/scripthash.go @@ -0,0 +1,89 @@ +package electrum + +import "context" + +// GetBalanceResp represents the response to GetBalance(). +type GetBalanceResp struct { + Result GetBalanceResult `json:"result"` +} + +// GetBalanceResult represents the content of the result field in the response to GetBalance(). +type GetBalanceResult struct { + Confirmed float64 `json:"confirmed"` + Unconfirmed float64 `json:"unconfirmed"` +} + +// GetBalance returns the confirmed and unconfirmed balance for a scripthash. +// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-scripthash-get-balance +func (s *Client) GetBalance(ctx context.Context, scripthash string) (GetBalanceResult, error) { + var resp GetBalanceResp + + err := s.request(ctx, "blockchain.scripthash.get_balance", []interface{}{scripthash}, &resp) + if err != nil { + return GetBalanceResult{}, err + } + + return resp.Result, err +} + +// GetMempoolResp represents the response to GetHistory() and GetMempool(). +type GetMempoolResp struct { + Result []*GetMempoolResult `json:"result"` +} + +// GetMempoolResult represents the content of the result field in the response +// to GetHistory() and GetMempool(). +type GetMempoolResult struct { + Hash string `json:"tx_hash"` + Height int32 `json:"height"` + Fee uint32 `json:"fee,omitempty"` +} + +// GetHistory returns the confirmed and unconfirmed history for a scripthash. +func (s *Client) GetHistory(ctx context.Context, scripthash string) ([]*GetMempoolResult, error) { + var resp GetMempoolResp + + err := s.request(ctx, "blockchain.scripthash.get_history", []interface{}{scripthash}, &resp) + if err != nil { + return nil, err + } + + return resp.Result, err +} + +// GetMempool returns the unconfirmed transacations of a scripthash. +func (s *Client) GetMempool(ctx context.Context, scripthash string) ([]*GetMempoolResult, error) { + var resp GetMempoolResp + + err := s.request(ctx, "blockchain.scripthash.get_mempool", []interface{}{scripthash}, &resp) + if err != nil { + return nil, err + } + + return resp.Result, err +} + +// ListUnspentResp represents the response to ListUnspent() +type ListUnspentResp struct { + Result []*ListUnspentResult `json:"result"` +} + +// ListUnspentResult represents the content of the result field in the response to ListUnspent() +type ListUnspentResult struct { + Height int32 `json:"height"` + Position uint32 `json:"tx_pos"` + Hash string `json:"tx_hash"` + Value uint64 `json:"value"` +} + +// ListUnspent returns an ordered list of UTXOs for a scripthash. +func (s *Client) ListUnspent(ctx context.Context, scripthash string) ([]*ListUnspentResult, error) { + var resp ListUnspentResp + + err := s.request(ctx, "blockchain.scripthash.listunspent", []interface{}{scripthash}, &resp) + if err != nil { + return nil, err + } + + return resp.Result, err +} diff --git a/third_party/go-electrum/electrum/server.go b/third_party/go-electrum/electrum/server.go new file mode 100644 index 0000000000..ac30619a7d --- /dev/null +++ b/third_party/go-electrum/electrum/server.go @@ -0,0 +1,109 @@ +package electrum + +import "context" + +// Ping send a ping to the target server to ensure it is responding and +// keeping the session alive. +// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#server-ping +func (s *Client) Ping(ctx context.Context) error { + err := s.request(ctx, "server.ping", []interface{}{}, nil) + + return err +} + +// ServerAddPeer adds your new server into the remote server own peers list. +// This should not be used if you are a client. +// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#server-add-peer +func (s *Client) ServerAddPeer(ctx context.Context, features *ServerFeaturesResult) error { + var resp basicResp + + err := s.request(ctx, "server.add_peer", []interface{}{features}, &resp) + + return err +} + +// ServerBanner returns the banner for this remote server. +// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#server-banner +func (s *Client) ServerBanner(ctx context.Context) (string, error) { + var resp basicResp + + err := s.request(ctx, "server.banner", []interface{}{}, &resp) + + return resp.Result, err +} + +// ServerDonation returns the donation address for this remote server +// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#server-donation-address +func (s *Client) ServerDonation(ctx context.Context) (string, error) { + var resp basicResp + + err := s.request(ctx, "server.donation_address", []interface{}{}, &resp) + + return resp.Result, err +} + +type host struct { + TCPPort uint16 `json:"tcp_port,omitempty"` + SSLPort uint16 `json:"ssl_port,omitempty"` +} + +// ServerFeaturesResp represent the response to GetFeatures(). +type ServerFeaturesResp struct { + Result *ServerFeaturesResult `json:"result"` +} + +// ServerFeaturesResult represent the data sent or receive in RPC call "server.features" and +// "server.add_peer". +type ServerFeaturesResult struct { + GenesisHash string `json:"genesis_hash"` + Hosts map[string]host `json:"hosts"` + ProtocolMax string `json:"protocol_max"` + ProtocolMin string `json:"protocol_min"` + Pruning bool `json:"pruning,omitempty"` + ServerVersion string `json:"server_version"` + HashFunction string `json:"hash_function"` +} + +// ServerFeatures returns a list of features and services supported by the remote server. +// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#server-features +func (s *Client) ServerFeatures(ctx context.Context) (*ServerFeaturesResult, error) { + var resp ServerFeaturesResp + + err := s.request(ctx, "server.features", []interface{}{}, &resp) + + return resp.Result, err +} + +// ServerPeers returns a list of peers this remote server is aware of. +// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#server-peers-subscribe +func (s *Client) ServerPeers(ctx context.Context) (interface{}, error) { + resp := &struct { + Result [][]interface{} `json:"result"` + }{} + err := s.request(ctx, "server.peers.subscribe", []interface{}{}, &resp) + + return resp.Result, err +} + +// ServerVersionResp represent the response to ServerVersion(). +type ServerVersionResp struct { + Result [2]string `json:"result"` +} + +// ServerVersion identify the client to the server, and negotiate the protocol version. +// This call must be sent first, or the server will default to an older protocol version. +// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#server-version +func (s *Client) ServerVersion(ctx context.Context) (serverVer, protocolVer string, err error) { + var resp ServerVersionResp + + err = s.request(ctx, "server.version", []interface{}{ClientVersion, ProtocolVersion}, &resp) + if err != nil { + serverVer = "" + protocolVer = "" + } else { + serverVer = resp.Result[0] + protocolVer = resp.Result[1] + } + + return +} diff --git a/third_party/go-electrum/electrum/subscribe.go b/third_party/go-electrum/electrum/subscribe.go new file mode 100644 index 0000000000..157711f9f4 --- /dev/null +++ b/third_party/go-electrum/electrum/subscribe.go @@ -0,0 +1,286 @@ +package electrum + +import ( + "context" + "encoding/json" + "errors" + "sync" +) + +// SubscribeHeadersResp represent the response to SubscribeHeaders(). +type SubscribeHeadersResp struct { + Result *SubscribeHeadersResult `json:"result"` +} + +// SubscribeHeadersNotif represent the notification to SubscribeHeaders(). +type SubscribeHeadersNotif struct { + Params []*SubscribeHeadersResult `json:"params"` +} + +// SubscribeHeadersResult represents the content of the result field in the response to SubscribeHeaders(). +type SubscribeHeadersResult struct { + Height int32 `json:"height,omitempty"` + Hex string `json:"hex"` +} + +// SubscribeHeaders subscribes to receive block headers notifications when new blocks are found. +// +// BEWARE: This function can lead to a memory leak if the caller stops +// pulling from the returned channel. See the SubscribeHeadersSingle method +// for a safer alternative. +// +// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-headers-subscribe +func (s *Client) SubscribeHeaders(ctx context.Context) (<-chan *SubscribeHeadersResult, error) { + var resp SubscribeHeadersResp + + err := s.request(ctx, "blockchain.headers.subscribe", []interface{}{}, &resp) + if err != nil { + return nil, err + } + + respChan := make(chan *SubscribeHeadersResult, 1) + respChan <- resp.Result + + go func() { + for msg := range s.listenPush("blockchain.headers.subscribe") { + if msg.err != nil { + return + } + + var resp SubscribeHeadersNotif + + err := json.Unmarshal(msg.content, &resp) + if err != nil { + return + } + + for _, param := range resp.Params { + respChan <- param + } + } + }() + + return respChan, nil +} + +// SubscribeHeadersSingle subscribes to receive the header of the current +// blockchain tip. Unlike SubscribeHeaders, this method only returns the tip +// and does not listen for new block headers. +// +// Worth noting that this action still creates a new subscription in the Electrum +// server. The protocol does neither support a single-shot request for the +// current blockchain tip nor subscription cancellation. Although this limitation +// causes a slight resource overhead on the client, it does not cause a memory +// leak like the SubscribeHeaders method which spawns a goroutine that may hang +// on the channel if the caller is no longer pulling from it. +// +// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-headers-subscribe +func (s *Client) SubscribeHeadersSingle(ctx context.Context) ( + *SubscribeHeadersResult, + error, +) { + var resp SubscribeHeadersResp + + err := s.request( + ctx, + "blockchain.headers.subscribe", + []interface{}{}, + &resp, + ) + if err != nil { + return nil, err + } + + return resp.Result, nil +} + +// ScripthashSubscription ... +type ScripthashSubscription struct { + server *Client + notifChan chan *SubscribeNotif + + subscribedSH []string + scripthashMap map[string]string + + lock sync.RWMutex +} + +// SubscribeNotif represent the notification to SubscribeScripthash() and SubscribeMasternode(). +type SubscribeNotif struct { + Params [2]string `json:"params"` +} + +// SubscribeScripthash ... +func (s *Client) SubscribeScripthash() (*ScripthashSubscription, <-chan *SubscribeNotif) { + sub := &ScripthashSubscription{ + server: s, + notifChan: make(chan *SubscribeNotif, 1), + scripthashMap: make(map[string]string), + } + + go func() { + for msg := range s.listenPush("blockchain.scripthash.subscribe") { + if msg.err != nil { + return + } + + var resp SubscribeNotif + + err := json.Unmarshal(msg.content, &resp) + if err != nil { + return + } + + sub.lock.Lock() + for _, a := range sub.subscribedSH { + if a == resp.Params[0] { + sub.notifChan <- &resp + break + } + } + sub.lock.Unlock() + } + }() + + return sub, sub.notifChan +} + +// Add ... +func (sub *ScripthashSubscription) Add(ctx context.Context, scripthash string, address ...string) error { + var resp basicResp + + err := sub.server.request(ctx, "blockchain.scripthash.subscribe", []interface{}{scripthash}, &resp) + if err != nil { + return err + } + + if len(resp.Result) > 0 { + sub.notifChan <- &SubscribeNotif{[2]string{scripthash, resp.Result}} + } + + sub.lock.Lock() + sub.subscribedSH = append(sub.subscribedSH[:], scripthash) + if len(address) > 0 { + sub.scripthashMap[scripthash] = address[0] + } + sub.lock.Unlock() + + return nil +} + +// GetAddress ... +func (sub *ScripthashSubscription) GetAddress(scripthash string) (string, error) { + address, ok := sub.scripthashMap[scripthash] + if ok { + return address, nil + } + + return "", errors.New("scripthash not found in map") +} + +// GetScripthash ... +func (sub *ScripthashSubscription) GetScripthash(address string) (string, error) { + var found bool + var scripthash string + + for k, v := range sub.scripthashMap { + if v == address { + scripthash = k + found = true + } + } + + if found { + return scripthash, nil + } + + return "", errors.New("address not found in map") +} + +// GetChannel ... +func (sub *ScripthashSubscription) GetChannel() <-chan *SubscribeNotif { + return sub.notifChan +} + +// Remove ... +func (sub *ScripthashSubscription) Remove(scripthash string) error { + for i, v := range sub.subscribedSH { + if v == scripthash { + sub.lock.Lock() + sub.subscribedSH = append(sub.subscribedSH[:i], sub.subscribedSH[i+1:]...) + sub.lock.Unlock() + return nil + } + } + + return errors.New("scripthash not found") +} + +// RemoveAddress ... +func (sub *ScripthashSubscription) RemoveAddress(address string) error { + scripthash, err := sub.GetScripthash(address) + if err != nil { + return err + } + + for i, v := range sub.subscribedSH { + if v == scripthash { + sub.lock.Lock() + sub.subscribedSH = append(sub.subscribedSH[:i], sub.subscribedSH[i+1:]...) + delete(sub.scripthashMap, scripthash) + sub.lock.Unlock() + return nil + } + } + + return errors.New("scripthash not found") +} + +// Resubscribe ... +func (sub *ScripthashSubscription) Resubscribe(ctx context.Context) error { + for _, v := range sub.subscribedSH { + err := sub.Add(ctx, v) + if err != nil { + return err + } + } + + return nil +} + +// SubscribeMasternode subscribes to receive notifications when a masternode status changes. +// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-headers-subscribe +func (s *Client) SubscribeMasternode(ctx context.Context, collateral string) (<-chan string, error) { + var resp basicResp + + err := s.request(ctx, "blockchain.masternode.subscribe", []interface{}{collateral}, &resp) + if err != nil { + return nil, err + } + + respChan := make(chan string, 1) + if len(resp.Result) > 0 { + respChan <- resp.Result + } + + go func() { + for msg := range s.listenPush("blockchain.masternode.subscribe") { + if msg.err != nil { + return + } + + var resp SubscribeNotif + + err := json.Unmarshal(msg.content, &resp) + if err != nil { + return + } + + for _, param := range resp.Params { + respChan <- param + } + } + }() + + return respChan, nil +} diff --git a/third_party/go-electrum/electrum/transaction.go b/third_party/go-electrum/electrum/transaction.go new file mode 100644 index 0000000000..77cf184b10 --- /dev/null +++ b/third_party/go-electrum/electrum/transaction.go @@ -0,0 +1,157 @@ +package electrum + +import "context" + +// BroadcastTransaction sends a raw transaction to the remote server to +// be broadcasted on the server network. +// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-transaction-broadcast +func (s *Client) BroadcastTransaction(ctx context.Context, rawTx string) (string, error) { + resp := &basicResp{} + err := s.request(ctx, "blockchain.transaction.broadcast", []interface{}{rawTx}, &resp) + if err != nil { + return "", err + } + + return resp.Result, nil +} + +// GetTransactionResp represents the response to GetTransaction(). +type GetTransactionResp struct { + Result *GetTransactionResult `json:"result"` +} + +// GetTransactionResult represents the content of the result field in the response to GetTransaction(). +type GetTransactionResult struct { + Blockhash string `json:"blockhash"` + Blocktime uint64 `json:"blocktime"` + Confirmations int32 `json:"confirmations"` + Hash string `json:"hash"` + Hex string `json:"hex"` + Locktime uint32 `json:"locktime"` + Size uint32 `json:"size"` + Time uint64 `json:"time"` + Version uint32 `json:"version"` + Vin []Vin `json:"vin"` + Vout []Vout `json:"vout"` + Merkle GetMerkleProofResult `json:"merkle,omitempty"` // For protocol v1.5 and up. +} + +// Vin represents the input side of a transaction. +type Vin struct { + Coinbase string `json:"coinbase"` + ScriptSig *ScriptSig `json:"scriptsig"` + Sequence uint32 `json:"sequence"` + TxID string `json:"txid"` + Vout uint32 `json:"vout"` +} + +// ScriptSig represents the signature script for that transaction input. +type ScriptSig struct { + Asm string `json:"asm"` + Hex string `json:"hex"` +} + +// Vout represents the output side of a transaction. +type Vout struct { + N uint32 `json:"n"` + ScriptPubkey ScriptPubkey `json:"scriptpubkey"` + Value float64 `json:"value"` +} + +// ScriptPubkey represents the script of that transaction output. +type ScriptPubkey struct { + Addresses []string `json:"addresses,omitempty"` + Asm string `json:"asm"` + Hex string `json:"hex,omitempty"` + ReqSigs uint32 `json:"reqsigs,omitempty"` + Type string `json:"type"` +} + +// GetTransaction gets the detailed information for a transaction. +// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-transaction-get +func (s *Client) GetTransaction(ctx context.Context, txHash string) (*GetTransactionResult, error) { + var resp GetTransactionResp + + err := s.request(ctx, "blockchain.transaction.get", []interface{}{txHash, true}, &resp) + if err != nil { + return nil, err + } + + return resp.Result, nil +} + +// GetRawTransaction gets a raw encoded transaction. +// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-transaction-get +func (s *Client) GetRawTransaction(ctx context.Context, txHash string) (string, error) { + var resp basicResp + + err := s.request(ctx, "blockchain.transaction.get", []interface{}{txHash, false}, &resp) + if err != nil { + return "", err + } + + return resp.Result, nil +} + +// GetMerkleProofResp represents the response to GetMerkleProof(). +type GetMerkleProofResp struct { + Result *GetMerkleProofResult `json:"result"` +} + +// GetMerkleProofResult represents the content of the result field in the response to GetMerkleProof(). +type GetMerkleProofResult struct { + Merkle []string `json:"merkle"` + Height uint32 `json:"block_height"` + Position uint32 `json:"pos"` +} + +// GetMerkleProof returns the merkle proof for a confirmed transaction. +// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-transaction-get-merkle +func (s *Client) GetMerkleProof(ctx context.Context, txHash string, height uint32) (*GetMerkleProofResult, error) { + var resp GetMerkleProofResp + + err := s.request(ctx, "blockchain.transaction.get_merkle", []interface{}{txHash, height}, &resp) + if err != nil { + return nil, err + } + + return resp.Result, err +} + +// GetHashFromPosition returns the transaction hash for a specific position in a block. +// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-transaction-id-from-pos +func (s *Client) GetHashFromPosition(ctx context.Context, height, position uint32) (string, error) { + var resp basicResp + + err := s.request(ctx, "blockchain.transaction.id_from_pos", []interface{}{height, position, false}, &resp) + if err != nil { + return "", err + } + + return resp.Result, err +} + +// GetMerkleProofFromPosResp represents the response to GetMerkleProofFromPosition(). +type GetMerkleProofFromPosResp struct { + Result *GetMerkleProofFromPosResult `json:"result"` +} + +// GetMerkleProofFromPosResult represents the content of the result field in the response +// to GetMerkleProofFromPosition(). +type GetMerkleProofFromPosResult struct { + Hash string `json:"tx_hash"` + Merkle []string `json:"merkle"` +} + +// GetMerkleProofFromPosition returns the merkle proof for a specific position in a block. +// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-transaction-id-from-pos +func (s *Client) GetMerkleProofFromPosition(ctx context.Context, height, position uint32) (*GetMerkleProofFromPosResult, error) { + var resp GetMerkleProofFromPosResp + + err := s.request(ctx, "blockchain.transaction.id_from_pos", []interface{}{height, position, true}, &resp) + if err != nil { + return nil, err + } + + return resp.Result, err +} diff --git a/third_party/go-electrum/electrum/transport.go b/third_party/go-electrum/electrum/transport.go new file mode 100644 index 0000000000..732606d8ff --- /dev/null +++ b/third_party/go-electrum/electrum/transport.go @@ -0,0 +1,153 @@ +package electrum + +import ( + "bufio" + "context" + "crypto/tls" + "errors" + "fmt" + "log" + "net" + "sync" + "time" +) + +// TCPTransport store information about the TCP transport. +type TCPTransport struct { + conn net.Conn + responses chan []byte + errors chan error + done chan struct{} + closeOnce sync.Once +} + +// NewTCPTransport opens a new TCP connection to the remote server. +func NewTCPTransport(ctx context.Context, addr string) (*TCPTransport, error) { + var d net.Dialer + + conn, err := d.DialContext(ctx, "tcp", addr) + if err != nil { + return nil, err + } + + tcp := &TCPTransport{ + conn: conn, + responses: make(chan []byte), + errors: make(chan error), + done: make(chan struct{}), + } + + go tcp.listen() + + return tcp, nil +} + +// NewSSLTransport opens a new SSL connection to the remote server. +func NewSSLTransport(ctx context.Context, addr string, config *tls.Config) (*TCPTransport, error) { + dialer := tls.Dialer{ + NetDialer: &net.Dialer{}, + Config: config, + } + conn, err := dialer.DialContext(ctx, "tcp", addr) + if err != nil { + return nil, err + } + + tcp := &TCPTransport{ + conn: conn, + responses: make(chan []byte), + errors: make(chan error), + done: make(chan struct{}), + } + + go tcp.listen() + + return tcp, nil +} + +// ErrMessageTooLarge indicates a transport read was abandoned because it +// exceeded the configured per-message size limit (maxLineSize here, +// SetReadLimit for the WebSocket transport), distinguishing an oversized +// response from a generic transport failure. +var ErrMessageTooLarge = errors.New("line exceeds maximum size") + +// maxLineSize bounds a single line read from the transport. Without a limit, +// a server withholding the trailing newline could force unbounded buffering. +// Electrum protocol 1.4 has no response pagination, so long script +// histories, large UTXO lists, and raw tx hex can legitimately approach +// several MiB; the limit stays well above realistic response sizes. +const maxLineSize = 32 << 20 + +// readBoundedLine reads up to and including the next nl-terminated line, +// accumulating buffer-sized chunks across bufio.ErrBufferFull. It returns an +// error once the accumulated line exceeds limit, instead of buffering +// without bound. +func readBoundedLine(reader *bufio.Reader, limit int) ([]byte, error) { + var line []byte + for { + chunk, err := reader.ReadSlice(nl) + line = append(line, chunk...) + if len(line) > limit { + return nil, fmt.Errorf("%w: %d bytes", ErrMessageTooLarge, limit) + } + if err == nil { + return line, nil + } + if err != bufio.ErrBufferFull { + return nil, err + } + } +} + +func (t *TCPTransport) listen() { + defer t.Close() + reader := bufio.NewReader(t.conn) + + for { + line, err := readBoundedLine(reader, maxLineSize) + if err != nil { + select { + case t.errors <- err: + case <-t.done: + } + break + } + if DebugMode { + log.Printf("%s [debug] %s -> %s", time.Now().Format("2006-01-02 15:04:05"), t.conn.RemoteAddr(), line) + } + + select { + case t.responses <- line: + case <-t.done: + return + } + } +} + +// SendMessage sends a message to the remote server through the TCP transport. +func (t *TCPTransport) SendMessage(body []byte) error { + if DebugMode { + log.Printf("%s [debug] %s <- %s", time.Now().Format("2006-01-02 15:04:05"), t.conn.RemoteAddr(), body) + } + + _, err := t.conn.Write(body) + return err +} + +// Responses returns chan to TCP transport responses. +func (t *TCPTransport) Responses() <-chan []byte { + return t.responses +} + +// Errors returns chan to TCP transport errors. +func (t *TCPTransport) Errors() <-chan error { + return t.errors +} + +func (t *TCPTransport) Close() (err error) { + t.closeOnce.Do(func() { + close(t.done) + err = t.conn.Close() + }) + return err +} diff --git a/third_party/go-electrum/electrum/transport_ws.go b/third_party/go-electrum/electrum/transport_ws.go new file mode 100644 index 0000000000..b880a07cf0 --- /dev/null +++ b/third_party/go-electrum/electrum/transport_ws.go @@ -0,0 +1,123 @@ +package electrum + +import ( + "context" + "crypto/tls" + "errors" + "fmt" + "log" + "sync" + "time" + + "github.com/gorilla/websocket" +) + +type WebSocketTransport struct { + conn *websocket.Conn + responses chan []byte + errors chan error + done chan struct{} + closeOnce sync.Once +} + +// NewWebSocketTransport initializes new WebSocket transport. +func NewWebSocketTransport( + ctx context.Context, + url string, + tlsConfig *tls.Config, +) (*WebSocketTransport, error) { + dialer := websocket.Dialer{ + TLSClientConfig: tlsConfig, + } + + conn, response, err := dialer.DialContext(ctx, url, nil) + if err != nil { + if DebugMode { + log.Printf( + "%s [debug] connect -> status: %v, error: %v", + time.Now().Format("2006-01-02 15:04:05"), + response.Status, + err, + ) + } + return nil, err + } + + // Bound per-message allocation: without a limit, a hostile or buggy + // server can force unbounded reads via ReadMessage. + conn.SetReadLimit(32 << 20) + + ws := &WebSocketTransport{ + conn: conn, + responses: make(chan []byte), + errors: make(chan error), + done: make(chan struct{}), + } + + go ws.listen() + + return ws, nil +} + +func (t *WebSocketTransport) listen() { + defer t.Close() + + for { + _, msg, err := t.conn.ReadMessage() + if DebugMode { + log.Printf( + "%s [debug] %s -> msg: %s, err: %v", + time.Now().Format("2006-01-02 15:04:05"), + t.conn.RemoteAddr(), + msg, + err, + ) + } + if err != nil { + if errors.Is(err, websocket.ErrReadLimit) { + err = fmt.Errorf("%w: %v", ErrMessageTooLarge, err) + } + select { + case t.errors <- err: + case <-t.done: + } + + break + } + + select { + case t.responses <- msg: + case <-t.done: + return + } + } +} + +// SendMessage sends a message to the remote server through the WebSocket transport. +func (t *WebSocketTransport) SendMessage(body []byte) error { + if DebugMode { + log.Printf("%s [debug] %s <- %s", time.Now().Format("2006-01-02 15:04:05"), t.conn.RemoteAddr(), body) + } + + return t.conn.WriteMessage(websocket.TextMessage, body) +} + +// Responses returns chan to WebSocket transport responses. +func (t *WebSocketTransport) Responses() <-chan []byte { + return t.responses +} + +// Errors returns chan to WebSocket transport errors. +func (t *WebSocketTransport) Errors() <-chan error { + return t.errors +} + +// Close aborts the connection. Gorilla permits Conn.Close concurrently with +// reads and writes; WriteMessage cannot be used here while a writer is active. +func (t *WebSocketTransport) Close() (err error) { + t.closeOnce.Do(func() { + close(t.done) + err = t.conn.Close() + }) + return err +} diff --git a/third_party/go-electrum/go.mod b/third_party/go-electrum/go.mod new file mode 100644 index 0000000000..3c671037ff --- /dev/null +++ b/third_party/go-electrum/go.mod @@ -0,0 +1,23 @@ +module github.com/checksum0/go-electrum + +go 1.18 + +require ( + github.com/btcsuite/btcd v0.23.1 + github.com/btcsuite/btcd/btcutil v1.1.1 + github.com/gorilla/websocket v1.5.0 + github.com/stretchr/testify v1.7.0 +) + +require ( + github.com/btcsuite/btcd/btcec/v2 v2.1.3 // indirect + github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect + github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect + golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed // indirect + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect +) diff --git a/third_party/go-electrum/go.sum b/third_party/go-electrum/go.sum new file mode 100644 index 0000000000..6f95641823 --- /dev/null +++ b/third_party/go-electrum/go.sum @@ -0,0 +1,107 @@ +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= +github.com/btcsuite/btcd v0.23.1 h1:IB8cVQcC2X5mHbnfirLG5IZnkWYNTPlLZVrxUYSotbE= +github.com/btcsuite/btcd v0.23.1/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= +github.com/btcsuite/btcd/btcec/v2 v2.1.1/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= +github.com/btcsuite/btcd/btcec/v2 v2.1.3 h1:xM/n3yIhHAhHy04z4i43C8p4ehixJZMsnrVJkgl+MTE= +github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= +github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= +github.com/btcsuite/btcd/btcutil v1.1.1 h1:hDcDaXiP0uEzR8Biqo2weECKqEw0uHDZ9ixIWevVQqY= +github.com/btcsuite/btcd/btcutil v1.1.1/go.mod h1:nbKlBMNm9FGsdvKvu0essceubPiAcI57pYBNnsLAa34= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= +github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed h1:J22ig1FUekjjkmZUM7pTKixYm8DvrYsvrBZdunYeIuQ= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tools.go b/tools.go index e0dacdde1c..40225ad7d2 100644 --- a/tools.go +++ b/tools.go @@ -1,8 +1,9 @@ //go:build tools -// tools.go: Build-time dependencies required for Ethereum bindings generation -// These are imported to ensure they remain in go.mod and go.sum even though -// they're not directly used in the runtime code. +// tools.go pins build-time-only dependencies that would otherwise be dropped +// by `go mod tidy`. They are anchored here with blank imports so they remain in +// go.mod and go.sum for reproducible builds, even though they are not +// referenced directly by runtime or generated code. package tools import ( diff --git a/tools/generators/ethereum/command.go.tmpl b/tools/generators/ethereum/command.go.tmpl new file mode 100644 index 0000000000..938bbbfa21 --- /dev/null +++ b/tools/generators/ethereum/command.go.tmpl @@ -0,0 +1,298 @@ +// Code generated - DO NOT EDIT. +// This file is a generated command and any manual changes will be lost. + +package cmd + +import ( + "sync" + + "{{.HostChainModule}}/common" + "{{.HostChainModule}}/common/hexutil" + "{{.HostChainModule}}/core/types" + "{{.HostChainModule}}/ethclient" + + chainutil "{{.ChainUtilPackage}}" + "github.com/keep-network/keep-core/pkg/cmd" +{{if .UsesDecode}} + "github.com/keep-network/keep-core/pkg/decode" +{{end}} +{{if .GenPackage}} + "{{.GenPackage}}/abi" + "{{.GenPackage}}/contract" +{{end}} + + "github.com/spf13/cobra" +) + +var {{.Class}}Command *cobra.Command + +var {{.FullVar}}Description = `The {{.DashedName}} command allows calling the {{.Class}} contract on an + Ethereum network. It has subcommands corresponding to each contract method, + which respectively each take parameters based on the contract method's + parameters. + + Subcommands will submit a non-mutating call to the network and output the + result. + + All subcommands can be called against a specific block by passing the + -b/--block flag. + + Subcommands for mutating methods may be submitted as a mutating transaction + by passing the -s/--submit flag. In this mode, this command will terminate + successfully once the transaction has been submitted, but will not wait for + the transaction to be included in a block. They return the transaction hash. + + Calls that require ether to be paid will get 0 ether by default, which can + be changed by passing the -v/--value flag.` + +func init() { + {{.Class}}Command := &cobra.Command{ + Use: "{{.DashedName}}", + Short: `Provides access to the {{.Class}} contract.`, + Long: {{.FullVar}}Description, + } + + {{.Class}}Command.AddCommand( + {{- $contract := . -}} + {{- range $i, $method := .ConstMethods }} + {{- if $method.CommandCallable }} + {{$contract.ShortVar}}{{$method.CapsName}}Command(), + {{- end -}} + {{- end -}} + {{- range $i, $method := .NonConstMethods }} + {{- if $method.CommandCallable }} + {{$contract.ShortVar}}{{$method.CapsName}}Command(), + {{- end -}} + {{- end }} + ) + + ModuleCommand.AddCommand({{.Class}}Command) +} + +/// ------------------- Const methods ------------------- + +{{- $contract := . -}} +{{- range $i, $method := .ConstMethods -}} +{{- if $method.CommandCallable }} + +func {{$contract.ShortVar}}{{$method.CapsName}}Command() *cobra.Command { + c := &cobra.Command{ + Use: "{{$method.DashedName}}{{ range $i, $param := $method.CmdArgInfos }} [{{$param.Name}}]{{ end }}", + Short: "Calls the {{$method.Modifiers -}} method {{$method.LowerName}} on the {{$contract.Class}} contract.", + Args: cmd.ArgCountChecker({{$method.CmdArgInfos | len}}), + RunE: {{$contract.ShortVar}}{{$method.CapsName}}, + SilenceUsage: true, + DisableFlagsInUseLine: true, + } + + cmd.InitConstFlags(c) + + return c +} + +func {{$contract.ShortVar}}{{$method.CapsName}}(c *cobra.Command, args []string) error { + contract, err := initialize{{$contract.Class}}(c) + if err != nil { + return err + } + + {{ range $i, $param := .CmdArgInfos }} + {{ if $param.Structured }} + {{ $param.Name }} := {{ $param.GoType }}{} + if err:= json.Unmarshal([]byte(args[{{ $i }}]), &{{ $param.Name }}); err != nil { + return fmt.Errorf("failed to unmarshal {{ $param.Name }} to {{ $param.GoType }}: %w", err) + } + {{- else -}} + {{ $param.Name }}, err := {{ printf "args[%d]" $i | printf $param.ParsingFn }} + if err != nil { + return fmt.Errorf( + "couldn't parse parameter {{$param.Name}}, a {{$param.Type}}, from passed value %v", + args[{{$i}}], + ) + } + {{- end }} + {{- end }} + + result, err := contract.{{$method.CapsName}}AtBlock( + {{- range $i, $param := .CmdArgInfos }} + {{ $param.Name }}, + {{- end }} + cmd.BlockFlagValue.Int, + ) + + if err != nil { + return err + } + + cmd.PrintOutput(result) + + return nil +} + +{{- end -}} +{{- end }} + +/// ------------------- Non-const methods ------------------- + +{{- range $i, $method := .NonConstMethods -}} +{{- if $method.CommandCallable }} + +func {{$contract.ShortVar}}{{$method.CapsName}}Command() *cobra.Command { + c := &cobra.Command{ + Use: "{{$method.DashedName}}{{ range $i, $param := $method.CmdArgInfos }} [{{$param.Name}}]{{ end }}", + Short: "Calls the {{$method.Modifiers -}} method {{$method.LowerName}} on the {{$contract.Class}} contract.", + Args: cmd.ArgCountChecker({{$method.CmdArgInfos | len}}), + RunE: {{$contract.ShortVar}}{{$method.CapsName}}, + SilenceUsage: true, + DisableFlagsInUseLine: true, + } + + {{if $method.Payable -}} + c.PreRunE = cmd.PayableArgsChecker + cmd.InitPayableFlags(c) + {{- else -}} + c.PreRunE = cmd.NonConstArgsChecker + cmd.InitNonConstFlags(c) + {{- end }} + + return c +} + +func {{$contract.ShortVar}}{{$method.CapsName}}(c *cobra.Command, args []string) error { + contract, err := initialize{{$contract.Class}}(c) + if err != nil { + return err + } + + {{ range $i, $param := .CmdArgInfos }} + {{ if $param.Structured }} + {{ $param.Name }} := {{ $param.GoType }}{} + if err:= json.Unmarshal([]byte(args[{{ $i }}]), &{{ $param.Name }}); err != nil { + return fmt.Errorf("failed to unmarshal {{ $param.Name }} to {{ $param.GoType }}: %w", err) + } + {{- else -}} + {{ $param.Name }}, err := {{ printf "args[%d]" $i | printf $param.ParsingFn }} + if err != nil { + return fmt.Errorf( + "couldn't parse parameter {{$param.Name}}, a {{$param.Type}}, from passed value %v", + args[{{$i}}], + ) + } + {{- end }} + {{- end }} + + var ( + transaction *types.Transaction + {{ if gt (len $method.Return.Type) 0 -}} + result {{$method.Return.Type}} + {{ end -}} + ) + + if shouldSubmit, _ := c.Flags().GetBool(cmd.SubmitFlag); shouldSubmit { + // Do a regular submission. Take payable into account. + transaction, err = contract.{{$method.CapsName}}( + {{- range $i, $param := .CmdArgInfos }} + {{ $param.Name }}, + {{- end }} + {{- if $method.Payable }} + cmd.ValueFlagValue.Int(), + {{- end }} + ) + if err != nil { + return err + } + + cmd.PrintOutput(transaction.Hash()) + } else { + // Do a call. + {{ if gt (len $method.Return.Type) 0 -}} result, {{ end -}} err = contract.Call{{$method.CapsName}}( + {{- range $i, $param := .CmdArgInfos }} + {{ $param.Name }}, + {{- end }} + {{- if $method.Payable }} + cmd.ValueFlagValue.Int(), + {{- end }} + cmd.BlockFlagValue.Int, + ) + if err != nil { + return err + } + + {{ if gt (len $method.Return.Type) 0 -}} + cmd.PrintOutput(result) + {{- else -}} + cmd.PrintOutput("success") + {{- end }} + + cmd.PrintOutput( + "the transaction was not submitted to the chain; " + + "please add the `--submit` flag", + ) + } + + return nil +} + +{{- end -}} +{{- end }} + +/// ------------------- Initialization ------------------- + +func initialize{{.Class}}(c *cobra.Command) (*contract.{{.Class}}, error) { + cfg := *ModuleCommand.GetConfig() + + client, err := ethclient.Dial(cfg.URL) + if err != nil { + return nil, fmt.Errorf("error connecting to host chain node: [%v]", err) + } + + chainID, err := client.ChainID(context.Background()) + if err != nil { + return nil, fmt.Errorf( + "failed to resolve host chain id: [%v]", + err, + ) + } + + key, err := chainutil.DecryptKeyFile( + cfg.Account.KeyFile, + cfg.Account.KeyFilePassword, + ) + if err != nil { + return nil, fmt.Errorf( + "failed to read KeyFile: %s: [%v]", + cfg.Account.KeyFile, + err, + ) + } + + miningWaiter := chainutil.NewMiningWaiter(client, cfg) + + blockCounter, err := chainutil.NewBlockCounter(client) + if err != nil { + return nil, fmt.Errorf( + "failed to create block counter: [%v]", + err, + ) + } + + address, err := cfg.ContractAddress("{{.Class}}") + if err != nil { + return nil, fmt.Errorf( + "failed to get %s address: [%w]", + "{{.Class}}", + err, + ) + } + + return contract.New{{.Class}}( + address, + chainID, + key, + client, + chainutil.NewNonceManager(client, key.Address), + miningWaiter, + blockCounter, + &sync.Mutex{}, + ) +} diff --git a/tools/generators/ethereum/command_template_content.go b/tools/generators/ethereum/command_template_content.go new file mode 100644 index 0000000000..6bc9a85e54 --- /dev/null +++ b/tools/generators/ethereum/command_template_content.go @@ -0,0 +1,302 @@ +package main + +// commandTemplateContent contains the template string from command.go.tmpl +var commandTemplateContent = `// Code generated - DO NOT EDIT. +// This file is a generated command and any manual changes will be lost. + +package cmd + +import ( + "sync" + + "{{.HostChainModule}}/common" + "{{.HostChainModule}}/common/hexutil" + "{{.HostChainModule}}/core/types" + "{{.HostChainModule}}/ethclient" + + chainutil "{{.ChainUtilPackage}}" + "github.com/keep-network/keep-core/pkg/cmd" +{{if .UsesDecode}} + "github.com/keep-network/keep-core/pkg/decode" +{{end}} +{{if .GenPackage}} + "{{.GenPackage}}/abi" + "{{.GenPackage}}/contract" +{{end}} + + "github.com/spf13/cobra" +) + +var {{.Class}}Command *cobra.Command + +var {{.FullVar}}Description = ` + "`" + `The {{.DashedName}} command allows calling the {{.Class}} contract on an + Ethereum network. It has subcommands corresponding to each contract method, + which respectively each take parameters based on the contract method's + parameters. + + Subcommands will submit a non-mutating call to the network and output the + result. + + All subcommands can be called against a specific block by passing the + -b/--block flag. + + Subcommands for mutating methods may be submitted as a mutating transaction + by passing the -s/--submit flag. In this mode, this command will terminate + successfully once the transaction has been submitted, but will not wait for + the transaction to be included in a block. They return the transaction hash. + + Calls that require ether to be paid will get 0 ether by default, which can + be changed by passing the -v/--value flag.` + "`" + ` + +func init() { + {{.Class}}Command := &cobra.Command{ + Use: "{{.DashedName}}", + Short: ` + "`" + `Provides access to the {{.Class}} contract.` + "`" + `, + Long: {{.FullVar}}Description, + } + + {{.Class}}Command.AddCommand( + {{- $contract := . -}} + {{- range $i, $method := .ConstMethods }} + {{- if $method.CommandCallable }} + {{$contract.ShortVar}}{{$method.CapsName}}Command(), + {{- end -}} + {{- end -}} + {{- range $i, $method := .NonConstMethods }} + {{- if $method.CommandCallable }} + {{$contract.ShortVar}}{{$method.CapsName}}Command(), + {{- end -}} + {{- end }} + ) + + ModuleCommand.AddCommand({{.Class}}Command) +} + +/// ------------------- Const methods ------------------- + +{{- $contract := . -}} +{{- range $i, $method := .ConstMethods -}} +{{- if $method.CommandCallable }} + +func {{$contract.ShortVar}}{{$method.CapsName}}Command() *cobra.Command { + c := &cobra.Command{ + Use: "{{$method.DashedName}}{{ range $i, $param := $method.CmdArgInfos }} [{{$param.Name}}]{{ end }}", + Short: "Calls the {{$method.Modifiers -}} method {{$method.LowerName}} on the {{$contract.Class}} contract.", + Args: cmd.ArgCountChecker({{$method.CmdArgInfos | len}}), + RunE: {{$contract.ShortVar}}{{$method.CapsName}}, + SilenceUsage: true, + DisableFlagsInUseLine: true, + } + + cmd.InitConstFlags(c) + + return c +} + +func {{$contract.ShortVar}}{{$method.CapsName}}(c *cobra.Command, args []string) error { + contract, err := initialize{{$contract.Class}}(c) + if err != nil { + return err + } + + {{ range $i, $param := .CmdArgInfos }} + {{ if $param.Structured }} + {{ $param.Name }} := {{ $param.GoType }}{} + if err:= json.Unmarshal([]byte(args[{{ $i }}]), &{{ $param.Name }}); err != nil { + return fmt.Errorf("failed to unmarshal {{ $param.Name }} to {{ $param.GoType }}: %w", err) + } + {{- else -}} + {{ $param.Name }}, err := {{ printf "args[%d]" $i | printf $param.ParsingFn }} + if err != nil { + return fmt.Errorf( + "couldn't parse parameter {{$param.Name}}, a {{$param.Type}}, from passed value %v", + args[{{$i}}], + ) + } + {{- end }} + {{- end }} + + result, err := contract.{{$method.CapsName}}AtBlock( + {{- range $i, $param := .CmdArgInfos }} + {{ $param.Name }}, + {{- end }} + cmd.BlockFlagValue.Int, + ) + + if err != nil { + return err + } + + cmd.PrintOutput(result) + + return nil +} + +{{- end -}} +{{- end }} + +/// ------------------- Non-const methods ------------------- + +{{- range $i, $method := .NonConstMethods -}} +{{- if $method.CommandCallable }} + +func {{$contract.ShortVar}}{{$method.CapsName}}Command() *cobra.Command { + c := &cobra.Command{ + Use: "{{$method.DashedName}}{{ range $i, $param := $method.CmdArgInfos }} [{{$param.Name}}]{{ end }}", + Short: "Calls the {{$method.Modifiers -}} method {{$method.LowerName}} on the {{$contract.Class}} contract.", + Args: cmd.ArgCountChecker({{$method.CmdArgInfos | len}}), + RunE: {{$contract.ShortVar}}{{$method.CapsName}}, + SilenceUsage: true, + DisableFlagsInUseLine: true, + } + + {{if $method.Payable -}} + c.PreRunE = cmd.PayableArgsChecker + cmd.InitPayableFlags(c) + {{- else -}} + c.PreRunE = cmd.NonConstArgsChecker + cmd.InitNonConstFlags(c) + {{- end }} + + return c +} + +func {{$contract.ShortVar}}{{$method.CapsName}}(c *cobra.Command, args []string) error { + contract, err := initialize{{$contract.Class}}(c) + if err != nil { + return err + } + + {{ range $i, $param := .CmdArgInfos }} + {{ if $param.Structured }} + {{ $param.Name }} := {{ $param.GoType }}{} + if err:= json.Unmarshal([]byte(args[{{ $i }}]), &{{ $param.Name }}); err != nil { + return fmt.Errorf("failed to unmarshal {{ $param.Name }} to {{ $param.GoType }}: %w", err) + } + {{- else -}} + {{ $param.Name }}, err := {{ printf "args[%d]" $i | printf $param.ParsingFn }} + if err != nil { + return fmt.Errorf( + "couldn't parse parameter {{$param.Name}}, a {{$param.Type}}, from passed value %v", + args[{{$i}}], + ) + } + {{- end }} + {{- end }} + + var ( + transaction *types.Transaction + {{ if gt (len $method.Return.Type) 0 -}} + result {{$method.Return.Type}} + {{ end -}} + ) + + if shouldSubmit, _ := c.Flags().GetBool(cmd.SubmitFlag); shouldSubmit { + // Do a regular submission. Take payable into account. + transaction, err = contract.{{$method.CapsName}}( + {{- range $i, $param := .CmdArgInfos }} + {{ $param.Name }}, + {{- end }} + {{- if $method.Payable }} + cmd.ValueFlagValue.Int(), + {{- end }} + ) + if err != nil { + return err + } + + cmd.PrintOutput(transaction.Hash()) + } else { + // Do a call. + {{ if gt (len $method.Return.Type) 0 -}} result, {{ end -}} err = contract.Call{{$method.CapsName}}( + {{- range $i, $param := .CmdArgInfos }} + {{ $param.Name }}, + {{- end }} + {{- if $method.Payable }} + cmd.ValueFlagValue.Int(), + {{- end }} + cmd.BlockFlagValue.Int, + ) + if err != nil { + return err + } + + {{ if gt (len $method.Return.Type) 0 -}} + cmd.PrintOutput(result) + {{- else -}} + cmd.PrintOutput("success") + {{- end }} + + cmd.PrintOutput( + "the transaction was not submitted to the chain; " + + "please add the ` + "`" + `--submit` + "`" + ` flag", + ) + } + + return nil +} + +{{- end -}} +{{- end }} + +/// ------------------- Initialization ------------------- + +func initialize{{.Class}}(c *cobra.Command) (*contract.{{.Class}}, error) { + cfg := *ModuleCommand.GetConfig() + + client, err := ethclient.Dial(cfg.URL) + if err != nil { + return nil, fmt.Errorf("error connecting to host chain node: [%v]", err) + } + + chainID, err := client.ChainID(context.Background()) + if err != nil { + return nil, fmt.Errorf( + "failed to resolve host chain id: [%v]", + err, + ) + } + + key, err := chainutil.DecryptKeyFile( + cfg.Account.KeyFile, + cfg.Account.KeyFilePassword, + ) + if err != nil { + return nil, fmt.Errorf( + "failed to read KeyFile: %s: [%v]", + cfg.Account.KeyFile, + err, + ) + } + + miningWaiter := chainutil.NewMiningWaiter(client, cfg) + + blockCounter, err := chainutil.NewBlockCounter(client) + if err != nil { + return nil, fmt.Errorf( + "failed to create block counter: [%v]", + err, + ) + } + + address, err := cfg.ContractAddress("{{.Class}}") + if err != nil { + return nil, fmt.Errorf( + "failed to get %s address: [%w]", + "{{.Class}}", + err, + ) + } + + return contract.New{{.Class}}( + address, + chainID, + key, + client, + chainutil.NewNonceManager(client, key.Address), + miningWaiter, + blockCounter, + &sync.Mutex{}, + ) +} +` diff --git a/tools/generators/ethereum/contract.go b/tools/generators/ethereum/contract.go new file mode 100644 index 0000000000..ef61628f63 --- /dev/null +++ b/tools/generators/ethereum/contract.go @@ -0,0 +1,281 @@ +// The *_template_content.go files in this package are baked from their +// matching *.go.tmpl sources by tools/generators/template. They are +// committed, static artifacts, not regenerated as part of routine builds - +// intentionally NOT wired up via //go:generate, since `make generate` runs +// `go generate ./...` repo-wide and doing so would require pkg/generate to +// be present in every build context that runs codegen (e.g. the Docker +// image build, which copies in only this package and the gen/ directories +// that consume it). After editing a .tmpl file, re-bake manually by running, +// for each changed template, from this directory: +// +// go run github.com/keep-network/keep-core/tools/generators/template \ +//